CoolControlsManager.cpp
上传用户:lydc80129
上传日期:2013-01-15
资源大小:979k
文件大小:77k
源码类别:

界面编程

开发平台:

Visual C++

  1. /******************************************************************
  2. $Archive: /MfcExt/Source/CoolControlsManager.cpp $
  3. $Workfile: CoolControlsManager.cpp $
  4. $Author: Bogdan Ledwig $
  5. $Date: 99-04-26 22:12 $
  6. $Revision: 13 $
  7. *******************************************************************/
  8. #include "StdAfx.h"
  9. #include "CoolControlsManager.h"
  10. // If you don't want to see extra TRACE diagnostics,
  11. // modify the line below to: #define CCM_TRACE
  12. #define CCM_TRACE TRACE
  13. #define CCM_TIMER_VAL 100        // 100 ms timer period seems to be good enough...
  14. #define MAX_CLASSNAME 64         // Length of buffer for retrieving the class name
  15. ////////////////////////////////////////////////////////////////////////
  16. // CCMControl static members initialization
  17. HWND CCoolControlsManager::CCMControl::m_hWndOld = NULL;
  18. CMapPtrToPtr CCoolControlsManager::m_ctrlMap = 10;
  19. CMapPtrToPtr CCoolControlsManager::m_dlgMap = 10;
  20. BOOL CCoolControlsManager::m_bEnabled = TRUE;
  21. // Changed 02.03.1999 Mike Walter
  22. CMapWordToPtr CCoolControlsManager::m_threadMap = 10;     
  23. ///////////////////////////////////////////////////////////////////////
  24. // Here is the one and only CCoolControlsManager object
  25. static CCoolControlsManager g_ctrlManager;
  26. CCoolControlsManager& GetCtrlManager()
  27. {
  28.    return g_ctrlManager;
  29. }
  30. ////////////////////////////////////////////////////////////////////////
  31. // WH_CALLWNDPROC hook procedure
  32. LRESULT CALLBACK CCM_CallWndProc( int nCode, WPARAM wParam, LPARAM lParam )
  33. {   
  34.    HOOKPROC hHookProc;
  35.    if ( g_ctrlManager.m_threadMap.Lookup( (WORD)GetCurrentThreadId(), (void*&)hHookProc ) == FALSE )
  36.    {
  37. //      TRACE( "CCoolControlsManager: No hook for this thread installed!n" );
  38.       return 0;
  39.    }
  40.    if ( nCode == HC_ACTION )
  41.    {      
  42.       CWPSTRUCT* pwp = (CWPSTRUCT*)lParam;
  43.       if ( g_ctrlManager.IsEnabled() )
  44.       {
  45.          if ( g_ctrlManager.m_bDialogOnly == TRUE )        
  46.          {
  47.             if ( pwp->message == WM_INITDIALOG )
  48.                g_ctrlManager.Install( pwp->hwnd );
  49.          }
  50.          else if ( pwp->message == WM_CREATE && g_ctrlManager.IsEnabled() )
  51.          {
  52.             TCHAR szBuf[MAX_CLASSNAME];
  53.             if ( GetWindowLong( pwp->hwnd, GWL_STYLE ) & WS_CHILD )
  54.             {
  55.                GetClassName( pwp->hwnd, szBuf, MAX_CLASSNAME );
  56.                if ( lstrcmp( szBuf, _T( "ScrollBar" ) ) ) // Don't add scrollbars
  57.                   g_ctrlManager.AddControl( pwp->hwnd );
  58.             }
  59.          }
  60.       }
  61.    }   
  62.    // Changed 02.03.1999 Mike Walter
  63.    return CallNextHookEx( (HHOOK)hHookProc, nCode, wParam, lParam );
  64. }
  65. // Install a hook for the current thread only
  66. void CCoolControlsManager::InstallHook( DWORD dwThreadID, BOOL bDialogOnly )
  67. {
  68.    // ASSERT( m_hkWndProc == NULL );
  69.    m_bDialogOnly = bDialogOnly;
  70.    // Changes 02.03.1999 Mike Walter
  71.    HOOKPROC hNewHook;
  72.    if ( m_threadMap.Lookup( (WORD)( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ), (void*&)hNewHook ) == FALSE )
  73.    {
  74.       hNewHook = (HOOKPROC)SetWindowsHookEx( WH_CALLWNDPROC,
  75.                                              (HOOKPROC)CCM_CallWndProc,
  76.                                              NULL,
  77.                                              ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) );
  78.       m_threadMap.SetAt( (WORD)( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ), hNewHook );
  79.       CCM_TRACE( "CCoolControlsManager: WH_CALLWNDPROC hook installed for thread: %dn", ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) );
  80.    }
  81.    else
  82.       CCM_TRACE( "CCoolControlsManager: WH_CALLWNDPROC hook already installed for thread: %d!n", ( dwThreadID == -1 ? GetCurrentThreadId() : dwThreadID ) );
  83. }
  84. // Install a global hook for all windows in the system.
  85. // This function may be called only when is put in a DLL.
  86. void CCoolControlsManager::InstallGlobalHook( HINSTANCE hInstance, BOOL bDialogOnly )
  87. {
  88.    ASSERT( hInstance );      // hInstance must not be NULL!
  89.    ASSERT( m_hkWndProc == NULL );
  90.    
  91.    m_bDialogOnly = bDialogOnly;
  92.    HOOKPROC hkProc = (HOOKPROC)GetProcAddress( hInstance, "CCM_CallWndProc" );
  93.    m_hkWndProc = (HOOKPROC)SetWindowsHookEx( WH_CALLWNDPROC,
  94.                                          (HOOKPROC)hkProc,
  95.                                          hInstance,
  96.                                          0 );   
  97.    CCM_TRACE( _T( "CCoolControlsManager: WH_CALLWNDPROC global hook installedn" ) );
  98. }
  99. void CCoolControlsManager::UninstallHook( DWORD dwThreadID )
  100. {
  101.    // ASSERT( m_hkWndProc != NULL );
  102.    // Changes 02.03.1999 Mike Walter
  103.    HOOKPROC hHookProc;
  104.    if ( dwThreadID == -1 )
  105.    {
  106.       if ( g_ctrlManager.m_threadMap.Lookup( (WORD)GetCurrentThreadId(), (void*&)hHookProc ) == FALSE )
  107.       {
  108.          CCM_TRACE( "CCoolControlsManager: No hook installed for thread: %d!n", GetCurrentThreadId() );
  109.          return;
  110.       }
  111.       UnhookWindowsHookEx( (HHOOK)hHookProc );
  112.       m_threadMap.RemoveKey( (WORD)GetCurrentThreadId() );
  113.       CCM_TRACE( "CCoolControlsManager: Hook uninstalled for thread: %dn", GetCurrentThreadId() );
  114.       CCM_TRACE( "CCoolControlsManager: Thread map has %d itemsn",g_ctrlManager.m_threadMap.GetCount() );
  115.    }
  116.    else
  117.    {
  118.       if ( g_ctrlManager.m_threadMap.Lookup( (WORD)dwThreadID, (void*&)hHookProc) == FALSE )
  119.       {
  120.          CCM_TRACE( "CCoolControlsManager: No hook installed for thread: %d!n", dwThreadID );
  121.          return;
  122.       }
  123.       UnhookWindowsHookEx( (HHOOK)hHookProc );
  124.       m_threadMap.RemoveKey( (WORD)dwThreadID );
  125.       CCM_TRACE( "CCoolControlsManager: Hook uninstalled for thread: %dn", dwThreadID );
  126.       CCM_TRACE( "CCoolControlsManager: Thread map has %d itemsn", g_ctrlManager.m_threadMap.GetCount() );
  127.    }
  128.    if ( m_uTimerID && g_ctrlManager.m_threadMap.IsEmpty() == TRUE )
  129.       KillTimer( NULL, m_uTimerID );
  130. }
  131. //////////////////////////////////////////////////////////////////////
  132. // Construction/Destruction
  133. //////////////////////////////////////////////////////////////////////
  134. CCoolControlsManager::CCoolControlsManager()
  135. {  
  136.    m_hkWndProc = NULL;
  137.    m_uTimerID = 0;
  138.    CCM_TRACE( _T( "CCoolControlsManager::CCoolControlsManager()n" ) );
  139. }
  140. CCoolControlsManager::~CCoolControlsManager()
  141. {  
  142.    // Changed 02.03.1999 Mike Walter
  143.    POSITION pos = m_threadMap.GetStartPosition();
  144.    while ( pos )
  145.    {
  146.       HOOKPROC hHook;
  147.       DWORD dwThreadID = 0;
  148.       m_threadMap.GetNextAssoc( pos, (WORD&)dwThreadID, (void*&)hHook );
  149.       UninstallHook( dwThreadID );
  150.    }
  151.    // If we have any elements in the map (normally impossible), unsubclass they and remove
  152.    pos = m_ctrlMap.GetStartPosition();
  153.    while ( pos )
  154.    {
  155.       HWND hWnd;
  156.       CCMControl* pCtl;
  157.       m_ctrlMap.GetNextAssoc( pos, (void*&)hWnd, (void*&)pCtl );
  158.       pCtl->Unsubclass();
  159.       m_ctrlMap.RemoveKey( hWnd );
  160.       delete pCtl;
  161.    }
  162.    // Now do the same things for dialog map
  163.    pos = m_dlgMap.GetStartPosition();
  164.    while ( pos )
  165.    {
  166.       HWND hWnd;
  167.       CCMDialog* pCtl;
  168.       m_dlgMap.GetNextAssoc( pos, (void*&)hWnd, (void*&)pCtl );
  169.       pCtl->Unsubclass();
  170.       m_dlgMap.RemoveKey( hWnd );
  171.       delete pCtl;
  172.    }
  173.    CCM_TRACE( "CCoolControlsManager::~CCoolControlsManager()n" ); 
  174. }
  175. void CCoolControlsManager::Install( HWND hWnd )
  176. {
  177.    CCMControl* pCtl;
  178.    if ( m_dlgMap.Lookup( hWnd, (void*&)pCtl ) ) // Already in the dialog map
  179.       return;
  180.    // Iterate through all child windows
  181.    HWND hCtrl = GetTopWindow( hWnd );
  182.    while ( hCtrl )
  183.    {
  184.       if ( GetWindowLong( hCtrl, GWL_STYLE ) & WS_CHILD )
  185.       {
  186.          TCHAR szBuf[MAX_CLASSNAME];
  187.          GetClassName( hCtrl, szBuf, MAX_CLASSNAME );
  188.          if ( lstrcmpi( szBuf, _T( "#32770" ) ) ) // Never add child dialogs!
  189.             AddControl( hCtrl );
  190.       }
  191.       hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT );
  192.    }    
  193.    AddDialog( hWnd ); // Add parent window as well
  194.    // Now redraw all recently inserted controls   
  195.    hCtrl = GetTopWindow( hWnd );
  196.    while ( hCtrl ) 
  197.    {
  198.       if ( m_ctrlMap.Lookup( hCtrl, (void*&)pCtl ) )
  199.          pCtl->DrawBorder();
  200.       hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT );
  201.    }    
  202. }
  203. void CCoolControlsManager::Uninstall( HWND hWnd )
  204. {
  205.    // Remove all window controls from the map
  206.    // when the window is about to destroy
  207.    CCM_TRACE( _T( "CCoolControlsManager: Uninstall, handle: %Xn" ), hWnd );
  208.    
  209.    HWND hCtrl = GetTopWindow( hWnd );
  210.    while ( hCtrl )
  211.    {
  212.       if ( GetWindowLong( hCtrl, GWL_STYLE ) & WS_CHILD )
  213.          RemoveControl( hCtrl );
  214.       hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT );
  215.    }
  216. }
  217. // In lpszClass you can specify class name, which will be used 
  218. // instead of true class name (useful for non-standard controls 
  219. // that are similar to the one of those we have supported)
  220. BOOL CCoolControlsManager::AddControl( HWND hWnd, LPCTSTR lpszClass )
  221. {  
  222.    CCMControl* pCtl = NULL; 
  223.    // Must not be NULL or already in the map
  224.    if ( hWnd == NULL || m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) )
  225.       return FALSE;   
  226.    
  227.    TCHAR szBuf[MAX_CLASSNAME];
  228.    if ( lpszClass == NULL )
  229.       GetClassName( hWnd, szBuf, MAX_CLASSNAME );
  230.    else
  231.       lstrcpy( szBuf, lpszClass );
  232.    DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE );
  233.    DWORD dwExStyle = GetWindowLong( hWnd, GWL_EXSTYLE );
  234.    if ( !lstrcmpi( szBuf, _T( "Button" ) ) )
  235.    {
  236.       if ( ( dwStyle & BS_OWNERDRAW ) == BS_OWNERDRAW )         
  237.          return FALSE;     // Do not subclass ownerdraw buttons
  238.       else if ( ( dwStyle & BS_GROUPBOX ) == BS_GROUPBOX ||
  239.            ( dwStyle & BS_FLAT ) == BS_FLAT ) 
  240.          return FALSE;     // Skip all group boxes and flat buttons
  241.       else if ( ( dwStyle & BS_AUTOCHECKBOX ) == BS_AUTOCHECKBOX ||
  242.                 ( dwStyle & BS_CHECKBOX ) == BS_CHECKBOX ||                
  243.                 ( dwStyle & BS_3STATE ) == BS_3STATE )
  244.          pCtl = new CCMCheckBox;
  245.       else if ( ( dwStyle & BS_AUTORADIOBUTTON ) == BS_AUTORADIOBUTTON || 
  246.            ( dwStyle & BS_RADIOBUTTON ) == BS_RADIOBUTTON )
  247.          pCtl = new CCMRadioButton;
  248.       else
  249.          pCtl = new CCMPushButton;     // If none of the above then it must be a pushbutton!
  250.    }
  251.    else if ( !lstrcmpi( szBuf, _T( "ComboBox" ) ) )
  252.    {      
  253.       // Special case for simple comboboxes
  254.       if ( ( dwStyle & 0x03 ) == CBS_SIMPLE )
  255.       {
  256.          hWnd = GetTopWindow( hWnd );
  257.          while ( hWnd )
  258.          {
  259.             AddControl( hWnd );
  260.             hWnd = GetNextWindow( hWnd, GW_HWNDNEXT );
  261.          }
  262.          return FALSE;
  263.       }   
  264.       else
  265.          pCtl = new CCMComboBox;
  266.    }
  267.    else if ( !lstrcmpi( szBuf, _T( "Edit" ) ) )
  268.    {
  269.       // Edit window in a simple combobox
  270.       GetClassName( GetParent( hWnd ), szBuf, MAX_CLASSNAME );
  271.       if ( !lstrcmpi( szBuf, _T( "ComboBox" ) ) && 
  272.             ( GetWindowLong( GetParent( hWnd ), GWL_STYLE ) & 0x03 ) == CBS_SIMPLE ) 
  273.          pCtl = new CCMEditCombo;
  274.       else
  275.       {
  276.          if ( dwExStyle & WS_EX_CLIENTEDGE )
  277.             pCtl = new CCMEdit;
  278.       }
  279.      #if defined _DEBUG
  280.        lstrcpy( szBuf, _T( "Edit" ) );
  281.      #endif
  282.    }
  283.    else if ( !lstrcmpi( szBuf, _T( "ListBox" ) ) )
  284.    {
  285.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  286.          pCtl = new CCMControl;
  287.    }
  288.    else if ( !lstrcmpi( szBuf, _T( "SysListView32" ) ) )
  289.    {
  290.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  291.       {
  292.          pCtl = new CCMControl;
  293.          AddControl( GetTopWindow( hWnd ) );  // Don't forget to add the header control
  294.       }
  295.    }
  296.    else if ( !lstrcmpi( szBuf, _T( "SHELLDLL_DefView" ) ) ) // In open/save common dialogs
  297.    {
  298.       AddControl( GetTopWindow( hWnd ) );  // Add child ListView control
  299.       return FALSE;
  300.    }
  301.    else if ( !lstrcmpi( szBuf, _T( "SysTreeView32" ) ) )
  302.    {
  303.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  304.          pCtl = new CCMControl;
  305.    }
  306.    else if ( !lstrcmpi( szBuf, _T( "SysDateTimePick32" ) ) )
  307.    {
  308.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  309.       {
  310.          pCtl = new CCMDateTime;
  311.          if ( dwStyle & DTS_UPDOWN )
  312.             AddControl( GetTopWindow( hWnd ) );  // Add up-down control as well
  313.       }
  314.    }
  315.    else if ( !lstrcmpi( szBuf, _T( "SysMonthCal32" ) ) )
  316.       pCtl = new CCMControl;
  317.    else if ( !lstrcmpi( szBuf, _T( "msctls_updown32" ) ) )
  318.       pCtl = new CCMUpDown;
  319.    else if ( !lstrcmpi( szBuf, _T( "ComboLBox" ) ) )
  320.    {
  321.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  322.          pCtl = new CCMControl;
  323.    }
  324.    else if ( !lstrcmpi( szBuf, _T( "ScrollBar" ) ) )
  325.    {
  326.       if ( !( dwStyle & SBS_SIZEBOX ) && !( dwStyle & SBS_SIZEGRIP ) )
  327.          pCtl = new CCMScrollBar;
  328.    }
  329.    else if ( !lstrcmpi( szBuf, _T( "ComboBoxEx32" ) ) )
  330.    {
  331.       AddControl( GetTopWindow( hWnd ) );
  332.       return FALSE;
  333.    }
  334.    else if ( !lstrcmpi( szBuf, _T( "msctls_hotkey32" ) ) )
  335.    {
  336.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  337.          pCtl = new CCMControl;
  338.    }
  339.    else if ( !lstrcmpi( szBuf, _T( "SysIPAddress32" ) ) )
  340.    {
  341.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  342.          pCtl = new CCMIPAddress;
  343.    }
  344.    else if ( !lstrcmpi( szBuf, _T( "msctls_trackbar32" ) ) )
  345.       pCtl = new CCMTrackbar;
  346.    else if ( !lstrcmpi( szBuf, _T( "RichEdit" ) ) )
  347.    {
  348.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  349.          pCtl = new CCMControl;
  350.    }
  351.    else if ( !lstrcmpi( szBuf, _T( "RichEdit20W" ) ) )
  352.    {
  353.       if ( dwExStyle & WS_EX_CLIENTEDGE )
  354.          pCtl = new CCMControl;
  355.    }
  356.    else if ( !lstrcmpi( szBuf, _T( "SysHeader32" ) ) )
  357.    {
  358.       if ( dwStyle & HDS_BUTTONS )         
  359.          pCtl = new CCMHeaderCtrl;
  360.       else
  361.          return FALSE;
  362.    }
  363.    else if ( !lstrcmpi( szBuf, _T( "ToolbarWindow32" ) ) )
  364.    {
  365.       // Skip the flat toolbars
  366.       if ( dwStyle & TBSTYLE_FLAT )
  367.          return FALSE;
  368.       HWND hCtrl = GetTopWindow( hWnd );  // Add additional toolbar controls
  369.       while ( hCtrl )
  370.       {
  371.          AddControl( hCtrl );
  372.          hCtrl = GetNextWindow( hCtrl, GW_HWNDNEXT );
  373.       }      
  374.       pCtl = new CCMToolbar;
  375.    }
  376.    else if ( !lstrcmpi( szBuf, _T( "SysTabControl32" ) ) )
  377.    {
  378.       pCtl = new CCMTabControl;
  379.       HWND hWndTop = GetTopWindow( hWnd );
  380.       if ( hWndTop )
  381.          AddControl( hWndTop );  // Also add the up-down control (horizontal tabs only)
  382.    }
  383.    else  // Unknown control, do not process
  384.       return FALSE;
  385.    if ( pCtl )
  386.    {
  387.       CCM_TRACE( _T( "CCoolControlsManager::AddControl, handle: %X, type: %sn" ), 
  388.                  hWnd, szBuf );
  389.       // Perform window subclassing
  390.       pCtl->Subclass( hWnd, CCM_ControlProc );
  391.       // Add the control to the map         
  392.       m_ctrlMap.SetAt( hWnd, pCtl );
  393.       
  394.       if ( m_uTimerID == 0 ) // If timer is not initialized yet
  395.       {    
  396.          m_uTimerID = SetTimer( NULL, 0, CCM_TIMER_VAL, CCM_TimerProc );
  397.          CCM_TRACE( _T( "CControlManager: Timer createdn" ) );
  398.          ASSERT( m_uTimerID );    // Failed to create the timer
  399.       }
  400.       return TRUE;
  401.    }
  402.    return FALSE;
  403. }
  404. BOOL CCoolControlsManager::RemoveControl( HWND hWnd )
  405. {
  406.    BOOL bResult = TRUE;   
  407.    CCMControl* pCtl;
  408.    if ( m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE )
  409.       bResult =  FALSE;   
  410.   #if defined _DEBUG
  411.    TCHAR szBuf[MAX_CLASSNAME];
  412.    GetClassName( hWnd, szBuf, MAX_CLASSNAME );         
  413.    CCM_TRACE( _T( "CCoolControlsManager::RemoveControl, handle: %X, class: %s, " ), 
  414.            hWnd, szBuf );
  415.    CCM_TRACE( bResult ? _T( "OKn" ) : _T( "failn" ) );
  416.   #endif
  417.    if ( bResult == TRUE )
  418.    {
  419.       // Unsubclass window and next remove it from the map
  420.       pCtl->Unsubclass();
  421.       m_ctrlMap.RemoveKey( hWnd );
  422.       delete pCtl;      // Destroy the object
  423.       if ( m_ctrlMap.IsEmpty() )
  424.       {
  425.          KillTimer( NULL, m_uTimerID );
  426.          CCM_TRACE( _T( "CCoolControlsManager: Timer killed, map is emptyn" ) );
  427.          m_uTimerID = 0;
  428.       }  
  429.       else
  430.          CCM_TRACE( _T( "CCoolControlsManager: map has %d itemsn" ), m_ctrlMap.GetCount() );
  431.    }
  432.    return bResult;
  433. }
  434. void CCoolControlsManager::AddDialog( HWND hWnd )
  435. {   
  436.    if ( hWnd  )
  437.    {
  438.       CCMDialog* pCtl = new CCMDialog;
  439.       pCtl->Subclass( hWnd, CCM_DialogProc );    // Perform window subclassing
  440.       m_dlgMap.SetAt( hWnd, pCtl ); // Add the dialog to the map   
  441.    }
  442. }
  443. void CCoolControlsManager::RemoveDialog( HWND hWnd )
  444. {   
  445.    CCMDialog* pCtl;
  446.    if ( m_dlgMap.Lookup( hWnd, (void*&)pCtl ) == TRUE )   
  447.    {
  448.       // Unsubclass window and next remove it from the map
  449.       pCtl->Unsubclass();
  450.       m_dlgMap.RemoveKey( hWnd );
  451.       delete pCtl;      // Destroy the object
  452.    }
  453. }
  454. static void CALLBACK CCM_TimerProc( HWND /*hwnd*/, UINT /*uMsg*/, 
  455.                                     UINT /*idEvent*/, DWORD /*dwTime*/ )
  456.    g_ctrlManager.TimerProc();
  457. }
  458. void CCoolControlsManager::TimerProc()
  459. {
  460.    // Do not process when the map is empty or the capture is set
  461.    if ( m_ctrlMap.IsEmpty() || GetCapture() != NULL )
  462.       return;
  463.    POINT point;
  464.    GetCursorPos( &point );
  465.    HWND hWnd = WindowFromPoint( point );
  466.    
  467.    CCMControl* pCtl;
  468.    // Lookup for a window in the map      
  469.    if ( m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE ) // Not found
  470.    {
  471.       // If window does not exist in the map, it can be
  472.       // a child of the control (e.g. edit control in ComboBox
  473.       // or header control in ListView). If so, get the parent window and
  474.       // carry on
  475.       hWnd = GetParent( hWnd );            
  476.       // Not our window, so just reset previous control and exit
  477.       if ( hWnd == NULL || m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE )
  478.       {            
  479.          // Not our window, so just reset previous control and exit
  480.          if ( m_ctrlMap.Lookup( CCMControl::m_hWndOld, (void*&)pCtl ) == TRUE )
  481.          {            
  482.             pCtl->SetState( dsHover, 0 );
  483.             CCMControl::m_hWndOld = NULL;
  484.          }
  485.          return;
  486.       }      
  487.    }
  488.    if ( pCtl->NeedRedraw( point ) ) // Window has been found and needs to be redrawn!
  489.    {
  490.       // First, reset old control (if any)      
  491.       CCMControl* pCtlOld;
  492.       if ( m_ctrlMap.Lookup( CCMControl::m_hWndOld, (void*&)pCtlOld ) == TRUE )            
  493.       {         
  494.          pCtlOld->SetState( dsHover, 0 );
  495.          CCMControl::m_hWndOld = NULL;
  496.       }
  497.       // Redraw control under the cursor            
  498.       pCtl->SetState( 0, dsHover );
  499.       CCMControl::m_hWndOld = hWnd;
  500.    }
  501. }
  502. ///////////////////////////////////////////////////////////////////////
  503. // All messages from subclassed dialogs will come here
  504. static LRESULT CALLBACK CCM_DialogProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  505. {  
  506.    // Try to find dialog in the dialog map    
  507.    CCoolControlsManager::CCMDialog* pCtl;
  508.    if ( g_ctrlManager.m_dlgMap.Lookup( hWnd, (void*&)pCtl ) == FALSE )
  509.    {
  510.       // This is not our dialog, so just apply default processing
  511.       return DefWindowProc( hWnd, uMsg, wParam, lParam ); 
  512.    }
  513.    // Otherwise, let the dialog to process this message
  514.    return pCtl->WindowProc( uMsg, wParam, lParam );
  515. }
  516. ///////////////////////////////////////////////////////////////////////
  517. // All messages from subclassed controls will come here
  518. static LRESULT CALLBACK CCM_ControlProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  519. {  
  520.    CCoolControlsManager::CCMControl* pCtl;
  521.    // Try to find window in the control map
  522.    if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) == FALSE )
  523.    {
  524.       // This is not our window, so just apply default processing
  525.       return DefWindowProc( hWnd, uMsg, wParam, lParam ); 
  526.    }
  527.    // Otherwise, let the control to process this message
  528.    return pCtl->WindowProc( uMsg, wParam, lParam );
  529. }
  530. //////////////////////////////////////////////////////////////////////////////
  531. // CCMControl and derived classes
  532. CCoolControlsManager::CCMControl::CCMControl()
  533. {
  534.    m_hWnd = NULL;
  535.    m_oldWndProc = NULL;
  536.    m_nState = dsNormal;
  537.    m_nOldState = dsNormal;
  538. }
  539. void CCoolControlsManager::CCMControl::PrepareDraw( HDC& hDC, RECT& rect )
  540. {
  541.    GetWindowRect( m_hWnd, &rect );         
  542.    OffsetRect( &rect, -rect.left, -rect.top );
  543.    hDC = GetWindowDC( m_hWnd );
  544. }
  545. void CCoolControlsManager::CCMControl::DrawBorder()
  546. {  
  547.    HDC hDC;
  548.    RECT rect;
  549.    PrepareDraw( hDC, rect );
  550.    if ( GetWindowLong( m_hWnd, GWL_EXSTYLE ) & WS_EX_CLIENTEDGE )
  551.    {
  552.       RECT rc;
  553.       GetWindowRect( m_hWnd, &rc );
  554.       POINT point = { 0, 0 };
  555.       ClientToScreen( m_hWnd, &point );
  556.       if ( point.x == rc.left + 3 )
  557.          InflateRect( &rect, -1, -1 );
  558.    }
  559.    if ( IsFocused() == TRUE )
  560.       m_nState |= dsFocus;    
  561.    else
  562.       m_nState &= ~dsFocus;    
  563.    // Single line control looks better when this style is added
  564.    if ( ( rect.bottom - rect.top ) < 30 ) 
  565.       m_nState |= dsAlternate;
  566.    else
  567.       m_nState &= ~dsAlternate;
  568.    if ( ( m_nOldState & dsHover && m_nState & dsHover ) ||
  569.         ( m_nOldState & dsFocus && m_nState & dsFocus ) )
  570.       ; // If previous state is the same as current state, do nothing
  571.    else
  572.    {         
  573.       // Perform control-specific drawing routines                  
  574.       CCM_TRACE( _T( "CCoolControlsManager::DrawBorder, handle: %X state: %dn" ), m_hWnd, m_nState );
  575.       DrawControl( hDC, rect );
  576.    }
  577.    // Update old state
  578.    m_nOldState = m_nState;
  579.    ReleaseDC( WindowFromDC( hDC ), hDC );
  580. }
  581. BOOL CCoolControlsManager::CCMControl::NeedRedraw( const POINT& /*point*/ )
  582. {
  583.    return m_hWnd != m_hWndOld ? TRUE : FALSE;
  584. }
  585. void CCoolControlsManager::CCMCore::Subclass( HWND hWnd, WNDPROC wndNewProc )
  586. {
  587.    ASSERT( hWnd );      // Do you really want to subclass a window that has a NULL handle?
  588.    m_hWnd = hWnd;   
  589.    // Store address of the original window procedure
  590.    m_oldWndProc = (WNDPROC)GetWindowLong( m_hWnd, GWL_WNDPROC );
  591.    // And set the new one
  592.    SetWindowLong( m_hWnd, GWL_WNDPROC, (LONG)wndNewProc );
  593. }
  594. void CCoolControlsManager::CCMCore::Unsubclass()
  595. {
  596.    SetWindowLong( m_hWnd, GWL_WNDPROC, (LONG)m_oldWndProc );
  597. }
  598. LRESULT CCoolControlsManager::CCMControl::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  599. {
  600.    switch ( uMsg )
  601.    {      
  602.       // Generic messages
  603.       case WM_KILLFOCUS:         
  604.       case WM_SETFOCUS:
  605.          DrawBorder();
  606.          break;
  607.       case WM_PAINT:
  608.       case WM_NCPAINT:
  609.       case WM_ENABLE:
  610.          CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  611.          DrawBorder();
  612.          return 0;
  613.       case WM_NCDESTROY:
  614.          // Unsubclass window and remove it from the map
  615.          CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  616.          g_ctrlManager.RemoveControl( m_hWnd );
  617.          return 0;
  618.    }
  619.    return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  620. }
  621. void CCoolControlsManager::CCMControl::DrawControl( HDC hDC, const RECT& rc )
  622.    if ( m_nState & dsHoverMask )
  623.    {
  624.       Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  625.                              COLOR_3DDKSHADOW, COLOR_3DLIGHT );
  626.    }
  627.    else
  628.    {
  629.       if ( IsWindowEnabled( m_hWnd ) == FALSE || m_nState & dsDisabled )
  630.          Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  631.                                 COLOR_3DFACE, COLOR_3DFACE );
  632.       else               
  633.          Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  634.                        m_nState & dsAlternate ? COLOR_3DHIGHLIGHT : COLOR_3DLIGHT, COLOR_3DLIGHT );
  635.    }
  636.    DrawScrollBars( hDC, rc );
  637. }
  638. void CCoolControlsManager::CCMControl::DrawScrollbarThumb( HDC hDC, const RECT& rc )
  639. {
  640.    if ( m_nState & dsHoverMask )
  641.       Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW, 
  642.                              COLOR_3DHIGHLIGHT, COLOR_3DSHADOW );
  643.    else
  644.       Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  645.                              COLOR_3DFACE, COLOR_3DFACE );
  646. }
  647. void CCoolControlsManager::CCMControl::DrawScrollBars( HDC hDC, const RECT& rect )
  648. {  
  649.    const int nFrameSize  = GetSystemMetrics( SM_CXEDGE ); 
  650.    const int nScrollSize = GetSystemMetrics( SM_CXHSCROLL );   
  651.    RECT rc; 
  652.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );  
  653.    if ( dwStyle & WS_HSCROLL &&  dwStyle & WS_VSCROLL )
  654.    {
  655.       rc.left = rect.left + nFrameSize; rc.top = rect.bottom - nFrameSize - nScrollSize;
  656.       rc.right = rect.right - nFrameSize - nScrollSize; rc.bottom = rect.bottom - nFrameSize;
  657.       DrawScrollBar( hDC, rc, SB_HORZ );
  658.       rc.left = rect.right - nFrameSize - nScrollSize; rc.top = rect.top + nFrameSize;
  659.       rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize - nScrollSize;
  660.       DrawScrollBar( hDC, rc, SB_VERT );
  661.    }
  662.    else if ( dwStyle & WS_VSCROLL )
  663.    {
  664.       rc.left = rect.right - nFrameSize - nScrollSize; rc.top = rect.top + nFrameSize;
  665.       rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize;
  666.       DrawScrollBar( hDC, rc, SB_VERT );
  667.    }
  668.    else if ( dwStyle & WS_HSCROLL )
  669.    {
  670.       rc.left = rect.left + nFrameSize; rc.top = rect.bottom - nFrameSize - nScrollSize;
  671.       rc.right = rect.right - nFrameSize; rc.bottom = rect.bottom - nFrameSize;
  672.       DrawScrollBar( hDC, rc, SB_HORZ );
  673.    }
  674. }
  675. void CCoolControlsManager::CCMControl::DrawScrollBar( HDC hDC, const RECT& rect, 
  676.                                                      int nType, BOOL bScrollbarCtrl )
  677. {   
  678.    int nScrollSize = GetSystemMetrics( SM_CXHSCROLL );
  679.    // The minimal thumb size depends on the system version
  680.    // For Windows 98 minimal thumb size is a half of scrollbar size 
  681.    // and for Windows NT is always 8 pixels regardless of system metrics. 
  682.    // I really don't know why.
  683.    int nMinThumbSize;
  684.    if ( GetVersion() & 0x80000000 ) // Windows 98 code
  685.       nMinThumbSize = nScrollSize / 2;
  686.    else                    
  687.       nMinThumbSize = 8;
  688.    
  689.    // Calculate the arrow rectangles
  690.    RECT rc1 = rect, rc2 = rect;   
  691.    if ( nType == SB_HORZ )
  692.    {
  693.       if ( ( rect.right - rect.left ) < 2 * nScrollSize )
  694.          nScrollSize = ( rect.right - rect.left ) / 2;
  695.       rc1.right = rect.left + nScrollSize;
  696.       rc2.left = rect.right - nScrollSize;
  697.    }
  698.    else // SB_VERT
  699.    {
  700.       if ( ( rect.bottom - rect.top ) < 2 * nScrollSize )
  701.          nScrollSize = ( rect.bottom - rect.top ) / 2;
  702.       rc1.bottom = rect.top + nScrollSize;      
  703.       rc2.top = rect.bottom - nScrollSize;
  704.    }   
  705.    // Draw the scrollbar arrows
  706.    DrawScrollbarThumb( hDC, rc1 );
  707.    DrawScrollbarThumb( hDC, rc2 );
  708.    // Disabled scrollbar never have a thumb
  709.    if ( bScrollbarCtrl == TRUE && IsWindowEnabled( m_hWnd ) == FALSE )
  710.       return;      
  711.  
  712.    SCROLLINFO si;
  713.    si.cbSize = sizeof( SCROLLINFO );
  714.    si.fMask = SIF_ALL;     
  715.    GetScrollInfo( m_hWnd, bScrollbarCtrl ? SB_CTL : nType, &si );
  716.    // Calculate the size and position of the thumb   
  717.    int nRange = si.nMax - si.nMin + 1;      
  718.    if ( nRange )
  719.    {
  720.       int nScrollArea = ( nType == SB_VERT ? ( rect.bottom - rect.top ) : ( rect.right - rect.left ) ) - 2 * nScrollSize;
  721.       int nThumbSize; 
  722.       if ( si.nPage == 0 ) // If nPage is not set then thumb has default size
  723.          nThumbSize = GetSystemMetrics( SM_CXHTHUMB );
  724.       else
  725.          nThumbSize = max( MulDiv( si.nPage ,nScrollArea, nRange ), nMinThumbSize );
  726.       if ( nThumbSize >= nScrollArea )
  727.       {
  728.          nThumbSize = nScrollArea;
  729.          if ( bScrollbarCtrl == FALSE )
  730.             return;
  731.       }
  732.       int nThumbPos;
  733.       if ( UINT( nRange ) == si.nPage )
  734.       {
  735.          nThumbPos = 0;
  736.          nThumbSize--;
  737.       }
  738.       else
  739.          nThumbPos = MulDiv( si.nPos - si.nMin, nScrollArea - nThumbSize, nRange - si.nPage );
  740.       if ( nType == SB_VERT )
  741.       {
  742.          rc1.top += nScrollSize + nThumbPos;
  743.          rc1.bottom = rc1.top + nThumbSize;
  744.       }
  745.       else // SB_HORZ
  746.       {
  747.          rc1.left += nScrollSize + nThumbPos;
  748.          rc1.right = rc1.left + nThumbSize;
  749.       }
  750.       if ( nThumbSize <= nScrollArea ) // Don't draw the thumb when it's larger than the scroll area
  751.          DrawScrollbarThumb( hDC, rc1 );
  752.    }   
  753. }
  754. BOOL CCoolControlsManager::CCMControl::IsFocused()
  755.    return m_hWnd == GetFocus() ? TRUE : FALSE;
  756. }
  757. //////////////////////////////////////////////////////////////////////////////
  758. // CCMEdit class
  759. void CCoolControlsManager::CCMEdit::DrawControl( HDC hDC, const RECT& rc )
  760. {
  761.    RECT rect = rc;
  762.    // Check if edit window has an associated up-down control.
  763.    // If so draw a border around both controls
  764.    HWND hWnd = GetNextWindow( m_hWnd, GW_HWNDNEXT );
  765.    if ( hWnd ) 
  766.    {
  767.       TCHAR szBuf[MAX_CLASSNAME];
  768.       // Retrieve window class name
  769.       GetClassName( hWnd, szBuf, MAX_CLASSNAME );
  770.       if ( lstrcmpi( szBuf, _T( "msctls_updown32" ) ) == 0 )   // Up-down is found
  771.       {
  772.          DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE );
  773.          if ( ( dwStyle & UDS_ALIGNRIGHT || dwStyle & UDS_ALIGNLEFT ) &&
  774.               SendMessage( hWnd, UDM_GETBUDDY, 0, 0L ) == (LONG)m_hWnd )
  775.          {         
  776.             RECT rc;
  777.             GetWindowRect( hWnd, &rc );
  778.             const int nEdge = GetSystemMetrics( SM_CXEDGE );
  779.             if ( dwStyle & UDS_ALIGNRIGHT )
  780.                rect.right += ( rc.right - rc.left ) - nEdge;
  781.             else // UDS_ALIGNLEFT
  782.                rect.left -= ( rc.right - rc.left ) - nEdge;
  783.             HDC hDC = GetDC( hWnd );   // We must draw the lines onto spin control DC
  784.             COLORREF clr = GetSysColor( m_nState & dsHoverMask ? COLOR_3DDKSHADOW : COLOR_3DHIGHLIGHT );
  785.             if ( !IsWindowEnabled( m_hWnd ) )
  786.                clr = GetSysColor( COLOR_3DFACE );
  787.             FillSolidRect( hDC, 1, 1, rc.right - rc.left - nEdge - 1, 1, clr );
  788.             if ( dwStyle & UDS_ALIGNLEFT )
  789.                FillSolidRect( hDC, 1, 1, 1, rc.bottom - rc.top - nEdge - 1, clr );
  790.             ReleaseDC( hWnd, hDC );
  791.          }
  792.       }
  793.    }
  794.    if ( GetWindowLong( m_hWnd, GWL_STYLE ) & ES_READONLY )
  795.       m_nState |= dsDisabled;
  796.    else
  797.       m_nState &= ~dsDisabled;
  798.    CCMControl::DrawControl( hDC, rect );
  799. }
  800. LRESULT CCoolControlsManager::CCMEdit::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  801. {
  802.    switch ( uMsg )
  803.    {      
  804.       case WM_ENABLE:
  805.          {
  806.             CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  807.             DrawBorder();
  808.             HWND hWnd = GetNextWindow( m_hWnd, GW_HWNDNEXT );
  809.             if ( hWnd ) 
  810.             {
  811.                TCHAR szBuf[MAX_CLASSNAME];
  812.                // Retrieve window class name
  813.                GetClassName( hWnd, szBuf, MAX_CLASSNAME );
  814.                if ( lstrcmpi( szBuf, _T( "msctls_updown32" ) ) == 0 &&   // Up-down is found
  815.                   SendMessage( hWnd, UDM_GETBUDDY, 0, 0L ) == (LONG)m_hWnd )
  816.                      SendMessage( hWnd, WM_PAINT, 0, 0L );  // Repaint up-down too
  817.             }         
  818.          }
  819.          return 0;
  820.       default:
  821.          return CCMControl::WindowProc( uMsg, wParam, lParam );
  822.    }
  823. }
  824. //////////////////////////////////////////////////////////////////////////////
  825. // CCMComboBox class
  826. void CCoolControlsManager::CCMComboBox::DrawControl( HDC hDC, const RECT& rect )
  827. {
  828.    // First, draw borders around the control   
  829.    CCMControl::DrawControl( hDC, rect );
  830.    // Now, we have to draw borders around the drop-down arrow
  831.    RECT rc = rect;
  832.    InflateRect( &rc, -2, -2 );
  833.    rc.left = rc.right - GetSystemMetrics( SM_CXHSCROLL );
  834.    
  835.    if ( IsWindowEnabled( m_hWnd ) == TRUE )
  836.    {
  837.       if ( m_nState & dsHoverMask )
  838.          Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW,
  839.                                 COLOR_3DHIGHLIGHT, COLOR_3DSHADOW );
  840.       else
  841.          Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  842.                                 COLOR_3DFACE, COLOR_3DFACE );
  843.    }
  844.    else
  845.       Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DFACE,
  846.                              COLOR_3DFACE, COLOR_3DFACE );
  847. }
  848. BOOL CCoolControlsManager::CCMComboBox::IsFocused()
  849.    // Special case for drop-down and simple ComboBoxes 
  850.    // which contain child edit control and focus always 
  851.    // goes to that edit window   
  852.    if ( ( GetWindowLong( m_hWnd, GWL_STYLE ) & 0x03 ) == CBS_DROPDOWN )
  853.    {
  854.       HWND hWnd = GetTopWindow( m_hWnd );
  855.       if ( hWnd && hWnd == GetFocus() )
  856.          return TRUE;
  857.    }
  858.    return CCMControl::IsFocused();
  859. }
  860. LRESULT CCoolControlsManager::CCMComboBox::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  861. {
  862.    switch ( uMsg )
  863.    {      
  864.       // Drop-down ComboBox receives neither WM_SETFOCUS nor WM_KILLFOCUS
  865.       // Instead, it receives these next two messages
  866.       case WM_LBUTTONUP:      // For kill focus
  867.          if ( lParam == -1 )
  868.             DrawBorder();
  869.          break;
  870.       case WM_COMMAND:
  871.          if ( HIWORD( wParam ) == EN_SETFOCUS )
  872.             DrawBorder();
  873.          break;
  874.       default:
  875.          return CCMControl::WindowProc( uMsg, wParam, lParam );
  876.    }
  877.    return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  878. }
  879. //////////////////////////////////////////////////////////////////////////////
  880. // CCMDateTime class
  881. void CCoolControlsManager::CCMDateTime::DrawControl( HDC hDC, const RECT& rc )
  882. {
  883.    if ( GetWindowLong( m_hWnd, GWL_STYLE ) & DTS_UPDOWN )
  884.       CCMControl::DrawControl( hDC, rc );
  885.    else
  886.       CCMComboBox::DrawControl( hDC, rc );
  887. }
  888. //////////////////////////////////////////////////////////////////////////////
  889. // CCMPushButton class
  890. void CCoolControlsManager::CCMPushButton::DrawControl( HDC hDC, const RECT& rc )
  891. {
  892.    BOOL bDefault = FALSE;
  893.    // Unfortunately BS_DEFPUSHBUTTON is defined as 0x00000001L,
  894.    // and BS_OWNERDRAW as 0x0000000BL (see winuser.h) so we cannot
  895.    // determine the default button for owner-draw controls
  896.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE ) & BS_OWNERDRAW;
  897.    if ( dwStyle != BS_OWNERDRAW )
  898.    {
  899.       if ( dwStyle == BS_DEFPUSHBUTTON && IsWindowEnabled( m_hWnd ) )
  900.          bDefault = TRUE;
  901.    }
  902.    int nCheck = SendMessage( m_hWnd, BM_GETCHECK, 0, 0 );
  903.    if ( m_nState & dsHoverMask )
  904.    {
  905.       if ( bDefault == TRUE )
  906.       {
  907.          Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW,
  908.                                 COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW,
  909.                                 COLOR_3DLIGHT, COLOR_3DSHADOW );
  910.       }
  911.       else
  912.       {
  913.          if ( nCheck )
  914.             Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT,
  915.                                    COLOR_3DSHADOW, COLOR_3DLIGHT );
  916.          else
  917.             Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW,
  918.                                    COLOR_3DLIGHT, COLOR_3DSHADOW,
  919.                                    COLOR_3DFACE, COLOR_3DFACE );
  920.       }
  921.    }
  922.    else
  923.    {
  924.       if ( bDefault == TRUE )
  925.       {
  926.          Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DDKSHADOW,
  927.                                 COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  928.                                 COLOR_3DFACE, COLOR_3DFACE );
  929.       }
  930.       else
  931.       {
  932.          if ( nCheck )
  933.             Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  934.                                    COLOR_3DFACE, COLOR_3DFACE );
  935.          else
  936.             Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  937.                                    COLOR_3DFACE, COLOR_3DFACE,
  938.                                    COLOR_3DFACE, COLOR_3DFACE );
  939.       }
  940.    }      
  941. }
  942. LRESULT CCoolControlsManager::CCMPushButton::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  943. {
  944.    switch ( uMsg )
  945.    {      
  946.       // Button messages
  947.       case BM_SETCHECK:
  948.       case WM_SETTEXT:
  949.          CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  950.          DrawBorder();
  951.          return 0;
  952.       default:
  953.          return CCMControl::WindowProc( uMsg, wParam, lParam );
  954.    }
  955. }
  956. //////////////////////////////////////////////////////////////////////////////
  957. // CCMCheckBox class
  958. void CCoolControlsManager::CCMCheckBox::DrawControl( HDC hDC, const RECT& rect )
  959. {
  960.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  961.    
  962.    if ( dwStyle & BS_PUSHLIKE )
  963.    {
  964.       CCMPushButton::DrawControl( hDC, rect );
  965.       return;
  966.    }  
  967.    RECT rc;
  968.    
  969.    // Checkmark square size, hard coded here because I couldn't find any
  970.    // method to obtain this value from the system.
  971.    // Maybe someone else knows how to do it? If so, please let me know!
  972.    const int nCheckSize = 13;
  973.    
  974.    if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER )
  975.       rc.top = rect.top + ( ( rect.bottom - rect.top ) - nCheckSize ) / 2;
  976.    else if ( dwStyle & BS_TOP )
  977.       rc.top = rect.top + 1;
  978.    else if ( dwStyle & BS_BOTTOM )
  979.       rc.top = rect.bottom - nCheckSize - 2;
  980.    else  // Default
  981.       rc.top = rect.top + ( ( rect.bottom - rect.top ) - nCheckSize ) / 2;
  982.    if ( dwStyle & BS_LEFTTEXT )
  983.       rc.left = rect.right - nCheckSize;
  984.    else
  985.       rc.left = rect.left;
  986.    rc.right = rc.left + nCheckSize;
  987.    rc.bottom = rc.top + nCheckSize;
  988.    if ( m_nState & dsHoverMask )
  989.    {
  990.       Draw3dBorder( hDC, rc, COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT,
  991.                              COLOR_3DSHADOW, COLOR_3DFACE );
  992.    }
  993.    else
  994.    {            
  995.       if ( IsWindowEnabled( m_hWnd ) == TRUE ) 
  996.       {
  997.          int nState = SendMessage( m_hWnd, BM_GETCHECK, 0, 0L );
  998.          Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  999.                                 nState == 2 ? COLOR_3DHIGHLIGHT : COLOR_WINDOW, 
  1000.                                 nState == 2 ? COLOR_3DHIGHLIGHT : COLOR_WINDOW );
  1001.       }
  1002.       else
  1003.          Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  1004.                                 COLOR_3DFACE, COLOR_3DFACE );
  1005.    }
  1006. }
  1007. //////////////////////////////////////////////////////////////////////////////
  1008. // CCMRadioButton class
  1009. void CCoolControlsManager::CCMRadioButton::DrawFrame( POINT* ptArr, int nColor, 
  1010.                                                      HDC hDC, int xOff, int yOff )
  1011. {
  1012.    for ( int i = 0; ; i++ )
  1013.    {
  1014.       if ( !ptArr[i].x && !ptArr[i].y )
  1015.          return;
  1016.       SetPixel( hDC, ptArr[i].x + xOff, ptArr[i].y + yOff, GetSysColor( nColor ) );
  1017.    }
  1018. }
  1019. void CCoolControlsManager::CCMRadioButton::DrawControl( HDC hDC, const RECT& rect )
  1020. {
  1021.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  1022.    if ( dwStyle & BS_PUSHLIKE )
  1023.    {
  1024.       CCMPushButton::DrawControl( hDC, rect );
  1025.       return;
  1026.    }  
  1027.    const int nRadioSize = 12;
  1028.    RECT rc;
  1029.    
  1030.    if ( ( dwStyle & BS_VCENTER ) == BS_VCENTER )
  1031.       rc.top = rect.top + ( ( rect.bottom - rect.top ) - nRadioSize - 1 ) / 2;
  1032.    else if ( dwStyle & BS_TOP )
  1033.       rc.top = rect.top + 1;
  1034.    else if ( dwStyle & BS_BOTTOM )
  1035.       rc.top = rect.bottom - nRadioSize - 3;
  1036.    else  // Default
  1037.       rc.top = rect.top + ( ( rect.bottom - rect.top ) - nRadioSize - 1 ) / 2;
  1038.    
  1039.    if ( dwStyle & BS_LEFTTEXT )
  1040.       rc.left = rect.right - nRadioSize;
  1041.    else
  1042.       rc.left = rect.left + 1;
  1043.    rc.right = rc.left + nRadioSize;
  1044.    rc.bottom = rc.top + nRadioSize;
  1045.    POINT pt1[] = { 
  1046.                   { 1,9 },{ 1,8 },
  1047.                   { 0,7 },{ 0,6 },{ 0,5 },{ 0,4 },
  1048.                   { 1,3 },{ 1,2 },
  1049.                   { 2,1 },{ 3,1 },
  1050.                   { 4,0 },{ 5,0 },{ 6,0 },{ 7,0 },
  1051.                   { 8,1 },{ 9,1 },
  1052.                   { 0,0 }
  1053.                };  
  1054.                
  1055.    POINT pt2[] = { 
  1056.                   { 2,8 },
  1057.                   { 1,7 },{ 1,6 },{ 1,5 },{ 1,4 },
  1058.                   { 2,3 },{ 2,2 },
  1059.                   { 3,2 },
  1060.                   { 4,1 },{ 5,1 },{ 6,1 },{ 7,1 },
  1061.                   { 8,2 },{ 9,2 },
  1062.                   { 0,0 }
  1063.                };  
  1064.    POINT pt3[] = { 
  1065.                   { 2,9 },{ 3,9 },
  1066.                   { 4,10 },{ 5,10 },{ 6,10 },{ 7,10 },
  1067.                   { 8,9 },{ 9,9 },
  1068.                   { 9,8 },
  1069.                   { 10,7 },{ 10,6 },{ 10,5 },{ 10,4 },
  1070.                   { 9,3 },
  1071.                   { 0,0 }
  1072.                };  
  1073.    POINT pt4[] = { 
  1074.                   { 2,10 },{ 3,10 },
  1075.                   { 4,11 },{ 5,11 },{ 6,11 },{ 7,11 },
  1076.                   { 8,10 },{ 9,10 },
  1077.                   { 10,9 },{ 10,8 },
  1078.                   { 11,7 },{ 11,6 },{ 11,5 },{ 11,4 },
  1079.                   { 10,3 },{ 10,2 },
  1080.                   { 0,0 }
  1081.                };  
  1082.    if ( m_nState & dsHoverMask )
  1083.    {
  1084.       DrawFrame( pt1, COLOR_3DSHADOW,
  1085.                       hDC, rc.left, rc.top );
  1086.       DrawFrame( pt2, COLOR_3DDKSHADOW,
  1087.                       hDC, rc.left, rc.top );
  1088.       DrawFrame( pt3, COLOR_3DFACE,
  1089.                       hDC, rc.left, rc.top );
  1090.       DrawFrame( pt4, COLOR_WINDOW,
  1091.                       hDC, rc.left, rc.top );
  1092.    }
  1093.    else
  1094.    {
  1095.       if ( IsWindowEnabled( m_hWnd ) == TRUE ) 
  1096.       {  
  1097.          DrawFrame( pt1, COLOR_3DSHADOW,
  1098.                          hDC, rc.left, rc.top );
  1099.          DrawFrame( pt2, COLOR_WINDOW,
  1100.                          hDC, rc.left, rc.top );
  1101.          DrawFrame( pt3, COLOR_3DFACE,
  1102.                          hDC, rc.left, rc.top );
  1103.          DrawFrame( pt4, COLOR_WINDOW,
  1104.                          hDC, rc.left, rc.top );                  
  1105.       }
  1106.       else
  1107.       {
  1108.          DrawFrame( pt1, COLOR_3DSHADOW,
  1109.                          hDC, rc.left, rc.top );
  1110.          DrawFrame( pt2, COLOR_3DFACE,
  1111.                          hDC, rc.left, rc.top );
  1112.          DrawFrame( pt3, COLOR_3DFACE,
  1113.                          hDC, rc.left, rc.top );
  1114.          DrawFrame( pt4, COLOR_3DHIGHLIGHT,
  1115.                          hDC, rc.left, rc.top );
  1116.       }
  1117.    }   
  1118. }
  1119. //////////////////////////////////////////////////////////////////////////////
  1120. // CCMUpDown class
  1121. void CCoolControlsManager::CCMUpDown::DrawButton( HDC hDC, const RECT& rc )
  1122. {
  1123.    // If associated edit control is disabled
  1124.    // draw the up-down as disabled too
  1125.    BOOL bEnabled = IsWindowEnabled( m_hWnd );
  1126.    HWND hWnd = (HWND)SendMessage( m_hWnd, UDM_GETBUDDY, 0, 0L );
  1127.    if ( hWnd )
  1128.       bEnabled = IsWindowEnabled( hWnd );
  1129.    if ( bEnabled && m_nState & dsHoverMask )
  1130.       Draw3dBorder( hDC, rc, COLOR_3DFACE, COLOR_3DDKSHADOW,
  1131.                              COLOR_3DHIGHLIGHT, COLOR_3DSHADOW );
  1132.    else
  1133.       Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  1134.                              COLOR_3DFACE, COLOR_3DFACE );
  1135. }
  1136. void CCoolControlsManager::CCMUpDown::DrawControl( HDC hDC, const RECT& rect )
  1137. {         
  1138.    RECT rc = rect;
  1139.    CCMControl* pCtl = NULL;
  1140.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  1141.    HWND hWnd = (HWND)SendMessage( m_hWnd, UDM_GETBUDDY, 0, 0L );
  1142.    if ( hWnd && ( dwStyle & UDS_ALIGNRIGHT || dwStyle & UDS_ALIGNLEFT ) )
  1143.    {
  1144.       if ( dwStyle & UDS_ALIGNLEFT )
  1145.          rc.left += 2;
  1146.       else   // UDS_ALIGNRIGHT
  1147.          rc.right -= 2;
  1148.       rc.top += 2;
  1149.       rc.bottom -= 2;
  1150.                  
  1151.       if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) && 
  1152.            !( pCtl->GetState() & dsHoverMask ) )
  1153.       {
  1154.          COLORREF clr1 = GetSysColor( IsWindowEnabled( hWnd ) ? COLOR_3DHIGHLIGHT : COLOR_3DFACE );
  1155.          COLORREF clr2 = GetSysColor( IsWindowEnabled( hWnd ) ? COLOR_3DLIGHT : COLOR_3DFACE );
  1156.          FillSolidRect( hDC, rc.left, rc.top - 1,
  1157.                              rc.right, 1,
  1158.                              clr1 );
  1159.          FillSolidRect( hDC, rc.left, rc.bottom,
  1160.                              rc.right, 1,                                  
  1161.                              clr2 );
  1162.          if ( dwStyle & UDS_ALIGNLEFT )
  1163.             FillSolidRect( hDC, rc.left - 1, rc.top - 1,
  1164.                                 1, rc.bottom,
  1165.                                 clr1 );
  1166.          else
  1167.             FillSolidRect( hDC, rc.right, rc.top - 1,
  1168.                                 1, rc.bottom,
  1169.                                 clr2 );
  1170.       }
  1171.    }
  1172.    RECT r = rc;
  1173.    if ( dwStyle & UDS_HORZ )
  1174.    {
  1175.       r.right = r.left + ( rc.right - rc.left ) / 2;
  1176.       DrawButton( hDC, r );
  1177.       r.left = r.right + ( rc.right - rc.left ) % 2;
  1178.       r.right = rc.right;
  1179.       DrawButton( hDC, r );
  1180.    }
  1181.    else
  1182.    {
  1183.       r.bottom = r.top + ( rc.bottom - rc.top ) / 2;
  1184.       DrawButton( hDC, r );
  1185.       r.top = r.bottom + ( rc.bottom - rc.top ) % 2;
  1186.       r.bottom = rc.bottom;
  1187.       DrawButton( hDC, r );
  1188.    }
  1189.    if ( pCtl == NULL )  // Get parent (e.g. for datetime with up-down controls)
  1190.    {
  1191.       hWnd = GetParent( m_hWnd );
  1192.       g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl );
  1193.    }
  1194.    if ( pCtl && IsWindowEnabled( hWnd ) )   // Redraw parent or buddy if neccesary
  1195.    {
  1196.       if ( m_nState & dsHoverMask )
  1197.          pCtl->SetState( 0, dsHover );
  1198.       else
  1199.          pCtl->SetState( dsHover, 0 );
  1200.    }
  1201. }
  1202. //////////////////////////////////////////////////////////////////////////////
  1203. // CCMEditCombo class
  1204. void CCoolControlsManager::CCMEditCombo::PrepareDraw( HDC& hDC, RECT& rect )
  1205. {
  1206.    GetWindowRect( m_hWnd, &rect );
  1207.    InflateRect( &rect, 3, 3 );
  1208.    OffsetRect( &rect, -rect.left, -rect.top );
  1209.    // Draw onto that DC that is most suitable for given class   
  1210.    hDC = GetWindowDC( GetParent( m_hWnd ) );
  1211. }
  1212. //////////////////////////////////////////////////////////////////////////////
  1213. // CCMScrollBar class
  1214. void CCoolControlsManager::CCMScrollBar::DrawControl( HDC hDC, const RECT& rc )
  1215. {  
  1216.    DrawScrollBar( hDC, rc, 
  1217.              ( GetWindowLong( m_hWnd, GWL_STYLE ) & SBS_VERT ) ? SB_VERT : SB_HORZ,
  1218.              TRUE );
  1219. }
  1220. LRESULT CCoolControlsManager::CCMScrollBar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1221. {
  1222.    switch ( uMsg )
  1223.    {      
  1224.       // Scrollbar messages
  1225.       case SBM_SETPOS:
  1226.          if ( !lParam )  // redraw flag
  1227.             break;
  1228.       case SBM_SETSCROLLINFO:      
  1229.          if ( !wParam )  // redraw flag
  1230.             break;
  1231.       case SBM_SETRANGEREDRAW:
  1232.          CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  1233.          DrawBorder();
  1234.          return 0;
  1235.       default:
  1236.          return CCMControl::WindowProc( uMsg, wParam, lParam );
  1237.    }
  1238.    return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  1239. }
  1240. //////////////////////////////////////////////////////////////////////////////
  1241. // CCMHeaderCtrl class
  1242. void CCoolControlsManager::CCMHeaderCtrl::DrawButton( HDC hDC, const RECT& rc, int nState )
  1243. {
  1244.    if ( nState & dsHoverMask )
  1245.       Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW,
  1246.                              COLOR_3DLIGHT, COLOR_3DSHADOW );
  1247.    else
  1248.       Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  1249.                              COLOR_3DFACE, COLOR_3DFACE );      
  1250. }
  1251. void CCoolControlsManager::CCMHeaderCtrl::DrawControl( HDC hDC, const RECT& /*rc*/ )
  1252. {
  1253.    int nOldItem = m_nOldItem;
  1254.    m_nOldItem = -1;
  1255.    RECT rc;
  1256.    POINT point;
  1257.    GetCursorPos( &point );
  1258.    // This code fails if we will have standalone header control but such cases are rare...
  1259.    HWND hWnd = GetParent( m_hWnd ); 
  1260.    GetClientRect( GetParent( m_hWnd ), &rc );
  1261.    ScreenToClient( GetParent( m_hWnd ), &point );
  1262.    // Test if mouse pointer is within the client area of the list control
  1263.    BOOL bInView = PtInRect( &rc, point );    
  1264.    GetClientRect( m_hWnd, &rc );
  1265.    rc.right = 0;
  1266.    GetCursorPos( &point );
  1267.    ScreenToClient( m_hWnd, &point );
  1268.    hDC = GetDC( m_hWnd );
  1269.    
  1270.    int nState;
  1271.    int nCount = SendMessage( m_hWnd, HDM_GETITEMCOUNT, 0, 0L );   
  1272.    for ( int i = 0; i < nCount; i++ )
  1273.    {
  1274.     #if (_WIN32_IE >= 0x0300)
  1275.       HDITEM hi;
  1276.       hi.mask = HDI_ORDER;
  1277.       SendMessage( m_hWnd, HDM_GETITEM, i, (LPARAM)&hi );
  1278.       SendMessage( m_hWnd, HDM_GETITEMRECT, hi.iOrder, (LPARAM)&rc );
  1279.     #else
  1280.       SendMessage( m_hWnd, HDM_GETITEMRECT, i, (LPARAM)&rc );
  1281.     #endif
  1282.       nState = 0;
  1283.       if ( bInView & PtInRect( &rc, point ) )
  1284.       {
  1285.          nState = dsHover;
  1286.        #if (_WIN32_IE >= 0x0300)
  1287.          m_nOldItem = hi.iOrder;
  1288.        #else
  1289.          m_nOldItem = i;
  1290.        #endif
  1291.       }
  1292.       DrawButton( hDC, rc, nState );
  1293.    }
  1294.    int l = rc.right;
  1295.    GetClientRect( m_hWnd, &rc );
  1296.    rc.left = l;
  1297.    DrawButton( hDC, rc, 0 );
  1298.    // If header is a child of ListView, redraw the list so 
  1299.    // it will indicate proper state      
  1300.    CCMControl* pCtl;   
  1301.    if ( g_ctrlManager.m_ctrlMap.Lookup( hWnd, (void*&)pCtl ) )
  1302.    {
  1303.       if ( m_nOldItem >= 0 )
  1304.          pCtl->SetState( 0, dsHover );
  1305.       else if ( nOldItem >= 0 )
  1306.          pCtl->SetState( dsHover, 0 );
  1307.    }
  1308.    ReleaseDC( m_hWnd, hDC );
  1309. }
  1310. BOOL CCoolControlsManager::CCMHeaderCtrl::NeedRedraw( const POINT& point )
  1311. {
  1312.    RECT rc;
  1313.    GetClientRect( m_hWnd, &rc );
  1314.    rc.right = 0;
  1315.    POINT pt = point;
  1316.    ScreenToClient( m_hWnd, &pt );
  1317.    int nItem = -1;
  1318.    int nCount = SendMessage( m_hWnd, HDM_GETITEMCOUNT, 0, 0L );
  1319.    for ( int i = 0; i < nCount; i++ )
  1320.    {
  1321.       HDITEM hi;
  1322.       hi.mask = HDI_WIDTH;      
  1323.       SendMessage( m_hWnd, HDM_GETITEM, i, (LPARAM)&hi );
  1324.       rc.left = rc.right;
  1325.       rc.right = rc.left + hi.cxy;
  1326.       if ( PtInRect( &rc, pt ) )
  1327.       {
  1328.          nItem = i;
  1329.          break;
  1330.       }
  1331.    }
  1332.    if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) )
  1333.       return TRUE;
  1334.    return FALSE;
  1335. }
  1336. //////////////////////////////////////////////////////////////////////////////
  1337. // CCMTrackbar class
  1338. void CCoolControlsManager::CCMTrackbar::DrawThumb( HDC hDC, const RECT& rc )
  1339. {
  1340.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  1341.    if ( dwStyle & TBS_BOTH )
  1342.    {
  1343.       FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) );
  1344.       if ( m_nState & dsHoverMask )
  1345.          Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW,
  1346.                                 COLOR_3DLIGHT, COLOR_3DSHADOW );
  1347.       else
  1348.          Draw3dBorder( hDC, rc, COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  1349.                                 COLOR_3DFACE, COLOR_3DFACE );      
  1350.       return;
  1351.    }
  1352.    
  1353.    HPEN penHighlight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1354.    HPEN penLight = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DLIGHT : COLOR_3DFACE ) );
  1355.    HPEN penDkShadow = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DDKSHADOW : COLOR_3DSHADOW ) );
  1356.    HPEN penShadow = CreatePen( PS_SOLID, 1, GetSysColor( m_nState & dsHoverMask ? COLOR_3DSHADOW : COLOR_3DFACE ) );
  1357.    int n;
  1358.    if ( dwStyle & TBS_VERT )
  1359.    {
  1360.       if ( dwStyle & TBS_LEFT )
  1361.       {    
  1362.          n = ( rc.bottom - rc.top ) / 2 + 1;
  1363.          FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) );
  1364.       
  1365.          HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight );
  1366.          MoveToEx( hDC, rc.right - 2, rc.top, NULL );
  1367.          LineTo( hDC, rc.left + n - 1, rc.top );
  1368.          LineTo( hDC, rc.left, rc.top + n - 1 );         
  1369.          
  1370.          SelectObject( hDC, penDkShadow );
  1371.          LineTo( hDC, rc.left + n - 1, rc.bottom - 1 );
  1372.          LineTo( hDC, rc.right - 1, rc.bottom - 1 );
  1373.          LineTo( hDC, rc.right - 1, rc.top - 1 );
  1374.          SelectObject( hDC, penLight );
  1375.          MoveToEx( hDC, rc.right - 3, rc.top + 1, NULL );
  1376.          LineTo( hDC, rc.left + n - 1, rc.top + 1 );
  1377.          LineTo( hDC, rc.left + 1, rc.top + n - 1 );
  1378.          SelectObject( hDC, penShadow );         
  1379.          LineTo( hDC, rc.left + n - 1, rc.bottom - 2 );
  1380.          LineTo( hDC, rc.right - 2, rc.bottom - 2 );
  1381.          LineTo( hDC, rc.right - 2, rc.top );
  1382.          SelectObject( hDC, hOldPen );         
  1383.       }
  1384.       else // TBS_RIGHT
  1385.       {
  1386.          n = ( rc.bottom - rc.top ) / 2 + 1;
  1387.          FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) );
  1388.       
  1389.          HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight );
  1390.          MoveToEx( hDC, rc.left, rc.bottom - 2, NULL );
  1391.          LineTo( hDC, rc.left, rc.top );
  1392.          LineTo( hDC, rc.right - n, rc.top );
  1393.          LineTo( hDC, rc.right - 1, rc.top + n - 1 );
  1394.          SelectObject( hDC, penDkShadow );          
  1395.          MoveToEx( hDC, rc.left, rc.bottom - 1, NULL );
  1396.          LineTo( hDC, rc.right - n, rc.bottom - 1 );
  1397.          LineTo( hDC, rc.right, rc.top + n - 2 );         
  1398.          SelectObject( hDC, penLight );
  1399.          MoveToEx( hDC, rc.left + 1, rc.bottom - 3, NULL );
  1400.          LineTo( hDC, rc.left + 1, rc.top + 1 );
  1401.          LineTo( hDC, rc.right - n, rc.top + 1 );
  1402.          LineTo( hDC, rc.right - 2, rc.top + n - 1 );
  1403.          SelectObject( hDC, penShadow );
  1404.          MoveToEx( hDC, rc.left + 1, rc.bottom - 2, NULL );
  1405.          LineTo( hDC, rc.right - n, rc.bottom - 2 );
  1406.          LineTo( hDC, rc.right - 1, rc.top + n - 2 );         
  1407.          SelectObject( hDC, hOldPen );
  1408.       }      
  1409.    }
  1410.    else
  1411.    {
  1412.       if ( dwStyle & TBS_TOP )
  1413.       {      
  1414.          n = ( rc.right - rc.left ) / 2 + 1;
  1415.          FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) );
  1416.       
  1417.          HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight );
  1418.          MoveToEx( hDC, rc.left + n - 2, rc.top + 1, NULL );
  1419.          LineTo( hDC, rc.left, rc.top + n - 1 );
  1420.          LineTo( hDC, rc.left, rc.bottom - 1 );
  1421.          SelectObject( hDC, penDkShadow );          
  1422.          LineTo( hDC, rc.right - 1, rc.bottom - 1 );
  1423.          LineTo( hDC, rc.right - 1, rc.top + n - 1 );
  1424.          LineTo( hDC, rc.left + n - 2, rc.top - 1 );
  1425.          SelectObject( hDC, penLight );
  1426.          MoveToEx( hDC, rc.left + n - 2, rc.top + 2, NULL );
  1427.          LineTo( hDC, rc.left + 1, rc.top + n - 1 );
  1428.          LineTo( hDC, rc.left + 1, rc.bottom - 2 );
  1429.      
  1430.          SelectObject( hDC, penShadow );
  1431.          LineTo( hDC, rc.right - 2, rc.bottom - 2 );
  1432.          LineTo( hDC, rc.right - 2, rc.top + n - 1 );
  1433.          LineTo( hDC, rc.left + n - 2, rc.top );
  1434.          SelectObject( hDC, hOldPen );
  1435.       }
  1436.       else // TBS_BOTTOM
  1437.       {
  1438.          n = ( rc.right - rc.left ) / 2 + 1;
  1439.          FillSolidRect( hDC, rc, GetSysColor( COLOR_3DFACE ) );
  1440.                
  1441.          HPEN hOldPen = (HPEN)SelectObject( hDC, penHighlight );
  1442.          MoveToEx( hDC, rc.left + n - 2, rc.bottom - 2, NULL );
  1443.          LineTo( hDC, rc.left, rc.bottom - n );
  1444.          LineTo( hDC, rc.left, rc.top );
  1445.          LineTo( hDC, rc.right - 1, rc.top );
  1446.          SelectObject( hDC, penDkShadow );          
  1447.          LineTo( hDC, rc.right - 1, rc.bottom - n );
  1448.          LineTo( hDC, rc.left + n - 2, rc.bottom );
  1449.          SelectObject( hDC, penLight );
  1450.          MoveToEx( hDC, rc.left + n - 2, rc.bottom - 3, NULL );
  1451.          LineTo( hDC, rc.left + 1, rc.bottom - n );
  1452.          LineTo( hDC, rc.left + 1, rc.top + 1 );
  1453.          LineTo( hDC, rc.right - 2, rc.top + 1 );
  1454.      
  1455.          SelectObject( hDC, penShadow );
  1456.          LineTo( hDC, rc.right - 2, rc.bottom - n );
  1457.          LineTo( hDC, rc.left + n - 2, rc.bottom - 1 );
  1458.          SelectObject( hDC, hOldPen );
  1459.       }
  1460.    }
  1461.    DeleteObject( penHighlight );
  1462.    DeleteObject( penLight );
  1463.    DeleteObject( penDkShadow );
  1464.    DeleteObject( penShadow );
  1465. }
  1466. void CCoolControlsManager::CCMTrackbar::DrawControl( HDC hDC, const RECT& /*rect*/ )
  1467. {  
  1468.    hDC = GetDC( m_hWnd );
  1469.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  1470.    
  1471.    RECT rc;   
  1472.    SendMessage( m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)&rc );   
  1473.    // BUG!: Windows incorrectly calculates the channel rectangle for
  1474.    // sliders with TBS_VERT style, so we have to calculate the rectangle
  1475.    // in different manner. This bug appears on all Windows platforms!
  1476.    if ( dwStyle & TBS_VERT )
  1477.    {  
  1478.       int w = ( rc.right - rc.left );
  1479.       int h = ( rc.bottom - rc.top );
  1480.       rc.top = rc.left;
  1481.       rc.bottom = rc.left + w;
  1482.       RECT r;
  1483.       SendMessage( m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)&r );         
  1484.       rc.left = r.left + ( ( r.right - r.left ) / 2 + 1 ) - h / 2;
  1485.       if ( dwStyle & TBS_LEFT )
  1486.          ;
  1487.       else if ( dwStyle & TBS_BOTH )
  1488.          rc.left -= 1;
  1489.       else
  1490.          rc.left -= 2;
  1491.       rc.right = rc.left + h;
  1492.    }
  1493.    // Draw the channel rect
  1494.    if ( m_nState & dsHoverMask )
  1495.       Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,                         
  1496.                              COLOR_3DDKSHADOW, COLOR_3DLIGHT );
  1497.    else
  1498.       Draw3dBorder( hDC, rc, COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,                         
  1499.                              COLOR_3DFACE, COLOR_3DFACE );
  1500.    
  1501.    // Draw the slider thumb
  1502.    if ( !( dwStyle & TBS_NOTHUMB ) )
  1503.    {
  1504.       SetRectEmpty( &rc );
  1505.       SendMessage( m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)&rc );
  1506.       DrawThumb( hDC, rc );
  1507.    }
  1508.    ReleaseDC( m_hWnd, hDC );
  1509. }
  1510. //////////////////////////////////////////////////////////////////////////////
  1511. // CCMToolbar class
  1512. void CCoolControlsManager::CCMToolbar::DrawButton( HDC hDC, const RECT& rc, int nState )
  1513. {
  1514.    if ( nState & bsChecked )
  1515.    {
  1516.       if ( nState & bsHover )
  1517.          Draw3dBorder( hDC, rc,
  1518.                        COLOR_3DDKSHADOW, COLOR_3DHIGHLIGHT,
  1519.                        COLOR_3DSHADOW, COLOR_3DSHADOW );
  1520.       else
  1521.          Draw3dBorder( hDC, rc,
  1522.                        COLOR_3DSHADOW, COLOR_3DHIGHLIGHT,
  1523.                        COLOR_3DFACE, COLOR_3DFACE );
  1524.    }
  1525.    else
  1526.    {
  1527.       if ( nState & bsHover )
  1528.          Draw3dBorder( hDC, rc,
  1529.                        COLOR_3DHIGHLIGHT, COLOR_3DDKSHADOW,
  1530.                        COLOR_3DLIGHT, COLOR_3DSHADOW );
  1531.       else
  1532.          Draw3dBorder( hDC, rc,
  1533.                        COLOR_3DHIGHLIGHT, COLOR_3DSHADOW,
  1534.                        COLOR_3DFACE, COLOR_3DFACE );
  1535.    }
  1536. }
  1537. void CCoolControlsManager::CCMToolbar::DrawControl( HDC hDC, const RECT& /*rc*/ )
  1538. {
  1539.    if ( GetWindowLong( m_hWnd, GWL_STYLE ) & TBSTYLE_FLAT ) // Skip flat toolbars
  1540.       return;
  1541.       
  1542.    int nCount = SendMessage( m_hWnd, TB_BUTTONCOUNT, 0, 0L );
  1543.    hDC = GetDC( m_hWnd );  // We will draw toolbar buttons on the client DC
  1544.    POINT point;
  1545.    GetCursorPos( &point );
  1546.    ScreenToClient( m_hWnd, &point );
  1547.    
  1548.    m_nOldItem = -1;
  1549.    int nState = 0;
  1550.            
  1551.    for ( int i = 0; i < nCount; i++ )
  1552.    {     
  1553.       RECT rc;       
  1554.       TBBUTTON ti;
  1555.       SendMessage( m_hWnd, TB_GETBUTTON, i, (LPARAM)&ti );
  1556.       SendMessage( m_hWnd, TB_GETITEMRECT, i, (LPARAM)&rc );
  1557.       if ( !( ti.fsStyle & TBSTYLE_SEP ) )
  1558.       {                  
  1559.          nState = ( ti.fsState & TBSTATE_CHECKED ) ? bsChecked : bsNormal;
  1560.          if ( PtInRect( &rc, point ) == TRUE )
  1561.          {
  1562.             if ( ti.fsState & TBSTATE_ENABLED )
  1563.                nState |= bsHover;
  1564.             m_nOldItem = i;
  1565.          }         
  1566.          DrawButton( hDC, rc, nState );
  1567.       }
  1568.    }
  1569.       
  1570.    ReleaseDC( m_hWnd, hDC );
  1571. }
  1572. BOOL CCoolControlsManager::CCMToolbar::NeedRedraw( const POINT& point )
  1573. {
  1574.    int nCount = SendMessage( m_hWnd, TB_BUTTONCOUNT, 0, 0L );
  1575.    POINT pt = point;
  1576.    ScreenToClient( m_hWnd, &pt );
  1577.    int nItem = -1;                
  1578.    for ( int i = 0; i < nCount; i++ )
  1579.    {            
  1580.       TBBUTTON ti;      
  1581.       SendMessage( m_hWnd, TB_GETBUTTON, i, (LPARAM)&ti );
  1582.       if ( !( ti.fsStyle & TBSTYLE_SEP ) )
  1583.       {
  1584.          RECT rc;         
  1585.          SendMessage( m_hWnd, TB_GETITEMRECT, i, (LPARAM)&rc );
  1586.          if ( PtInRect( &rc, pt ) )
  1587.          {
  1588.             nItem = i;
  1589.             break;
  1590.          }
  1591.       }
  1592.    }
  1593.    if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) )
  1594.       return TRUE;
  1595.    return FALSE;
  1596. }
  1597. LRESULT CCoolControlsManager::CCMToolbar::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1598. {
  1599.    switch ( uMsg )
  1600.    {  
  1601.       case WM_PAINT:
  1602.       case WM_NCPAINT:
  1603.          m_nOldItem = -1;   // Redraw the whole toolbar unconditionally
  1604.       default:
  1605.          return CCMControl::WindowProc( uMsg, wParam, lParam );
  1606.    }
  1607. }
  1608. //////////////////////////////////////////////////////////////////////////////
  1609. // CCMTabControl class
  1610. void CCoolControlsManager::CCMTabControl::DrawTab( HDC hDC, const RECT& rect, 
  1611.                                                    int nItem, int nState )
  1612. {
  1613.    RECT rc = rect;
  1614.    int nCurSel = SendMessage( m_hWnd, TCM_GETCURSEL, 0, 0L );
  1615.    if ( nCurSel == -1 )
  1616.       nCurSel = -2;
  1617.    switch ( GetOrientation() )
  1618.    {
  1619.       case tabLeft:
  1620.          if ( nState & bsChecked )
  1621.          {
  1622.             rc.top -= 2;
  1623.             rc.bottom += 2;
  1624.             rc.left -= 2;
  1625.             rc.right += 1;
  1626.          }
  1627.          if ( nState & bsHover )
  1628.          {
  1629.             if ( nCurSel != nItem - 1 )
  1630.             {
  1631.                FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1632.                FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DLIGHT ) );
  1633.                SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1634.             }
  1635.             FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1636.             FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DLIGHT ) );
  1637.             if ( nCurSel != nItem + 1 )
  1638.             {
  1639.                FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DDKSHADOW ) );
  1640.                FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) );                        
  1641.                SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) );
  1642.             }
  1643.          }
  1644.          else
  1645.          {
  1646.             if ( nCurSel != nItem - 1 )
  1647.             {
  1648.                FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1649.                FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) );
  1650.                SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1651.             }
  1652.             FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1653.             FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DFACE ) );
  1654.             if ( nCurSel != nItem + 1 )
  1655.             {
  1656.                FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) );
  1657.                FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) );                        
  1658.                SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) );
  1659.             }
  1660.          }       
  1661.          break;
  1662.       case tabTop:
  1663.          if ( nState & bsChecked )
  1664.          {
  1665.             rc.top -= 2;
  1666.             rc.bottom += 1;
  1667.             rc.left -= 2;
  1668.             rc.right += 2;
  1669.          }
  1670.          if ( nState & bsHover )
  1671.          {
  1672.             if ( nCurSel != nItem - 1 )
  1673.             {
  1674.                FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1675.                FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DLIGHT ) );
  1676.                SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1677.             }
  1678.             FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1679.             FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DLIGHT ) );
  1680.             if ( nCurSel != nItem + 1 )
  1681.             {
  1682.                FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DDKSHADOW ) );
  1683.                FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) );            
  1684.                SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DDKSHADOW ) );
  1685.             }                       
  1686.          }
  1687.          else
  1688.          {
  1689.             if ( nCurSel != nItem - 1 )
  1690.             {
  1691.                FillSolidRect( hDC, rc.left, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1692.                FillSolidRect( hDC, rc.left+1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) );
  1693.                SetPixel( hDC, rc.left+1, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1694.             }
  1695.             FillSolidRect( hDC, rc.left+2, rc.top, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1696.             FillSolidRect( hDC, rc.left+2, rc.top+1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DFACE ) );
  1697.             if ( nCurSel != nItem + 1 )
  1698.             {
  1699.                FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) );
  1700.                FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) );                        
  1701.                SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DSHADOW ) );
  1702.             }
  1703.          }       
  1704.          break;
  1705.       
  1706.       case tabRight:
  1707.          if ( nState & bsChecked )
  1708.          {
  1709.             rc.top -= 2;
  1710.             rc.bottom += 2;
  1711.             rc.right += 2;
  1712.             rc.left -= 1;
  1713.          }
  1714.          if ( nState & bsHover )
  1715.          {
  1716.             if ( nCurSel != nItem - 1 )
  1717.             {
  1718.                FillSolidRect( hDC, rc.left, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1719.                FillSolidRect( hDC, rc.left, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DLIGHT ) );
  1720.                SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1721.             }
  1722.             FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DDKSHADOW ) );
  1723.             FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DSHADOW ) );
  1724.             if ( nCurSel != nItem + 1 )
  1725.             {
  1726.                FillSolidRect( hDC, rc.left, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) );
  1727.                FillSolidRect( hDC, rc.left, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DDKSHADOW ) );
  1728.                SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) );
  1729.             }
  1730.          }
  1731.          else
  1732.          {
  1733.             if ( nCurSel != nItem - 1 )
  1734.             {
  1735.                FillSolidRect( hDC, rc.left, rc.top, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1736.                FillSolidRect( hDC, rc.left, rc.top+1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) );
  1737.                SetPixel( hDC, rc.right-2, rc.top+1, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1738.             }
  1739.             FillSolidRect( hDC, rc.right-1, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DSHADOW ) );
  1740.             FillSolidRect( hDC, rc.right-2, rc.top+2, 1, rc.bottom-rc.top-4, GetSysColor( COLOR_3DFACE ) );            
  1741.             if ( nCurSel != nItem + 1 )
  1742.             {
  1743.                FillSolidRect( hDC, rc.left, rc.bottom-1, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DSHADOW ) );            
  1744.                FillSolidRect( hDC, rc.left, rc.bottom-2, rc.right-rc.left-2, 1, GetSysColor( COLOR_3DFACE ) );
  1745.                SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) );
  1746.             }                        
  1747.          }       
  1748.          break;
  1749.       case tabBottom:
  1750.          if ( nState & bsChecked )
  1751.          {
  1752.             rc.bottom += 2;
  1753.             rc.left -= 2;
  1754.             rc.right += 2;
  1755.             rc.top -=1;
  1756.          }
  1757.          if ( nState & bsHover )
  1758.          {
  1759.             if ( nCurSel != nItem - 1 )
  1760.             {
  1761.                FillSolidRect( hDC, rc.left, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1762.                FillSolidRect( hDC, rc.left+1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DLIGHT ) );
  1763.                SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1764.             }
  1765.             FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DDKSHADOW ) );
  1766.             FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DSHADOW ) );
  1767.             if ( nCurSel != nItem + 1 )
  1768.             {
  1769.                FillSolidRect( hDC, rc.right-1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DDKSHADOW ) );
  1770.                FillSolidRect( hDC, rc.right-2, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) );                        
  1771.                SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DDKSHADOW ) );
  1772.             }
  1773.          }
  1774.          else
  1775.          {
  1776.             if ( nCurSel != nItem - 1 )
  1777.             {
  1778.                FillSolidRect( hDC, rc.left, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1779.                FillSolidRect( hDC, rc.left+1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) );
  1780.                SetPixel( hDC, rc.left+1, rc.bottom-2, GetSysColor( COLOR_3DHIGHLIGHT ) );
  1781.             }
  1782.             FillSolidRect( hDC, rc.left+2, rc.bottom-1, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DSHADOW ) );
  1783.             FillSolidRect( hDC, rc.left+2, rc.bottom-2, rc.right-rc.left-4, 1, GetSysColor( COLOR_3DFACE ) );
  1784.             if ( nCurSel != nItem + 1 )
  1785.             {
  1786.                FillSolidRect( hDC, rc.right-1, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DSHADOW ) );
  1787.                FillSolidRect( hDC, rc.right-2, rc.top, 1, rc.bottom-rc.top-2, GetSysColor( COLOR_3DFACE ) );
  1788.                SetPixel( hDC, rc.right-2, rc.bottom-2, GetSysColor( COLOR_3DSHADOW ) );
  1789.             }
  1790.          }       
  1791.          break;
  1792.    }
  1793. }
  1794. CCoolControlsManager::CCMTabControl::OrientationsEnum CCoolControlsManager::CCMTabControl::GetOrientation() const
  1795. {
  1796.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  1797.    if ( dwStyle & TCS_BOTTOM )
  1798.    {
  1799.       if ( dwStyle & TCS_VERTICAL )
  1800.          return tabRight;
  1801.       else
  1802.          return tabBottom;               
  1803.    }
  1804.    else  
  1805.    { 
  1806.       if ( dwStyle & TCS_VERTICAL )
  1807.          return tabLeft;
  1808.       else
  1809.          return tabTop;
  1810.    }
  1811. }
  1812. void CCoolControlsManager::CCMTabControl::DrawControl( HDC hDC, const RECT& rect )
  1813. {
  1814.    DWORD dwStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  1815.    if ( dwStyle & TCS_BUTTONS ) // Skip button-like tab controls
  1816.       return;
  1817.       
  1818.    hDC = GetDC( m_hWnd );  // We will draw on the client DC
  1819.    RECT rc = rect;
  1820.    SendMessage( m_hWnd, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc );   
  1821.    InflateRect( &rc, 4, 4 );
  1822.    RECT rcSel;
  1823.    int nCurSel = SendMessage( m_hWnd, TCM_GETCURSEL, 0, 0L );
  1824.    SendMessage( m_hWnd, TCM_GETITEMRECT, nCurSel, (LPARAM)&rcSel );
  1825.    switch ( GetOrientation() )
  1826.    {
  1827.       case tabLeft:
  1828.          rc.left += 2;
  1829.          FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) );
  1830.          FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) );         
  1831.          break;
  1832.       case tabTop:
  1833.          rc.top += 2;                  
  1834.          FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) );
  1835.          FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) );
  1836.          break;
  1837.       case tabRight:
  1838.          rc.right -= 2;         
  1839.          FillSolidRect( hDC, rc.left, rc.bottom, rc.right-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) );
  1840.          FillSolidRect( hDC, rc.right, rc.top, -1, rcSel.top-rc.top, GetSysColor( COLOR_3DSHADOW ) );
  1841.          FillSolidRect( hDC, rc.right, rcSel.bottom, -1, rc.bottom-rcSel.bottom, GetSysColor( COLOR_3DSHADOW ) );
  1842.          break;
  1843.       case tabBottom:
  1844.          rc.bottom -= 2;         
  1845.          FillSolidRect( hDC, rc.left, rc.bottom, rcSel.left-rc.left, -1, GetSysColor( COLOR_3DSHADOW ) );
  1846.          FillSolidRect( hDC, rcSel.right, rc.bottom, rc.right-rcSel.right, -1, GetSysColor( COLOR_3DSHADOW ) );
  1847.          FillSolidRect( hDC, rc.right, rc.top, -1, rc.bottom-rc.top, GetSysColor( COLOR_3DSHADOW ) );
  1848.          break;
  1849.    }
  1850.    Draw3dRect( hDC, rc.left+1, rc.top+1, rc.right-rc.left-2, rc.bottom-rc.top-2, 
  1851.                GetSysColor( COLOR_3DFACE ), GetSysColor( COLOR_3DFACE ) );
  1852.    m_nOldItem = -1;
  1853.    int nState = 0;   
  1854.    POINT point;
  1855.    GetCursorPos( &point );
  1856.    ScreenToClient( m_hWnd, &point );
  1857.    int nCount = SendMessage( m_hWnd, TCM_GETITEMCOUNT, 0, 0L );
  1858.       
  1859.    for ( int i = 0; i < nCount; i++ )
  1860.    {     
  1861.       SendMessage( m_hWnd, TCM_GETITEMRECT, i, (LPARAM)&rc );
  1862.    
  1863.       nState = bsNormal;
  1864.       if ( nCurSel != i )
  1865.       {
  1866.          if ( PtInRect( &rc, point ) == TRUE )
  1867.          {
  1868.             nState |= bsHover;
  1869.             m_nOldItem = i;
  1870.          }         
  1871.          DrawTab( hDC, rc, i, nState );
  1872.       }
  1873.    }
  1874.       
  1875.    nState = bsChecked;
  1876.    if ( PtInRect( &rcSel, point ) == TRUE )
  1877.    {
  1878.       nState |= bsHover;
  1879.       m_nOldItem = nCurSel;
  1880.    }         
  1881.    DrawTab( hDC, rcSel, nCurSel, nState );
  1882.    
  1883.    if ( nCurSel != 0 )
  1884.       switch ( GetOrientation() )
  1885.       {
  1886.          case tabTop:
  1887.             FillSolidRect( hDC, rect.left, rect.top, 2, rcSel.bottom-rcSel.top+2, GetSysColor( COLOR_3DFACE ) );
  1888.             break;
  1889.          case tabBottom:
  1890.             FillSolidRect( hDC, rect.left, rect.bottom, 2, -rcSel.bottom+rcSel.top-2, GetSysColor( COLOR_3DFACE ) );
  1891.             break;
  1892.       }
  1893.    ReleaseDC( m_hWnd, hDC );
  1894. }
  1895. BOOL CCoolControlsManager::CCMTabControl::NeedRedraw( const POINT& point )
  1896. {   
  1897.    int nCount = SendMessage( m_hWnd, TCM_GETITEMCOUNT, 0, 0L );                  
  1898.    TCHITTESTINFO thti;
  1899.    thti.pt = point;
  1900.    ScreenToClient( m_hWnd, &thti.pt );
  1901.    int nItem = SendMessage( m_hWnd, TCM_HITTEST, 0, (LPARAM)&thti );
  1902.    if ( m_hWnd != m_hWndOld || ( m_hWnd == m_hWndOld && m_nOldItem != nItem ) )
  1903.       return TRUE;
  1904.    return FALSE;
  1905. }
  1906. LRESULT CCoolControlsManager::CCMTabControl::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1907. {
  1908.    switch ( uMsg )
  1909.    {  
  1910.       case WM_PAINT:
  1911.       case WM_NCPAINT:
  1912.          m_nOldItem = -1;   // Redraw the whole control unconditionally
  1913.          break;
  1914.    }
  1915.    return CCMControl::WindowProc( uMsg, wParam, lParam );
  1916. }
  1917. //////////////////////////////////////////////////////////////////////////////
  1918. // CCMIPAddress class
  1919. BOOL CCoolControlsManager::CCMIPAddress::IsFocused()
  1920. {
  1921.    HWND hWnd = GetTopWindow( m_hWnd );
  1922.    while ( hWnd )
  1923.    {
  1924.       if ( hWnd == GetFocus() )
  1925.          return TRUE;
  1926.       hWnd = GetNextWindow( hWnd, GW_HWNDNEXT );
  1927.    }
  1928.    return FALSE;
  1929. }
  1930. LRESULT CCoolControlsManager::CCMIPAddress::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1931. {
  1932.    switch ( uMsg )
  1933.    {      
  1934.       case WM_COMMAND:
  1935.          if ( HIWORD( wParam ) == EN_SETFOCUS || HIWORD( wParam ) == EN_KILLFOCUS )
  1936.             DrawBorder();
  1937.          break;
  1938.       default:
  1939.          return CCMControl::WindowProc( uMsg, wParam, lParam );
  1940.    }
  1941.    return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  1942. }
  1943. //////////////////////////////////////////////////////////////////////////////
  1944. // CCMDialog class
  1945. LRESULT CCoolControlsManager::CCMDialog::WindowProc( UINT uMsg, WPARAM wParam, LPARAM lParam )
  1946. {
  1947.    switch ( uMsg )
  1948.    {      
  1949.       case WM_PARENTNOTIFY:         
  1950.          if ( LOWORD( wParam ) == WM_CREATE )   // Add dynamically created controls to the map
  1951.             g_ctrlManager.AddControl( (HWND)lParam );
  1952.          break;
  1953.       case WM_NCDESTROY:
  1954.          // Unsubclass window and remove it from the map
  1955.          CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  1956.          g_ctrlManager.RemoveDialog( m_hWnd );
  1957.          return 0;
  1958.    }
  1959.    return CallWindowProc( m_oldWndProc, m_hWnd, uMsg, wParam, lParam );
  1960. }
  1961. ///////////////////////////////////////////////////////////////////////////////////
  1962. // Helper functions for drawing 3D frames (borrowed from CDC class)
  1963. void CCoolControlsManager::CCMControl::FillSolidRect( HDC hDC, int x, int y, int cx, int cy, COLORREF clr )
  1964. {
  1965.    SetBkColor( hDC, clr );
  1966.    RECT rect;
  1967.    SetRect( &rect, x, y, x + cx, y + cy );
  1968.    ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
  1969. }
  1970. void CCoolControlsManager::CCMControl::FillSolidRect( HDC hDC, const RECT& rect, COLORREF clr )
  1971. {
  1972.    SetBkColor( hDC, clr );
  1973.    ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
  1974. }
  1975. void CCoolControlsManager::CCMControl::Draw3dRect( HDC hDC, int x, int y, int cx, int cy,
  1976.                                                   COLORREF clrTopLeft, COLORREF clrBottomRight )
  1977. {
  1978.    FillSolidRect( hDC, x, y, cx - 1, 1, clrTopLeft );
  1979.    FillSolidRect( hDC, x, y, 1, cy - 1, clrTopLeft );
  1980.    FillSolidRect( hDC, x + cx, y, -1, cy, clrBottomRight );
  1981.    FillSolidRect( hDC, x, y + cy, cx, -1, clrBottomRight );
  1982. }
  1983. void CCoolControlsManager::CCMControl::Draw3dRect( HDC hDC, const RECT& rect,
  1984.                                                   COLORREF clrTopLeft, COLORREF clrBottomRight )
  1985. {
  1986.    Draw3dRect( hDC, rect.left, rect.top, rect.right - rect.left,
  1987.                     rect.bottom - rect.top, clrTopLeft, clrBottomRight );
  1988. }
  1989. void CCoolControlsManager::CCMControl::Draw3dBorder( HDC hDC, const RECT& rc, 
  1990.                                                     int nColor1, int nColor2,
  1991.                                                     int nColor3, int nColor4 )
  1992. {
  1993.    Draw3dRect( hDC, rc, GetSysColor( nColor1 ), GetSysColor( nColor2 ) );
  1994.    Draw3dRect( hDC, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2, 
  1995.                         GetSysColor( nColor3 ), GetSysColor( nColor4 ) );
  1996. }
  1997. void CCoolControlsManager::CCMControl::Draw3dBorder( HDC hDC, const RECT& rc, 
  1998.                                                     int nColor1, int nColor2,
  1999.                                                     int nColor3, int nColor4,
  2000.                                                     int nColor5, int nColor6 )
  2001. {
  2002.    Draw3dRect( hDC, rc, GetSysColor( nColor1 ), GetSysColor( nColor2 ) );
  2003.    Draw3dRect( hDC, rc.left + 1, rc.top + 1, rc.right - rc.left - 2, rc.bottom - rc.top - 2, 
  2004.                         GetSysColor( nColor3 ), GetSysColor( nColor4 ) );
  2005.    Draw3dRect( hDC, rc.left + 2, rc.top + 2, rc.right - rc.left - 4, rc.bottom - rc.top - 4, 
  2006.                   GetSysColor( nColor5 ), GetSysColor( nColor6 ) );
  2007. }