// ========================================================================== // Class Specification : // COXCoolCtrl // ========================================================================== // Version: 9.3 // This software along with its related components, documentation and files ("The Libraries") // is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is // governed by a software license agreement ("Agreement"). Copies of the Agreement are // available at The Code Project (www.codeproject.com), as part of the package you downloaded // to obtain this file, or directly from our office. For a copy of the license governing // this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900. // ////////////////////////////////////////////////////////////////////////// /* DESCRIPTION Almost every application uses some of common controls in its implementation. Users used to see these common controls and khow how to use them. This the primary reason why you usually don't want to change the look and functionality of existing controls too much. But sometimes even by slightly changing the appearance of a control you can achive good results in terms of enhancing the feel and look of your application's user interface. We suggest the following new feature for common controls: every control (generally speaking, any window) can be in normal or hot state. By definition, window is in hot state when mouse cursor is over it or it has focus. Otherwise window is in normal state. Naturally, in order to distinguish window in different states some graphical effects should be applied. E.g. the drawing of window borders in different states might be different. We call controls that support normal and hot state - cool controls. We designed template class COXCoolCtrl that simplifies process of converting of common controls to cool ones. COXCoolCtrl template has one argument that specifies the parent class of the new cool control. E.g. if you would like to design your own cool listbox class you can declare it as following: class CCoolListBox : public COXCoolCtrl While implementing cool control using COXCoolCtrl derivation you might would like to override the following protected virtual functions: virtual void OnChangeHotState(BOOL bInHotState); virtual void OnFocusChange(CWnd* pWndGainFocus, CWnd* pWndLooseFocus); virtual void OnMouseEnter(const CPoint& ptCursor); virtual void OnMouseLeave(const CPoint& ptCursor); virtual BOOL HandleKey(int nVirtKey); virtual BOOL OnChangeTooltipText(const CString& sTooltipText); Refer to the class reference for detailed function explanations. Almost always you would like to override OnChangeHotState() function which is called when window is about to change its state from hot to normal and vise versa. n your implementation of this function you might redraw the window in order to show that window has changed its state. OnFocusChange() is called every time window looses or gains focus and OnMouseEnter() and OnMouseLeave() functions are called every time mouse enters or leaves the screen space taken by the window correspondingly. HandleKey() function will be called every time when user presses any key down. Overriding this function you can handle pressed key before control has a chance to do that. By returning TRUE you will notify control that you handled the event yourself and don't want to run default handler implementation. One of the additional useful feature that COXCoolCtrl supports is tooltip for the control. You can set/retrieve tooltip text using the following functions: BOOL SetTooltipText(const CString& sTooltipText); BOOL GetTooltipText(CString& sTooltipText) const; Every time you change the tooltip text OnChangeTooltipText() function will be called. By overriding this function you can control the process of setting of tooltip text. By returning FALSE you specify that you don't allow to change the tooltip text. There are a few additional public functions that you might find useful: BOOL IsInHotState() const; BOOL IsMouseOver() const; IsInHotState() function retrieves the flag that specifies whether the window is in hot or normal state. IsMouseOver() function retrieves the flag that specifies whether the current mouse position is over the window or not. Although it's not a must requirement but it would be nice if control was able to support standard and new cool state. By default when control is created of subclassed the existing one it is set to cool state. But calling the following function you can set it back to statndard state: virtual void SetCoolState(BOOL bCoolState); You can retrieve the flag that specifies whether the control is in cool or normal state virtual BOOL IsInCoolState() const; As you can see both of these functions are declared as virtual so if you don't want to support standard appearance of the control you might override this function (SetCoolState() would do nothing and IsInCoolState() would always return TRUE). Again we would like to emphasize that COXCoolCtrl class is designed specifically in order to help you to create cool common controls. We are going to come up with classes that implements some common controls as cool ones (take look at the COXCoolComboBox class which implements cool combobox). ================================================================================ Cool Controls Just as a reminder we assume that a common control can be called the "cool" one if it can take normal or hot state. By definition, window is in hot state when mouse cursor is over it or it has focus. Otherwise window is in normal state. Naturally, in order to distinguish window in different states some graphical effects should be applied. E.g. the drawing of window borders in different states might be different. COXCoolCtrl class is the basic class that is used to create cool controls. This is a template class and it can be easily used in order to create "cool" versions of common controls. Actually our implementation of classes for cool common controls doesn't have any public functions, so it's strongly recommended to refer to COXCoolCtrl reference for the functionality available for all cool controls (e.g. all cool controls support tooltips). When we were talking about implementation of "cool" versions of cool controls we mentioned that it didn't require too much job to be done because almost everything is covered by COXCoolCtrl. Actually for the following common controls "cool" state will be supported automatically if you use corresponding MFC class as template argument. Common Control MFC class UTB class Edit control CEdit COXCoolCtrl Rich edit control CRichEditCtrl COXCoolCtrl Tree view CTreeCtrl COXCoolCtrl List view CListCtrl COXCoolCtrl List box CListBox COXCoolCtrl Progress bar CProgressCtrl COXCoolCtrl Hot key control CHotKeyCtrl COXCoolCtrl Date-time picker CDateTimeCtrl COXCoolCtrl Month calendar CMonthCalCtrl COXCoolCtrl IP Address control CIPAddressCtrl COXCoolCtrl For the other common controls we had to come up with new classes as long as additional drawing routines have been required. Below you will find the list of all such controls and the corresponding Ultimate Toolbox classes. Common Control MFC class UTB class Push button Check button CButton COXCoolButton Radio button controls Spin button CSpinButtonCtrl COXCoolSpinButtonCtrl Combo box CComboBox COXCoolComboBox Slider CSliderCtrl COXCoolSliderCtrl Scroll bar CScrollBar COXCoolScrollBar We would like to emphasize again that these classes doesn't have any public functions of their own. Refer to the COXCoolCtrl function reference for details on the functionality available for all cool controls. All above mentioned classes can be used without any restrictions instead the standard ones. Take look at the CoolControls sample that demonstrates the use of all cool controls classes. This sample can be found in .\Samples\gui\CoolControls ================================================================================ Dependencies: #include "OXCoolCtrl.h" Source code files: "OXCoolCtrl.h" */ #if !defined(_OXCOOLCTRL_H__) #define _OXCOOLCTRL_H__ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 #include "OXDllExt.h" #ifndef __AFXTEMPL_H__ #include #define __AFXTEMPL_H__ #endif #include "UTB64Bit.h" #define IDT_COOLCTRL_CHECKMOUSETIMER 210 // default delay #ifndef ID_COOLCTRL_DFLT_CHECKMOUSEDELAY #define ID_COOLCTRL_DFLT_CHECKMOUSEDELAY 150 #endif // DFLT_CHECKMOUSEDELAY #define OXCOOLCTRL_TOOLTIP_ID 1000 ///////////////////////////////////////////////////////////////////////////// // COXCoolCtrl window template class COXCoolCtrl : public PARENTWND { // Construction public: // --- In : // --- Out : // --- Returns: // --- Effect : Constructs the object COXCoolCtrl(); // helper for detecting whether child descendent of parent // (works with owned popups as well) static BOOL IsDescendant(CWnd* pWndParent, CWnd* pWndChild); static BOOL IsEditControl(HWND hWnd); static BOOL IsComboBox(HWND hWnd); static BOOL IsListBox(HWND hWnd); static BOOL IsSpinButtonControl(HWND hWnd); static HWND FindAttachedSpinButton(HWND hWnd); // Attributes public: protected: // TRUE if window in cool state and FALSE if in normal state BOOL m_bCoolState; // timer id for checking mouse position UINT_PTR m_nCheckMouseTimerID; // flag that specifies if mouse is over the window BOOL m_bMouseIsOver; // flag that specifies if window in a hot state BOOL m_bInHotState; // tooltip control CToolTipCtrl m_toolTip; // internal flag that specifies whether the window is needed to be // properly initialized BOOL m_bInitializedCoolCtrl; // Operations public: // --- In : // --- Out : // --- Returns: TRUE if window is in cool state, or FALSE if it is // in normal state // --- Effect : Retrieves the flag that specifies whether the object is // in cool state or not virtual BOOL IsInCoolState() const; // --- In : bCoolState - TRUE if window will be set to cool state, // or FALSE if it will be set to normal state // --- Out : // --- Returns: // --- Effect : Sets the object in cool state, or restore the normal // state of the object virtual void SetCoolState(BOOL bCoolState); // --- In : // --- Out : // --- Returns: TRUE if window is in hot state, or FALSE otherwise // --- Effect : Retrieves the flag that specifies whether the object is // in hot state or not BOOL IsInHotState() const; // --- In : // --- Out : // --- Returns: TRUE if mouse cursor is currently over the window, // or FALSE otherwise // --- Effect : Retrieves the flag that specifies whether the mouse // cursor is currently over the window or not BOOL IsMouseOver() const; // --- In : sTooltipText - tooltip text // --- Out : // --- Returns: TRUE if new tooltip text was successfully set // --- Effect : Sets new tooltip text BOOL SetTooltipText(const CString& sTooltipText); // --- In : // --- Out : sTooltipText - reference to string variable that will be // populated with tooltip text // --- Returns: TRUE if tooltip text was successfully retrieved // --- Effect : Retrieves tooltip text BOOL GetTooltipText(CString& sTooltipText) const; // Implementation public: // --- In : // --- Out : // --- Returns: // --- Effect : Destructs the object virtual ~COXCoolCtrl(); // pretranslates messages in internal purposes virtual BOOL PreTranslateMessage(MSG* pMsg); protected: // check if mouse is over the window or not virtual void CheckMousePos(BOOL bChildren=TRUE); // initialize mouse timer and tooltip control virtual BOOL InitializeCoolCtrl(); // virtual functions // // The following virtual functions are called every time corresponding // event happens. In derived classes you can override them in order to // handle these events in specific way // // // --- In : bInHotState - TRUE if window's state is about to be changed // from normal to hot, FALSE if window's state is // about to be changed from hot to normal // --- Out : // --- Returns: // --- Effect : Called when object is about to change its state from // hot to normal or from normal to hot virtual void OnChangeHotState(BOOL bInHotState); // --- In : pWndGainFocus - pointer to the window that gains focus // pWndLooseFocus - pointer to the window that looses focus // --- Out : // --- Returns: // --- Effect : Called when window is loosing or gaining focus virtual void OnFocusChange(CWnd* pWndGainFocus, CWnd* pWndLooseFocus); // --- In : nVirtKey - virtual-key code of the pressed key // --- Out : // --- Returns: TRUE if you don't want to call default handler for pressed key, // or FALSE otherwise // --- Effect : Called when any key is pressed virtual BOOL HandleKey(int nVirtKey); // --- In : ptCursor - mouse cursor coordinates when it entered // the screen space taken by the object // --- Out : // --- Returns: // --- Effect : Called when mouse enteres the screen space taken by the object virtual void OnMouseEnter(const CPoint& ptCursor); // --- In : ptCursor - mouse cursor coordinates when it left // the screen space taken by the object // --- Out : // --- Returns: // --- Effect : Called when mouse leaves the screen space taken by the object virtual void OnMouseLeave(const CPoint& ptCursor); // --- In : sTooltipText - new tooltip text // --- Out : // --- Returns: FALSE if you don't want to set the specified text as new tooltip, // or TRUE otherwise // --- Effect : Called when new tooltip text is about to be set virtual BOOL OnChangeTooltipText(const CString& sTooltipText); // ///////////////////////////////// void DrawNcBorders(); void DrawScrollBar(CDC* pDC,CRect rectBar,BOOL bHorz); // is handled in order to properly initialize the subclassed window virtual void PreSubclassWindow(); // handles some messages that are important for internal implementation virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); }; ///////////////////////////////////////////////////////////////////////////// // COXCoolCtrl implementation template COXCoolCtrl::COXCoolCtrl() { m_bCoolState=TRUE; m_nCheckMouseTimerID=0; m_bMouseIsOver=FALSE; m_bInHotState=FALSE; m_bInitializedCoolCtrl=FALSE; } template COXCoolCtrl::~COXCoolCtrl() { } template BOOL COXCoolCtrl::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class // ... Pass the message on to the tool tip if(::IsWindow(m_toolTip.GetSafeHwnd())) { m_toolTip.Activate(TRUE); m_toolTip.RelayEvent(pMsg); } if(pMsg->message==WM_KEYDOWN) { if(HandleKey(PtrToInt(pMsg->wParam))) return TRUE; } return PARENTWND::PreTranslateMessage(pMsg); } template LRESULT COXCoolCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { #if defined (_WINDLL) #if defined (_AFXDLL) AFX_MANAGE_STATE(AfxGetAppModuleState()); #else AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif #endif // TODO: Add your specialized code here and/or call the base class ASSERT_VALID(this); if(!m_bInitializedCoolCtrl && message==WM_CREATE) { m_bInitializedCoolCtrl=TRUE; InitializeCoolCtrl(); } switch(message) { case WM_DESTROY: { if(m_nCheckMouseTimerID!=0) { ASSERT(::IsWindow(GetSafeHwnd())); VERIFY(KillTimer(m_nCheckMouseTimerID)); m_nCheckMouseTimerID=0; } if(::IsWindow(m_toolTip.GetSafeHwnd())) m_toolTip.DestroyWindow(); break; } case WM_NCDESTROY: { LRESULT lResult=PARENTWND::WindowProc(message,wParam,lParam); m_nCheckMouseTimerID=0; m_bMouseIsOver=FALSE; m_bInitializedCoolCtrl=FALSE; return lResult; } case WM_NCPAINT: { // draw the non-client area using default implementation LRESULT lResult=PARENTWND::WindowProc(message,wParam,lParam); DrawNcBorders(); return lResult; } case WM_TIMER: { if(IDT_COOLCTRL_CHECKMOUSETIMER==(UINT)wParam) { if(IsInCoolState()) { CheckMousePos(); } return 0; } break; } case WM_SETFOCUS: { if(IsInCoolState()) { OnFocusChange(this,CWnd::FromHandle((HWND)wParam)); } break; } case WM_KILLFOCUS: { if(IsInCoolState()) { OnFocusChange(CWnd::FromHandle((HWND)wParam),this); } break; } case WM_SIZE: { LRESULT lResult=PARENTWND::WindowProc(message,wParam,lParam); CString sTooltipText; if(GetTooltipText(sTooltipText)) { m_toolTip.DelTool(this,OXCOOLCTRL_TOOLTIP_ID); CRect rect; GetClientRect(rect); VERIFY(m_toolTip.AddTool( this,sTooltipText,rect,OXCOOLCTRL_TOOLTIP_ID)); } return lResult; } case WM_ENABLE: { if(IsInCoolState()) { LRESULT lResult=PARENTWND::WindowProc(message,wParam,lParam); RedrawWindow(NULL,NULL, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_FRAME); return lResult; } break; } default: { if(!IsMouseOver() && IsInCoolState() && ((message>=WM_MOUSEFIRST && message<=WM_MOUSELAST) || (message>=WM_NCMOUSEMOVE && message<=WM_NCMBUTTONDBLCLK))) { CheckMousePos(); } break; } } return PARENTWND::WindowProc(message, wParam, lParam); } template void COXCoolCtrl::PreSubclassWindow() { // TODO: Add your specialized code here and/or call the base class _AFX_THREAD_STATE* pThreadState=AfxGetThreadState(); // hook not already in progress if(pThreadState->m_pWndInit==NULL && !m_bInitializedCoolCtrl) { m_bInitializedCoolCtrl=TRUE; InitializeCoolCtrl(); } PARENTWND::PreSubclassWindow(); } template void COXCoolCtrl::CheckMousePos(BOOL bChildren/*=TRUE*/) { ASSERT(::IsWindow(GetSafeHwnd())); // Check whether the mouse is over the hooked window CPoint point; ::GetCursorPos(&point); CWnd* pWnd=CWnd::WindowFromPoint(point); BOOL bIsMouseOver=(pWnd->GetSafeHwnd()==GetSafeHwnd()); if(!bIsMouseOver && bChildren) { bIsMouseOver=IsDescendant(this,pWnd); } if(IsEditControl(GetSafeHwnd()) && IsSpinButtonControl(pWnd->GetSafeHwnd())) { if((HWND)::SendMessage(pWnd->GetSafeHwnd(), UDM_GETBUDDY,NULL,NULL)==GetSafeHwnd()) { bIsMouseOver=TRUE; } } if(IsSpinButtonControl(GetSafeHwnd())) { HWND hWndBuddy=(HWND)::SendMessage(pWnd->GetSafeHwnd(), UDM_GETBUDDY,NULL,NULL); if(hWndBuddy!=NULL && IsEditControl(hWndBuddy)) { ::SendMessage(hWndBuddy,WM_TIMER,IDT_COOLCTRL_CHECKMOUSETIMER,NULL); } } if(bIsMouseOver!=m_bMouseIsOver) { m_bMouseIsOver=bIsMouseOver; if(m_bMouseIsOver) { OnMouseEnter(point); } else { OnMouseLeave(point); } if(m_bMouseIsOver) { if(m_nCheckMouseTimerID==0) { m_nCheckMouseTimerID=SetTimer(IDT_COOLCTRL_CHECKMOUSETIMER, ID_COOLCTRL_DFLT_CHECKMOUSEDELAY,NULL); if(m_nCheckMouseTimerID==0) { TRACE(_T("COXCoolCtrl::CheckMousePos: failed to set timer\n")); } } } else { if(m_nCheckMouseTimerID!=0) { ASSERT(::IsWindow(GetSafeHwnd())); VERIFY(KillTimer(m_nCheckMouseTimerID)); m_nCheckMouseTimerID=0; } } } } template BOOL COXCoolCtrl::IsDescendant(CWnd* pWndParent, CWnd* pWndChild) // helper for detecting whether child descendent of parent // (works with owned popups as well) { ASSERT(pWndParent!=NULL); ASSERT(::IsWindow(pWndParent->GetSafeHwnd())); if(pWndChild==NULL) return FALSE; ASSERT(::IsWindow(pWndChild->GetSafeHwnd())); HWND hWndParent=pWndParent->GetSafeHwnd(); HWND hWndChild=pWndChild->GetSafeHwnd(); do { if (hWndParent == hWndChild) return TRUE; // check for permanent-owned window first CWnd* pWnd=CWnd::FromHandlePermanent(hWndChild); if(pWnd!=NULL) hWndChild=pWnd->GetOwner()->GetSafeHwnd(); else hWndChild=(::GetWindowLong(hWndChild,GWL_STYLE)&WS_CHILD) ? ::GetParent(hWndChild) : ::GetWindow(hWndChild,GW_OWNER); } while (hWndChild != NULL); return FALSE; } template BOOL COXCoolCtrl::IsEditControl(HWND hWnd) { CString sClassName; ::GetClassName(hWnd,sClassName.GetBuffer(256),256); if(sClassName.CompareNoCase(_T("Edit"))==0) return TRUE; return FALSE; } template BOOL COXCoolCtrl::IsComboBox(HWND hWnd) { CString sClassName; ::GetClassName(hWnd,sClassName.GetBuffer(256),256); if(sClassName.CompareNoCase(_T("ComboBox"))==0) return TRUE; return FALSE; } template BOOL COXCoolCtrl::IsListBox(HWND hWnd) { CString sClassName; ::GetClassName(hWnd,sClassName.GetBuffer(256),256); if(sClassName.CompareNoCase(_T("LISTBOX"))==0) return TRUE; return FALSE; } template BOOL COXCoolCtrl::IsSpinButtonControl(HWND hWnd) { CString sClassName; ::GetClassName(hWnd,sClassName.GetBuffer(256),256); if(sClassName.CompareNoCase(_T("msctls_updown32"))==0) return TRUE; return FALSE; } template HWND COXCoolCtrl::FindAttachedSpinButton(HWND hWnd) { if(!IsEditControl(hWnd)) return NULL; CWnd* pParentWnd=CWnd::FromHandle(::GetParent(hWnd)); if(pParentWnd==NULL) return NULL; CWnd* pChildWnd=pParentWnd->GetWindow(GW_CHILD); while(pChildWnd!=NULL) { if(IsSpinButtonControl(pChildWnd->GetSafeHwnd())) { if(CWnd::FromHandlePermanent(pChildWnd->GetSafeHwnd())!=NULL) { if((HWND)pChildWnd->SendMessage(UDM_GETBUDDY,NULL,NULL)==hWnd) { if(pChildWnd->GetStyle()&UDS_ALIGNRIGHT || pChildWnd->GetStyle()&UDS_ALIGNLEFT) { return pChildWnd->GetSafeHwnd(); } } } } pChildWnd=pChildWnd->GetWindow(GW_HWNDNEXT); } return NULL; } template BOOL COXCoolCtrl::InitializeCoolCtrl() { ASSERT(::IsWindow(GetSafeHwnd())); ASSERT(m_nCheckMouseTimerID==0); OnChangeHotState(IsDescendant(this,GetFocus())); ASSERT(!::IsWindow(m_toolTip.GetSafeHwnd())); if(!m_toolTip.Create(this)) { TRACE(_T("COXCoolCtrl::Initialize: Failed to create tool tip control\n")); return FALSE; } m_toolTip.Activate(TRUE); return TRUE; } template BOOL COXCoolCtrl::SetTooltipText(const CString& sTooltipText) { ASSERT(::IsWindow(GetSafeHwnd())); if(::IsWindow(m_toolTip.GetSafeHwnd())) { if(!OnChangeTooltipText(sTooltipText)) return FALSE; if(!sTooltipText.IsEmpty()) { CString sOldTooltipText; if(GetTooltipText(sOldTooltipText)) { if(sTooltipText.Collate(sOldTooltipText)==0) return TRUE; m_toolTip.DelTool(this,OXCOOLCTRL_TOOLTIP_ID); } CRect rect; GetClientRect(rect); VERIFY(m_toolTip.AddTool(this, sTooltipText, rect, OXCOOLCTRL_TOOLTIP_ID)); } else { m_toolTip.DelTool(this,OXCOOLCTRL_TOOLTIP_ID); } return TRUE; } return FALSE; } template BOOL COXCoolCtrl::GetTooltipText(CString& sTooltipText) const { ASSERT(::IsWindow(GetSafeHwnd())); if(::IsWindow(m_toolTip.GetSafeHwnd())) { CToolInfo toolInfo; if(m_toolTip.GetToolInfo(toolInfo,(CWnd*)this,OXCOOLCTRL_TOOLTIP_ID)) sTooltipText=toolInfo.lpszText; else sTooltipText=_T(""); return TRUE; } return FALSE; } template BOOL COXCoolCtrl::IsInCoolState() const { return m_bCoolState; } template void COXCoolCtrl::SetCoolState(BOOL bCoolState) { if(m_bCoolState!=bCoolState) { m_bCoolState=bCoolState; if(m_bCoolState) { CheckMousePos(); if(!IsInHotState() && IsDescendant(this,GetFocus())) OnChangeHotState(TRUE); } RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME); } } template BOOL COXCoolCtrl::IsInHotState() const { return m_bInHotState; } template BOOL COXCoolCtrl::IsMouseOver() const { return m_bMouseIsOver; } template void COXCoolCtrl::OnChangeHotState(BOOL bInHotState) { ASSERT(::IsWindow(GetSafeHwnd())); if(!bInHotState && IsDescendant(this,GetFocus())) return; if(m_bInHotState!=bInHotState) { m_bInHotState=bInHotState; RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_FRAME); HWND hAttachedSpinButton=FindAttachedSpinButton(GetSafeHwnd()); if(hAttachedSpinButton!=NULL) { ::RedrawWindow(hAttachedSpinButton,NULL,NULL, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_FRAME); } } } template void COXCoolCtrl::OnFocusChange(CWnd* pWndGainFocus, CWnd* pWndLooseFocus) { if((pWndGainFocus==this && !m_bInHotState) || (pWndLooseFocus==this && m_bInHotState)) { if(pWndLooseFocus!=NULL && pWndGainFocus!=NULL) { if(FindAttachedSpinButton(pWndLooseFocus->GetSafeHwnd())== pWndGainFocus->GetSafeHwnd()) { ASSERT(IsSpinButtonControl(pWndGainFocus->GetSafeHwnd())); // don't reset hot state return; } else if(IsDescendant(pWndLooseFocus,pWndGainFocus)) { // don't reset hot state return; } } OnChangeHotState(!m_bInHotState); } } template BOOL COXCoolCtrl::HandleKey(int nVirtKey) { UNREFERENCED_PARAMETER(nVirtKey); return FALSE; } template void COXCoolCtrl::OnMouseEnter(const CPoint& ptCursor) { UNREFERENCED_PARAMETER(ptCursor); if(!m_bInHotState) OnChangeHotState(!m_bInHotState); } template void COXCoolCtrl::OnMouseLeave(const CPoint& ptCursor) { UNREFERENCED_PARAMETER(ptCursor); if(m_bInHotState) OnChangeHotState(!m_bInHotState); } template BOOL COXCoolCtrl::OnChangeTooltipText(const CString& sTooltipText) { UNREFERENCED_PARAMETER(sTooltipText); return TRUE; } template void COXCoolCtrl::DrawNcBorders() { if(!IsInCoolState()) return; // set up all the pens we are likely to need static CPen penHilite(PS_SOLID,1,::GetSysColor(COLOR_3DHIGHLIGHT)); static CPen penShadow(PS_SOLID,1,::GetSysColor(COLOR_3DSHADOW)); static CPen penFace3D(PS_SOLID,1,::GetSysColor(COLOR_3DFACE)); static CPen penDkShad3D(PS_SOLID,1,::GetSysColor(COLOR_3DDKSHADOW)); CRect rectClient; GetClientRect(rectClient); CRect rectWindow; GetWindowRect(rectWindow); ClientToScreen(rectClient); if(rectClient==rectWindow) return; CRect rectAttached(0,0,0,0); HWND hAttachedSpinButton=FindAttachedSpinButton(GetSafeHwnd()); if(hAttachedSpinButton!=NULL) { ASSERT(IsSpinButtonControl(hAttachedSpinButton)); ::GetWindowRect(hAttachedSpinButton,rectAttached); } rectAttached-=rectWindow.TopLeft(); rectClient-=rectWindow.TopLeft(); rectWindow-=rectWindow.TopLeft(); rectAttached.IntersectRect(rectAttached,rectWindow); const BOOL bIsEnabled=IsWindowEnabled(); const BOOL bIsHot=IsInHotState() & bIsEnabled; // paint background CWindowDC dc(this); // set up rectangles for scrollbars BOOL bHasHScrollBar=((GetStyle()&WS_HSCROLL)==WS_HSCROLL); BOOL bHasVScrollBar=((GetStyle()&WS_VSCROLL)==WS_VSCROLL); CRect rectHorzScrollBar(0,0,0,0); if(bHasHScrollBar) { rectHorzScrollBar=rectClient; rectHorzScrollBar.top=rectHorzScrollBar.bottom; rectHorzScrollBar.bottom+=::GetSystemMetrics(SM_CYHSCROLL); DrawScrollBar(&dc,rectHorzScrollBar,TRUE); } CRect rectVertScrollBar(0,0,0,0); if(bHasVScrollBar) { rectVertScrollBar=rectClient; rectVertScrollBar.left=rectVertScrollBar.right; rectVertScrollBar.right+=::GetSystemMetrics(SM_CXVSCROLL); DrawScrollBar(&dc,rectVertScrollBar,FALSE); } // but first exclude the 'real' client area from the DC dc.SelectClipRgn(NULL); // from drawing background dc.ExcludeClipRect(&rectAttached); dc.ExcludeClipRect(&rectClient); dc.ExcludeClipRect(&rectHorzScrollBar); dc.ExcludeClipRect(&rectVertScrollBar); // working rect CRect rect; // draw border if(!bIsHot) { // now paint background rect=rectWindow; if(bIsEnabled) dc.SelectObject(penHilite); else dc.SelectObject(penShadow); dc.Rectangle(rect); rect.DeflateRect(1,1); dc.Rectangle(rect); } else { // HOT case - difficult to describe, but reasonably obvious rect=rectWindow; // paint the border dc.Draw3dRect(rect,::GetSysColor(COLOR_3DSHADOW), ::GetSysColor(COLOR_3DHIGHLIGHT)); rect.DeflateRect(1,1); dc.Draw3dRect(rect,::GetSysColor(COLOR_3DDKSHADOW), ::GetSysColor(COLOR_3DFACE)); } // unselect the clip region dc.SelectClipRgn(NULL); // now draw highlight border, if disabled if(!bIsEnabled) { ::SelectObject(dc.m_hDC,::GetStockObject(NULL_BRUSH)); dc.SelectObject(penHilite); dc.Rectangle(rectWindow); } if(hAttachedSpinButton!=NULL) { ::RedrawWindow(hAttachedSpinButton,NULL,NULL, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_FRAME); } } #define SCROLLTHUMB_MIN_LENGTH 8 template void COXCoolCtrl::DrawScrollBar(CDC* pDC,CRect rectBar,BOOL bHorz) { if(!IsInCoolState() || IsInHotState()) return; // draw scroll bar arrow buttons // CRect rectScrollButton1=rectBar; CRect rectScrollButton2=rectBar; CRect rectThumb=rectBar; int nButtonWidth=::GetSystemMetrics(SM_CXHSCROLL); int nButtonHeight=::GetSystemMetrics(SM_CYVSCROLL); int nScrollBarLength=0; if(bHorz) { if(nButtonWidth*2>rectBar.Width()) nButtonWidth=rectBar.Width()/2; rectScrollButton1.right=rectScrollButton1.left+nButtonWidth; rectScrollButton2.left=rectScrollButton2.right-nButtonWidth; nScrollBarLength=rectBar.Width()-nButtonWidth*2; rectThumb.left+=nButtonWidth; rectThumb.right-=nButtonWidth; } else { if(nButtonHeight*2>rectBar.Height()) nButtonHeight=rectBar.Height()/2; rectScrollButton1.bottom=rectScrollButton1.top+nButtonHeight; rectScrollButton2.top=rectScrollButton2.bottom-nButtonHeight; nScrollBarLength=rectBar.Height()-nButtonHeight*2; rectThumb.top+=nButtonHeight; rectThumb.bottom-=nButtonHeight; } pDC->Draw3dRect(rectScrollButton1,::GetSysColor(COLOR_3DHIGHLIGHT), ::GetSysColor(COLOR_3DSHADOW)); rectScrollButton1.DeflateRect(1,1); pDC->Draw3dRect(rectScrollButton1,::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DFACE)); pDC->Draw3dRect(rectScrollButton2,::GetSysColor(COLOR_3DHIGHLIGHT), ::GetSysColor(COLOR_3DSHADOW)); rectScrollButton2.DeflateRect(1,1); pDC->Draw3dRect(rectScrollButton2,::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DFACE)); // ///////////////////////////// // draw thumb // SCROLLINFO scrollInfo={ sizeof(SCROLLINFO) }; scrollInfo.fMask=SIF_ALL; if(!CWnd::GetScrollInfo((bHorz ? SB_HORZ : SB_VERT),&scrollInfo,SIF_ALL)) { SendMessage(SBM_GETSCROLLINFO,NULL,(LPARAM)&scrollInfo); } int nThumbWidth=0; if((int)scrollInfo.nPage>scrollInfo.nMax || scrollInfo.nPage==0 || nScrollBarLength0) { int nThumbPos=(int)((float)((nScrollBarLength-nThumbWidth)*scrollInfo.nPos)/ (float)(scrollInfo.nMax-scrollInfo.nPage+1)+0.5); if(bHorz) { rectThumb.left+=nThumbPos; rectThumb.right=rectThumb.left+nThumbWidth; if(rectThumb.right>nScrollBarLength+nButtonWidth+rectBar.left) { rectThumb.OffsetRect(nScrollBarLength+ nButtonWidth+rectBar.left-rectThumb.right,0); } } else { rectThumb.top+=nThumbPos; rectThumb.bottom=rectThumb.top+nThumbWidth; if(rectThumb.bottom>nScrollBarLength+nButtonHeight+rectBar.top) { rectThumb.OffsetRect(0,nScrollBarLength+ nButtonHeight+rectBar.top-rectThumb.bottom); } } pDC->Draw3dRect(rectThumb,::GetSysColor(COLOR_3DHIGHLIGHT), ::GetSysColor(COLOR_3DSHADOW)); rectThumb.DeflateRect(1,1); pDC->Draw3dRect(rectThumb,::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DFACE)); } // ///////////////////////////// } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // COXCoolButton window class OX_CLASS_DECL COXCoolButton : public COXCoolCtrl { // Construction public: // --- In : // --- Out : // --- Returns: // --- Effect : Constructs the object COXCoolButton() {}; // Attributes public: protected: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(COXCoolButton) //}}AFX_VIRTUAL protected: // overriden virtual functions // called when hot state is about to be changed virtual void OnChangeHotState(BOOL bInHotState); ///////////////////////////////////////// // Implementation public: // --- In : // --- Out : // --- Returns: // --- Effect : Destructs the object virtual ~COXCoolButton() {}; // Generated message map functions protected: //{{AFX_MSG(COXCoolButton) afx_msg void OnPaint(); //}}AFX_MSG DECLARE_MESSAGE_MAP() virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); }; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // COXCoolScrollBar window class OX_CLASS_DECL COXCoolScrollBar : public COXCoolCtrl { // Construction public: // --- In : // --- Out : // --- Returns: // --- Effect : Constructs the object COXCoolScrollBar() {}; // Attributes public: protected: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(COXCoolScrollBar) //}}AFX_VIRTUAL protected: // overriden virtual functions // called when hot state is about to be changed virtual void OnChangeHotState(BOOL bInHotState); ///////////////////////////////////////// // Implementation public: // --- In : // --- Out : // --- Returns: // --- Effect : Destructs the object virtual ~COXCoolScrollBar() {}; // Generated message map functions protected: //{{AFX_MSG(COXCoolScrollBar) afx_msg void OnPaint(); //}}AFX_MSG DECLARE_MESSAGE_MAP() virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); }; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // COXCoolSpinButtonCtrl window class OX_CLASS_DECL COXCoolSpinButtonCtrl : public COXCoolCtrl { // Construction public: // --- In : // --- Out : // --- Returns: // --- Effect : Constructs the object COXCoolSpinButtonCtrl() {}; // Attributes public: protected: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(COXCoolSpinButtonCtrl) //}}AFX_VIRTUAL protected: // overriden virtual functions // called when hot state is about to be changed virtual void OnChangeHotState(BOOL bInHotState); ///////////////////////////////////////// // Implementation public: // --- In : // --- Out : // --- Returns: // --- Effect : Destructs the object virtual ~COXCoolSpinButtonCtrl() {}; BOOL IsAttached(); // Generated message map functions protected: //{{AFX_MSG(COXCoolSpinButtonCtrl) afx_msg void OnPaint(); //}}AFX_MSG DECLARE_MESSAGE_MAP() virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); }; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // COXCoolSliderCtrl window class OX_CLASS_DECL COXCoolSliderCtrl : public COXCoolCtrl { // Construction public: // --- In : // --- Out : // --- Returns: // --- Effect : Constructs the object COXCoolSliderCtrl() {}; // Attributes public: protected: // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(COXCoolSliderCtrl) //}}AFX_VIRTUAL protected: // overriden virtual functions // called when hot state is about to be changed virtual void OnChangeHotState(BOOL bInHotState); ///////////////////////////////////////// // Implementation public: // --- In : // --- Out : // --- Returns: // --- Effect : Destructs the object virtual ~COXCoolSliderCtrl() {}; // Generated message map functions protected: //{{AFX_MSG(COXCoolSliderCtrl) afx_msg void OnPaint(); //}}AFX_MSG DECLARE_MESSAGE_MAP() virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); }; ///////////////////////////////////////////////////////////////////////////// typedef COXCoolCtrl COXCoolEdit; typedef COXCoolCtrl COXCoolRichEditCtrl; typedef COXCoolCtrl COXCoolTreeCtrl; typedef COXCoolCtrl COXCoolListCtrl; typedef COXCoolCtrl COXCoolListBox; typedef COXCoolCtrl COXCoolProgressCtrl; typedef COXCoolCtrl COXCoolHotKeyCtrl; #if _MFC_VER > 0x0421 #include "afxdtctl.h" typedef COXCoolCtrl COXCoolDateTimeCtrl; typedef COXCoolCtrl COXCoolMonthCalCtrl; typedef COXCoolCtrl COXCoolIPAddressCtrl; #endif // _MFC_VER > 0x0421 //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(_OXCOOLCTRL_H__)