LONG FAR PASCAL SubClassFunc( HWND hwnd, WORD msg, WORD wParam, LONG lParam ) { switch( msg ) { case WM_CREATE: { Property *pProp = new Property; pProp->m_defaults.m_rcMargins.Set( 2, 2, 5, 5 ); SetProp( hwnd, g_pcszProperty, reinterpret_cast<HANDLE>( pProp ) ); } break; case WM_DESTROY: { Property *pProp = reinterpret_cast<Property *>( RemoveProp( hwnd, g_pcszProperty ) ); delete pProp; } break; case WM_WINDOWPOSCHANGING: { WINDOWPOS &pos = *(WINDOWPOS *)lParam; Property *pProp = reinterpret_cast<Property *>( GetProp( hwnd, g_pcszProperty ) ); if( !(pos.flags & SWP_NOSIZE) && !( pos.flags & SWP_NOMOVE ) && pProp ) { CWindowText text( hwnd ); if( text.GetLength() ) { HFONT hFont = (HFONT)SendMessage( hwnd, WM_GETFONT, 0, 0 ); pProp->m_defaults.SetFont( hFont ); pProp->m_sectHTML.SetHTML( text, text.GetLength(), NULL ); } return 0; } } break; case WM_WINDOWPOSCHANGED: { static bool bDealingWithIt = false; Property *pProp = reinterpret_cast<Property *>( GetProp( hwnd, g_pcszProperty ) ); if( pProp && !bDealingWithIt ) { bDealingWithIt = true; CRect rcTip( 0, 0, 300, 5 ); CDrawContext dc; pProp->m_sectHTML.OnLayout( rcTip, dc ); const CSize size( pProp->m_sectHTML.GetSize() ); rcTip.SetSize( size ); pProp->m_sectHTML.bottom = size.cy; pProp->m_sectHTML.right = size.cx; CPoint ptCursor; GetCursorPos( ptCursor ); ptCursor.x += g_knTipClearanceX; ptCursor.y += g_knTipClearanceY; rcTip.Offset( ptCursor.x, ptCursor.y ); CRect rcDesktop; GetDisplayWorkArea( hwnd, rcDesktop ); if( rcTip.right >= rcDesktop.right ) { rcTip.Offset( -(rcTip.right - rcDesktop.right) - g_knTipClearanceX, 0 ); } if( rcTip.bottom >= rcDesktop.bottom ) { rcTip.Offset( 0, -rcTip.Height() - g_knTipClearanceY ); } SetWindowPos( hwnd, NULL, rcTip.left, rcTip.top, rcTip.Width(), rcTip.Height(), SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOZORDER ); bDealingWithIt = false; } return 0; } case WM_PAINT: { Property *pProp = reinterpret_cast<Property *>( GetProp( hwnd, g_pcszProperty ) ); if( pProp ) { PAINTSTRUCT ps; BeginPaint( hwnd, &ps ); CRect rcPaint( ps.rcPaint ); if( rcPaint.IsEmpty() ) { GetClientRect( hwnd, &rcPaint ); } // // Scoped to allow the draw context to go out of scope before EndPaint is called. { CDrawContext dc( &rcPaint, ps.hdc ); SelectPalette( ps.hdc, GetCurrentWindowsPalette(), TRUE ); RealizePalette( ps.hdc ); pProp->m_sectHTML.OnDraw( dc ); } EndPaint( hwnd, &ps ); return 0; } break; } } return CallWindowProc( g_lpfnOldWndProc, hwnd, msg, wParam, lParam); }
CTipWindow::CTipWindow( LPCTSTR pcszTip, CPoint &pt ) : CWindowSection( TIP_WINDOW ) , m_defaults( g_defaults ) , m_htmlSection( this, &m_defaults ) { NONCLIENTMETRICS ncm; ncm.cbSize = sizeof( ncm ); if( SystemParametersInfo( SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0 ) ) { m_defaults.SetFont( ncm.lfStatusFont ); } ASSERT( pcszTip ); m_strTip = pcszTip; CRect rcDesktop; GetDisplayWorkArea( pt, rcDesktop ); m_htmlSection.SetZoomLevel( QHTM_ZOOM_DEFAULT ); // // Stop tip exceeding 'g_knMaxHeight' pixels bool bDeleted = false; while( HeightExceedsTipMax( m_strTip, g_knMaxHeight ) ) { int iDeleteAt = m_strTip.GetLength() - m_strTip.GetLength() / 100 * 15; // Knock 15% off m_strTip.Delete( iDeleteAt, m_strTip.GetLength() - iDeleteAt ); UINT iCheckHTML = m_strTip.GetLength() - 1; while( iCheckHTML + 5 > m_strTip.GetLength() ) { if( m_strTip[iCheckHTML] == '<' ) { m_strTip.Delete( iCheckHTML, m_strTip.GetLength() - iCheckHTML ); break; } iCheckHTML--; } bDeleted = true; } if( bDeleted ) { m_strTip += _T("...<br><b>more</b>"); } m_defaults.m_crBackground = GetSysColor( COLOR_INFOBK ); m_defaults.m_crDefaultForeColour = GetSysColor( COLOR_INFOTEXT ); m_htmlSection.SetHTML( m_strTip, m_strTip.GetLength(), NULL ); CRect rcMargins( 2, 2, 2, 5 ); m_htmlSection.SetDefaultMargins( rcMargins ); CRect rcTip( 0, 0, g_knMaxTipWidth, 30 ); CDrawContext dc; m_htmlSection.OnLayout( rcTip, dc ); const CSize size( m_htmlSection.GetSize() ); // // Adjust for mouse size pt.x += g_knTipClearanceX; pt.y += g_knTipClearanceY; rcTip.Set( pt.x, pt.y , pt.x + size.cx + 3, pt.y + size.cy ); // // Move rect around based on desktop rect if( rcTip.right > rcDesktop.right ) { rcTip.Offset( -(rcTip.right - rcDesktop.right - g_knTipClearanceX), 0 ); } if( rcTip.bottom > rcDesktop.bottom ) { rcTip.Offset( 0, -rcTip.Height() - g_knTipClearanceY ); } // // Adjust tip so that it is within bounds VERIFY( CWindowSection::Create( rcTip ) ); m_nLastTipCreated = GetTickCount(); ShowWindow( SW_SHOW ); }