/*
 * TProgram.cc
 *
 * Turbo Vision - Version 2.0
 *
 * Copyright (c) 1994 by Borland International
 * All Rights Reserved.
 *
 * Modified by Sergio Sigala <sergio@sigala.it>
 */

#define Uses_TKeys
#define Uses_TProgram
#define Uses_TEvent
#define Uses_TScreen
#define Uses_TStatusLine
#define Uses_TMenu
#define Uses_TGroup
#define Uses_TDeskTop
#define Uses_TEventQueue
#define Uses_TMenuBar
#define Uses_TStatusDef
#define Uses_TStatusItem
#define Uses_TDialog
#include <tvision/tv.h>

// Public variables

TStatusLine * TProgram::statusLine = 0;
TMenuBar * TProgram::menuBar = 0;
TDeskTop * TProgram::deskTop = 0;
TProgram * TProgram::application = 0;
int TProgram::appPalette = apColor;
TEvent TProgram::pending;

extern TPoint shadowSize;

TProgInit::TProgInit( TStatusLine *(*cStatusLine)( TRect ),
                            TMenuBar *(*cMenuBar)( TRect ),
                            TDeskTop *(*cDeskTop )( TRect )
                          ) :
    createStatusLine( cStatusLine ),
    createMenuBar( cMenuBar ),
    createDeskTop( cDeskTop )
{
}


TProgram::TProgram() :
    TProgInit( &TProgram::initStatusLine,
                  &TProgram::initMenuBar,
                  &TProgram::initDeskTop
                ),
    TGroup( TRect( 0,0,TScreen::screenWidth,TScreen::screenHeight ) )
{
    application = this;
    initScreen();
    state = sfVisible | sfSelected | sfFocused | sfModal | sfExposed;
    options = 0;
    buffer = TScreen::screenBuffer;

    if( createDeskTop != 0 &&
        (deskTop = createDeskTop( getExtent() )) != 0
      )
        insert(deskTop);

    if( createStatusLine != 0 &&
        (statusLine = createStatusLine( getExtent() )) != 0
      )
        insert(statusLine);

    if( createMenuBar != 0 &&
        (menuBar = createMenuBar( getExtent() )) != 0
      )
        insert(menuBar);

}

TProgram::~TProgram()
{
    application = 0;
}

void TProgram::shutDown()
{
    statusLine = 0;
    menuBar = 0;
    deskTop = 0;
    TGroup::shutDown();
}

Boolean TProgram::canMoveFocus()
{
    return deskTop->valid(cmReleasedFocus);
}

ushort TProgram::executeDialog( TDialog* pD, void* data )
{
    ushort c=cmCancel;

    if (validView(pD))
        {
        if (data)
        pD->setData(data);
        c = deskTop->execView(pD);
        if ((c != cmCancel) && (data))
            pD->getData(data);
        destroy(pD);
        }

    return c;
}

/*
 * This patch works around a "GOT relocation burb" under FreeBSD.  The actual
 * bug is in gcc-2.7.2.1, but there is no easy fix for it there.
 * Patch from: John Polstra <jdp@polstra.com>
 * Date: Wed, 28 May 1997 22:08:59 -0700
 */
#ifdef __FreeBSD__
static Boolean hasMouse( TView *p, void *s )
#else
inline Boolean hasMouse( TView *p, void *s )
#endif
{
    return Boolean( (p->state & sfVisible) != 0 &&
                     p->mouseInView( ((TEvent *)s)->mouse.where ));
}

void TProgram::getEvent(TEvent& event)
{
    if( pending.what != evNothing )
        {
        event = pending;
        pending.what = evNothing;
        }
    else
        {
		/* SS: changed */

		TScreen::getEvent(event);
		if (event.what == evCommand) switch (event.message.command)
		{
		case cmSysRepaint:
			/*
			 * This command redraws the screen.  Useful when the
			 * user restarts the process after a ctrl-z.
			 */
			redraw();
			clearEvent(event);
			break;
		case cmSysResize:
			/*
			 * Generated after a SIGWINCH signal.
			 */
			buffer = TScreen::screenBuffer;
			changeBounds(TRect(0, 0, TScreen::screenWidth,
				TScreen::screenHeight));
			setState(sfExposed, False);
			setState(sfExposed, True);
			redraw();
			clearEvent(event);
			break;
		case cmSysWakeup:
			idle();
			clearEvent(event);
		}
        }

    if( statusLine != 0 )
        {
        if( (event.what & evKeyDown) != 0 ||
            ( (event.what & evMouseDown) != 0 &&
              firstThat( hasMouse, &event ) == statusLine
            )
          )
            statusLine->handleEvent( event );
        }
}

TPalette& TProgram::getPalette() const
{
    static TPalette color ( cpAppColor, sizeof( cpAppColor )-1 );
    static TPalette blackwhite(cpAppBlackWhite, sizeof( cpAppBlackWhite )-1 );
    static TPalette monochrome(cpAppMonochrome, sizeof( cpAppMonochrome )-1 );
    static TPalette *palettes[] =
        {
        &color,
        &blackwhite,
        &monochrome
        };
    return *(palettes[appPalette]);
}

void TProgram::handleEvent( TEvent& event )
{
    if( event.what == evKeyDown )
        {
        char c = getAltChar( event.keyDown.keyCode );
        if( c >= '1' && c <= '9' )
            {
#ifndef __UNPATCHED
            if(canMoveFocus())      //<--- Check valid first.
            {
                if( message(deskTop, evBroadcast, cmSelectWindowNum,
                  (void *)(c - '0')) != 0 )
                    clearEvent( event );
            }
            else
                clearEvent(event);
#else
            if( message( deskTop,
                         evBroadcast,
                         cmSelectWindowNum,
                         (void *)(c - '0')
                       ) != 0 )
                clearEvent( event );
#endif
            }
        }
    TGroup::handleEvent( event );
    if( event.what == evCommand && event.message.command == cmQuit )
        {
        endModal( cmQuit );
        clearEvent( event );
        }
}

void TProgram::idle()
{
    if( statusLine != 0 )
        statusLine->update();

    if( commandSetChanged == True )
        {
        message( this, evBroadcast, cmCommandSetChanged, 0 );
        commandSetChanged = False;
        }
}

TDeskTop *TProgram::initDeskTop( TRect r )
{
    r.a.y++;
    r.b.y--;
    return new TDeskTop( r );
}

TMenuBar *TProgram::initMenuBar( TRect r )
{
    r.b.y = r.a.y + 1;
    return new TMenuBar( r, (TMenu *)0 );
}

void TProgram::initScreen()
{
    if( (TScreen::screenMode & 0x00FF) != TDisplay::smMono )
        {
        if( (TScreen::screenMode & TDisplay::smFont8x8) != 0 )
            shadowSize.x = 1;
        else
            shadowSize.x = 2;
        shadowSize.y = 1;
        showMarkers = False;
        if( (TScreen::screenMode & 0x00FF) == TDisplay::smBW80 )
            appPalette = apBlackWhite;
        else
            appPalette = apColor;
        }
    else
        {

        shadowSize.x = 0;
        shadowSize.y = 0;
        showMarkers = True;
        appPalette = apMonochrome;
        }
}

TStatusLine *TProgram::initStatusLine( TRect r )
{
    r.a.y = r.b.y - 1;
    return new TStatusLine( r,
        *new TStatusDef( 0, 0xFFFF ) +
            *new TStatusItem( exitText, kbAltX, cmQuit ) +
            *new TStatusItem( 0, kbF10, cmMenu ) +
            *new TStatusItem( 0, kbAltF3, cmClose ) +
            *new TStatusItem( 0, kbF5, cmZoom ) +
            *new TStatusItem( 0, kbCtrlF5, cmResize )
            );
}

TWindow* TProgram::insertWindow(TWindow* pWin)
{
    if (validView(pWin))
        if (canMoveFocus())
            {
            deskTop->insert(pWin);
            return pWin;
            }
        else
            destroy(pWin);

   return NULL;
}

void TProgram::putEvent( TEvent & event )
{
    pending = event;
}

void TProgram::run()
{
    execute();
}

void TProgram::setScreenMode( ushort )
{
    /* SS: changed */

    TRect r = TRect( 0, 0, TScreen::screenWidth, TScreen::screenHeight );
    changeBounds( r );
    setState(sfExposed, False);
    setState(sfExposed, True);
    redraw();
}

TView* TProgram::validView(TView* p)
{
    if( p == 0 )
        return 0;
    if( !p->valid( cmValid ) )
        {
        destroy( p );
        return 0;
        }
    return p;
}


syntax highlighted by Code2HTML, v. 0.9.1