www.pudn.com > VPNClient-Source.rar > CoolControlsManager.cpp


 
/****************************************************************** 
 
$Archive: /MfcExt/Source/CoolControlsManager.cpp $ 
$Workfile: CoolControlsManager.cpp $ 
$Author: Bogdan Ledwig $ 
$Date: 99-04-26 22:12 $ 
$Revision: 13 $ 
 
*******************************************************************/ 
 
#include "StdAfx.h" 
 
#include "CoolControlsManager.h" 
 
// If you don't want to see extra TRACE diagnostics, 
// modify the line below to: #define CCM_TRACE 
#define CCM_TRACE TRACE 
 
#define CCM_TIMER_VAL 100        // 100 ms timer period seems to be good enough... 
#define MAX_CLASSNAME 64         // Length of buffer for retrieving the class name 
 
//////////////////////////////////////////////////////////////////////// 
// CCMControl static members initialization 
 
HWND CCoolControlsManager::CCMControl::m_hWndOld = NULL; 
CMapPtrToPtr CCoolControlsManager::m_ctrlMap = 10; 
CMapPtrToPtr CCoolControlsManager::m_dlgMap = 10; 
BOOL CCoolControlsManager::m_bEnabled = TRUE; 
 
// Changed 02.03.1999 Mike Walter 
CMapWordToPtr CCoolControlsManager::m_threadMap = 10;      
 
/////////////////////////////////////////////////////////////////////// 
// Here is the one and only CCoolControlsManager object 
static CCoolControlsManager g_ctrlManager; 
 
CCoolControlsManager& GetCtrlManager() 
{ 
   return g_ctrlManager; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// WH_CALLWNDPROC hook procedure 
 
LRESULT CALLBACK CCM_CallWndProc( int nCode, WPARAM wParam, LPARAM lParam ) 
{    
   HOOKPROC hHookProc; 
   if ( g_ctrlManager.m_threadMap.Lookup( (WORD)GetCurrentThreadId(), (void*&)hHookProc ) == FALSE ) 
   { 
      //TRACE( "CCoolControlsManager: No hook for this thread installed!\n" ); 
      return 0; 
   } 
 
   if ( nCode == HC_ACTION ) 
   {       
      CWPSTRUCT* pwp = (CWPSTRUCT*)lParam; 
      if ( g_ctrlManager.IsEnabled() ) 
      { 
         if ( g_ctrlManager.m_bDialogOnly == TRUE )         
         { 
            if ( pwp->message == WM_INITDIALOG ) 
               g_ctrlManager.Install( pwp->hwnd ); 
         } 
         else if ( pwp->message == WM_CREATE && g_ctrlManager.IsEnabled() ) 
         { 
            TCHAR szBuf[MAX_CLASSNAME]; 
            if ( GetWindowLong( pwp->hwnd, GWL_STYLE ) & WS_CHILD ) 
            { 
               GetClassName( pwp->hwnd, szBuf, MAX_CLASSNAME ); 
               if ( lstrcmp( szBuf, _T( "ScrollBar" ) ) ) // Don't add scrollbars 
                  g_ctrlManager.AddControl( pwp->hwnd ); 
            } 
         } 
      } 
   }    
   // Changed 02.03.1999 Mike Walter 
   return CallNextHookEx( (HHOOK)hHookProc, nCode, wParam, lParam ); 
} 
 
// Install a hook for the current thread only 
void CCoolControlsManager::InstallHook( DWORD dwThreadID, BOOL bDialogOnly ) 
{ 
   // ASSERT( m_hkWndProc == NULL ); 
 
   m_bDialogOnly = bDialogOnly; 
 
   // Changes 02.03.1999 Mike Walter 
   HOOKPROC hNewHook; 
 
   if ( m_threadMap.Lookup( (WORD)( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ), (void*&)hNewHook ) == FALSE ) 
   { 
      hNewHook = (HOOKPROC)SetWindowsHookEx( WH_CALLWNDPROC, 
                                             (HOOKPROC)CCM_CallWndProc, 
                                             NULL, 
                                             ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) ); 
 
      m_threadMap.SetAt( (WORD)( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ), hNewHook ); 
 
  } 
} 
 
// Install a global hook for all windows in the system. 
// This function may be called only when is put in a DLL. 
void CCoolControlsManager::InstallGlobalHook( HINSTANCE hInstance, BOOL bDialogOnly ) 
{ 
   ASSERT( hInstance );      // hInstance must not be NULL! 
   ASSERT( m_hkWndProc == NULL ); 
    
   m_bDialogOnly = bDialogOnly; 
 
   HOOKPROC hkProc = (HOOKPROC)GetProcAddress( hInstance, "CCM_CallWndProc" ); 
 
   m_hkWndProc = (HOOKPROC)SetWindowsHookEx( WH_CALLWNDPROC, 
                                         (HOOKPROC)hkProc, 
                                         hInstance, 
                                         0 );    
 
   CCM_TRACE( _T( "CCoolControlsManager: WH_CALLWNDPROC global hook installed\n" ) ); 
} 
 
void CCoolControlsManager::UninstallHook( DWORD dwThreadID ) 
{ 
   // ASSERT( m_hkWndProc != NULL ); 
 
   // Changes 02.03.1999 Mike Walter 
   HOOKPROC hHookProc; 
 
   if ( dwThreadID == -1 ) 
   { 
      if ( g_ctrlManager.m_threadMap.Lookup( (WORD)GetCurrentThreadId(), (void*&)hHookProc ) == FALSE ) 
		  return; 
 
      UnhookWindowsHookEx( (HHOOK)hHookProc ); 
      m_threadMap.RemoveKey( (WORD)GetCurrentThreadId() ); 
   } 
   else 
   { 
      if ( g_ctrlManager.m_threadMap.Lookup( (WORD)dwThreadID, (void*&)hHookProc) == FALSE ) 
      { 
         return; 
      } 
 
      UnhookWindowsHookEx( (HHOOK)hHookProc ); 
      m_threadMap.RemoveKey( (WORD)dwThreadID ); 
   } 
 
   if ( m_uTimerID && g_ctrlManager.m_threadMap.IsEmpty() == TRUE ) 
      KillTimer( NULL, m_uTimerID ); 
} 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CCoolControlsManager::CCoolControlsManager() 
{   
   m_hkWndProc = NULL; 
   m_uTimerID = 0; 
   CCM_TRACE( _T( "CCoolControlsManager::CCoolControlsManager()\n" ) ); 
} 
 
CCoolControlsManager::~CCoolControlsManager() 
{   
   // Changed 02.03.1999 Mike Walter 
   POSITION pos = m_threadMap.GetStartPosition(); 
 
   while ( pos ) 
   { 
      HOOKPROC hHook; 
      DWORD dwThreadID = 0; 
 
      m_threadMap.GetNextAssoc( pos, (WORD&)dwThreadID, (void*&)hHook ); 
      UninstallHook( dwThreadID ); 
   } 
 
   // If we have any elements in the map (normally impossible), unsubclass they and remove 
   pos = m_ctrlMap.GetStartPosition(); 
 
   while ( pos ) 
   { 
      HWND hWnd; 
 
      CCMControl* pCtl; 
      m_ctrlMap.GetNextAssoc( pos, (void*&)hWnd, (void*&)pCtl ); 
      pCtl->Unsubclass(); 
      m_ctrlMap.RemoveKey( hWnd ); 
      delete pCtl; 
   } 
 
   // Now do the same things for dialog map 
   pos = m_dlgMap.GetStartPosition(); 
 
   while ( pos ) 
   { 
      HWND hWnd; 
      CCMDialog* pCtl; 
      m_dlgMap.GetNextAssoc( pos, (void*&)hWnd, (void*&)pCtl ); 
 
      pCtl->Unsubclass(); 
      m_dlgMap.RemoveKey( hWnd ); 
      delete pCtl; 
   } 
} 
 
void CCoolControlsManager::Install( HWND hWnd ) 
{ 
   CCMControl* pCtl; 
   if ( m_dlgMap.Lookup( hWnd, (void*&)pCtl ) ) // Already in the dialog map 
      return; 
 
   // Iterate through all child windows 
   HWND hCtrl = GetTopWindow( hWnd ); 
 
   while ( hCtrl ) 
   { 
      if ( GetWindowLong( hCtrl, GWL_STYLE ) & WS_CHILD ) 
      { 
         TCHAR szBuf[MAX_CLASSNAME]; 
         GetClassName( hCtrl, szBuf, MAX_CLASSNAME ); 
         if ( lstrcmpi( szBuf, _T( "#32770" ) ) ) // Never add child dialogs! 
            AddControl( hCtrl ); 
      } 
      hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); 
   }     
 
   AddDialog( hWnd ); // Add parent window as well 
 
   // Now redraw all recently inserted controls    
   hCtrl = GetTopWindow( hWnd ); 
   while ( hCtrl )  
   { 
      if ( m_ctrlMap.Lookup( hCtrl, (void*&)pCtl ) ) 
         pCtl->DrawBorder(); 
      hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); 
   }     
} 
 
void CCoolControlsManager::Uninstall( HWND hWnd ) 
{ 
   // Remove all window controls from the map 
   // when the window is about to destroy 
   CCM_TRACE( _T( "CCoolControlsManager: Uninstall, handle: %X\n" ), hWnd ); 
    
   HWND hCtrl = GetTopWindow( hWnd ); 
   while ( hCtrl ) 
   { 
      if ( GetWindowLong( hCtrl, GWL_STYLE ) & WS_CHILD ) 
         RemoveControl( hCtrl ); 
      hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); 
   } 
} 
 
// In lpszClass you can specify class name, which will be used  
// instead of true class name (useful for non-standard controls  
// that are similar to the one of those we have supported) 
BOOL CCoolControlsManager::AddControl( HWND hWnd, LPCTSTR lpszClass ) 
{   
   CCMControl* pCtl = NULL;  
 
   // Must not be NULL or already in the map 
   if ( hWnd == NULL || m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) ) 
      return FALSE;    
    
   TCHAR szBuf[MAX_CLASSNAME]; 
   if ( lpszClass == NULL ) 
      GetClassName( hWnd, szBuf, MAX_CLASSNAME ); 
   else 
      lstrcpy( szBuf, lpszClass ); 
 
   DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE ); 
   DWORD dwExStyle = GetWindowLong( hWnd, GWL_EXSTYLE ); 
 
   if ( !lstrcmpi( szBuf, _T( "Button" ) ) ) 
   { 
      if ( ( dwStyle & BS_OWNERDRAW ) == BS_OWNERDRAW )          
         return FALSE;     // Do not subclass ownerdraw buttons 
      else if ( ( dwStyle & BS_GROUPBOX ) == BS_GROUPBOX || 
           ( dwStyle & BS_FLAT ) == BS_FLAT )  
         return FALSE;     // Skip all group boxes and flat buttons 
      else if ( ( dwStyle & BS_AUTOCHECKBOX ) == BS_AUTOCHECKBOX || 
                ( dwStyle & BS_CHECKBOX ) == BS_CHECKBOX ||                 
                ( dwStyle & BS_3STATE ) == BS_3STATE ) 
         pCtl = new CCMCheckBox; 
      else if ( ( dwStyle & BS_AUTORADIOBUTTON ) == BS_AUTORADIOBUTTON ||  
           ( dwStyle & BS_RADIOBUTTON ) == BS_RADIOBUTTON ) 
         pCtl = new CCMRadioButton; 
      else 
         pCtl = new CCMPushButton;     // If none of the above then it must be a pushbutton! 
   } 
   else if ( !lstrcmpi( szBuf, _T( "ComboBox" ) ) ) 
   {       
      // Special case for simple comboboxes 
      if ( ( dwStyle & 0x03 ) == CBS_SIMPLE ) 
      { 
         hWnd = GetTopWindow( hWnd ); 
         while ( hWnd ) 
         { 
            AddControl( hWnd ); 
            hWnd = GetNextWindow( hWnd, GW_HWNDNEXT ); 
         } 
         return FALSE; 
      }    
      else 
         pCtl = new CCMComboBox; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "Edit" ) ) ) 
   { 
      // Edit window in a simple combobox 
      GetClassName( GetParent( hWnd ), szBuf, MAX_CLASSNAME ); 
      if ( !lstrcmpi( szBuf, _T( "ComboBox" ) ) &&  
            ( GetWindowLong( GetParent( hWnd ), GWL_STYLE ) & 0x03 ) == CBS_SIMPLE )  
         pCtl = new CCMEditCombo; 
      else 
      { 
         if ( dwExStyle & WS_EX_CLIENTEDGE ) 
            pCtl = new CCMEdit; 
      } 
     #if defined _DEBUG 
       lstrcpy( szBuf, _T( "Edit" ) ); 
     #endif 
   } 
   else if ( !lstrcmpi( szBuf, _T( "ListBox" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMControl; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysListView32" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
      { 
         pCtl = new CCMControl; 
         AddControl( GetTopWindow( hWnd ) );  // Don't forget to add the header control 
      } 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SHELLDLL_DefView" ) ) ) // In open/save common dialogs 
   { 
      AddControl( GetTopWindow( hWnd ) );  // Add child ListView control 
      return FALSE; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysTreeView32" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMControl; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysDateTimePick32" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
      { 
         pCtl = new CCMDateTime; 
         if ( dwStyle & DTS_UPDOWN ) 
            AddControl( GetTopWindow( hWnd ) );  // Add up-down control as well 
      } 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysMonthCal32" ) ) ) 
      pCtl = new CCMControl; 
   else if ( !lstrcmpi( szBuf, _T( "msctls_updown32" ) ) ) 
      pCtl = new CCMUpDown; 
   else if ( !lstrcmpi( szBuf, _T( "ComboLBox" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMControl; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "ScrollBar" ) ) ) 
   { 
      if ( !( dwStyle & SBS_SIZEBOX ) && !( dwStyle & SBS_SIZEGRIP ) ) 
         pCtl = new CCMScrollBar; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "ComboBoxEx32" ) ) ) 
   { 
      AddControl( GetTopWindow( hWnd ) ); 
      return FALSE; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "msctls_hotkey32" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMControl; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysIPAddress32" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMIPAddress; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "msctls_trackbar32" ) ) ) 
      pCtl = new CCMTrackbar; 
   else if ( !lstrcmpi( szBuf, _T( "RichEdit" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMControl; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "RichEdit20W" ) ) ) 
   { 
      if ( dwExStyle & WS_EX_CLIENTEDGE ) 
         pCtl = new CCMControl; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysHeader32" ) ) ) 
   { 
      if ( dwStyle & HDS_BUTTONS )          
         pCtl = new CCMHeaderCtrl; 
      else 
         return FALSE; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "ToolbarWindow32" ) ) ) 
   { 
      // Skip the flat toolbars 
      if ( dwStyle & TBSTYLE_FLAT ) 
         return FALSE; 
      HWND hCtrl = GetTopWindow( hWnd );  // Add additional toolbar controls 
      while ( hCtrl ) 
      { 
         AddControl( hCtrl ); 
         hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT ); 
      }       
      pCtl = new CCMToolbar; 
   } 
   else if ( !lstrcmpi( szBuf, _T( "SysTabControl32" ) ) ) 
   { 
      pCtl = new CCMTabControl; 
      HWND hWndTop = GetTopWindow( hWnd ); 
      if ( hWndTop ) 
         AddControl( hWndTop );  // Also add the up-down control (horizontal tabs only) 
   } 
   else  // Unknown control, do not process 
      return FALSE; 
 
   if ( pCtl ) 
   { 
      CCM_TRACE( _T( "CCoolControlsManager::AddControl, handle: %X, type: %s\n" ),  
                 hWnd, szBuf ); 
 
      // Perform window subclassing 
      pCtl->Subclass( hWnd, CCM_ControlProc ); 
 
      // Add the control to the map          
      m_ctrlMap.SetAt( hWnd, pCtl ); 
       
      if ( m_uTimerID == 0 ) // If timer is not initialized yet 
      {     
         m_uTimerID = SetTimer( NULL, 0, CCM_TIMER_VAL, CCM_TimerProc ); 
         CCM_TRACE( _T( "CControlManager: Timer created\n" ) ); 
         ASSERT( m_uTimerID );    // Failed to create the timer 
      } 
      return TRUE; 
   } 
   return FALSE; 
} 
 
BOOL CCoolControlsManager::RemoveControl( HWND hWnd ) 
{ 
   BOOL bResult = TRUE;    
   CCMControl* pCtl; 
   if ( m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) 
      bResult =  FALSE;    
 
  #if defined _DEBUG 
   TCHAR szBuf[MAX_CLASSNAME]; 
   GetClassName( hWnd, szBuf, MAX_CLASSNAME );          
   CCM_TRACE( _T( "CCoolControlsManager::RemoveControl, handle: %X, class: %s, " ),  
           hWnd, szBuf ); 
   CCM_TRACE( bResult ? _T( "OK\n" ) : _T( "fail\n" ) ); 
  #endif 
 
   if ( bResult == TRUE ) 
   { 
      // Unsubclass window and next remove it from the map 
      pCtl->Unsubclass(); 
      m_ctrlMap.RemoveKey( hWnd ); 
      delete pCtl;      // Destroy the object 
 
      if ( m_ctrlMap.IsEmpty() ) 
      { 
         KillTimer( NULL, m_uTimerID ); 
         CCM_TRACE( _T( "CCoolControlsManager: Timer killed, map is empty\n" ) ); 
         m_uTimerID = 0; 
      }   
      else 
         CCM_TRACE( _T( "CCoolControlsManager: map has %d items\n" ), m_ctrlMap.GetCount() ); 
   } 
   return bResult; 
} 
 
void CCoolControlsManager::AddDialog( HWND hWnd ) 
{    
   if ( hWnd  ) 
   { 
      CCMDialog* pCtl = new CCMDialog; 
      pCtl->Subclass( hWnd, CCM_DialogProc );    // Perform window subclassing 
      m_dlgMap.SetAt( hWnd, pCtl ); // Add the dialog to the map    
   } 
} 
 
void CCoolControlsManager::RemoveDialog( HWND hWnd ) 
{    
   CCMDialog* pCtl; 
   if ( m_dlgMap.Lookup( hWnd, (void*&)pCtl ) == TRUE )    
   { 
      // Unsubclass window and next remove it from the map 
      pCtl->Unsubclass(); 
      m_dlgMap.RemoveKey( hWnd ); 
      delete pCtl;      // Destroy the object 
   } 
} 
 
static void CALLBACK CCM_TimerProc( HWND /*hwnd*/, UINT /*uMsg*/,  
                                    UINT /*idEvent*/, DWORD /*dwTime*/ ) 
{  
   g_ctrlManager.TimerProc(); 
} 
 
void CCoolControlsManager::TimerProc() 
{ 
   // Do not process when the map is empty or the capture is set 
   if ( m_ctrlMap.IsEmpty() || GetCapture() != NULL ) 
      return; 
 
   POINT point; 
   GetCursorPos( &point ); 
   HWND hWnd = WindowFromPoint( point ); 
    
   CCMControl* pCtl; 
   // Lookup for a window in the map       
   if ( m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) // Not found 
   { 
      // If window does not exist in the map, it can be 
      // a child of the control (e.g. edit control in ComboBox 
      // or header control in ListView). If so, get the parent window and 
      // carry on 
      hWnd = GetParent( hWnd );             
      // Not our window, so just reset previous control and exit 
      if ( hWnd == NULL || m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) 
      {             
         // Not our window, so just reset previous control and exit 
         if ( m_ctrlMap.Lookup( CCMControl::m_hWndOld, (void*&)pCtl ) == TRUE ) 
         {             
            pCtl->SetState( dsHover, 0 ); 
            CCMControl::m_hWndOld = NULL; 
         } 
         return; 
      }       
   } 
 
   if ( pCtl->NeedRedraw( point ) ) // Window has been found and needs to be redrawn! 
   { 
      // First, reset old control (if any)       
      CCMControl* pCtlOld; 
      if ( m_ctrlMap.Lookup( CCMControl::m_hWndOld, (void*&)pCtlOld ) == TRUE )             
      {          
         pCtlOld->SetState( dsHover, 0 ); 
         CCMControl::m_hWndOld = NULL; 
      } 
 
      // Redraw control under the cursor             
      pCtl->SetState( 0, dsHover ); 
      CCMControl::m_hWndOld = hWnd; 
   } 
} 
 
/////////////////////////////////////////////////////////////////////// 
// All messages from subclassed dialogs will come here 
 
static LRESULT CALLBACK CCM_DialogProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{   
   // Try to find dialog in the dialog map     
   CCoolControlsManager::CCMDialog* pCtl; 
   if ( g_ctrlManager.m_dlgMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) 
   { 
      // This is not our dialog, so just apply default processing 
      return DefWindowProc( hWnd, uMsg, wParam, lParam );  
   } 
 
   // Otherwise, let the dialog to process this message 
   return pCtl->WindowProc( uMsg, wParam, lParam ); 
} 
 
/////////////////////////////////////////////////////////////////////// 
// All messages from subclassed controls will come here 
 
static LRESULT CALLBACK CCM_ControlProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{   
   CCoolControlsManager::CCMControl* pCtl; 
 
   // Try to find window in the control map 
   if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) 
   { 
      // This is not our window, so just apply default processing 
      return DefWindowProc( hWnd, uMsg, wParam, lParam );  
   } 
 
   // Otherwise, let the control to process this message 
   return pCtl->WindowProc( uMsg, wParam, lParam ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMControl and derived classes 
 
CCoolControlsManager::CCMControl::CCMControl() 
{ 
   m_hWnd = NULL; 
   m_oldWndProc = NULL; 
   m_nState = dsNormal; 
   m_nOldState = dsNormal; 
} 
 
void CCoolControlsManager::CCMControl::PrepareDraw( HDC& hDC, RECT& rect ) 
{ 
   GetWindowRect( m_hWnd, &rect );          
   OffsetRect( &rect, -rect.left, -rect.top ); 
   hDC = GetWindowDC( m_hWnd ); 
} 
 
void CCoolControlsManager::CCMControl::DrawBorder() 
{   
   HDC hDC; 
   RECT rect; 
   PrepareDraw( hDC, rect ); 
 
   if ( GetWindowLong( m_hWnd, GWL_EXSTYLE ) & WS_EX_CLIENTEDGE ) 
   { 
      RECT rc; 
      GetWindowRect( m_hWnd, &rc ); 
      POINT point = { 0, 0 }; 
      ClientToScreen( m_hWnd, &point ); 
      if ( point.x == rc.left + 3 ) 
         InflateRect( &rect, -1, -1 ); 
   } 
 
   if ( IsFocused() == TRUE ) 
      m_nState |= dsFocus;     
   else 
      m_nState &= ~dsFocus;     
 
   // Single line control looks better when this style is added 
   if ( ( rect.bottom - rect.top ) < 30 )  
      m_nState |= dsAlternate; 
   else 
      m_nState &= ~dsAlternate; 
 
   if ( ( m_nOldState & dsHover && m_nState & dsHover ) || 
        ( m_nOldState & dsFocus && m_nState & dsFocus ) ) 
      ; // If previous state is the same as current state, do nothing 
   else 
   {          
      // Perform control-specific drawing routines                   
      CCM_TRACE( _T( "CCoolControlsManager::DrawBorder, handle: %X state: %d\n" ), m_hWnd, m_nState ); 
      DrawControl( hDC, rect ); 
   } 
 
   // Update old state 
   m_nOldState = m_nState; 
 
   ReleaseDC( WindowFromDC( hDC ), hDC ); 
} 
 
BOOL CCoolControlsManager::CCMControl::NeedRedraw( const POINT& /*point*/ ) 
{ 
   return m_hWnd != m_hWndOld ? TRUE : FALSE; 
} 
 
void CCoolControlsManager::CCMCore::Subclass( HWND hWnd, WNDPROC wndNewProc ) 
{ 
   ASSERT( hWnd );      // Do you really want to subclass a window that has a NULL handle? 
   m_hWnd = hWnd;    
 
   // Store address of the original window procedure 
   m_oldWndProc = (WNDPROC)GetWindowLong( m_hWnd, GWL_WNDPROC ); 
 
   // And set the new one 
   SetWindowLong( m_hWnd, GWL_WNDPROC, (LONG)wndNewProc ); 
} 
 
void CCoolControlsManager::CCMCore::Unsubclass() 
{ 
   SetWindowLong( m_hWnd, GWL_WNDPROC, (LONG)m_oldWndProc ); 
} 
 
LRESULT CCoolControlsManager::CCMControl::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      // Generic messages 
      case WM_KILLFOCUS:          
      case WM_SETFOCUS: 
         DrawBorder(); 
         break; 
 
      case WM_PAINT: 
      case WM_NCPAINT: 
      case WM_ENABLE: 
         CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
         DrawBorder(); 
         return 0; 
 
      case WM_NCDESTROY: 
         // Unsubclass window and remove it from the map 
         CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
         g_ctrlManager.RemoveControl( m_hWnd ); 
         return 0; 
   } 
 
   return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
} 
 
void CCoolControlsManager::CCMControl::DrawControl( HDC hDC, const RECT& rc ) 
{  
   if ( m_nState & dsHoverMask ) 
   { 
      Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                             COLOR_3DDKSHADOW, COLOR_3DLIGHT ); 
   } 
   else 
   { 
      if ( IsWindowEnabled( m_hWnd ) == FALSE || m_nState & dsDisabled ) 
         Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                                COLOR_3DFACE, COLOR_3DFACE ); 
      else                
         Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                       m_nState & dsAlternate ? COLOR_3DHIGHLIGHT : COLOR_3DLIGHT, COLOR_3DLIGHT ); 
   } 
 
   DrawScrollBars( hDC, rc ); 
} 
 
void CCoolControlsManager::CCMControl::DrawScrollbarThumb( HDC hDC, const RECT& rc ) 
{ 
   if ( m_nState & dsHoverMask ) 
      Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW,  
                             COLOR_3DHIGHLIGHT, COLOR_3DSHADOW ); 
   else 
      Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                             COLOR_3DFACE, COLOR_3DFACE ); 
} 
 
void CCoolControlsManager::CCMControl::DrawScrollBars( HDC hDC, const RECT& rect ) 
{   
   const int nFrameSize  = GetSystemMetrics( SM_CXEDGE );  
   const int nScrollSize = GetSystemMetrics( SM_CXHSCROLL );    
 
   RECT rc;  
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );   
   if ( dwStyle & WS_HSCROLL &&  dwStyle & WS_VSCROLL ) 
   { 
      rc.left = rect.left + nFrameSize; rc.top = rect.bottom - nFrameSize - nScrollSize; 
      rc.right = rect.right - nFrameSize - nScrollSize; rc.bottom = rect.bottom - nFrameSize; 
      DrawScrollBar( hDC, rc, SB_HORZ ); 
 
      rc.left = rect.right - nFrameSize - nScrollSize; rc.top = rect.top + nFrameSize; 
      rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize - nScrollSize; 
      DrawScrollBar( hDC, rc, SB_VERT ); 
   } 
   else if ( dwStyle & WS_VSCROLL ) 
   { 
      rc.left = rect.right - nFrameSize - nScrollSize; rc.top = rect.top + nFrameSize; 
      rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize; 
      DrawScrollBar( hDC, rc, SB_VERT ); 
   } 
   else if ( dwStyle & WS_HSCROLL ) 
   { 
      rc.left = rect.left + nFrameSize; rc.top = rect.bottom - nFrameSize - nScrollSize; 
      rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize; 
      DrawScrollBar( hDC, rc, SB_HORZ ); 
   } 
} 
 
void CCoolControlsManager::CCMControl::DrawScrollBar( HDC hDC, const RECT& rect,  
                                                     int nType, BOOL bScrollbarCtrl ) 
{    
   int nScrollSize = GetSystemMetrics( SM_CXHSCROLL ); 
 
   // The minimal thumb size depends on the system version 
   // For Windows 98 minimal thumb size is a half of scrollbar size  
   // and for Windows NT is always 8 pixels regardless of system metrics.  
   // I really don't know why. 
   int nMinThumbSize; 
   if ( GetVersion() & 0x80000000 ) // Windows 98 code 
      nMinThumbSize = nScrollSize / 2; 
   else                     
      nMinThumbSize = 8; 
    
   // Calculate the arrow rectangles 
   RECT rc1 = rect, rc2 = rect;    
   if ( nType == SB_HORZ ) 
   { 
      if ( ( rect.right - rect.left ) < 2 * nScrollSize ) 
         nScrollSize = ( rect.right - rect.left ) / 2; 
 
      rc1.right = rect.left + nScrollSize; 
      rc2.left = rect.right - nScrollSize; 
   } 
   else // SB_VERT 
   { 
      if ( ( rect.bottom - rect.top ) < 2 * nScrollSize ) 
         nScrollSize = ( rect.bottom - rect.top ) / 2; 
 
      rc1.bottom = rect.top + nScrollSize;       
      rc2.top = rect.bottom - nScrollSize; 
   }    
 
   // Draw the scrollbar arrows 
   DrawScrollbarThumb( hDC, rc1 ); 
   DrawScrollbarThumb( hDC, rc2 ); 
 
   // Disabled scrollbar never have a thumb 
   if ( bScrollbarCtrl == TRUE && IsWindowEnabled( m_hWnd ) == FALSE ) 
      return;       
  
   SCROLLINFO si; 
   si.cbSize = sizeof( SCROLLINFO ); 
   si.fMask = SIF_ALL;      
   GetScrollInfo( m_hWnd, bScrollbarCtrl ? SB_CTL : nType, &si ); 
 
   // Calculate the size and position of the thumb    
   int nRange = si.nMax - si.nMin + 1;       
   if ( nRange ) 
   { 
      int nScrollArea = ( nType == SB_VERT ? ( rect.bottom - rect.top ) : ( rect.right - rect.left ) ) - 2 * nScrollSize; 
 
      int nThumbSize;  
      if ( si.nPage == 0 ) // If nPage is not set then thumb has default size 
         nThumbSize = GetSystemMetrics( SM_CXHTHUMB ); 
      else 
         nThumbSize = max( MulDiv( si.nPage ,nScrollArea, nRange ), nMinThumbSize ); 
 
      if ( nThumbSize >= nScrollArea ) 
      { 
         nThumbSize = nScrollArea; 
         if ( bScrollbarCtrl == FALSE ) 
            return; 
      } 
 
      int nThumbPos; 
      if ( UINT( nRange ) == si.nPage ) 
      { 
         nThumbPos = 0; 
         nThumbSize--; 
      } 
      else 
         nThumbPos = MulDiv( si.nPos - si.nMin, nScrollArea - nThumbSize, nRange - si.nPage ); 
 
      if ( nType == SB_VERT ) 
      { 
         rc1.top += nScrollSize + nThumbPos; 
         rc1.bottom = rc1.top + nThumbSize; 
      } 
      else // SB_HORZ 
      { 
         rc1.left += nScrollSize + nThumbPos; 
         rc1.right = rc1.left + nThumbSize; 
      } 
 
      if ( nThumbSize <= nScrollArea ) // Don't draw the thumb when it's larger than the scroll area 
         DrawScrollbarThumb( hDC, rc1 ); 
   }    
} 
 
BOOL CCoolControlsManager::CCMControl::IsFocused() 
{  
   return m_hWnd == GetFocus() ? TRUE : FALSE; 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMEdit class 
 
void CCoolControlsManager::CCMEdit::DrawControl( HDC hDC, const RECT& rc ) 
{ 
   RECT rect = rc; 
 
   // Check if edit window has an associated up-down control. 
   // If so draw a border around both controls 
   HWND hWnd = GetNextWindow( m_hWnd, GW_HWNDNEXT ); 
 
   if ( hWnd )  
   { 
      TCHAR szBuf[MAX_CLASSNAME]; 
      // Retrieve window class name 
      GetClassName( hWnd, szBuf, MAX_CLASSNAME ); 
      if ( lstrcmpi( szBuf, _T( "msctls_updown32" ) ) == 0 )   // Up-down is found 
      { 
         DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE ); 
         if ( ( dwStyle & UDS_ALIGNRIGHT || dwStyle & UDS_ALIGNLEFT ) && 
              SendMessage( hWnd, UDM_GETBUDDY, 0, 0L ) == (LONG)m_hWnd ) 
         {          
            RECT rc; 
            GetWindowRect( hWnd, &rc ); 
            const int nEdge = GetSystemMetrics( SM_CXEDGE ); 
            if ( dwStyle & UDS_ALIGNRIGHT ) 
               rect.right += ( rc.right - rc.left ) - nEdge; 
            else // UDS_ALIGNLEFT 
               rect.left -= ( rc.right - rc.left ) - nEdge; 
 
            HDC hDC = GetDC( hWnd );   // We must draw the lines onto spin control DC 
 
            COLORREF clr = GetSysColor( m_nState & dsHoverMask ? COLOR_3DDKSHADOW : COLOR_3DHIGHLIGHT ); 
            if ( !IsWindowEnabled( m_hWnd ) ) 
               clr = GetSysColor( COLOR_3DFACE ); 
            FillSolidRect( hDC, 1, 1, rc.right - rc.left - nEdge - 1, 1, clr ); 
            if ( dwStyle & UDS_ALIGNLEFT ) 
               FillSolidRect( hDC, 1, 1, 1, rc.bottom - rc.top - nEdge - 1, clr ); 
 
            ReleaseDC( hWnd, hDC ); 
         } 
      } 
   } 
 
   if ( GetWindowLong( m_hWnd, GWL_STYLE ) & ES_READONLY ) 
      m_nState |= dsDisabled; 
   else 
      m_nState &= ~dsDisabled; 
   CCMControl::DrawControl( hDC, rect ); 
} 
 
LRESULT CCoolControlsManager::CCMEdit::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      case WM_ENABLE: 
         { 
            CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
            DrawBorder(); 
            HWND hWnd = GetNextWindow( m_hWnd, GW_HWNDNEXT ); 
            if ( hWnd )  
            { 
               TCHAR szBuf[MAX_CLASSNAME]; 
               // Retrieve window class name 
               GetClassName( hWnd, szBuf, MAX_CLASSNAME ); 
               if ( lstrcmpi( szBuf, _T( "msctls_updown32" ) ) == 0 &&   // Up-down is found 
                  SendMessage( hWnd, UDM_GETBUDDY, 0, 0L ) == (LONG)m_hWnd ) 
                     SendMessage( hWnd, WM_PAINT, 0, 0L );  // Repaint up-down too 
            }          
         } 
         return 0; 
 
      default: 
         return CCMControl::WindowProc( uMsg, wParam, lParam ); 
   } 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMComboBox class 
 
void CCoolControlsManager::CCMComboBox::DrawControl( HDC hDC, const RECT& rect ) 
{ 
   // First, draw borders around the control    
   CCMControl::DrawControl( hDC, rect ); 
 
   // Now, we have to draw borders around the drop-down arrow 
   RECT rc = rect; 
   InflateRect( &rc, -2, -2 ); 
   rc.left = rc.right - GetSystemMetrics( SM_CXHSCROLL ); 
    
   if ( IsWindowEnabled( m_hWnd ) == TRUE ) 
   { 
      if ( m_nState & dsHoverMask ) 
         Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW, 
                                COLOR_3DHIGHLIGHT, COLOR_3DSHADOW ); 
      else 
         Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                                COLOR_3DFACE, COLOR_3DFACE ); 
   } 
   else 
      Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DFACE, 
                             COLOR_3DFACE, COLOR_3DFACE ); 
} 
 
BOOL CCoolControlsManager::CCMComboBox::IsFocused() 
{  
   // Special case for drop-down and simple ComboBoxes  
   // which contain child edit control and focus always  
   // goes to that edit window    
   if ( ( GetWindowLong( m_hWnd, GWL_STYLE ) & 0x03 ) == CBS_DROPDOWN ) 
   { 
      HWND hWnd = GetTopWindow( m_hWnd ); 
      if ( hWnd && hWnd == GetFocus() ) 
         return TRUE; 
   } 
 
   return CCMControl::IsFocused(); 
} 
 
LRESULT CCoolControlsManager::CCMComboBox::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      // Drop-down ComboBox receives neither WM_SETFOCUS nor WM_KILLFOCUS 
      // Instead, it receives these next two messages 
      case WM_LBUTTONUP:      // For kill focus 
         if ( lParam == -1 ) 
            DrawBorder(); 
         break; 
 
      case WM_COMMAND: 
         if ( HIWORD( wParam ) == EN_SETFOCUS ) 
            DrawBorder(); 
         break; 
 
      default: 
         return CCMControl::WindowProc( uMsg, wParam, lParam ); 
   } 
 
   return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMDateTime class 
 
void CCoolControlsManager::CCMDateTime::DrawControl( HDC hDC, const RECT& rc ) 
{ 
   if ( GetWindowLong( m_hWnd, GWL_STYLE ) & DTS_UPDOWN ) 
      CCMControl::DrawControl( hDC, rc ); 
   else 
      CCMComboBox::DrawControl( hDC, rc ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMPushButton class 
 
void CCoolControlsManager::CCMPushButton::DrawControl( HDC hDC, const RECT& rc ) 
{ 
   BOOL bDefault = FALSE; 
   // Unfortunately BS_DEFPUSHBUTTON is defined as 0x00000001L, 
   // and BS_OWNERDRAW as 0x0000000BL (see winuser.h) so we cannot 
   // determine the default button for owner-draw controls 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ) & BS_OWNERDRAW; 
 
   if ( dwStyle != BS_OWNERDRAW ) 
   { 
      if ( dwStyle == BS_DEFPUSHBUTTON && IsWindowEnabled( m_hWnd ) ) 
         bDefault = TRUE; 
   } 
 
   int nCheck = SendMessage( m_hWnd, BM_GETCHECK, 0, 0 ); 
   if ( m_nState & dsHoverMask ) 
   { 
      if ( bDefault == TRUE ) 
      { 
         Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, 
                                COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, 
                                COLOR_3DLIGHT, COLOR_3DSHADOW ); 
      } 
      else 
      { 
         if ( nCheck ) 
            Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, 
                                   COLOR_3DSHADOW, COLOR_3DLIGHT ); 
         else 
            Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, 
                                   COLOR_3DLIGHT, COLOR_3DSHADOW, 
                                   COLOR_3DFACE, COLOR_3DFACE ); 
      } 
   } 
   else 
   { 
      if ( bDefault == TRUE ) 
      { 
         Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW, 
                                COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                                COLOR_3DFACE, COLOR_3DFACE ); 
      } 
      else 
      { 
         if ( nCheck ) 
            Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                                   COLOR_3DFACE, COLOR_3DFACE ); 
         else 
            Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                                   COLOR_3DFACE, COLOR_3DFACE, 
                                   COLOR_3DFACE, COLOR_3DFACE ); 
      } 
   }       
} 
 
LRESULT CCoolControlsManager::CCMPushButton::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      // Button messages 
      case BM_SETCHECK: 
      case WM_SETTEXT: 
         CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
         DrawBorder(); 
         return 0; 
 
      default: 
         return CCMControl::WindowProc( uMsg, wParam, lParam ); 
   } 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMCheckBox class 
 
void CCoolControlsManager::CCMCheckBox::DrawControl( HDC hDC, const RECT& rect ) 
{ 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
    
   if ( dwStyle & BS_PUSHLIKE ) 
   { 
      CCMPushButton::DrawControl( hDC, rect ); 
      return; 
   }   
 
   RECT rc; 
    
   // Checkmark square size, hard coded here because I couldn't find any 
   // method to obtain this value from the system. 
   // Maybe someone else knows how to do it? If so, please let me know! 
   const int nCheckSize = 13; 
    
   if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER ) 
      rc.top = rect.top + ( ( rect.bottom - rect.top ) - nCheckSize ) / 2; 
   else if ( dwStyle & BS_TOP ) 
      rc.top = rect.top + 1; 
   else if ( dwStyle & BS_BOTTOM ) 
      rc.top = rect.bottom - nCheckSize - 2; 
   else  // Default 
      rc.top = rect.top + ( ( rect.bottom - rect.top ) - nCheckSize ) / 2; 
 
   if ( dwStyle & BS_LEFTTEXT ) 
      rc.left = rect.right - nCheckSize; 
   else 
      rc.left = rect.left; 
 
   rc.right = rc.left + nCheckSize; 
   rc.bottom = rc.top + nCheckSize; 
 
   if ( m_nState & dsHoverMask ) 
   { 
      Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, 
                             COLOR_3DSHADOW, COLOR_3DFACE ); 
   } 
   else 
   {             
      if ( IsWindowEnabled( m_hWnd ) == TRUE )  
      { 
         int nState = SendMessage( m_hWnd, BM_GETCHECK, 0, 0L ); 
         Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                                nState == 2 ? COLOR_3DHIGHLIGHT : COLOR_WINDOW,  
                                nState == 2 ? COLOR_3DHIGHLIGHT : COLOR_WINDOW ); 
      } 
      else 
         Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                                COLOR_3DFACE, COLOR_3DFACE ); 
   } 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMRadioButton class 
 
void CCoolControlsManager::CCMRadioButton::DrawFrame( POINT* ptArr, int nColor,  
                                                     HDC hDC, int xOff, int yOff ) 
{ 
   for ( int i = 0; ; i++ ) 
   { 
      if ( !ptArr[i].x && !ptArr[i].y ) 
         return; 
 
      SetPixel( hDC, ptArr[i].x + xOff, ptArr[i].y + yOff, GetSysColor( nColor ) ); 
   } 
} 
 
void CCoolControlsManager::CCMRadioButton::DrawControl( HDC hDC, const RECT& rect ) 
{ 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
 
   if ( dwStyle & BS_PUSHLIKE ) 
   { 
      CCMPushButton::DrawControl( hDC, rect ); 
      return; 
   }   
 
   const int nRadioSize = 12; 
   RECT rc; 
    
   if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER ) 
      rc.top = rect.top + ( ( rect.bottom - rect.top ) - nRadioSize - 1 ) / 2; 
   else if ( dwStyle & BS_TOP ) 
      rc.top = rect.top + 1; 
   else if ( dwStyle & BS_BOTTOM ) 
      rc.top = rect.bottom - nRadioSize - 3; 
   else  // Default 
      rc.top = rect.top + ( ( rect.bottom - rect.top ) - nRadioSize - 1 ) / 2; 
    
   if ( dwStyle & BS_LEFTTEXT ) 
      rc.left = rect.right - nRadioSize; 
   else 
      rc.left = rect.left + 1; 
 
   rc.right = rc.left + nRadioSize; 
   rc.bottom = rc.top + nRadioSize; 
 
   POINT pt1[] = {  
                  { 1,9 },{ 1,8 }, 
                  { 0,7 },{ 0,6 },{ 0,5 },{ 0,4 }, 
                  { 1,3 },{ 1,2 }, 
                  { 2,1 },{ 3,1 }, 
                  { 4,0 },{ 5,0 },{ 6,0 },{ 7,0 }, 
                  { 8,1 },{ 9,1 }, 
                  { 0,0 } 
               };   
                
   POINT pt2[] = {  
                  { 2,8 }, 
                  { 1,7 },{ 1,6 },{ 1,5 },{ 1,4 }, 
                  { 2,3 },{ 2,2 }, 
                  { 3,2 }, 
                  { 4,1 },{ 5,1 },{ 6,1 },{ 7,1 }, 
                  { 8,2 },{ 9,2 }, 
                  { 0,0 } 
               };   
 
 
   POINT pt3[] = {  
                  { 2,9 },{ 3,9 }, 
                  { 4,10 },{ 5,10 },{ 6,10 },{ 7,10 }, 
                  { 8,9 },{ 9,9 }, 
                  { 9,8 }, 
                  { 10,7 },{ 10,6 },{ 10,5 },{ 10,4 }, 
                  { 9,3 }, 
                  { 0,0 } 
               };   
 
   POINT pt4[] = {  
                  { 2,10 },{ 3,10 }, 
                  { 4,11 },{ 5,11 },{ 6,11 },{ 7,11 }, 
                  { 8,10 },{ 9,10 }, 
                  { 10,9 },{ 10,8 }, 
                  { 11,7 },{ 11,6 },{ 11,5 },{ 11,4 }, 
                  { 10,3 },{ 10,2 }, 
                  { 0,0 } 
               };   
 
   if ( m_nState & dsHoverMask ) 
   { 
      DrawFrame( pt1, COLOR_3DSHADOW, 
                      hDC, rc.left, rc.top ); 
      DrawFrame( pt2, COLOR_3DDKSHADOW, 
                      hDC, rc.left, rc.top ); 
      DrawFrame( pt3, COLOR_3DFACE, 
                      hDC, rc.left, rc.top ); 
      DrawFrame( pt4, COLOR_WINDOW, 
                      hDC, rc.left, rc.top ); 
   } 
   else 
   { 
      if ( IsWindowEnabled( m_hWnd ) == TRUE )  
      {   
         DrawFrame( pt1, COLOR_3DSHADOW, 
                         hDC, rc.left, rc.top ); 
         DrawFrame( pt2, COLOR_WINDOW, 
                         hDC, rc.left, rc.top ); 
         DrawFrame( pt3, COLOR_3DFACE, 
                         hDC, rc.left, rc.top ); 
         DrawFrame( pt4, COLOR_WINDOW, 
                         hDC, rc.left, rc.top );                   
      } 
      else 
      { 
         DrawFrame( pt1, COLOR_3DSHADOW, 
                         hDC, rc.left, rc.top ); 
         DrawFrame( pt2, COLOR_3DFACE, 
                         hDC, rc.left, rc.top ); 
         DrawFrame( pt3, COLOR_3DFACE, 
                         hDC, rc.left, rc.top ); 
         DrawFrame( pt4, COLOR_3DHIGHLIGHT, 
                         hDC, rc.left, rc.top ); 
      } 
   }    
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMUpDown class 
 
void CCoolControlsManager::CCMUpDown::DrawButton( HDC hDC, const RECT& rc ) 
{ 
   // If associated edit control is disabled 
   // draw the up-down as disabled too 
   BOOL bEnabled = IsWindowEnabled( m_hWnd ); 
   HWND hWnd = (HWND)SendMessage( m_hWnd, UDM_GETBUDDY, 0, 0L ); 
   if ( hWnd ) 
      bEnabled = IsWindowEnabled( hWnd ); 
 
   if ( bEnabled && m_nState & dsHoverMask ) 
      Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW, 
                             COLOR_3DHIGHLIGHT, COLOR_3DSHADOW ); 
   else 
      Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                             COLOR_3DFACE, COLOR_3DFACE ); 
} 
 
void CCoolControlsManager::CCMUpDown::DrawControl( HDC hDC, const RECT& rect ) 
{          
   RECT rc = rect; 
   CCMControl* pCtl = NULL; 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
   HWND hWnd = (HWND)SendMessage( m_hWnd, UDM_GETBUDDY, 0, 0L ); 
   if ( hWnd && ( dwStyle & UDS_ALIGNRIGHT || dwStyle & UDS_ALIGNLEFT ) ) 
   { 
      if ( dwStyle & UDS_ALIGNLEFT ) 
         rc.left += 2; 
      else   // UDS_ALIGNRIGHT 
         rc.right -= 2; 
      rc.top += 2; 
      rc.bottom -= 2; 
                  
      if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) &&  
           !( pCtl->GetState() & dsHoverMask ) ) 
      { 
         COLORREF clr1 = GetSysColor( IsWindowEnabled( hWnd ) ? COLOR_3DHIGHLIGHT : COLOR_3DFACE ); 
         COLORREF clr2 = GetSysColor( IsWindowEnabled( hWnd ) ? COLOR_3DLIGHT : COLOR_3DFACE ); 
 
         FillSolidRect( hDC, rc.left, rc.top - 1, 
                             rc.right, 1, 
                             clr1 ); 
         FillSolidRect( hDC, rc.left, rc.bottom, 
                             rc.right, 1,                                   
                             clr2 ); 
 
         if ( dwStyle & UDS_ALIGNLEFT ) 
            FillSolidRect( hDC, rc.left - 1, rc.top - 1, 
                                1, rc.bottom, 
                                clr1 ); 
         else 
            FillSolidRect( hDC, rc.right, rc.top - 1, 
                                1, rc.bottom, 
                                clr2 ); 
      } 
   } 
 
   RECT r = rc; 
   if ( dwStyle & UDS_HORZ ) 
   { 
      r.right = r.left + ( rc.right - rc.left ) / 2; 
      DrawButton( hDC, r ); 
 
      r.left = r.right + ( rc.right - rc.left ) % 2; 
      r.right = rc.right; 
      DrawButton( hDC, r ); 
   } 
   else 
   { 
      r.bottom = r.top + ( rc.bottom - rc.top ) / 2; 
      DrawButton( hDC, r ); 
 
      r.top = r.bottom + ( rc.bottom - rc.top ) % 2; 
      r.bottom = rc.bottom; 
      DrawButton( hDC, r ); 
   } 
 
   if ( pCtl == NULL )  // Get parent (e.g. for datetime with up-down controls) 
   { 
      hWnd = GetParent( m_hWnd ); 
      g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ); 
   } 
 
   if ( pCtl && IsWindowEnabled( hWnd ) )   // Redraw parent or buddy if neccesary 
   { 
      if ( m_nState & dsHoverMask ) 
         pCtl->SetState( 0, dsHover ); 
      else 
         pCtl->SetState( dsHover, 0 ); 
   } 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMEditCombo class 
 
void CCoolControlsManager::CCMEditCombo::PrepareDraw( HDC& hDC, RECT& rect ) 
{ 
   GetWindowRect( m_hWnd, &rect ); 
   InflateRect( &rect, 3, 3 ); 
   OffsetRect( &rect, -rect.left, -rect.top ); 
   // Draw onto that DC that is most suitable for given class    
   hDC = GetWindowDC( GetParent( m_hWnd ) ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMScrollBar class 
 
void CCoolControlsManager::CCMScrollBar::DrawControl( HDC hDC, const RECT& rc ) 
{   
   DrawScrollBar( hDC, rc,  
             ( GetWindowLong( m_hWnd, GWL_STYLE ) & SBS_VERT ) ? SB_VERT : SB_HORZ, 
             TRUE ); 
} 
 
LRESULT CCoolControlsManager::CCMScrollBar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      // Scrollbar messages 
      case SBM_SETPOS: 
         if ( !lParam )  // redraw flag 
            break; 
 
      case SBM_SETSCROLLINFO:       
         if ( !wParam )  // redraw flag 
            break; 
 
      case SBM_SETRANGEREDRAW: 
         CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
         DrawBorder(); 
         return 0; 
 
      default: 
         return CCMControl::WindowProc( uMsg, wParam, lParam ); 
   } 
 
   return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMHeaderCtrl class 
 
void CCoolControlsManager::CCMHeaderCtrl::DrawButton( HDC hDC, const RECT& rc, int nState ) 
{ 
   if ( nState & dsHoverMask ) 
      Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, 
                             COLOR_3DLIGHT, COLOR_3DSHADOW ); 
   else 
      Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                             COLOR_3DFACE, COLOR_3DFACE );       
} 
 
void CCoolControlsManager::CCMHeaderCtrl::DrawControl( HDC hDC, const RECT& /*rc*/ ) 
{ 
   int nOldItem = m_nOldItem; 
   m_nOldItem = -1; 
 
   RECT rc; 
   POINT point; 
   GetCursorPos( &point ); 
 
   // This code fails if we will have standalone header control but such cases are rare... 
   HWND hWnd = GetParent( m_hWnd );  
   GetClientRect( GetParent( m_hWnd ), &rc ); 
   ScreenToClient( GetParent( m_hWnd ), &point ); 
   // Test if mouse pointer is within the client area of the list control 
   BOOL bInView = PtInRect( &rc, point );     
 
   GetClientRect( m_hWnd, &rc ); 
   rc.right = 0; 
   GetCursorPos( &point ); 
   ScreenToClient( m_hWnd, &point ); 
   hDC = GetDC( m_hWnd ); 
    
   int nState; 
   int nCount = SendMessage( m_hWnd, HDM_GETITEMCOUNT, 0, 0L );    
 
   for ( int i = 0; i < nCount; i++ ) 
   { 
    #if (_WIN32_IE >= 0x0300) 
      HDITEM hi; 
      hi.mask = HDI_ORDER; 
      SendMessage( m_hWnd, HDM_GETITEM, i, (LPARAM)&hi ); 
      SendMessage( m_hWnd, HDM_GETITEMRECT, hi.iOrder, (LPARAM)&rc ); 
    #else 
      SendMessage( m_hWnd, HDM_GETITEMRECT, i, (LPARAM)&rc ); 
    #endif 
      nState = 0; 
      if ( bInView & PtInRect( &rc, point ) ) 
      { 
         nState = dsHover; 
       #if (_WIN32_IE >= 0x0300) 
         m_nOldItem = hi.iOrder; 
       #else 
         m_nOldItem = i; 
       #endif 
      } 
      DrawButton( hDC, rc, nState ); 
   } 
 
   int l = rc.right; 
   GetClientRect( m_hWnd, &rc ); 
   rc.left = l; 
   DrawButton( hDC, rc, 0 ); 
 
   // If header is a child of ListView, redraw the list so  
   // it will indicate proper state       
   CCMControl* pCtl;    
   if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) ) 
   { 
      if ( m_nOldItem >= 0 ) 
         pCtl->SetState( 0, dsHover ); 
      else if ( nOldItem >= 0 ) 
         pCtl->SetState( dsHover, 0 ); 
   } 
 
   ReleaseDC( m_hWnd, hDC ); 
} 
 
BOOL CCoolControlsManager::CCMHeaderCtrl::NeedRedraw( const POINT& point ) 
{ 
   RECT rc; 
   GetClientRect( m_hWnd, &rc ); 
   rc.right = 0; 
 
   POINT pt = point; 
   ScreenToClient( m_hWnd, &pt ); 
 
   int nItem = -1; 
   int nCount = SendMessage( m_hWnd, HDM_GETITEMCOUNT, 0, 0L ); 
 
   for ( int i = 0; i < nCount; i++ ) 
   { 
      HDITEM hi; 
      hi.mask = HDI_WIDTH;       
      SendMessage( m_hWnd, HDM_GETITEM, i, (LPARAM)&hi ); 
      rc.left = rc.right; 
      rc.right = rc.left + hi.cxy; 
      if ( PtInRect( &rc, pt ) ) 
      { 
         nItem = i; 
         break; 
      } 
   } 
 
   if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) ) 
      return TRUE; 
   return FALSE; 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMTrackbar class 
 
void CCoolControlsManager::CCMTrackbar::DrawThumb( HDC hDC, const RECT& rc ) 
{ 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
 
   if ( dwStyle & TBS_BOTH ) 
   { 
      FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); 
      if ( m_nState & dsHoverMask ) 
         Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, 
                                COLOR_3DLIGHT, COLOR_3DSHADOW ); 
      else 
         Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                                COLOR_3DFACE, COLOR_3DFACE );       
      return; 
   } 
    
   HPEN penHighlight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
   HPEN penLight = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DLIGHT : COLOR_3DFACE ) ); 
   HPEN penDkShadow = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DDKSHADOW : COLOR_3DSHADOW ) ); 
   HPEN penShadow = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DSHADOW : COLOR_3DFACE ) ); 
 
   int n; 
   if ( dwStyle & TBS_VERT ) 
   { 
      if ( dwStyle & TBS_LEFT ) 
      {     
         n = ( rc.bottom - rc.top ) / 2 + 1; 
 
         FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); 
       
         HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); 
         MoveToEx( hDC, rc.right - 2, rc.top, NULL ); 
         LineTo( hDC, rc.left + n - 1, rc.top ); 
         LineTo( hDC, rc.left, rc.top + n - 1 );          
          
         SelectObject( hDC, penDkShadow ); 
         LineTo( hDC, rc.left + n - 1, rc.bottom - 1 ); 
         LineTo( hDC, rc.right - 1, rc.bottom - 1 ); 
         LineTo( hDC, rc.right - 1, rc.top - 1 ); 
 
         SelectObject( hDC, penLight ); 
         MoveToEx( hDC, rc.right - 3, rc.top + 1, NULL ); 
         LineTo( hDC, rc.left + n - 1, rc.top + 1 ); 
         LineTo( hDC, rc.left + 1, rc.top + n - 1 ); 
 
         SelectObject( hDC, penShadow );          
         LineTo( hDC, rc.left + n - 1, rc.bottom - 2 ); 
         LineTo( hDC, rc.right - 2, rc.bottom - 2 ); 
         LineTo( hDC, rc.right - 2, rc.top ); 
 
         SelectObject( hDC, hOldPen );          
      } 
      else // TBS_RIGHT 
      { 
         n = ( rc.bottom - rc.top ) / 2 + 1; 
 
         FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); 
       
         HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); 
         MoveToEx( hDC, rc.left, rc.bottom - 2, NULL ); 
         LineTo( hDC, rc.left, rc.top ); 
         LineTo( hDC, rc.right - n, rc.top ); 
         LineTo( hDC, rc.right - 1, rc.top + n - 1 ); 
 
         SelectObject( hDC, penDkShadow );           
         MoveToEx( hDC, rc.left, rc.bottom - 1, NULL ); 
         LineTo( hDC, rc.right - n, rc.bottom - 1 ); 
         LineTo( hDC, rc.right, rc.top + n - 2 );          
 
         SelectObject( hDC, penLight ); 
         MoveToEx( hDC, rc.left + 1, rc.bottom - 3, NULL ); 
         LineTo( hDC, rc.left + 1, rc.top + 1 ); 
         LineTo( hDC, rc.right - n, rc.top + 1 ); 
         LineTo( hDC, rc.right - 2, rc.top + n - 1 ); 
 
         SelectObject( hDC, penShadow ); 
         MoveToEx( hDC, rc.left + 1, rc.bottom - 2, NULL ); 
         LineTo( hDC, rc.right - n, rc.bottom - 2 ); 
         LineTo( hDC, rc.right - 1, rc.top + n - 2 );          
 
         SelectObject( hDC, hOldPen ); 
      }       
   } 
   else 
   { 
      if ( dwStyle & TBS_TOP ) 
      {       
         n = ( rc.right - rc.left ) / 2 + 1; 
 
         FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); 
       
         HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); 
         MoveToEx( hDC, rc.left + n - 2, rc.top + 1, NULL ); 
         LineTo( hDC, rc.left, rc.top + n - 1 ); 
         LineTo( hDC, rc.left, rc.bottom - 1 ); 
 
         SelectObject( hDC, penDkShadow );           
         LineTo( hDC, rc.right - 1, rc.bottom - 1 ); 
         LineTo( hDC, rc.right - 1, rc.top + n - 1 ); 
         LineTo( hDC, rc.left + n - 2, rc.top - 1 ); 
 
         SelectObject( hDC, penLight ); 
         MoveToEx( hDC, rc.left + n - 2, rc.top + 2, NULL ); 
         LineTo( hDC, rc.left + 1, rc.top + n - 1 ); 
         LineTo( hDC, rc.left + 1, rc.bottom - 2 ); 
      
         SelectObject( hDC, penShadow ); 
         LineTo( hDC, rc.right - 2, rc.bottom - 2 ); 
         LineTo( hDC, rc.right - 2, rc.top + n - 1 ); 
         LineTo( hDC, rc.left + n - 2, rc.top ); 
 
         SelectObject( hDC, hOldPen ); 
      } 
      else // TBS_BOTTOM 
      { 
         n = ( rc.right - rc.left ) / 2 + 1; 
 
         FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) ); 
                
         HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight ); 
         MoveToEx( hDC, rc.left + n - 2, rc.bottom - 2, NULL ); 
         LineTo( hDC, rc.left, rc.bottom - n ); 
         LineTo( hDC, rc.left, rc.top ); 
         LineTo( hDC, rc.right - 1, rc.top ); 
 
         SelectObject( hDC, penDkShadow );           
         LineTo( hDC, rc.right - 1, rc.bottom - n ); 
         LineTo( hDC, rc.left + n - 2, rc.bottom ); 
 
         SelectObject( hDC, penLight ); 
         MoveToEx( hDC, rc.left + n - 2, rc.bottom - 3, NULL ); 
         LineTo( hDC, rc.left + 1, rc.bottom - n ); 
         LineTo( hDC, rc.left + 1, rc.top + 1 ); 
         LineTo( hDC, rc.right - 2, rc.top + 1 ); 
      
         SelectObject( hDC, penShadow ); 
         LineTo( hDC, rc.right - 2, rc.bottom - n ); 
         LineTo( hDC, rc.left + n - 2, rc.bottom - 1 ); 
 
         SelectObject( hDC, hOldPen ); 
      } 
   } 
 
   DeleteObject( penHighlight ); 
   DeleteObject( penLight ); 
   DeleteObject( penDkShadow ); 
   DeleteObject( penShadow ); 
} 
 
void CCoolControlsManager::CCMTrackbar::DrawControl( HDC hDC, const RECT& /*rect*/ ) 
{   
   hDC = GetDC( m_hWnd ); 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
    
   RECT rc;    
   SendMessage( m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)&rc );    
 
   // BUG!: Windows incorrectly calculates the channel rectangle for 
   // sliders with TBS_VERT style, so we have to calculate the rectangle 
   // in different manner. This bug appears on all Windows platforms! 
   if ( dwStyle & TBS_VERT ) 
   {   
      int w = ( rc.right - rc.left ); 
      int h = ( rc.bottom - rc.top ); 
      rc.top = rc.left; 
      rc.bottom = rc.left + w; 
 
      RECT r; 
      SendMessage( m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)&r );          
 
      rc.left = r.left + ( ( r.right - r.left ) / 2 + 1 ) - h / 2; 
      if ( dwStyle & TBS_LEFT ) 
         ; 
      else if ( dwStyle & TBS_BOTH ) 
         rc.left -= 1; 
      else 
         rc.left -= 2; 
 
      rc.right = rc.left + h; 
   } 
 
   // Draw the channel rect 
   if ( m_nState & dsHoverMask ) 
      Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,                          
                             COLOR_3DDKSHADOW, COLOR_3DLIGHT ); 
   else 
      Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,                          
                             COLOR_3DFACE, COLOR_3DFACE ); 
    
   // Draw the slider thumb 
   if ( !( dwStyle & TBS_NOTHUMB ) ) 
   { 
      SetRectEmpty( &rc ); 
      SendMessage( m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)&rc ); 
      DrawThumb( hDC, rc ); 
   } 
 
   ReleaseDC( m_hWnd, hDC ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMToolbar class 
 
void CCoolControlsManager::CCMToolbar::DrawButton( HDC hDC, const RECT& rc, int nState ) 
{ 
   if ( nState & bsChecked ) 
   { 
      if ( nState & bsHover ) 
         Draw3dBorder( hDC, rc, 
                       COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT, 
                       COLOR_3DSHADOW, COLOR_3DSHADOW ); 
      else 
         Draw3dBorder( hDC, rc, 
                       COLOR_3DSHADOW, COLOR_3DHIGHLIGHT, 
                       COLOR_3DFACE, COLOR_3DFACE ); 
   } 
   else 
   { 
      if ( nState & bsHover ) 
         Draw3dBorder( hDC, rc, 
                       COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW, 
                       COLOR_3DLIGHT, COLOR_3DSHADOW ); 
      else 
         Draw3dBorder( hDC, rc, 
                       COLOR_3DHIGHLIGHT, COLOR_3DSHADOW, 
                       COLOR_3DFACE, COLOR_3DFACE ); 
   } 
} 
 
void CCoolControlsManager::CCMToolbar::DrawControl( HDC hDC, const RECT& /*rc*/ ) 
{ 
   if ( GetWindowLong( m_hWnd, GWL_STYLE ) & TBSTYLE_FLAT ) // Skip flat toolbars 
      return; 
       
   int nCount = SendMessage( m_hWnd, TB_BUTTONCOUNT, 0, 0L ); 
 
   hDC = GetDC( m_hWnd );  // We will draw toolbar buttons on the client DC 
 
   POINT point; 
   GetCursorPos( &point ); 
   ScreenToClient( m_hWnd, &point ); 
    
   m_nOldItem = -1; 
   int nState = 0; 
            
   for ( int i = 0; i < nCount; i++ ) 
   {      
      RECT rc;        
      TBBUTTON ti; 
      SendMessage( m_hWnd, TB_GETBUTTON, i, (LPARAM)&ti ); 
      SendMessage( m_hWnd, TB_GETITEMRECT, i, (LPARAM)&rc ); 
 
      if ( !( ti.fsStyle & TBSTYLE_SEP ) ) 
      {                   
         nState = ( ti.fsState & TBSTATE_CHECKED ) ? bsChecked : bsNormal; 
         if ( PtInRect( &rc, point ) == TRUE ) 
         { 
            if ( ti.fsState & TBSTATE_ENABLED ) 
               nState |= bsHover; 
            m_nOldItem = i; 
         }          
         DrawButton( hDC, rc, nState ); 
      } 
   } 
       
   ReleaseDC( m_hWnd, hDC ); 
} 
 
BOOL CCoolControlsManager::CCMToolbar::NeedRedraw( const POINT& point ) 
{ 
   int nCount = SendMessage( m_hWnd, TB_BUTTONCOUNT, 0, 0L ); 
 
   POINT pt = point; 
   ScreenToClient( m_hWnd, &pt ); 
   int nItem = -1;                 
   for ( int i = 0; i < nCount; i++ ) 
   {             
      TBBUTTON ti;       
      SendMessage( m_hWnd, TB_GETBUTTON, i, (LPARAM)&ti ); 
 
      if ( !( ti.fsStyle & TBSTYLE_SEP ) ) 
      { 
         RECT rc;          
         SendMessage( m_hWnd, TB_GETITEMRECT, i, (LPARAM)&rc ); 
         if ( PtInRect( &rc, pt ) ) 
         { 
            nItem = i; 
            break; 
         } 
      } 
   } 
 
   if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) ) 
      return TRUE; 
   return FALSE; 
} 
 
LRESULT CCoolControlsManager::CCMToolbar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {   
      case WM_PAINT: 
      case WM_NCPAINT: 
         m_nOldItem = -1;   // Redraw the whole toolbar unconditionally 
 
      default: 
         return CCMControl::WindowProc( uMsg, wParam, lParam ); 
   } 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMTabControl class 
 
void CCoolControlsManager::CCMTabControl::DrawTab( HDC hDC, const RECT& rect,  
                                                   int nItem, int nState ) 
{ 
   RECT rc = rect; 
   int nCurSel = SendMessage( m_hWnd, TCM_GETCURSEL, 0, 0L ); 
   if ( nCurSel == -1 ) 
      nCurSel = -2; 
 
   switch ( GetOrientation() ) 
   { 
      case tabLeft: 
         if ( nState & bsChecked ) 
         { 
            rc.top -= 2; 
            rc.bottom += 2; 
            rc.left -= 2; 
            rc.right += 1; 
         } 
 
         if ( nState & bsHover ) 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DLIGHT ) ); 
               SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DLIGHT ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DDKSHADOW ) ); 
               FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) );                         
               SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) ); 
            } 
         } 
         else 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); 
               SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DFACE ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) ); 
               FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) );                         
               SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) ); 
            } 
         }        
         break; 
 
      case tabTop: 
         if ( nState & bsChecked ) 
         { 
            rc.top -= 2; 
            rc.bottom += 1; 
            rc.left -= 2; 
            rc.right += 2; 
         } 
 
         if ( nState & bsHover ) 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DLIGHT ) ); 
               SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DLIGHT ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DDKSHADOW ) ); 
               FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) );             
               SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DDKSHADOW ) ); 
            }                        
         } 
         else 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); 
               SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DFACE ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) ); 
               FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) );                         
               SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DSHADOW ) ); 
            } 
         }        
         break; 
       
      case tabRight: 
         if ( nState & bsChecked ) 
         { 
            rc.top -= 2; 
            rc.bottom += 2; 
            rc.right += 2; 
            rc.left -= 1; 
         } 
 
         if ( nState & bsHover ) 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DLIGHT ) ); 
               SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DDKSHADOW ) ); 
            FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DSHADOW ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) ); 
               FillSolidRect( hDC, rc.left, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DDKSHADOW ) ); 
               SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) ); 
            } 
         } 
         else 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); 
               SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DSHADOW ) ); 
            FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DFACE ) );             
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) );             
               FillSolidRect( hDC, rc.left, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) ); 
               SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) ); 
            }                         
         }        
         break; 
 
      case tabBottom: 
         if ( nState & bsChecked ) 
         { 
            rc.bottom += 2; 
            rc.left -= 2; 
            rc.right += 2; 
            rc.top -=1; 
         } 
 
         if ( nState & bsHover ) 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left+1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DLIGHT ) ); 
               SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DDKSHADOW ) ); 
            FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DSHADOW ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.right-1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DDKSHADOW ) ); 
               FillSolidRect( hDC, rc.right-2, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) );                         
               SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) ); 
            } 
         } 
         else 
         { 
            if ( nCurSel != nItem - 1 ) 
            { 
               FillSolidRect( hDC, rc.left, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
               FillSolidRect( hDC, rc.left+1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); 
               SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DHIGHLIGHT ) ); 
            } 
 
            FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DSHADOW ) ); 
            FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DFACE ) ); 
 
            if ( nCurSel != nItem + 1 ) 
            { 
               FillSolidRect( hDC, rc.right-1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) ); 
               FillSolidRect( hDC, rc.right-2, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) ); 
               SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) ); 
            } 
         }        
         break; 
   } 
} 
 
CCoolControlsManager::CCMTabControl::OrientationsEnum CCoolControlsManager::CCMTabControl::GetOrientation() const 
{ 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
   if ( dwStyle & TCS_BOTTOM ) 
   { 
      if ( dwStyle & TCS_VERTICAL ) 
         return tabRight; 
      else 
         return tabBottom;                
   } 
   else   
   {  
      if ( dwStyle & TCS_VERTICAL ) 
         return tabLeft; 
      else 
         return tabTop; 
   } 
} 
 
void CCoolControlsManager::CCMTabControl::DrawControl( HDC hDC, const RECT& rect ) 
{ 
   DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ); 
   if ( dwStyle & TCS_BUTTONS ) // Skip button-like tab controls 
      return; 
       
   hDC = GetDC( m_hWnd );  // We will draw on the client DC 
 
   RECT rc = rect; 
   SendMessage( m_hWnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc );    
   InflateRect( &rc, 4, 4 ); 
 
   RECT rcSel; 
   int nCurSel = SendMessage( m_hWnd, TCM_GETCURSEL, 0, 0L ); 
   SendMessage( m_hWnd, TCM_GETITEMRECT, nCurSel, (LPARAM)&rcSel ); 
 
   switch ( GetOrientation() ) 
   { 
      case tabLeft: 
         rc.left += 2; 
         FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); 
         FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) );          
         break; 
 
      case tabTop: 
         rc.top += 2;                   
         FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); 
         FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) ); 
         break; 
 
      case tabRight: 
         rc.right -= 2;          
         FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); 
         FillSolidRect( hDC, rc.right, rc.top, -1, rcSel.top-rc.top, GetSysColor( COLOR_3DSHADOW ) ); 
         FillSolidRect( hDC, rc.right, rcSel.bottom, -1, rc.bottom-rcSel.bottom, GetSysColor( COLOR_3DSHADOW ) ); 
         break; 
 
      case tabBottom: 
         rc.bottom -= 2;          
         FillSolidRect( hDC, rc.left, rc.bottom, rcSel.left-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) ); 
         FillSolidRect( hDC, rcSel.right, rc.bottom, rc.right-rcSel.right, -1, GetSysColor( COLOR_3DSHADOW ) ); 
         FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) ); 
         break; 
   } 
 
   Draw3dRect( hDC, rc.left+1, rc.top+1, rc.right-rc.left-2, rc.bottom-rc.top-2,  
               GetSysColor( COLOR_3DFACE ), GetSysColor( COLOR_3DFACE ) ); 
 
   m_nOldItem = -1; 
   int nState = 0;    
   POINT point; 
   GetCursorPos( &point ); 
   ScreenToClient( m_hWnd, &point ); 
   int nCount = SendMessage( m_hWnd, TCM_GETITEMCOUNT, 0, 0L ); 
       
   for ( int i = 0; i < nCount; i++ ) 
   {      
      SendMessage( m_hWnd, TCM_GETITEMRECT, i, (LPARAM)&rc ); 
    
      nState = bsNormal; 
      if ( nCurSel != i ) 
      { 
         if ( PtInRect( &rc, point ) == TRUE ) 
         { 
            nState |= bsHover; 
            m_nOldItem = i; 
         }          
         DrawTab( hDC, rc, i, nState ); 
      } 
   } 
       
   nState = bsChecked; 
   if ( PtInRect( &rcSel, point ) == TRUE ) 
   { 
      nState |= bsHover; 
      m_nOldItem = nCurSel; 
   }          
   DrawTab( hDC, rcSel, nCurSel, nState ); 
    
   if ( nCurSel != 0 ) 
      switch ( GetOrientation() ) 
      { 
         case tabTop: 
            FillSolidRect( hDC, rect.left, rect.top, 2, rcSel.bottom-rcSel.top+2, GetSysColor( COLOR_3DFACE ) ); 
            break; 
         case tabBottom: 
            FillSolidRect( hDC, rect.left, rect.bottom, 2, -rcSel.bottom+rcSel.top-2, GetSysColor( COLOR_3DFACE ) ); 
            break; 
      } 
 
   ReleaseDC( m_hWnd, hDC ); 
} 
 
BOOL CCoolControlsManager::CCMTabControl::NeedRedraw( const POINT& point ) 
{    
   int nCount = SendMessage( m_hWnd, TCM_GETITEMCOUNT, 0, 0L );                   
 
   TCHITTESTINFO thti; 
   thti.pt = point; 
   ScreenToClient( m_hWnd, &thti.pt ); 
   int nItem = SendMessage( m_hWnd, TCM_HITTEST, 0, (LPARAM)&thti ); 
 
   if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) ) 
      return TRUE; 
   return FALSE; 
} 
 
LRESULT CCoolControlsManager::CCMTabControl::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {   
      case WM_PAINT: 
      case WM_NCPAINT: 
         m_nOldItem = -1;   // Redraw the whole control unconditionally 
         break; 
   } 
   return CCMControl::WindowProc( uMsg, wParam, lParam ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMIPAddress class 
 
BOOL CCoolControlsManager::CCMIPAddress::IsFocused() 
{ 
   HWND hWnd = GetTopWindow( m_hWnd ); 
   while ( hWnd ) 
   { 
      if ( hWnd == GetFocus() ) 
         return TRUE; 
      hWnd = GetNextWindow( hWnd, GW_HWNDNEXT ); 
   } 
 
   return FALSE; 
} 
 
LRESULT CCoolControlsManager::CCMIPAddress::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      case WM_COMMAND: 
         if ( HIWORD( wParam ) == EN_SETFOCUS || HIWORD( wParam ) == EN_KILLFOCUS ) 
            DrawBorder(); 
         break; 
 
      default: 
         return CCMControl::WindowProc( uMsg, wParam, lParam ); 
   } 
 
   return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
} 
 
////////////////////////////////////////////////////////////////////////////// 
// CCMDialog class 
 
LRESULT CCoolControlsManager::CCMDialog::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
   switch ( uMsg ) 
   {       
      case WM_PARENTNOTIFY:          
         if ( LOWORD( wParam ) == WM_CREATE )   // Add dynamically created controls to the map 
            g_ctrlManager.AddControl( (HWND)lParam ); 
         break; 
 
      case WM_NCDESTROY: 
         // Unsubclass window and remove it from the map 
         CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
         g_ctrlManager.RemoveDialog( m_hWnd ); 
         return 0; 
   } 
 
   return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam ); 
} 
 
/////////////////////////////////////////////////////////////////////////////////// 
// Helper functions for drawing 3D frames (borrowed from CDC class) 
 
void CCoolControlsManager::CCMControl::FillSolidRect( HDC hDC, int x, int y, int cx, int cy, COLORREF clr ) 
{ 
   SetBkColor( hDC, clr ); 
   RECT rect; 
   SetRect( &rect, x, y, x + cx, y + cy ); 
   ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL ); 
} 
 
void CCoolControlsManager::CCMControl::FillSolidRect( HDC hDC, const RECT& rect, COLORREF clr ) 
{ 
   SetBkColor( hDC, clr ); 
   ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL ); 
} 
 
void CCoolControlsManager::CCMControl::Draw3dRect( HDC hDC, int x, int y, int cx, int cy, 
                                                  COLORREF clrTopLeft, COLORREF clrBottomRight ) 
{ 
   FillSolidRect( hDC, x, y, cx - 1, 1, clrTopLeft ); 
   FillSolidRect( hDC, x, y, 1, cy - 1, clrTopLeft ); 
   FillSolidRect( hDC, x + cx, y, -1, cy, clrBottomRight ); 
   FillSolidRect( hDC, x, y + cy, cx, -1, clrBottomRight ); 
} 
 
void CCoolControlsManager::CCMControl::Draw3dRect( HDC hDC, const RECT& rect, 
                                                  COLORREF clrTopLeft, COLORREF clrBottomRight ) 
{ 
   Draw3dRect( hDC, rect.left, rect.top, rect.right - rect.left, 
                    rect.bottom - rect.top, clrTopLeft, clrBottomRight ); 
} 
 
void CCoolControlsManager::CCMControl::Draw3dBorder( HDC hDC, const RECT& rc,  
                                                    int nColor1, int nColor2, 
                                                    int nColor3, int nColor4 ) 
{ 
   Draw3dRect( hDC, rc, GetSysColor( nColor1 ), GetSysColor( nColor2 ) ); 
 
   Draw3dRect( hDC, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2,  
                        GetSysColor( nColor3 ), GetSysColor( nColor4 ) ); 
} 
 
void CCoolControlsManager::CCMControl::Draw3dBorder( HDC hDC, const RECT& rc,  
                                                    int nColor1, int nColor2, 
                                                    int nColor3, int nColor4, 
                                                    int nColor5, int nColor6 ) 
{ 
   Draw3dRect( hDC, rc, GetSysColor( nColor1 ), GetSysColor( nColor2 ) ); 
 
   Draw3dRect( hDC, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2,  
                        GetSysColor( nColor3 ), GetSysColor( nColor4 ) ); 
   Draw3dRect( hDC, rc.left + 2, rc.top + 2, rc.right - rc.left - 4, rc.bottom - rc.top - 4,  
                  GetSysColor( nColor5 ), GetSysColor( nColor6 ) ); 
}