📄 win32term.cpp
字号:
case '\r' :
m_Position.x = 0 ;
break;
case '\n' :
if ( m_Position.y++ == ( m_VirtualSize.y - 1 ) )
{
for ( int j = 0 ; j < ( m_VirtualSize.y - 1 ) ; j++ ) {
m_ScreenText[ j ] = m_ScreenText[ j + 1 ];
m_ScreenColor[ j ] = m_ScreenColor[ j + 1 ];
}
fill( m_ScreenText.back().begin(),
m_ScreenText.back().end(),
' ' );
fill( m_ScreenColor.back().begin(),
m_ScreenColor.back().end(),
m_CurrentColor );
InvalidateRect( m_hWnd, NULL, FALSE );
m_Position.y--;
}
break;
default:
{
RECT rect;
m_ScreenText[ m_Position.y ][ m_Position.x ] = pBuf[ i ];
m_ScreenColor[ m_Position.y ][ m_Position.x ] = m_CurrentColor;
rect.left = ( m_Position.x * m_CharSize.x ) - m_Offset.x;
rect.right = rect.left + m_CharSize.x;
rect.top = ( m_Position.y * m_CharSize.y ) - m_Offset.y;
rect.bottom = rect.top + m_CharSize.y;
::InvalidateRect( m_hWnd, &rect, FALSE ) ;
//
// Check to see if we wrapped
//
if ( m_Position.x < ( m_VirtualSize.x - 1) )
m_Position.x++ ;
else if ( m_bWrap )
Output( "\r\n", 2 ) ;
break;
}
}
}
UpdateCursor();
}
//
// There are a big bunch of possible messages that
// we can get from the scroll bars. All we have to
// do in the handler is determine how far to scroll
// the screen based on the input we receive in the
// form of a message. Note that the total span of
// the scroll bar is stored in m_ScrollRange.
//
void Win32Term::VerticalScroll( WPARAM wParam )
{
int ScrollCommand = LOWORD( wParam );
int ScrollPosition = HIWORD( wParam );
int nScrollAmt;
switch ( ScrollCommand )
{
case SB_TOP :
nScrollAmt = -m_Offset.y;
break;
case SB_BOTTOM :
nScrollAmt = m_ScrollRange.y - m_Offset.y;
break;
case SB_PAGEUP :
nScrollAmt = -m_VisibleSize.y;
break;
case SB_PAGEDOWN :
nScrollAmt = m_VisibleSize.y;
break;
case SB_LINEUP:
nScrollAmt = -m_CharSize.y;
break;
case SB_LINEDOWN:
nScrollAmt = m_CharSize.y;
break;
case SB_THUMBPOSITION:
nScrollAmt = ScrollPosition - m_Offset.y;
break;
default:
return;
}
if ( ( m_Offset.y + nScrollAmt ) > m_ScrollRange.y )
nScrollAmt = m_ScrollRange.y - m_Offset.y;
if ( ( m_Offset.y + nScrollAmt ) < 0 )
nScrollAmt = -m_Offset.y;
::ScrollWindowEx( m_hWnd,
0,
-nScrollAmt,
NULL,
NULL,
NULL,
NULL,
SW_INVALIDATE | SW_ERASE );
m_Offset.y += nScrollAmt;
SetScrollPos( m_hWnd, SB_VERT, m_Offset.y, TRUE ) ;
}
void Win32Term::HorizontalScroll( WPARAM wParam )
{
int ScrollCommand = LOWORD( wParam );
int ScrollPosition = HIWORD( wParam );
int nScrollAmt;
switch ( ScrollCommand )
{
case SB_TOP:
nScrollAmt = -m_Offset.x;
break;
case SB_BOTTOM:
nScrollAmt = m_ScrollRange.x - m_Offset.x;
break ;
case SB_PAGEUP:
nScrollAmt = -m_VisibleSize.x;
break;
case SB_PAGEDOWN:
nScrollAmt = m_VisibleSize.x;
break ;
case SB_LINEUP:
nScrollAmt = -m_CharSize.x;
break ;
case SB_LINEDOWN:
nScrollAmt = m_CharSize.x;
break;
case SB_THUMBPOSITION:
nScrollAmt = ScrollPosition - m_Offset.x;
break;
default:
return;
}
if ( ( m_Offset.x + nScrollAmt ) > m_ScrollRange.x )
nScrollAmt = m_ScrollRange.x - m_Offset.x;
if ( ( m_Offset.x + nScrollAmt ) < 0 )
nScrollAmt = -m_Offset.x;
ScrollWindowEx( m_hWnd,
-nScrollAmt,
0,
NULL,
NULL,
NULL,
NULL,
SW_INVALIDATE | SW_ERASE );
m_Offset.x = m_Offset.x + nScrollAmt;
::SetScrollPos( m_hWnd, SB_HORZ, m_Offset.x, TRUE );
}
//
// See the text in the book for details on the Size()
// message handler. In principle this routine should
// not be too tricky, but it is complicated by the
// fact that scroll bars can pop up or disappear as
// things change.
//
void Win32Term::Size( int x, int y )
{
//
// First, we will try to do everything with no scroll bars.
// If there are scroll bars, we're going to give their space
// back, at least temporarily
//
long style = ::GetWindowLong( m_hWnd, GWL_STYLE );
if ( style & WS_VSCROLL )
x += ::GetSystemMetrics( SM_CXVSCROLL );
if ( style & WS_HSCROLL )
y += ::GetSystemMetrics( SM_CYHSCROLL );
//
// adjust vertical settings
//
m_VisibleSize.y = y;
m_ScrollRange.y = max( 0, (m_VirtualSize.y * m_CharSize.y ) + m_iCharDescent - m_VisibleSize.y ) ;
int nScrollAmt = min( m_ScrollRange.y, m_Offset.y ) - m_Offset.y;
m_Offset.y = m_Offset.y + nScrollAmt;
//
// adjust horz settings
//
m_VisibleSize.x = x;
m_ScrollRange.x = max( 0, (m_VirtualSize.x * m_CharSize.x ) - m_VisibleSize.x );
nScrollAmt = min( m_ScrollRange.x, m_Offset.x ) - m_Offset.x;
m_Offset.x = m_Offset.x + nScrollAmt;
//
// If we created a vertical scrollbar, we need to go back and adjust the horizontal
//
if ( m_ScrollRange.y > 0 ) {
m_VisibleSize.x = x - ::GetSystemMetrics( SM_CXVSCROLL );
m_ScrollRange.x = max( 0, (m_VirtualSize.x * m_CharSize.x ) - m_VisibleSize.x );
nScrollAmt = min( m_ScrollRange.x, m_Offset.x ) - m_Offset.x;
m_Offset.x = m_Offset.x + nScrollAmt;
}
//
// If we created a horzontal scrollbar, we need to go back and adjust the vertical
//
if ( m_ScrollRange.x > 0 ) {
m_VisibleSize.y = y - ::GetSystemMetrics( SM_CYHSCROLL );
m_ScrollRange.y = max( 0, (m_VirtualSize.y * m_CharSize.y ) + m_iCharDescent - m_VisibleSize.y ) ;
int nScrollAmt = min( m_ScrollRange.y, m_Offset.y ) - m_Offset.y;
m_Offset.y = m_Offset.y + nScrollAmt;
//
// And it's actually still possible that we need to readjust the X scrollbar
//
m_VisibleSize.x = x - ::GetSystemMetrics( SM_CXVSCROLL );
m_ScrollRange.x = max( 0, (m_VirtualSize.x * m_CharSize.x ) - m_VisibleSize.x );
nScrollAmt = min( m_ScrollRange.x, m_Offset.x ) - m_Offset.x;
m_Offset.x = m_Offset.x + nScrollAmt;
}
//
// Now we do the actual scrolling. Note that at this
// point, the number i m_ScrollRange represents the
// difference between the pixels needed to display the
// Virtual screen and the number of pixels in the visible
// window.
//
ScrollWindow( m_hWnd, 0, -nScrollAmt, NULL, NULL );
SetScrollRange( m_hWnd, SB_VERT, 0, m_ScrollRange.y, TRUE );
SetScrollPos( m_hWnd, SB_VERT, m_Offset.y, FALSE );
//
ScrollWindow( m_hWnd, nScrollAmt, 0, NULL, NULL );
SetScrollRange( m_hWnd, SB_HORZ, 0, m_ScrollRange.x, FALSE ) ;
SetScrollPos( m_hWnd, SB_HORZ, m_Offset.x, TRUE ) ;
InvalidateRect( m_hWnd, NULL, FALSE ) ; // redraw entire window
}
//
// This is the dispatcher for messages coming into
// this window. This is the C++ equivaelnt of a
// WinProc, and in fact is called by the WinProc
// for this window class.
//
LRESULT Win32Term::Dispatch( HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
switch( uMsg ) {
case WM_VSCROLL:
VerticalScroll( wParam );
break;
case WM_HSCROLL:
HorizontalScroll( wParam );
break ;
case WM_SIZE:
Size( LOWORD( lParam ), HIWORD( lParam ) );
break;
case WM_PAINT:
Paint();
break;
case WM_CHAR:
Output( (char) wParam );
break;
case WM_SETFOCUS:
SetFocus();
break ;
case WM_KILLFOCUS:
KillFocus();
break;
case WM_MOUSEACTIVATE:
::SetFocus( hWnd );
return MA_ACTIVATE;
break;
case WM_DESTROY :
SetWindowLong( hWnd, 0, 0 );
m_hWnd = 0;
break;
default:
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
return 0L;
}
//
// The WinProc for this class is what Windows
// will call when any messages are to be dispatched.
// The only time we actually do anything in this
// routine is when the window is first created,
// because then we get a special pointer to the
// C++ object passed in. We extract that pointer
// and store it in a window long word so that all
// subsequent calls to ths routine can get a pointer
// to the C++ object. Thus, all subseuqent calls can
// also be handled by the C++ member function
// Dispatch().
//
// Why am I so eager to have commands handled by a
// C++ member function? Most importantly, it gives
// me the opportunity to derive new classes from
// Win32Term, and let them write their own versions
// of Dispatch, allowing them to override some or
// all of the behavior of the class. This is how the
// Chapter 13 example works.
//
LRESULT CALLBACK Win32Term::WindowProc( HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
Win32Term *p = (Win32Term *) ::GetWindowLong( hWnd, 0 );
if ( p )
return p->Dispatch( hWnd, uMsg, wParam, lParam );
//
// If we haven't defined the window yet, I want to make sure I don't do
// anything that requires the pointer to the object
//
if ( uMsg == WM_CREATE )
{
CreateData UNALIGNED *pData = (CreateData UNALIGNED *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
pData->pTerm->m_hParent = ::GetParent( hWnd );
pData->pTerm->m_hWnd = hWnd;
SetWindowLong( hWnd, 0, (LONG) pData->pTerm );
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
//
// Normally clearing the screen is very simple. We
// just fill the screen with blanks of a certain color.
// However, sometimes it is nice to have calibration data
// on the screen so that we can do some experimentation.
// By changing the "#if 1" to "#if 0", we can turn that
// code on. It isn't pretty, but sometimes it is very
// handy.
//
void Win32Term::Clear()
{
#if 1
for ( int row = 0 ; row < m_VirtualSize.y ; row++ ) {
fill( m_ScreenText[ row ].begin(),
m_ScreenText[ row ].end(),
' ' );
fill( m_ScreenColor[ row ].begin(),
m_ScreenColor[ row ].end(),
m_CurrentColor );
}
#else
TextColor bars[ 2 ] = {
TextColor( RGB( 0, 0, 0 ), RGB( 224, 224, 224 ) ),
TextColor( RGB( 255, 255, 255 ), RGB( 0, 0, 0 ) )
};
bool temp_wrap = m_bWrap;
m_bWrap = false;
int temp_row;
int temp_col;
GetCursorPosition( temp_row, temp_col );
for ( int row = 0 ; row < m_VirtualSize.y ; row++ ) {
fill( m_ScreenText[ row ].begin(),
m_ScreenText[ row ].end(),
' ' );
fill( m_ScreenColor[ row ].begin(),
m_ScreenColor[ row ].end(),
bars[ row & 1 ] );
SetForegroundColor( bars[ row & 1 ].m_Foreground );
SetBackgroundColor( bars[ row & 1 ].m_Background );
ostringstream s1;
ostringstream s2;
s1 << "*** Row " << setw( 2 ) << row;
s2 << "Row " << setw( 2 ) << row << " ***";
SetCursorPosition( row, 0 );
Output( s1.str().c_str() );
SetCursorPosition( row, m_VirtualSize.x - s2.str().size() );
Output( s2.str().c_str() );
}
m_bWrap = temp_wrap;
SetCursorPosition( temp_row, temp_col );
#endif
::InvalidateRect( m_hWnd, NULL, TRUE );
}
//
// The border color is truly just the background
// color for the window. When we get a new
// color in for the background, we just create
// a brush for that color and stuff it into the
// class data for this window. The rest of it
// is automatic, we never have to actually draw
// the border, it's done automatically as part
// of the paint process.
//
void Win32Term::SetBorderColor( COLORREF color )
{
HBRUSH brush = (HBRUSH) ::GetClassLong( m_hWnd, GCL_HBRBACKGROUND );
if ( brush )
DeleteObject( brush );
brush = ::CreateSolidBrush( color );
::SetClassLong( m_hWnd, GCL_HBRBACKGROUND, (LONG) brush );
m_BorderColor = color;
::InvalidateRect( m_hWnd, NULL, TRUE );
}
//
// Done just like you might think, with a bit
// of error checking
//
int Win32Term::SetCursorPosition( int row, int col )
{
if ( row < 0 || col < 0 )
return 0;
if ( row >= m_VirtualSize.y )
return 0;
if ( col >= m_VirtualSize.x )
return 0;
m_Position.x = col;
m_Position.y = row;
UpdateCursor();
return 1;
}
void Win32Term::GetCursorPosition( int &row, int &col )
{
row = m_Position.y;
col = m_Position.x;
}
//EOF Win32Term.cpp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -