/**[txh]******************************************************************** Copyright (c) 2002 José Angel Sánchez Caso (JASC) skeletons by Salvador E. Tropea (SET) Description: Windows GUI Display routines. ***************************************************************************/ #include #define Uses_stdio #define Uses_stdlib #define Uses_TDisplay #define Uses_TScreen #define Uses_TEvent #define Uses_TGKey #define Uses_TMouse #define Uses_TProgram #define Uses_TVCodePage #define Uses_TDeskTop #define Uses_TRect #define Uses_TDialog #define Uses_TSItem // JASC, ago 2002 #define Uses_TCheckBoxes // JASC, ago 2002 #define Uses_TRadioButtons // JASC, ago 2002 #define Uses_TButton // JASC, ago 2002 #define Uses_TLabel // JASC, ago 2002 #include #if defined(TVOS_Win32) && !defined(TV_Disable_WinGr_Driver) #define WIN32_LEAN_AND_MEAN #include #include #include #include const int maxTitleSize= 256; char TDisplayWinGr::cShapeFr; char TDisplayWinGr::cShapeTo; unsigned TDisplayWinGr::xPos= UINT_MAX; /* X axis of the cursor */ unsigned TDisplayWinGr::yPos= UINT_MAX; /* Y axis of the cursor */ unsigned TDisplayWinGr::zPos; /* Z axis of the cursor (means size )*/ int TDisplayWinGr::sizeChanged= 0; /* Resizinf counter */ int TDisplayWinGr::forceRedraw= 0; TEvent TDisplayWinGr::storedEvent; /* Correctly processes message queue */ HWND TDisplayWinGr::hwnd= NULL; /* Main window handler */ HFONT TDisplayWinGr::hFont; /* Font properties */ HDC TDisplayWinGr::hdc; /* A device context used for drawing */ COLORREF TDisplayWinGr::colorMap[ 16 ]; TEXTMETRIC TDisplayWinGr::tm; HCURSOR TDisplayWinGr::normCursor; HCURSOR TDisplayWinGr::sizeCursor; HCURSOR TDisplayWinGr::handCursor; RECT TDisplayWinGr::mSize; /* Windows resizing calculations */ LOGFONTA * TDisplayWinGr::fonts= NULL; // To hold available fonts dialogModeRec TDisplayWinGr::mode= { -1, 0 }; // To hold modes /* -------------------------------------------------------------------------- */ void TDisplayWinGr::lowSetCursor( int x , int y , bool dir ) /* -------------------------------------------------------------------------- */ { ushort * dst; char fg, bg; char letra; RECT rect; if ( sizeChanged ) // Don't draw on resizing { return; } if ( !TScreen::screenBuffer ) { return; } if ( zPos ) // Cursor not visible now { dir= false; } if ((unsigned) x >= (unsigned)getCols() ) // JASC, this tests both bounds { return; } if ((unsigned) y >= (unsigned)getRows() ) // JASC, this tests both bounds { return; } dst = TScreen::screenBuffer // Calc new cursor position + x + y*TScreen::screenWidth; if ( dir ) { fg= attrColor(*dst) >> 4; // Normal bg= attrColor(*dst) & 0xF; } else { bg= attrColor(*dst) >> 4; // Swap colors (reverse) fg= attrColor(*dst) & 0xF; } letra= attrChar( *dst ); SetBkColor ( hdc, colorMap[(int)bg] ); // Background color SetTextColor( hdc, colorMap[(int)fg] ); // Foreground color rect.top= y * tm.tmHeight + cShapeFr; rect.bottom= y * tm.tmHeight + cShapeTo; rect.left= x * tm.tmMaxCharWidth + 0; rect.right= x * tm.tmMaxCharWidth + 8; DrawText( hdc // Output text , &letra, 1 , &rect , DT_NOPREFIX | DT_SINGLELINE | DT_BOTTOM ); } /* -------------------------------------------------------------------------- */ void TDisplayWinGr::winRecalc( int w , int h ) /* -------------------------------------------------------------------------- */ { RECT wSize; GetWindowRect( hwnd /* acquire window size */ , &wSize ); if ( w ) { TScreen::screenWidth = ( w + tm.tmMaxCharWidth / 2 )/ tm.tmMaxCharWidth; } /* quantize width */ if ( h ) { TScreen::screenHeight= ( h + tm.tmHeight / 2 )/ tm.tmHeight; } /* quantize height */ wSize.right= getCols() * tm.tmMaxCharWidth; /* quantize width */ wSize.bottom= getRows() * tm.tmHeight; /* quantize height */ MoveWindow( hwnd , wSize.left , wSize.top , wSize.right + mSize.right + mSize.left , wSize.bottom+ mSize.top + mSize.bottom , true ); // repaintin soon sizeChanged++; } /* ------------------------------------------------------------------------- */ int CALLBACK EnumFonts( const LOGFONT * lplf // address of logical-font data structure , const TEXTMETRIC * lpntm // address of physical-font data structure , long unsigned int /*FontType*/ // type of font , LPARAM /*lpData*/ ) // address of application-defined data /* ------------------------------------------------------------------------- */ { int arraySize= 1; // Terminator space if ( lplf->lfCharSet != OEM_CHARSET ) // Only pc 437 charset { return( 1 ); } if ( lplf->lfItalic ) // No italics (bad box drawings) { return( 2 ); } if ( lplf->lfUnderline ) // No underlines (evident) { return( 3 ); } if ( lpntm->tmPitchAndFamily // Only fixed width & TMPF_FIXED_PITCH ) { return( 4 ); } if ( TDisplayWinGr::fonts ) // Previously allocated { for ( LOGFONT * ptr= // Estimate array size TDisplayWinGr::fonts ; ptr->lfWeight ; ptr ++ ) { arraySize++; } // Enlarge array size TDisplayWinGr::fonts= // Get more room (LOGFONT *) realloc( TDisplayWinGr::fonts , arraySize * sizeof( LOGFONT )); } else { TDisplayWinGr::fonts= // Get more room (LOGFONT *) calloc( arraySize , sizeof( LOGFONT )); } TDisplayWinGr::fonts[ arraySize-1 ]= *lplf; // store new font TDisplayWinGr::fonts[ arraySize ].lfWeight= 0; // terminate array return( 6 ); } /* ------------------------------------------------------------------------- */ int CALLBACK EnumFamilies( const LOGFONTA * lplf // address of logical-font data structure , const TEXTMETRICA * /*lpntm*/ // address of physical-font data structure , long unsigned int /*FontType*/ // type of font , LPARAM lpData ) // address of application-defined data /* ------------------------------------------------------------------------- */ { EnumFontFamilies( TDisplayWinGr::hdc , lplf->lfFaceName , EnumFonts , lpData ); return(1); } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::testCreate( HWND hw , LPARAM lParam ) /* ------------------------------------------------------------------------- */ { CREATESTRUCT * lpcs; RECT wSize; lpcs= (CREATESTRUCT *)lParam; hdc= GetDC( hw ); EnumFontFamilies( hdc /* Get a list of possible fonts */ , NULL , EnumFamilies , 0 ); hwnd= hw; SetCrtMode( "Terminal 10 x 18" ); /* Set a nice font set */ GetWindowRect ( hwnd, &mSize ); /* acquire window size */ GetClientRect ( hwnd, &wSize ); /* acquire client size */ mSize.left= wSize.left - mSize.left; mSize.right -= wSize.right; mSize.top = wSize.top - mSize.top ; mSize.bottom-= wSize.bottom; winRecalc( wSize.right , wSize.bottom ); } /* Recalc windows parameters */ /* ------------------------------------------------------------------------- */ int TDisplayWinGr::testEvents( UINT message , WPARAM wParam , LPARAM lParam ) /* ------------------------------------------------------------------------- */ { PAINTSTRUCT ps; /* Also used during window drawing */ switch( message ) { case WM_QUIT: storedEvent.what= evCommand; storedEvent.message.command= cmQuit; return( 1 ); case WM_DESTROY: /* send a WM_QUIT to the messagequeue */ DeleteObject( hFont ); /* Free fonn resource */ PostQuitMessage(0); storedEvent.what= evCommand; storedEvent.message.command= cmQuit; return( 2 ); case WM_SIZE: switch( wParam ) { case SIZE_MINIMIZED: return(0); case SIZE_MAXIMIZED: TScreen::screenWidth = ( LOWORD(lParam) + tm.tmMaxCharWidth / 2 )/ tm.tmMaxCharWidth; /* quantize width */ TScreen::screenHeight= ( HIWORD(lParam) + tm.tmHeight - 1 )/ tm.tmHeight; /* quantize height */ break; case SIZE_RESTORED: if ( lParam ) { TScreen::screenWidth = ( LOWORD(lParam) + tm.tmMaxCharWidth / 2 )/ tm.tmMaxCharWidth; /* quantize width */ TScreen::screenHeight= ( HIWORD(lParam) + tm.tmHeight / 2 )/ tm.tmHeight; } /* quantize height */ break; } sizeChanged++; return(4); case WM_PAINT: /* The window needs to be painted (redrawn). */ BeginPaint( hwnd, &ps ); if ( !sizeChanged ) /* if size changed, later repainting. crash repaninting now */ { if ( TScreen::screenBuffer ) { int x= ps.rcPaint.left / tm.tmMaxCharWidth; int y= ps.rcPaint.top / tm.tmHeight; int w= ps.rcPaint.right / tm.tmMaxCharWidth; int h= ps.rcPaint.bottom/ tm.tmHeight; w-= x; h -= y; unsigned ofs= getCols()*y+x; ushort *src= TScreen::screenBuffer+ofs; forceRedraw=1; while (h>=0) { TScreen::setCharacters( ofs , src , w+1 ); src+= getCols(); /* Next line */ ofs+= getCols(); h --; y ++; }}} /* A line minus left */ forceRedraw=0; EndPaint( hwnd, &ps ); return( 5 ); } return( 0 ); } /* for messages that we don't deal with */ /* -------------------------------------------------------------------------- */ LRESULT CALLBACK WindowProcedure( HWND hwnd /* This function is called by the Windowsfunction DispatchMessage( ) */ , UINT message , WPARAM wParam , LPARAM lParam ) /* -------------------------------------------------------------------------- */ { if ( THWMouseWinGr::hwnd ) { if ( THWMouseWinGr::testEvents( message /* Try for mouse envens */ , wParam , lParam )) { return( 0 ); } /* Mouse event found */ if ( TGKeyWinGr::testEvents( message /* Try for key envens */ , wParam , lParam )) { return( 0 ); } /* Key event found */ if ( TDisplayWinGr::testEvents( message /* Try another interesting envents */ , wParam , lParam )) { return( 0 ); }} /* Interesting event found */ else { if ( message == WM_CREATE ) { TDisplayWinGr::testCreate( hwnd , lParam ); return(0); }} return( DefWindowProc( hwnd // Other events must be forwardwed , message , wParam , lParam )); } /* ------------------------------------------------------------------------- */ bool TDisplayWinGr::processEvent( ) /* ------------------------------------------------------------------------- */ { MSG message; /* Here messages to the application is saved */ if ( PeekMessage( &message , NULL /* Default window */ , 0, 0 /* All messages */ , PM_REMOVE )) /* Remove mensagges from queue */ { switch( message.message ) /* Catch some keys */ { case WM_KEYUP: case WM_KEYDOWN: TGKeyWinGr::testEvents( message.message /* Try for key envens */ , message.wParam , message.lParam ); } TranslateMessage( &message ); /* Arrange key events */ DispatchMessage ( &message ); /* Send message to WindowProcedure */ return( true ); } return( false ); } /* ------------------------------------------------------- JASC, jul 2002 -- */ void TDisplayWinGr::SetCursorPos( unsigned x , unsigned y ) /* ------------------------------------------------------------------------- */ { if (( x != (unsigned)xPos ) || ( y != (unsigned)yPos )) { lowSetCursor( xPos // Remove old cursor , yPos , false ); } xPos= x; yPos= y; // Update cursor position lowSetCursor( x , y , true ); } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::GetCursorPos( unsigned & x , unsigned & y ) /* ------------------------------------------------------------------------- */ { x= xPos; y= yPos; } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::GetCursorShape( unsigned & start // From SET code , unsigned & end ) /* ------------------------------------------------------------------------- */ { start= cShapeFr; start*= 100; start/= tm.tmHeight; // Force integer aritmethic end = cShapeTo; end *= 100; end /= tm.tmHeight; } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::SetCursorShape( unsigned start // From SET code , unsigned end ) /* ------------------------------------------------------------------------- */ { lowSetCursor( xPos // First of all, remove old cursor , yPos , false ); cShapeFr= ( start*tm.tmHeight ) / 100; // Force integer aritmethic cShapeTo= ( end*tm.tmHeight ) / 100; if ( start>=end && getShowCursorEver() ) { return; } if ((unsigned)cShapeFr > (unsigned)tm.tmHeight ) // Pretty range test ( 1 test 2 comprobations ) { cShapeFr= tm.tmHeight; } if ((unsigned)cShapeTo > (unsigned)tm.tmHeight ) // Pretty range test ( 1 test 2 comprobations ) { cShapeTo= tm.tmHeight; } if ( start >= end ) { zPos |= 1; } /* Disable cursor */ else { zPos &= ~1; } lowSetCursor( xPos , yPos , true ); } /* ------------------------------------------------------------------------- */ ushort TDisplayWinGr::GetRows() /* ------------------------------------------------------------------------- */ { return( TScreen::screenHeight ); } /* ------------------------------------------------------------------------- */ ushort TDisplayWinGr::GetCols() /* ------------------------------------------------------------------------- */ { return( TScreen::screenWidth ); } /* ------------------------------------------------------------------------- */ int TDisplayWinGr::CheckForWindowSize() /* ------------------------------------------------------------------------- */ { int ret= sizeChanged; sizeChanged= 0; return( ret ); } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::SetCrtMode( ushort ) /* ------------------------------------------------------------------------- */ { SetCursorShape( 0x58 , 0x64 ); } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::SetFontMode( int fontIdx ) /* ------------------------------------------------------------------------- */ { static int lastFont= -1; // Change tracing LOGFONT * ptr; // Font operations if ( fontIdx < 0 ) // Reloads mode { fontIdx= mode.font; } if ( fontIdx == lastFont ) // All done { return; } else { lastFont= fontIdx; } ptr= TDisplayWinGr::fonts + fontIdx; // Point to font definition hFont= CreateFont( ptr->lfHeight /* Font height */ , ptr->lfWidth /* Font width */ , ptr->lfEscapement /* Escapement */ , ptr->lfOrientation /* Orientation */ , ptr->lfWeight /* Weigth */ , ptr->lfItalic /* Italic */ , ptr->lfUnderline /* Underline */ , ptr->lfStrikeOut /* Bold */ , ptr->lfCharSet /* Charset */ , ptr->lfOutPrecision /* output precision */ , ptr->lfClipPrecision /* clipping precision */ , ptr->lfQuality /* output quality */ , ptr->lfPitchAndFamily /* pitch and family */ , ptr->lfFaceName ); /* typeface name */ SelectObject ( hdc, hFont ); GetTextMetrics( hdc, &tm ); cShapeTo= tm.tmHeight; cShapeFr= tm.tmHeight-2; mode.font= fontIdx; } // Store font mode /* ------------------------------------------------------------------------- */ void TDisplayWinGr::SetCrtMode( const char * modeName ) /* ------------------------------------------------------------------------- */ { int wd, hd; // Desired size char fontName[ LF_FACESIZE + 1 ]; LOGFONT * ptr; // Font operations int delta= INT_MAX; // Chossing suitable font int pick= 0; int index= 0; if (!modeName ) { return; } if ( sscanf( modeName /* Extract font name and sizes */ , "%s%d%*s%d" , fontName , &wd , &hd ) == 3 ) { for ( ptr= TDisplayWinGr::fonts // Estimate array size ; ptr->lfWeight ; ptr ++ ) { int w= wd-ptr->lfWidth; w*= w; int h= hd-ptr->lfHeight; h*= h; if ( ( w + h ) < delta ) // Better font { delta= w+h; // new approx pick= index; } // New selection if ( !delta ) // Perfect match { break; } index ++; }} SetFontMode( pick ); } // Take new mode /* ------------------------------------------------------------------------- */ void TDisplayWinGr::SetCrtModeExt( char * modeName ) /* ------------------------------------------------------------------------- */ { TSItem * item= NULL; TView * b = NULL; LOGFONT * ptr = NULL; // Font operations int nFonts= 0; if ( modeName ) { SetCrtMode( modeName ); return; } TDialog *pd = new TDialog( TRect( 20, 4, 60, 20) , "Screen mode selector" ); if( !pd ) { return; } for ( ptr= TDisplayWinGr::fonts // Estimate array size ; ptr->lfWeight ; ptr ++ ) { nFonts ++; } while( --ptr >= TDisplayWinGr::fonts ) // Load fonts backwards { char buff[64]; sprintf( buff , "%s %2ld x %2ld" , ptr->lfFaceName , ptr->lfWidth , ptr->lfHeight /* , ptr->lfWeight */ ); item= new TSItem( buff, item ); } b= new TRadioButtons( TRect( 2, 3 , 25, 3 + nFonts ) , item ); pd->insert( b ); pd->insert( new TLabel( TRect( 3, 2, 25, 3) , "Available fonts" , b )); b= new TRadioButtons( TRect( 27, 3, 38, 6) , new TSItem( "~C~olor" , new TSItem( "~B~/W" , new TSItem( "~M~ono" , 0 )))); pd->insert( b ); pd->insert( new TLabel( TRect( 29, 2, 37, 3) , "Mode" , b )); pd->insert( new TButton( TRect( 28, 9, 38, 11 ), "~A~pply" , cmYes , bfNormal )); pd->insert( new TButton( TRect( 28, 11, 38, 13 ), "~O~K" , cmOK , bfDefault )); pd->insert( new TButton( TRect( 28, 13, 38, 15 ), "~C~ancel", cmCancel, bfNormal )); pd->setData( &mode ); ushort control; // Default dialogModeRec savedMode= mode; // Temp mode do { control= TProgram::deskTop->execView( pd ); if ( control == cmYes ) // and read it back when the dialog box is successfully closed { pd->getData( &mode ); SetFontMode( mode.font ); // Change font winRecalc( 0, 0 ); }} // Modify window size while ( control == cmYes ); switch ( control ) { case cmOK: pd->getData( &mode ); break; // Restore previous case cmCancel: mode= savedMode; break; } // Get new pd->setData( &mode ); // Store ratio list SetFontMode( mode.font ); // Change hard font winRecalc ( 0, 0 ); // Modify window size CLY_destroy( pd ); // No longer needed SetCursorShape( 0x58 , 0x64 ); } /* ------------------------------------------------------------------------- */ const char * TDisplayWinGr::GetWindowTitle(void) /* ------------------------------------------------------------------------- */ { static char buff[ maxTitleSize ]; GetWindowText( hwnd , buff , sizeof( buff) ); return( buff );} /* ------------------------------------------------------------------------- */ int TDisplayWinGr::SetWindowTitle( const char *name ) /* ------------------------------------------------------------------------- */ { SetWindowText( hwnd , name ); return(0); } /* ------------------------------------------------------------------------- */ ushort TDisplayWinGr::GetCrtMode() /* ------------------------------------------------------------------------- */ { switch( mode.mode ) { case 0: return(smCO80); case 1: return(smBW80); case 2: return(smMono); } return(smCO80); } /* ------------------------------------------------------------------------- */ TDisplayWinGr::~TDisplayWinGr() /* ------------------------------------------------------------------------- */ { free( TDisplayWinGr::fonts ); TDisplayWinGr::fonts= NULL; } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::Beep() /* ------------------------------------------------------------------------- */ { MessageBeep(0xFFFFFFFF); } /* ------------------------------------------------------------------------- */ void TDisplayWinGr::Init() /* ------------------------------------------------------------------------- */ { getRows= GetRows; getCols= GetCols; setCrtMode= SetCrtMode; getCrtMode= GetCrtMode; setCursorPos= SetCursorPos; getCursorPos= GetCursorPos; setCrtModeExt= SetCrtModeExt; setWindowTitle= SetWindowTitle; getWindowTitle= GetWindowTitle; getCursorShape= GetCursorShape; setCursorShape= SetCursorShape; checkForWindowSize= CheckForWindowSize; beep= Beep; TProgram::doNotReleaseCPU= true; } // annoys windows loop, implemented here #else #include #include #include #endif // TVOS_Win32