1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
10 #define __ATLCTRLW_H__
15 #error ATL requires C++ compilation (use a .cpp suffix)
19 #error atlctrlw.h is not supported on Windows CE
23 #error atlctrlw.h requires atlapp.h to be included first
26 #ifndef __ATLCTRLS_H__
27 #error atlctrlw.h requires atlctrls.h to be included first
30 #if (_WIN32_IE < 0x0400)
31 #error atlctrlw.h requires _WIN32_IE >= 0x0400
34 // Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support
35 #if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
36 #define _WTL_CMDBAR_VISTA_MENUS 1
39 #if _WTL_CMDBAR_VISTA_MENUS
40 #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501))
41 #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
46 ///////////////////////////////////////////////////////////////////////////////
47 // Classes in this file:
49 // CCommandBarCtrlImpl<T, TBase, TWinTraits>
51 // CMDICommandBarCtrlImpl<T, TBase, TWinTraits>
58 ///////////////////////////////////////////////////////////////////////////////
62 #define CBRWS_TOP CCS_TOP
63 #define CBRWS_BOTTOM CCS_BOTTOM
64 #define CBRWS_NORESIZE CCS_NORESIZE
65 #define CBRWS_NOPARENTALIGN CCS_NOPARENTALIGN
66 #define CBRWS_NODIVIDER CCS_NODIVIDER
69 #define CBR_EX_TRANSPARENT 0x00000001L
70 #define CBR_EX_SHAREMENU 0x00000002L
71 #define CBR_EX_ALTFOCUSMODE 0x00000004L
72 #define CBR_EX_TRACKALWAYS 0x00000008L
73 #define CBR_EX_NOVISTAMENUS 0x00000010L
75 // standard command bar styles
76 #define ATL_SIMPLE_CMDBAR_PANE_STYLE \
77 (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)
79 // Messages - support chevrons for frame windows
80 #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND
81 #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
82 #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
84 typedef struct tagCBRPOPUPMENU
87 HMENU hMenu
; // popup menu do display
88 UINT uFlags
; // TPM_* flags for ::TrackPopupMenuEx
91 LPTPMPARAMS lptpm
; // ptr to TPMPARAMS for ::TrackPopupMenuEx
92 } CBRPOPUPMENU
, *LPCBRPOPUPMENU
;
96 class CSimpleStack
: public ATL::CSimpleArray
< T
>
101 #ifdef _CMDBAR_EXTRA_TRACE
102 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t
, GetSize());
109 int nLast
= GetSize() - 1;
111 return NULL
; // must be able to convert to NULL
113 #ifdef _CMDBAR_EXTRA_TRACE
114 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t
, GetSize());
123 int nLast
= GetSize() - 1;
125 return NULL
; // must be able to convert to NULL
131 ///////////////////////////////////////////////////////////////////////////////
132 // CCommandBarCtrlBase - base class for the Command Bar implementation
134 class CCommandBarCtrlBase
: public CToolBarCtrl
142 _MsgHookData() : hMsgHook(NULL
), dwUsage(0)
146 typedef ATL::CSimpleMap
<DWORD
, _MsgHookData
*> CMsgHookMap
;
147 static CMsgHookMap
* s_pmapMsgHook
;
149 static HHOOK s_hCreateHook
;
150 static bool s_bW2K
; // For animation flag
151 static CCommandBarCtrlBase
* s_pCurrentBar
;
152 static bool s_bStaticInit
;
154 CSimpleStack
<HWND
> m_stackMenuWnd
;
155 CSimpleStack
<HMENU
> m_stackMenuHandle
;
161 CCommandBarCtrlBase() : m_hWndHook(NULL
), m_dwMagic(1314)
163 // init static variables
166 CStaticDataInitCriticalSectionLock lock
;
167 if(FAILED(lock
.Lock()))
169 ATLTRACE2(atlTraceUI
, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n"));
177 AtlInitCommonControls(ICC_COOL_CLASSES
| ICC_BAR_CLASSES
);
178 // Animation on Win2000 only
179 s_bW2K
= !AtlIsOldWindows();
181 s_bStaticInit
= true;
188 bool IsCommandBarBase() const { return m_dwMagic
== 1314; }
191 __declspec(selectany
) CCommandBarCtrlBase::CMsgHookMap
* CCommandBarCtrlBase::s_pmapMsgHook
= NULL
;
192 __declspec(selectany
) HHOOK
CCommandBarCtrlBase::s_hCreateHook
= NULL
;
193 __declspec(selectany
) CCommandBarCtrlBase
* CCommandBarCtrlBase::s_pCurrentBar
= NULL
;
194 __declspec(selectany
) bool CCommandBarCtrlBase::s_bW2K
= false;
195 __declspec(selectany
) bool CCommandBarCtrlBase::s_bStaticInit
= false;
198 ///////////////////////////////////////////////////////////////////////////////
199 // CCommandBarCtrl - ATL implementation of Command Bars
201 template <class T
, class TBase
= CCommandBarCtrlBase
, class TWinTraits
= ATL::CControlWinTraits
>
202 class ATL_NO_VTABLE CCommandBarCtrlImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>
205 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
208 struct _MenuItemData
// menu item data
216 _MenuItemData() { dwMagic
= 0x1313; }
217 bool IsCmdBarMenuItem() { return (dwMagic
== 0x1313); }
220 struct _ToolBarData
// toolbar resource data
226 //WORD aItems[wItemCount]
229 { return (WORD
*)(this+1); }
233 enum _CmdBarDrawConstants
237 s_kcxButtonMargin
= 3,
238 s_kcyButtonMargin
= 3
243 _nMaxMenuItemTextLength
= 100,
244 _chChevronShortcut
= _T('/')
247 #ifndef DT_HIDEPREFIX
248 enum { DT_HIDEPREFIX
= 0x00100000 };
249 #endif // !DT_HIDEPREFIX
253 HIMAGELIST m_hImageList
;
254 ATL::CSimpleValArray
<WORD
> m_arrCommand
;
256 DWORD m_dwExtendedStyle
; // Command Bar specific extended styles
258 ATL::CContainedWindow m_wndParent
;
260 bool m_bMenuActive
:1;
261 bool m_bAttachedMenu
:1;
262 bool m_bImagesVisible
:1;
264 bool m_bContextMenu
:1;
265 bool m_bEscapePressed
:1;
267 bool m_bParentActive
:1;
269 bool m_bUseKeyboardCues
:1;
270 bool m_bShowKeyboardCues
:1;
271 bool m_bAllowKeyboardCues
:1;
272 bool m_bKeyboardInput
:1;
273 bool m_bAlphaImages
:1;
275 bool m_bSkipPostDown
:1;
276 bool m_bVistaMenus
:1;
285 CFont m_fontMenu
; // used internally, only to measure text
289 HWND m_hWndFocus
; // Alternate focus mode
291 int m_cxExtraSpacing
;
293 #if _WTL_CMDBAR_VISTA_MENUS
294 ATL::CSimpleValArray
<HBITMAP
> m_arrVistaBitmap
; // Bitmaps for Vista menus
295 #endif // _WTL_CMDBAR_VISTA_MENUS
297 // Constructor/destructor
298 CCommandBarCtrlImpl() :
301 m_wndParent(this, 1),
302 m_bMenuActive(false),
303 m_bAttachedMenu(false),
307 m_bImagesVisible(true),
311 m_bContextMenu(false),
312 m_bEscapePressed(false),
313 m_clrMask(RGB(192, 192, 192)),
314 m_dwExtendedStyle(CBR_EX_TRANSPARENT
| CBR_EX_SHAREMENU
| CBR_EX_TRACKALWAYS
),
315 m_bParentActive(true),
317 m_bUseKeyboardCues(false),
318 m_bShowKeyboardCues(false),
319 m_bAllowKeyboardCues(true),
320 m_bKeyboardInput(false),
322 m_bAlphaImages(false),
324 m_bSkipPostDown(false),
327 SetImageSize(16, 15); // default
330 ~CCommandBarCtrlImpl()
332 if(m_wndParent
.IsWindow())
333 /*scary!*/ m_wndParent
.UnsubclassWindow();
335 if(m_hMenu
!= NULL
&& (m_dwExtendedStyle
& CBR_EX_SHAREMENU
) == 0)
336 ::DestroyMenu(m_hMenu
);
338 if(m_hImageList
!= NULL
)
339 ::ImageList_Destroy(m_hImageList
);
343 DWORD
GetCommandBarExtendedStyle() const
345 return m_dwExtendedStyle
;
348 DWORD
SetCommandBarExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
350 DWORD dwPrevStyle
= m_dwExtendedStyle
;
352 m_dwExtendedStyle
= dwExtendedStyle
;
354 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
358 CMenuHandle
GetMenu() const
360 ATLASSERT(::IsWindow(m_hWnd
));
364 COLORREF
GetImageMaskColor() const
369 COLORREF
SetImageMaskColor(COLORREF clrMask
)
371 COLORREF clrOld
= m_clrMask
;
376 bool GetImagesVisible() const
378 return m_bImagesVisible
;
381 bool SetImagesVisible(bool bVisible
)
383 bool bOld
= m_bImagesVisible
;
384 m_bImagesVisible
= bVisible
;
388 void GetImageSize(SIZE
& size
) const
393 bool SetImageSize(SIZE
& size
)
395 return SetImageSize(size
.cx
, size
.cy
);
398 bool SetImageSize(int cx
, int cy
)
400 if(m_hImageList
!= NULL
)
402 if(::ImageList_GetImageCount(m_hImageList
) == 0) // empty
404 ::ImageList_Destroy(m_hImageList
);
409 return false; // can't set, image list exists
413 if(cx
== 0 || cy
== 0)
418 m_szButton
.cx
= m_szBitmap
.cx
+ 2 * s_kcxButtonMargin
;
419 m_szButton
.cy
= m_szBitmap
.cy
+ 2 * s_kcyButtonMargin
;
424 bool GetAlphaImages() const
426 return m_bAlphaImages
;
429 bool SetAlphaImages(bool bAlphaImages
)
431 if(m_hImageList
!= NULL
)
433 if(::ImageList_GetImageCount(m_hImageList
) == 0) // empty
435 ::ImageList_Destroy(m_hImageList
);
440 return false; // can't set, image list exists
444 m_bAlphaImages
= bAlphaImages
;
448 HWND
GetCmdBar() const
450 ATLASSERT(::IsWindow(m_hWnd
));
451 return (HWND
)::SendMessage(m_hWnd
, CBRM_GETCMDBAR
, 0, 0L);
455 HWND
Create(HWND hWndParent
, RECT
& rcPos
, LPCTSTR szWindowName
= NULL
,
456 DWORD dwStyle
= 0, DWORD dwExStyle
= 0,
457 UINT nID
= 0, LPVOID lpCreateParam
= NULL
)
459 // These styles are required for command bars
460 dwStyle
|= TBSTYLE_LIST
| TBSTYLE_FLAT
;
461 #if (_MSC_VER >= 1300)
462 return ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::Create(hWndParent
, rcPos
, szWindowName
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
463 #else // !(_MSC_VER >= 1300)
464 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
465 return _baseClass::Create(hWndParent
, rcPos
, szWindowName
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
466 #endif // !(_MSC_VER >= 1300)
469 BOOL
AttachToWindow(HWND hWnd
)
471 ATLASSERT(m_hWnd
== NULL
);
472 ATLASSERT(::IsWindow(hWnd
));
473 BOOL bRet
= SubclassWindow(hWnd
);
476 m_bAttachedMenu
= true;
477 T
* pT
= static_cast<T
*>(this);
478 pT
->GetSystemSettings();
483 BOOL
LoadMenu(ATL::_U_STRINGorID menu
)
485 ATLASSERT(::IsWindow(m_hWnd
));
487 if(m_bAttachedMenu
) // doesn't work in this mode
489 if(menu
.m_lpstr
== NULL
)
492 HMENU hMenu
= ::LoadMenu(ModuleHelper::GetResourceInstance(), menu
.m_lpstr
);
496 return AttachMenu(hMenu
);
499 BOOL
AttachMenu(HMENU hMenu
)
501 ATLASSERT(::IsWindow(m_hWnd
));
502 ATLASSERT(hMenu
== NULL
|| ::IsMenu(hMenu
));
503 if(hMenu
!= NULL
&& !::IsMenu(hMenu
))
506 #if _WTL_CMDBAR_VISTA_MENUS
507 // remove Vista bitmaps if used
508 if(m_bVistaMenus
&& (m_hMenu
!= NULL
))
510 T
* pT
= static_cast<T
*>(this);
511 pT
->_RemoveVistaBitmapsFromMenu();
513 #endif // _WTL_CMDBAR_VISTA_MENUS
515 // destroy old menu, if needed, and set new one
516 if(m_hMenu
!= NULL
&& (m_dwExtendedStyle
& CBR_EX_SHAREMENU
) == 0)
517 ::DestroyMenu(m_hMenu
);
521 if(m_bAttachedMenu
) // Nothing else in this mode
524 // Build buttons according to menu
528 int nCount
= GetButtonCount();
529 for(int i
= 0; i
< nCount
; i
++)
530 ATLVERIFY(DeleteButton(0) != FALSE
);
532 // Add buttons for each menu item
535 int nItems
= ::GetMenuItemCount(m_hMenu
);
537 T
* pT
= static_cast<T
*>(this);
538 pT
; // avoid level 4 warning
539 TCHAR szString
[pT
->_nMaxMenuItemTextLength
];
540 for(int i
= 0; i
< nItems
; i
++)
543 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
;
544 mii
.fType
= MFT_STRING
;
545 mii
.dwTypeData
= szString
;
546 mii
.cch
= pT
->_nMaxMenuItemTextLength
;
547 BOOL bRet
= ::GetMenuItemInfo(m_hMenu
, i
, TRUE
, &mii
);
549 // If we have more than the buffer, we assume we have bitmaps bits
550 if(lstrlen(szString
) > pT
->_nMaxMenuItemTextLength
- 1)
552 mii
.fType
= MFT_BITMAP
;
553 ::SetMenuItemInfo(m_hMenu
, i
, TRUE
, &mii
);
557 // NOTE: Command Bar currently supports only drop-down menu items
558 ATLASSERT(mii
.hSubMenu
!= NULL
);
560 TBBUTTON btn
= { 0 };
563 btn
.fsState
= (BYTE
)(((mii
.fState
& MFS_DISABLED
) == 0) ? TBSTATE_ENABLED
: 0);
564 btn
.fsStyle
= TBSTYLE_BUTTON
| TBSTYLE_AUTOSIZE
| TBSTYLE_DROPDOWN
;
568 bRet
= InsertButton(-1, &btn
);
571 TBBUTTONINFO bi
= { 0 };
572 bi
.cbSize
= sizeof(TBBUTTONINFO
);
573 bi
.dwMask
= TBIF_TEXT
;
574 bi
.pszText
= szString
;
576 bRet
= SetButtonInfo(i
, &bi
);
588 BOOL
LoadImages(ATL::_U_STRINGorID image
)
590 return _LoadImagesHelper(image
, false);
593 BOOL
LoadMappedImages(UINT nIDImage
, UINT nFlags
= 0, LPCOLORMAP lpColorMap
= NULL
, int nMapSize
= 0)
595 return _LoadImagesHelper(nIDImage
, true, nFlags
, lpColorMap
, nMapSize
);
598 BOOL
_LoadImagesHelper(ATL::_U_STRINGorID image
, bool bMapped
, UINT nFlags
= 0, LPCOLORMAP lpColorMap
= NULL
, int nMapSize
= 0)
600 ATLASSERT(::IsWindow(m_hWnd
));
601 HINSTANCE hInstance
= ModuleHelper::GetResourceInstance();
603 HRSRC hRsrc
= ::FindResource(hInstance
, image
.m_lpstr
, (LPTSTR
)RT_TOOLBAR
);
607 HGLOBAL hGlobal
= ::LoadResource(hInstance
, hRsrc
);
611 _ToolBarData
* pData
= (_ToolBarData
*)::LockResource(hGlobal
);
614 ATLASSERT(pData
->wVersion
== 1);
616 WORD
* pItems
= pData
->items();
617 int nItems
= pData
->wItemCount
;
620 SetImageSize(pData
->wWidth
, pData
->wHeight
);
622 // Create image list if needed
623 if(m_hImageList
== NULL
)
625 // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only)
626 T
* pT
= static_cast<T
*>(this);
627 m_bAlphaImages
= AtlIsAlphaBitmapResource(image
);
629 if(!pT
->CreateInternalImageList(pData
->wItemCount
))
633 #if _WTL_CMDBAR_VISTA_MENUS
634 int nOldImageCount
= ::ImageList_GetImageCount(m_hImageList
);
635 #endif // _WTL_CMDBAR_VISTA_MENUS
637 // Add bitmap to our image list
641 ATLASSERT(HIWORD(PtrToUlong(image
.m_lpstr
)) == 0); // if mapped, must be a numeric ID
642 int nIDImage
= (int)(short)LOWORD(PtrToUlong(image
.m_lpstr
));
643 bmp
.LoadMappedBitmap(nIDImage
, (WORD
)nFlags
, lpColorMap
, nMapSize
);
648 bmp
= (HBITMAP
)::LoadImage(ModuleHelper::GetResourceInstance(), image
.m_lpstr
, IMAGE_BITMAP
, 0, 0, LR_CREATEDIBSECTION
| LR_DEFAULTSIZE
);
650 bmp
.LoadBitmap(image
.m_lpstr
);
652 ATLASSERT(bmp
.m_hBitmap
!= NULL
);
653 if(bmp
.m_hBitmap
== NULL
)
655 if(::ImageList_AddMasked(m_hImageList
, bmp
, m_clrMask
) == -1)
658 // Fill the array with command IDs
659 for(int i
= 0; i
< nItems
; i
++)
662 m_arrCommand
.Add(pItems
[i
]);
665 int nImageCount
= ::ImageList_GetImageCount(m_hImageList
);
666 ATLASSERT(nImageCount
== m_arrCommand
.GetSize());
667 if(nImageCount
!= m_arrCommand
.GetSize())
670 #if _WTL_CMDBAR_VISTA_MENUS
671 if(RunTimeHelper::IsVista())
673 T
* pT
= static_cast<T
*>(this);
674 pT
->_AddVistaBitmapsFromImageList(nOldImageCount
, nImageCount
- nOldImageCount
);
675 ATLASSERT(nImageCount
== m_arrVistaBitmap
.GetSize());
677 #endif // _WTL_CMDBAR_VISTA_MENUS
682 BOOL
AddBitmap(ATL::_U_STRINGorID bitmap
, int nCommandID
)
684 ATLASSERT(::IsWindow(m_hWnd
));
686 bmp
.LoadBitmap(bitmap
.m_lpstr
);
687 if(bmp
.m_hBitmap
== NULL
)
689 return AddBitmap(bmp
, nCommandID
);
692 BOOL
AddBitmap(HBITMAP hBitmap
, UINT nCommandID
)
694 ATLASSERT(::IsWindow(m_hWnd
));
695 T
* pT
= static_cast<T
*>(this);
696 // Create image list if it doesn't exist
697 if(m_hImageList
== NULL
)
699 if(!pT
->CreateInternalImageList(1))
703 CBitmapHandle bmp
= hBitmap
;
704 SIZE size
= { 0, 0 };
706 if(size
.cx
!= m_szBitmap
.cx
|| size
.cy
!= m_szBitmap
.cy
)
708 ATLASSERT(FALSE
); // must match size!
712 int nRet
= ::ImageList_AddMasked(m_hImageList
, hBitmap
, m_clrMask
);
715 BOOL bRet
= m_arrCommand
.Add((WORD
)nCommandID
);
716 ATLASSERT(::ImageList_GetImageCount(m_hImageList
) == m_arrCommand
.GetSize());
717 #if _WTL_CMDBAR_VISTA_MENUS
718 if(RunTimeHelper::IsVista())
720 pT
->_AddVistaBitmapFromImageList(m_arrCommand
.GetSize() - 1);
721 ATLASSERT(m_arrVistaBitmap
.GetSize() == m_arrCommand
.GetSize());
723 #endif // _WTL_CMDBAR_VISTA_MENUS
727 BOOL
AddIcon(ATL::_U_STRINGorID icon
, UINT nCommandID
)
729 ATLASSERT(::IsWindow(m_hWnd
));
730 HICON hIcon
= ::LoadIcon(ModuleHelper::GetResourceInstance(), icon
.m_lpstr
);
733 return AddIcon(hIcon
, nCommandID
);
736 BOOL
AddIcon(HICON hIcon
, UINT nCommandID
)
738 ATLASSERT(::IsWindow(m_hWnd
));
739 T
* pT
= static_cast<T
*>(this);
740 // create image list if it doesn't exist
741 if(m_hImageList
== NULL
)
743 if(!pT
->CreateInternalImageList(1))
747 int nRet
= ::ImageList_AddIcon(m_hImageList
, hIcon
);
750 BOOL bRet
= m_arrCommand
.Add((WORD
)nCommandID
);
751 ATLASSERT(::ImageList_GetImageCount(m_hImageList
) == m_arrCommand
.GetSize());
752 #if _WTL_CMDBAR_VISTA_MENUS
753 if(RunTimeHelper::IsVista())
755 pT
->_AddVistaBitmapFromImageList(m_arrCommand
.GetSize() - 1);
756 ATLASSERT(m_arrVistaBitmap
.GetSize() == m_arrCommand
.GetSize());
758 #endif // _WTL_CMDBAR_VISTA_MENUS
762 BOOL
ReplaceBitmap(ATL::_U_STRINGorID bitmap
, int nCommandID
)
764 ATLASSERT(::IsWindow(m_hWnd
));
766 bmp
.LoadBitmap(bitmap
.m_lpstr
);
767 if(bmp
.m_hBitmap
== NULL
)
769 return ReplaceBitmap(bmp
, nCommandID
);
772 BOOL
ReplaceBitmap(HBITMAP hBitmap
, UINT nCommandID
)
774 ATLASSERT(::IsWindow(m_hWnd
));
776 for(int i
= 0; i
< m_arrCommand
.GetSize(); i
++)
778 if(m_arrCommand
[i
] == nCommandID
)
780 bRet
= ::ImageList_Remove(m_hImageList
, i
);
783 m_arrCommand
.RemoveAt(i
);
784 #if _WTL_CMDBAR_VISTA_MENUS
785 if(RunTimeHelper::IsVista())
787 if(m_arrVistaBitmap
[i
] != NULL
)
788 ::DeleteObject(m_arrVistaBitmap
[i
]);
789 m_arrVistaBitmap
.RemoveAt(i
);
791 #endif // _WTL_CMDBAR_VISTA_MENUS
797 bRet
= AddBitmap(hBitmap
, nCommandID
);
801 BOOL
ReplaceIcon(ATL::_U_STRINGorID icon
, UINT nCommandID
)
803 ATLASSERT(::IsWindow(m_hWnd
));
804 HICON hIcon
= ::LoadIcon(ModuleHelper::GetResourceInstance(), icon
.m_lpstr
);
807 return ReplaceIcon(hIcon
, nCommandID
);
810 BOOL
ReplaceIcon(HICON hIcon
, UINT nCommandID
)
812 ATLASSERT(::IsWindow(m_hWnd
));
814 for(int i
= 0; i
< m_arrCommand
.GetSize(); i
++)
816 if(m_arrCommand
[i
] == nCommandID
)
818 bRet
= (::ImageList_ReplaceIcon(m_hImageList
, i
, hIcon
) != -1);
819 #if _WTL_CMDBAR_VISTA_MENUS
820 if(RunTimeHelper::IsVista() && bRet
!= FALSE
)
822 T
* pT
= static_cast<T
*>(this);
823 pT
->_ReplaceVistaBitmapFromImageList(i
);
825 #endif // _WTL_CMDBAR_VISTA_MENUS
832 BOOL
RemoveImage(int nCommandID
)
834 ATLASSERT(::IsWindow(m_hWnd
));
837 for(int i
= 0; i
< m_arrCommand
.GetSize(); i
++)
839 if(m_arrCommand
[i
] == nCommandID
)
841 bRet
= ::ImageList_Remove(m_hImageList
, i
);
844 m_arrCommand
.RemoveAt(i
);
845 #if _WTL_CMDBAR_VISTA_MENUS
846 if(RunTimeHelper::IsVista())
848 if(m_arrVistaBitmap
[i
] != NULL
)
849 ::DeleteObject(m_arrVistaBitmap
[i
]);
850 m_arrVistaBitmap
.RemoveAt(i
);
852 #endif // _WTL_CMDBAR_VISTA_MENUS
860 BOOL
RemoveAllImages()
862 ATLASSERT(::IsWindow(m_hWnd
));
864 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Removing all images\n"));
865 BOOL bRet
= ::ImageList_RemoveAll(m_hImageList
);
868 m_arrCommand
.RemoveAll();
869 #if _WTL_CMDBAR_VISTA_MENUS
870 for(int i
= 0; i
< m_arrVistaBitmap
.GetSize(); i
++)
872 if(m_arrVistaBitmap
[i
] != NULL
)
873 ::DeleteObject(m_arrVistaBitmap
[i
]);
875 m_arrVistaBitmap
.RemoveAll();
876 #endif // _WTL_CMDBAR_VISTA_MENUS
881 BOOL
TrackPopupMenu(HMENU hMenu
, UINT uFlags
, int x
, int y
, LPTPMPARAMS lpParams
= NULL
)
883 ATLASSERT(::IsWindow(m_hWnd
));
884 ATLASSERT(::IsMenu(hMenu
));
887 m_bContextMenu
= true;
888 if(m_bUseKeyboardCues
)
889 m_bShowKeyboardCues
= m_bKeyboardInput
;
890 T
* pT
= static_cast<T
*>(this);
891 return pT
->DoTrackPopupMenu(hMenu
, uFlags
, x
, y
, lpParams
);
894 BOOL
SetMDIClient(HWND
/*hWndMDIClient*/)
896 // Use CMDICommandBarCtrl for MDI support
901 // Message map and handlers
902 BEGIN_MSG_MAP(CCommandBarCtrlImpl
)
903 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
904 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
905 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
906 MESSAGE_HANDLER(WM_INITMENU
, OnInitMenu
)
907 MESSAGE_HANDLER(WM_INITMENUPOPUP
, OnInitMenuPopup
)
908 MESSAGE_HANDLER(WM_MENUSELECT
, OnMenuSelect
)
909 MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup
)
910 MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar
)
911 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChange
)
912 MESSAGE_HANDLER(WM_MENUCHAR
, OnMenuChar
)
914 MESSAGE_HANDLER(WM_KEYDOWN
, OnKeyDown
)
915 MESSAGE_HANDLER(WM_KEYUP
, OnKeyUp
)
916 MESSAGE_HANDLER(WM_CHAR
, OnChar
)
917 MESSAGE_HANDLER(WM_SYSKEYDOWN
, OnSysKeyDown
)
918 MESSAGE_HANDLER(WM_SYSKEYUP
, OnSysKeyUp
)
919 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
920 // public API handlers - these stay to support chevrons in atlframe.h
921 MESSAGE_HANDLER(CBRM_GETMENU
, OnAPIGetMenu
)
922 MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU
, OnAPITrackPopupMenu
)
923 MESSAGE_HANDLER(CBRM_GETCMDBAR
, OnAPIGetCmdBar
)
925 MESSAGE_HANDLER(WM_DRAWITEM
, OnDrawItem
)
926 MESSAGE_HANDLER(WM_MEASUREITEM
, OnMeasureItem
)
928 MESSAGE_HANDLER(WM_FORWARDMSG
, OnForwardMsg
)
929 ALT_MSG_MAP(1) // Parent window messages
930 NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE
, OnParentHotItemChange
)
931 NOTIFY_CODE_HANDLER(TBN_DROPDOWN
, OnParentDropDown
)
932 MESSAGE_HANDLER(WM_INITMENUPOPUP
, OnParentInitMenuPopup
)
933 MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar
)
934 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnParentSysCommand
)
935 MESSAGE_HANDLER(CBRM_GETMENU
, OnParentAPIGetMenu
)
936 MESSAGE_HANDLER(WM_MENUCHAR
, OnParentMenuChar
)
937 MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU
, OnParentAPITrackPopupMenu
)
938 MESSAGE_HANDLER(CBRM_GETCMDBAR
, OnParentAPIGetCmdBar
)
939 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnParentSettingChange
)
941 MESSAGE_HANDLER(WM_DRAWITEM
, OnParentDrawItem
)
942 MESSAGE_HANDLER(WM_MEASUREITEM
, OnParentMeasureItem
)
944 MESSAGE_HANDLER(WM_ACTIVATE
, OnParentActivate
)
945 NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW
, OnParentCustomDraw
)
946 ALT_MSG_MAP(2) // MDI client window messages
947 // Use CMDICommandBarCtrl for MDI support
948 ALT_MSG_MAP(3) // Message hook messages
949 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnHookMouseMove
)
950 MESSAGE_HANDLER(WM_SYSKEYDOWN
, OnHookSysKeyDown
)
951 MESSAGE_HANDLER(WM_SYSKEYUP
, OnHookSysKeyUp
)
952 MESSAGE_HANDLER(WM_SYSCHAR
, OnHookSysChar
)
953 MESSAGE_HANDLER(WM_KEYDOWN
, OnHookKeyDown
)
954 MESSAGE_HANDLER(WM_NEXTMENU
, OnHookNextMenu
)
955 MESSAGE_HANDLER(WM_CHAR
, OnHookChar
)
958 LRESULT
OnForwardMsg(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
960 LPMSG pMsg
= (LPMSG
)lParam
;
961 if(pMsg
->message
>= WM_MOUSEFIRST
&& pMsg
->message
<= WM_MOUSELAST
)
962 m_bKeyboardInput
= false;
963 else if(pMsg
->message
>= WM_KEYFIRST
&& pMsg
->message
<= WM_KEYLAST
)
964 m_bKeyboardInput
= true;
966 ProcessWindowMessage(pMsg
->hwnd
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, lRet
, 3);
970 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
972 // Let the toolbar initialize itself
973 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
974 // get and use system settings
975 T
* pT
= static_cast<T
*>(this);
976 pT
->GetSystemSettings();
978 ATL::CWindow wndParent
= GetParent();
979 ATL::CWindow wndTopLevelParent
= wndParent
.GetTopLevelParent();
980 m_wndParent
.SubclassWindow(wndTopLevelParent
);
982 SetButtonStructSize();
985 // Create message hook if needed
986 CWindowCreateCriticalSectionLock lock
;
987 if(FAILED(lock
.Lock()))
989 ATLTRACE2(atlTraceUI
, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n"));
994 if(s_pmapMsgHook
== NULL
)
996 ATLTRY(s_pmapMsgHook
= new CMsgHookMap
);
997 ATLASSERT(s_pmapMsgHook
!= NULL
);
1000 if(s_pmapMsgHook
!= NULL
)
1002 DWORD dwThreadID
= ::GetCurrentThreadId();
1003 _MsgHookData
* pData
= s_pmapMsgHook
->Lookup(dwThreadID
);
1006 ATLTRY(pData
= new _MsgHookData
);
1007 ATLASSERT(pData
!= NULL
);
1008 HHOOK hMsgHook
= ::SetWindowsHookEx(WH_GETMESSAGE
, MessageHookProc
, ModuleHelper::GetModuleInstance(), dwThreadID
);
1009 ATLASSERT(hMsgHook
!= NULL
);
1010 if(pData
!= NULL
&& hMsgHook
!= NULL
)
1012 pData
->hMsgHook
= hMsgHook
;
1014 BOOL bRet
= s_pmapMsgHook
->Add(dwThreadID
, pData
);
1027 #if (WINVER >= 0x0500)
1028 m_bLayoutRTL
= ((GetExStyle() & WS_EX_LAYOUTRTL
) != 0);
1029 #endif // (WINVER >= 0x0500)
1034 LRESULT
OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
1036 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
1038 #if _WTL_CMDBAR_VISTA_MENUS
1039 if(m_bVistaMenus
&& (m_hMenu
!= NULL
))
1041 T
* pT
= static_cast<T
*>(this);
1042 pT
->_RemoveVistaBitmapsFromMenu();
1045 for(int i
= 0; i
< m_arrVistaBitmap
.GetSize(); i
++)
1047 if(m_arrVistaBitmap
[i
] != NULL
)
1048 ::DeleteObject(m_arrVistaBitmap
[i
]);
1050 #endif // _WTL_CMDBAR_VISTA_MENUS
1052 if(m_bAttachedMenu
) // nothing to do in this mode
1055 CWindowCreateCriticalSectionLock lock
;
1056 if(FAILED(lock
.Lock()))
1058 ATLTRACE2(atlTraceUI
, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n"));
1063 if(s_pmapMsgHook
!= NULL
)
1065 DWORD dwThreadID
= ::GetCurrentThreadId();
1066 _MsgHookData
* pData
= s_pmapMsgHook
->Lookup(dwThreadID
);
1070 if(pData
->dwUsage
== 0)
1072 BOOL bRet
= ::UnhookWindowsHookEx(pData
->hMsgHook
);
1074 bRet
= s_pmapMsgHook
->Remove(dwThreadID
);
1080 if(s_pmapMsgHook
->GetSize() == 0)
1082 delete s_pmapMsgHook
;
1083 s_pmapMsgHook
= NULL
;
1093 LRESULT
OnKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1095 #ifdef _CMDBAR_EXTRA_TRACE
1096 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnKeyDown\n"));
1099 // Simulate Alt+Space for the parent
1100 if(wParam
== VK_SPACE
)
1102 m_wndParent
.PostMessage(WM_SYSKEYDOWN
, wParam
, lParam
| (1 << 29));
1105 #if (_WIN32_IE >= 0x0500)
1106 else if(wParam
== VK_LEFT
|| wParam
== VK_RIGHT
)
1108 WPARAM wpNext
= m_bLayoutRTL
? VK_LEFT
: VK_RIGHT
;
1112 T
* pT
= static_cast<T
*>(this);
1113 int nBtn
= GetHotItem();
1114 int nNextBtn
= (wParam
== wpNext
) ? pT
->GetNextMenuItem(nBtn
) : pT
->GetPreviousMenuItem(nBtn
);
1118 if(pT
->DisplayChevronMenu())
1123 #endif // (_WIN32_IE >= 0x0500)
1127 LRESULT
OnKeyUp(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1129 #ifdef _CMDBAR_EXTRA_TRACE
1130 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnKeyUp\n"));
1132 if(wParam
!= VK_SPACE
)
1137 LRESULT
OnChar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1139 #ifdef _CMDBAR_EXTRA_TRACE
1140 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnChar\n"));
1142 if(wParam
!= VK_SPACE
)
1147 if(!m_wndParent
.IsWindowEnabled() || ::GetFocus() != m_hWnd
)
1150 // Handle mnemonic press when we have focus
1152 if(wParam
!= VK_RETURN
&& !MapAccelerator((TCHAR
)LOWORD(wParam
), nBtn
))
1154 #if (_WIN32_IE >= 0x0500)
1155 if((TCHAR
)LOWORD(wParam
) != _chChevronShortcut
)
1156 #endif // (_WIN32_IE >= 0x0500)
1161 #if (_WIN32_IE >= 0x0500)
1162 RECT rcClient
= { 0 };
1163 GetClientRect(&rcClient
);
1165 GetItemRect(nBtn
, &rcBtn
);
1166 TBBUTTON tbb
= { 0 };
1167 GetButton(nBtn
, &tbb
);
1168 if((tbb
.fsState
& TBSTATE_ENABLED
) != 0 && (tbb
.fsState
& TBSTATE_HIDDEN
) == 0 && rcBtn
.right
<= rcClient
.right
)
1170 #endif // (_WIN32_IE >= 0x0500)
1171 PostMessage(WM_KEYDOWN
, VK_DOWN
, 0L);
1172 if(wParam
!= VK_RETURN
)
1174 #if (_WIN32_IE >= 0x0500)
1181 #endif // (_WIN32_IE >= 0x0500)
1186 LRESULT
OnSysKeyDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1188 #ifdef _CMDBAR_EXTRA_TRACE
1189 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnSysKeyDown\n"));
1195 LRESULT
OnSysKeyUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1197 #ifdef _CMDBAR_EXTRA_TRACE
1198 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnSysKeyUp\n"));
1204 LRESULT
OnSysChar(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1206 #ifdef _CMDBAR_EXTRA_TRACE
1207 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnSysChar\n"));
1213 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1215 if(m_bAttachedMenu
|| (m_dwExtendedStyle
& CBR_EX_TRANSPARENT
))
1221 CDCHandle dc
= (HDC
)wParam
;
1223 GetClientRect(&rect
);
1224 dc
.FillRect(&rect
, COLOR_MENU
);
1226 return 1; // don't do the default erase
1229 LRESULT
OnInitMenu(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1231 int nIndex
= GetHotItem();
1232 SendMessage(WM_MENUSELECT
, MAKEWPARAM(nIndex
, MF_POPUP
|MF_HILITE
), (LPARAM
)m_hMenu
);
1237 LRESULT
OnInitMenuPopup(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1239 if((BOOL
)HIWORD(lParam
)) // System menu, do nothing
1245 if(!(m_bAttachedMenu
|| m_bMenuActive
)) // Not attached or ours, do nothing
1251 #ifdef _CMDBAR_EXTRA_TRACE
1252 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnInitMenuPopup\n"));
1254 // forward to the parent or subclassed window, so it can handle update UI
1257 lRet
= DefWindowProc(uMsg
, wParam
, (lParam
|| m_bContextMenu
) ? lParam
: GetHotItem());
1259 lRet
= m_wndParent
.DefWindowProc(uMsg
, wParam
, (lParam
|| m_bContextMenu
) ? lParam
: GetHotItem());
1261 #if _WTL_CMDBAR_VISTA_MENUS
1262 // If Vista menus are active, just set bitmaps and return
1265 CMenuHandle menu
= (HMENU
)wParam
;
1266 ATLASSERT(menu
.m_hMenu
!= NULL
);
1268 for(int i
= 0; i
< menu
.GetMenuItemCount(); i
++)
1270 WORD nID
= (WORD
)menu
.GetMenuItemID(i
);
1271 int nIndex
= m_arrCommand
.Find(nID
);
1274 mii
.fMask
= MIIM_BITMAP
;
1275 mii
.hbmpItem
= (m_bImagesVisible
&& (nIndex
!= -1)) ? m_arrVistaBitmap
[nIndex
] : NULL
;
1276 menu
.SetMenuItemInfo(i
, TRUE
, &mii
);
1281 #endif // _WTL_CMDBAR_VISTA_MENUS
1283 // Convert menu items to ownerdraw, add our data
1284 if(m_bImagesVisible
)
1286 CMenuHandle menuPopup
= (HMENU
)wParam
;
1287 ATLASSERT(menuPopup
.m_hMenu
!= NULL
);
1289 T
* pT
= static_cast<T
*>(this);
1290 pT
; // avoid level 4 warning
1291 TCHAR szString
[pT
->_nMaxMenuItemTextLength
];
1293 for(int i
= 0; i
< menuPopup
.GetMenuItemCount(); i
++)
1296 mii
.cch
= pT
->_nMaxMenuItemTextLength
;
1297 mii
.fMask
= MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_ID
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_TYPE
;
1298 mii
.dwTypeData
= szString
;
1299 bRet
= menuPopup
.GetMenuItemInfo(i
, TRUE
, &mii
);
1302 if(!(mii
.fType
& MFT_OWNERDRAW
)) // Not already an ownerdraw item
1304 mii
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_STATE
;
1305 _MenuItemData
* pMI
= NULL
;
1306 ATLTRY(pMI
= new _MenuItemData
);
1307 ATLASSERT(pMI
!= NULL
);
1310 pMI
->fType
= mii
.fType
;
1311 pMI
->fState
= mii
.fState
;
1312 mii
.fType
|= MFT_OWNERDRAW
;
1314 for(int j
= 0; j
< m_arrCommand
.GetSize(); j
++)
1316 if(m_arrCommand
[j
] == mii
.wID
)
1322 int cchLen
= lstrlen(szString
) + 1;
1323 pMI
->lpstrText
= NULL
;
1324 ATLTRY(pMI
->lpstrText
= new TCHAR
[cchLen
]);
1325 ATLASSERT(pMI
->lpstrText
!= NULL
);
1326 if(pMI
->lpstrText
!= NULL
)
1327 SecureHelper::strcpy_x(pMI
->lpstrText
, cchLen
, szString
);
1328 mii
.dwItemData
= (ULONG_PTR
)pMI
;
1329 bRet
= menuPopup
.SetMenuItemInfo(i
, TRUE
, &mii
);
1335 // Add it to the list
1336 m_stackMenuHandle
.Push(menuPopup
.m_hMenu
);
1342 LRESULT
OnMenuSelect(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1344 if(!m_bAttachedMenu
) // Not attached, do nothing, forward to parent
1346 m_bPopupItem
= (lParam
!= NULL
) && ((HMENU
)lParam
!= m_hMenu
) && (HIWORD(wParam
) & MF_POPUP
);
1347 if(m_wndParent
.IsWindow())
1348 m_wndParent
.SendMessage(uMsg
, wParam
, lParam
);
1353 // Check if a menu is closing, do a cleanup
1354 if(HIWORD(wParam
) == 0xFFFF && lParam
== NULL
) // Menu closing
1356 #ifdef _CMDBAR_EXTRA_TRACE
1357 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n"));
1359 ATLASSERT(m_stackMenuWnd
.GetSize() == 0);
1360 // Restore the menu items to the previous state for all menus that were converted
1361 if(m_bImagesVisible
)
1364 while((hMenu
= m_stackMenuHandle
.Pop()) != NULL
)
1366 CMenuHandle menuPopup
= hMenu
;
1367 ATLASSERT(menuPopup
.m_hMenu
!= NULL
);
1368 // Restore state and delete menu item data
1370 for(int i
= 0; i
< menuPopup
.GetMenuItemCount(); i
++)
1373 mii
.fMask
= MIIM_DATA
| MIIM_TYPE
;
1374 bRet
= menuPopup
.GetMenuItemInfo(i
, TRUE
, &mii
);
1377 _MenuItemData
* pMI
= (_MenuItemData
*)mii
.dwItemData
;
1378 if(pMI
!= NULL
&& pMI
->IsCmdBarMenuItem())
1380 mii
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_STATE
;
1381 mii
.fType
= pMI
->fType
;
1382 mii
.dwTypeData
= pMI
->lpstrText
;
1383 mii
.cch
= lstrlen(pMI
->lpstrText
);
1384 mii
.dwItemData
= NULL
;
1386 bRet
= menuPopup
.SetMenuItemInfo(i
, TRUE
, &mii
);
1389 delete [] pMI
->lpstrText
;
1390 pMI
->dwMagic
= 0x6666;
1402 LRESULT
OnInternalAutoPopup(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1404 int nIndex
= (int)wParam
;
1405 T
* pT
= static_cast<T
*>(this);
1406 pT
->DoPopupMenu(nIndex
, false);
1410 LRESULT
OnInternalGetBar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1412 // Let's make sure we're not embedded in another process
1413 if((LPVOID
)wParam
!= NULL
)
1414 *((DWORD
*)wParam
) = GetCurrentProcessId();
1415 if(IsWindowVisible())
1416 return (LRESULT
)static_cast<CCommandBarCtrlBase
*>(this);
1421 LRESULT
OnSettingChange(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1423 #ifndef SPI_GETKEYBOARDCUES
1424 const UINT SPI_SETKEYBOARDCUES
= 0x100B;
1425 #endif // !SPI_GETKEYBOARDCUES
1426 #ifndef SPI_GETFLATMENU
1427 const UINT SPI_SETFLATMENU
= 0x1023;
1428 #endif // !SPI_GETFLATMENU
1430 if(wParam
== SPI_SETNONCLIENTMETRICS
|| wParam
== SPI_SETKEYBOARDCUES
|| wParam
== SPI_SETFLATMENU
)
1432 T
* pT
= static_cast<T
*>(this);
1433 pT
->GetSystemSettings();
1439 LRESULT
OnWindowPosChanging(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
1441 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
1443 LPWINDOWPOS lpWP
= (LPWINDOWPOS
)lParam
;
1444 int cyMin
= ::GetSystemMetrics(SM_CYMENU
);
1445 if(lpWP
->cy
< cyMin
)
1451 LRESULT
OnMenuChar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1453 #ifdef _CMDBAR_EXTRA_TRACE
1454 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - OnMenuChar\n"));
1457 T
* pT
= static_cast<T
*>(this);
1460 if(m_bMenuActive
&& LOWORD(wParam
) != 0x0D)
1463 lRet
= MAKELRESULT(1, 1);
1465 if(m_bMenuActive
&& HIWORD(wParam
) == MF_POPUP
)
1467 // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout
1468 TCHAR ch
= (TCHAR
)LOWORD(wParam
);
1469 CMenuHandle menu
= (HMENU
)lParam
;
1470 int nCount
= ::GetMenuItemCount(menu
);
1471 int nRetCode
= MNC_EXECUTE
;
1473 TCHAR szString
[pT
->_nMaxMenuItemTextLength
];
1475 bool bFound
= false;
1476 for(int i
= 0; i
< nCount
; i
++)
1479 mii
.cch
= pT
->_nMaxMenuItemTextLength
;
1480 mii
.fMask
= MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_ID
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_TYPE
;
1481 mii
.dwTypeData
= szString
;
1482 bRet
= menu
.GetMenuItemInfo(i
, TRUE
, &mii
);
1483 if(!bRet
|| (mii
.fType
& MFT_SEPARATOR
))
1485 _MenuItemData
* pmd
= (_MenuItemData
*)mii
.dwItemData
;
1486 if(pmd
!= NULL
&& pmd
->IsCmdBarMenuItem())
1488 LPTSTR p
= pmd
->lpstrText
;
1492 while(*p
&& *p
!= _T('&'))
1496 DWORD dwP
= MAKELONG(*(++p
), 0);
1497 DWORD dwC
= MAKELONG(ch
, 0);
1498 if(::CharLower((LPTSTR
)ULongToPtr(dwP
)) == ::CharLower((LPTSTR
)ULongToPtr(dwC
)))
1507 nRetCode
= MNC_SELECT
;
1517 if(nRetCode
== MNC_EXECUTE
)
1519 PostMessage(TB_SETHOTITEM
, (WPARAM
)-1, 0L);
1520 pT
->GiveFocusBack();
1523 lRet
= MAKELRESULT(wMnem
, nRetCode
);
1526 else if(!m_bMenuActive
)
1529 if(!MapAccelerator((TCHAR
)LOWORD(wParam
), nBtn
))
1532 PostMessage(TB_SETHOTITEM
, (WPARAM
)-1, 0L);
1533 pT
->GiveFocusBack();
1535 #if (_WIN32_IE >= 0x0500)
1536 // check if we should display chevron menu
1537 if((TCHAR
)LOWORD(wParam
) == pT
->_chChevronShortcut
)
1539 if(pT
->DisplayChevronMenu())
1542 #endif // (_WIN32_IE >= 0x0500)
1544 else if(m_wndParent
.IsWindowEnabled())
1546 #if (_WIN32_IE >= 0x0500)
1547 RECT rcClient
= { 0 };
1548 GetClientRect(&rcClient
);
1550 GetItemRect(nBtn
, &rcBtn
);
1551 TBBUTTON tbb
= { 0 };
1552 GetButton(nBtn
, &tbb
);
1553 if((tbb
.fsState
& TBSTATE_ENABLED
) != 0 && (tbb
.fsState
& TBSTATE_HIDDEN
) == 0 && rcBtn
.right
<= rcClient
.right
)
1555 #endif // (_WIN32_IE >= 0x0500)
1556 if(m_bUseKeyboardCues
&& !m_bShowKeyboardCues
)
1558 m_bAllowKeyboardCues
= true;
1559 ShowKeyboardCues(true);
1562 PostMessage(WM_KEYDOWN
, VK_DOWN
, 0L);
1564 #if (_WIN32_IE >= 0x0500)
1570 #endif // (_WIN32_IE >= 0x0500)
1577 LRESULT
OnDrawItem(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
1579 LPDRAWITEMSTRUCT lpDrawItemStruct
= (LPDRAWITEMSTRUCT
)lParam
;
1580 _MenuItemData
* pmd
= (_MenuItemData
*)lpDrawItemStruct
->itemData
;
1581 if(lpDrawItemStruct
->CtlType
== ODT_MENU
&& pmd
!= NULL
&& pmd
->IsCmdBarMenuItem())
1583 T
* pT
= static_cast<T
*>(this);
1584 pT
->DrawItem(lpDrawItemStruct
);
1590 return (LRESULT
)TRUE
;
1593 LRESULT
OnMeasureItem(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
1595 LPMEASUREITEMSTRUCT lpMeasureItemStruct
= (LPMEASUREITEMSTRUCT
)lParam
;
1596 _MenuItemData
* pmd
= (_MenuItemData
*)lpMeasureItemStruct
->itemData
;
1597 if(lpMeasureItemStruct
->CtlType
== ODT_MENU
&& pmd
!= NULL
&& pmd
->IsCmdBarMenuItem())
1599 T
* pT
= static_cast<T
*>(this);
1600 pT
->MeasureItem(lpMeasureItemStruct
);
1606 return (LRESULT
)TRUE
;
1609 // API message handlers
1610 LRESULT
OnAPIGetMenu(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1612 return (LRESULT
)m_hMenu
;
1615 LRESULT
OnAPITrackPopupMenu(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
1619 LPCBRPOPUPMENU lpCBRPopupMenu
= (LPCBRPOPUPMENU
)lParam
;
1620 if(lpCBRPopupMenu
->cbSize
!= sizeof(CBRPOPUPMENU
))
1623 T
* pT
= static_cast<T
*>(this);
1624 return pT
->TrackPopupMenu(lpCBRPopupMenu
->hMenu
, lpCBRPopupMenu
->uFlags
, lpCBRPopupMenu
->x
, lpCBRPopupMenu
->y
, lpCBRPopupMenu
->lptpm
);
1627 LRESULT
OnAPIGetCmdBar(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1629 return (LRESULT
)m_hWnd
;
1632 // Parent window message handlers
1633 LRESULT
OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
1635 LPNMTBHOTITEM lpNMHT
= (LPNMTBHOTITEM
)pnmh
;
1637 // Check if this comes from us
1638 if(pnmh
->hwndFrom
!= m_hWnd
)
1644 bool bBlockTracking
= false;
1645 if((m_dwExtendedStyle
& CBR_EX_TRACKALWAYS
) == 0)
1648 ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID
);
1649 bBlockTracking
= (::GetCurrentProcessId() != dwProcessID
);
1652 if((!m_wndParent
.IsWindowEnabled() || bBlockTracking
) && (lpNMHT
->dwFlags
& HICF_MOUSE
))
1659 const DWORD HICF_LMOUSE
= 0x00000080; // left mouse button selected
1663 // Send WM_MENUSELECT to the app if it needs to display a status text
1664 if(!(lpNMHT
->dwFlags
& HICF_MOUSE
)
1665 && !(lpNMHT
->dwFlags
& HICF_ACCELERATOR
)
1666 && !(lpNMHT
->dwFlags
& HICF_LMOUSE
))
1668 if(lpNMHT
->dwFlags
& HICF_ENTERING
)
1669 m_wndParent
.SendMessage(WM_MENUSELECT
, 0, (LPARAM
)m_hMenu
);
1670 if(lpNMHT
->dwFlags
& HICF_LEAVING
)
1671 m_wndParent
.SendMessage(WM_MENUSELECT
, MAKEWPARAM(0, 0xFFFF), NULL
);
1678 LRESULT
OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
1680 // Check if this comes from us
1681 if(pnmh
->hwndFrom
!= m_hWnd
)
1687 T
* pT
= static_cast<T
*>(this);
1688 if(::GetFocus() != m_hWnd
)
1690 LPNMTOOLBAR pNMToolBar
= (LPNMTOOLBAR
)pnmh
;
1691 int nIndex
= CommandToIndex(pNMToolBar
->iItem
);
1692 m_bContextMenu
= false;
1693 m_bEscapePressed
= false;
1694 pT
->DoPopupMenu(nIndex
, true);
1696 return TBDDRET_DEFAULT
;
1699 LRESULT
OnParentInitMenuPopup(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1701 return OnInitMenuPopup(uMsg
, wParam
, lParam
, bHandled
);
1704 LRESULT
OnParentInternalGetBar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1706 return OnInternalGetBar(uMsg
, wParam
, lParam
, bHandled
);
1709 LRESULT
OnParentSysCommand(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1712 if((m_uSysKey
== VK_MENU
1713 || (m_uSysKey
== VK_F10
&& !(::GetKeyState(VK_SHIFT
) & 0x80))
1714 || m_uSysKey
== VK_SPACE
)
1715 && wParam
== SC_KEYMENU
)
1717 T
* pT
= static_cast<T
*>(this);
1718 if(::GetFocus() == m_hWnd
)
1720 pT
->GiveFocusBack(); // exit menu "loop"
1721 PostMessage(TB_SETHOTITEM
, (WPARAM
)-1, 0L);
1723 else if(m_uSysKey
!= VK_SPACE
&& !m_bSkipMsg
)
1725 if(m_bUseKeyboardCues
&& !m_bShowKeyboardCues
&& m_bAllowKeyboardCues
)
1726 ShowKeyboardCues(true);
1728 pT
->TakeFocus(); // enter menu "loop"
1731 else if(m_uSysKey
!= VK_SPACE
)
1740 LRESULT
OnParentAPIGetMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1742 return OnAPIGetMenu(uMsg
, wParam
, lParam
, bHandled
);
1745 LRESULT
OnParentMenuChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1747 return OnMenuChar(uMsg
, wParam
, lParam
, bHandled
);
1750 LRESULT
OnParentAPITrackPopupMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1752 return OnAPITrackPopupMenu(uMsg
, wParam
, lParam
, bHandled
);
1755 LRESULT
OnParentAPIGetCmdBar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1757 return OnAPIGetCmdBar(uMsg
, wParam
, lParam
, bHandled
);
1760 LRESULT
OnParentSettingChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1762 OnSettingChange(uMsg
, wParam
, lParam
, bHandled
);
1767 LRESULT
OnParentDrawItem(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1769 return OnDrawItem(uMsg
, wParam
, lParam
, bHandled
);
1772 LRESULT
OnParentMeasureItem(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1774 return OnMeasureItem(uMsg
, wParam
, lParam
, bHandled
);
1777 LRESULT
OnParentActivate(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1779 m_bParentActive
= (LOWORD(wParam
) != WA_INACTIVE
);
1780 if(!m_bParentActive
&& m_bUseKeyboardCues
&& m_bShowKeyboardCues
)
1782 ShowKeyboardCues(false); // this will repaint our window
1793 LRESULT
OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
1795 LRESULT lRet
= CDRF_DODEFAULT
;
1797 if(pnmh
->hwndFrom
== m_hWnd
)
1799 LPNMTBCUSTOMDRAW lpTBCustomDraw
= (LPNMTBCUSTOMDRAW
)pnmh
;
1800 if(lpTBCustomDraw
->nmcd
.dwDrawStage
== CDDS_PREPAINT
)
1802 lRet
= CDRF_NOTIFYITEMDRAW
;
1805 else if(lpTBCustomDraw
->nmcd
.dwDrawStage
== CDDS_ITEMPREPAINT
)
1809 #ifndef COLOR_MENUHILIGHT
1810 const int COLOR_MENUHILIGHT
= 29;
1811 #endif // !COLOR_MENUHILIGHT
1812 bool bDisabled
= ((lpTBCustomDraw
->nmcd
.uItemState
& CDIS_DISABLED
) == CDIS_DISABLED
);
1813 if(!bDisabled
&& ((lpTBCustomDraw
->nmcd
.uItemState
& CDIS_HOT
) == CDIS_HOT
||
1814 (lpTBCustomDraw
->nmcd
.uItemState
& CDIS_SELECTED
) == CDIS_SELECTED
))
1816 ::FillRect(lpTBCustomDraw
->nmcd
.hdc
, &lpTBCustomDraw
->nmcd
.rc
, ::GetSysColorBrush(COLOR_MENUHILIGHT
));
1817 ::FrameRect(lpTBCustomDraw
->nmcd
.hdc
, &lpTBCustomDraw
->nmcd
.rc
, ::GetSysColorBrush(COLOR_HIGHLIGHT
));
1818 lpTBCustomDraw
->clrText
= ::GetSysColor(m_bParentActive
? COLOR_HIGHLIGHTTEXT
: COLOR_GRAYTEXT
);
1820 else if(bDisabled
|| !m_bParentActive
)
1822 lpTBCustomDraw
->clrText
= ::GetSysColor(COLOR_GRAYTEXT
);
1824 CDCHandle dc
= lpTBCustomDraw
->nmcd
.hdc
;
1825 dc
.SetTextColor(lpTBCustomDraw
->clrText
);
1826 dc
.SetBkMode(lpTBCustomDraw
->nStringBkMode
);
1827 HFONT hFont
= GetFont();
1828 HFONT hFontOld
= NULL
;
1830 hFontOld
= dc
.SelectFont(hFont
);
1831 const int cchText
= 200;
1832 TCHAR szText
[cchText
] = { 0 };
1833 TBBUTTONINFO tbbi
= { 0 };
1834 tbbi
.cbSize
= sizeof(TBBUTTONINFO
);
1835 tbbi
.dwMask
= TBIF_TEXT
;
1836 tbbi
.pszText
= szText
;
1837 tbbi
.cchText
= cchText
;
1838 GetButtonInfo((int)lpTBCustomDraw
->nmcd
.dwItemSpec
, &tbbi
);
1839 dc
.DrawText(szText
, -1, &lpTBCustomDraw
->nmcd
.rc
, DT_SINGLELINE
| DT_CENTER
| DT_VCENTER
| (m_bShowKeyboardCues
? 0 : DT_HIDEPREFIX
));
1841 dc
.SelectFont(hFontOld
);
1842 lRet
= CDRF_SKIPDEFAULT
;
1845 else if(!m_bParentActive
)
1847 lpTBCustomDraw
->clrText
= ::GetSysColor(COLOR_GRAYTEXT
);
1855 // Message hook handlers
1856 LRESULT
OnHookMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1858 static POINT s_point
= { -1, -1 };
1859 DWORD dwPoint
= ::GetMessagePos();
1860 POINT point
= { GET_X_LPARAM(dwPoint
), GET_Y_LPARAM(dwPoint
) };
1865 if(::WindowFromPoint(point
) == m_hWnd
)
1867 ScreenToClient(&point
);
1868 int nHit
= HitTest(&point
);
1870 if((point
.x
!= s_point
.x
|| point
.y
!= s_point
.y
) && nHit
>= 0 && nHit
< ::GetMenuItemCount(m_hMenu
) && nHit
!= m_nPopBtn
&& m_nPopBtn
!= -1)
1872 TBBUTTON tbb
= { 0 };
1873 GetButton(nHit
, &tbb
);
1874 if((tbb
.fsState
& TBSTATE_ENABLED
) != 0)
1876 m_nNextPopBtn
= nHit
| 0xFFFF0000;
1877 HWND hWndMenu
= m_stackMenuWnd
.GetCurrent();
1878 ATLASSERT(hWndMenu
!= NULL
);
1880 // this one is needed to close a menu if mouse button was down
1881 ::PostMessage(hWndMenu
, WM_LBUTTONUP
, 0, MAKELPARAM(point
.x
, point
.y
));
1882 // this one closes a popup menu
1883 ::PostMessage(hWndMenu
, WM_KEYDOWN
, VK_ESCAPE
, 0L);
1892 ScreenToClient(&point
);
1899 LRESULT
OnHookSysKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1902 #ifdef _CMDBAR_EXTRA_TRACE
1903 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam
);
1906 if(wParam
== VK_MENU
&& m_bParentActive
&& m_bUseKeyboardCues
&& !m_bShowKeyboardCues
&& m_bAllowKeyboardCues
)
1907 ShowKeyboardCues(true);
1909 if(wParam
!= VK_SPACE
&& !m_bMenuActive
&& ::GetFocus() == m_hWnd
)
1911 m_bAllowKeyboardCues
= false;
1912 PostMessage(TB_SETHOTITEM
, (WPARAM
)-1, 0L);
1913 T
* pT
= static_cast<T
*>(this);
1914 pT
->GiveFocusBack();
1919 if(wParam
== VK_SPACE
&& m_bUseKeyboardCues
&& m_bShowKeyboardCues
)
1921 m_bAllowKeyboardCues
= true;
1922 ShowKeyboardCues(false);
1924 m_uSysKey
= (UINT
)wParam
;
1929 LRESULT
OnHookSysKeyUp(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1931 if(!m_bAllowKeyboardCues
)
1932 m_bAllowKeyboardCues
= true;
1935 #ifdef _CMDBAR_EXTRA_TRACE
1936 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam
);
1941 LRESULT
OnHookSysChar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1944 #ifdef _CMDBAR_EXTRA_TRACE
1945 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam
);
1948 if(!m_bMenuActive
&& m_hWndHook
!= m_hWnd
&& wParam
!= VK_SPACE
)
1953 LRESULT
OnHookKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1955 #ifdef _CMDBAR_EXTRA_TRACE
1956 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam
);
1959 T
* pT
= static_cast<T
*>(this);
1961 if(wParam
== VK_ESCAPE
&& m_stackMenuWnd
.GetSize() <= 1)
1963 if(m_bMenuActive
&& !m_bContextMenu
)
1965 int nHot
= GetHotItem();
1973 m_bEscapePressed
= true; // To keep focus
1974 m_bSkipPostDown
= false;
1976 else if(::GetFocus() == m_hWnd
&& m_wndParent
.IsWindow())
1979 pT
->GiveFocusBack();
1983 else if(wParam
== VK_RETURN
|| wParam
== VK_UP
|| wParam
== VK_DOWN
)
1985 if(!m_bMenuActive
&& ::GetFocus() == m_hWnd
&& m_wndParent
.IsWindow())
1987 int nHot
= GetHotItem();
1990 if(wParam
!= VK_RETURN
)
1992 if(!m_bSkipPostDown
)
1994 // IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click
1995 #if (_WIN32_IE < 0x0500)
1996 DWORD dwMajor
= 0, dwMinor
= 0;
1997 ATL::AtlGetCommCtrlVersion(&dwMajor
, &dwMinor
);
1998 if(dwMajor
<= 4 || (dwMajor
== 5 && dwMinor
< 80))
2001 GetItemRect(nHot
, &rect
);
2002 PostMessage(WM_LBUTTONDOWN
, MK_LBUTTON
, MAKELPARAM(rect
.left
, rect
.top
));
2004 #endif // (_WIN32_IE < 0x0500)
2005 PostMessage(WM_KEYDOWN
, VK_DOWN
, 0L);
2006 m_bSkipPostDown
= true;
2010 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - skipping posting another VK_DOWN\n"));
2011 m_bSkipPostDown
= false;
2017 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Can't find hot button\n"));
2020 if(wParam
== VK_RETURN
&& m_bMenuActive
)
2022 PostMessage(TB_SETHOTITEM
, (WPARAM
)-1, 0L);
2024 pT
->GiveFocusBack();
2027 else if(wParam
== VK_LEFT
|| wParam
== VK_RIGHT
)
2029 WPARAM wpNext
= m_bLayoutRTL
? VK_LEFT
: VK_RIGHT
;
2030 WPARAM wpPrev
= m_bLayoutRTL
? VK_RIGHT
: VK_LEFT
;
2032 if(m_bMenuActive
&& !m_bContextMenu
&& !(wParam
== wpNext
&& m_bPopupItem
))
2034 bool bAction
= false;
2035 if(wParam
== wpPrev
&& s_pCurrentBar
->m_stackMenuWnd
.GetSize() == 1)
2037 m_nNextPopBtn
= pT
->GetPreviousMenuItem(m_nPopBtn
);
2038 if(m_nNextPopBtn
!= -1)
2041 else if(wParam
== wpNext
)
2043 m_nNextPopBtn
= pT
->GetNextMenuItem(m_nPopBtn
);
2044 if(m_nNextPopBtn
!= -1)
2047 HWND hWndMenu
= m_stackMenuWnd
.GetCurrent();
2048 ATLASSERT(hWndMenu
!= NULL
);
2050 // Close the popup menu
2053 ::PostMessage(hWndMenu
, WM_KEYDOWN
, VK_ESCAPE
, 0L);
2054 if(wParam
== wpNext
)
2056 int cItem
= m_stackMenuWnd
.GetSize() - 1;
2059 hWndMenu
= m_stackMenuWnd
[cItem
];
2060 if(hWndMenu
!= NULL
)
2061 ::PostMessage(hWndMenu
, WM_KEYDOWN
, VK_ESCAPE
, 0L);
2065 #if (_WIN32_IE >= 0x0500)
2066 if(m_nNextPopBtn
== -2)
2069 pT
->DisplayChevronMenu();
2071 #endif // (_WIN32_IE >= 0x0500)
2079 LRESULT
OnHookNextMenu(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
2081 #ifdef _CMDBAR_EXTRA_TRACE
2082 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook WM_NEXTMENU\n"));
2088 LRESULT
OnHookChar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
2090 #ifdef _CMDBAR_EXTRA_TRACE
2091 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam
);
2093 bHandled
= (wParam
== VK_ESCAPE
);
2097 // Implementation - ownerdraw overrideables and helpers
2098 void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct
)
2100 T
* pT
= static_cast<T
*>(this);
2102 pT
->DrawItemFlat(lpDrawItemStruct
);
2104 pT
->DrawItem3D(lpDrawItemStruct
);
2108 void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct
)
2110 _MenuItemData
* pmd
= (_MenuItemData
*)lpDrawItemStruct
->itemData
;
2111 CDCHandle dc
= lpDrawItemStruct
->hDC
;
2112 const RECT
& rcItem
= lpDrawItemStruct
->rcItem
;
2113 T
* pT
= static_cast<T
*>(this);
2115 if(pmd
->fType
& MFT_SEPARATOR
)
2119 rc
.top
+= (rc
.bottom
- rc
.top
) / 2; // vertical center
2120 dc
.DrawEdge(&rc
, EDGE_ETCHED
, BF_TOP
); // draw separator line
2122 else // not a separator
2124 BOOL bDisabled
= lpDrawItemStruct
->itemState
& ODS_GRAYED
;
2125 BOOL bSelected
= lpDrawItemStruct
->itemState
& ODS_SELECTED
;
2126 BOOL bChecked
= lpDrawItemStruct
->itemState
& ODS_CHECKED
;
2127 BOOL bHasImage
= FALSE
;
2129 if(LOWORD(lpDrawItemStruct
->itemID
) == (WORD
)-1)
2131 RECT rcButn
= { rcItem
.left
, rcItem
.top
, rcItem
.left
+ m_szButton
.cx
, rcItem
.top
+ m_szButton
.cy
}; // button rect
2132 ::OffsetRect(&rcButn
, 0, ((rcItem
.bottom
- rcItem
.top
) - (rcButn
.bottom
- rcButn
.top
)) / 2); // center vertically
2134 int iButton
= pmd
->iButton
;
2139 // calc drawing point
2140 SIZE sz
= { rcButn
.right
- rcButn
.left
- m_szBitmap
.cx
, rcButn
.bottom
- rcButn
.top
- m_szBitmap
.cy
};
2143 POINT point
= { rcButn
.left
+ sz
.cx
, rcButn
.top
+ sz
.cy
};
2145 // fill background depending on state
2146 if(!bChecked
|| (bSelected
&& !bDisabled
))
2149 dc
.FillRect(&rcButn
, (bChecked
&& !bSelected
) ? COLOR_3DLIGHT
: COLOR_MENU
);
2151 dc
.FillRect(&rcButn
, COLOR_MENU
);
2155 COLORREF crTxt
= dc
.SetTextColor(::GetSysColor(COLOR_BTNFACE
));
2156 COLORREF crBk
= dc
.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT
));
2157 CBrush
hbr(CDCHandle::GetHalftoneBrush());
2158 dc
.SetBrushOrg(rcButn
.left
, rcButn
.top
);
2159 dc
.FillRect(&rcButn
, hbr
);
2160 dc
.SetTextColor(crTxt
);
2161 dc
.SetBkColor(crBk
);
2164 // draw disabled or normal
2167 // draw pushed-in or popped-out edge
2168 if(bSelected
|| bChecked
)
2171 dc
.DrawEdge(&rc2
, bChecked
? BDR_SUNKENOUTER
: BDR_RAISEDINNER
, BF_RECT
);
2174 ::ImageList_Draw(m_hImageList
, iButton
, dc
, point
.x
, point
.y
, ILD_TRANSPARENT
);
2178 HBRUSH hBrushBackground
= bChecked
? NULL
: ::GetSysColorBrush(COLOR_MENU
);
2179 pT
->DrawBitmapDisabled(dc
, iButton
, point
, hBrushBackground
);
2184 // no image - look for custom checked/unchecked bitmaps
2186 info
.fMask
= MIIM_CHECKMARKS
| MIIM_TYPE
;
2187 ::GetMenuItemInfo((HMENU
)lpDrawItemStruct
->hwndItem
, lpDrawItemStruct
->itemID
, MF_BYCOMMAND
, &info
);
2188 if(bChecked
|| info
.hbmpUnchecked
!= NULL
)
2190 BOOL bRadio
= ((info
.fType
& MFT_RADIOCHECK
) != 0);
2191 bHasImage
= pT
->DrawCheckmark(dc
, rcButn
, bSelected
, bDisabled
, bRadio
, bChecked
? info
.hbmpChecked
: info
.hbmpUnchecked
);
2196 int cxButn
= m_szButton
.cx
;
2197 COLORREF colorBG
= ::GetSysColor(bSelected
? COLOR_HIGHLIGHT
: COLOR_MENU
);
2198 if(bSelected
|| lpDrawItemStruct
->itemAction
== ODA_SELECT
)
2202 rcBG
.left
+= cxButn
+ s_kcxGap
;
2203 dc
.FillRect(&rcBG
, bSelected
? COLOR_HIGHLIGHT
: COLOR_MENU
);
2206 // calc text rectangle and colors
2207 RECT rcText
= rcItem
;
2208 rcText
.left
+= cxButn
+ s_kcxGap
+ s_kcxTextMargin
;
2209 rcText
.right
-= cxButn
;
2210 dc
.SetBkMode(TRANSPARENT
);
2211 COLORREF colorText
= ::GetSysColor(bDisabled
? (bSelected
? COLOR_GRAYTEXT
: COLOR_3DSHADOW
) : (bSelected
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
));
2213 // font already selected by Windows
2214 if(bDisabled
&& (!bSelected
|| colorText
== colorBG
))
2216 // disabled - draw shadow text shifted down and right 1 pixel (unles selected)
2217 RECT rcDisabled
= rcText
;
2218 ::OffsetRect(&rcDisabled
, 1, 1);
2219 pT
->DrawMenuText(dc
, rcDisabled
, pmd
->lpstrText
, ::GetSysColor(COLOR_3DHILIGHT
));
2221 pT
->DrawMenuText(dc
, rcText
, pmd
->lpstrText
, colorText
); // finally!
2225 void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct
)
2227 _MenuItemData
* pmd
= (_MenuItemData
*)lpDrawItemStruct
->itemData
;
2228 CDCHandle dc
= lpDrawItemStruct
->hDC
;
2229 const RECT
& rcItem
= lpDrawItemStruct
->rcItem
;
2230 T
* pT
= static_cast<T
*>(this);
2232 #ifndef COLOR_MENUHILIGHT
2233 const int COLOR_MENUHILIGHT
= 29;
2234 #endif // !COLOR_MENUHILIGHT
2236 BOOL bDisabled
= lpDrawItemStruct
->itemState
& ODS_GRAYED
;
2237 BOOL bSelected
= lpDrawItemStruct
->itemState
& ODS_SELECTED
;
2238 BOOL bChecked
= lpDrawItemStruct
->itemState
& ODS_CHECKED
;
2241 if(bSelected
|| lpDrawItemStruct
->itemAction
== ODA_SELECT
)
2245 dc
.FillRect(&rcItem
, ::GetSysColorBrush(COLOR_MENUHILIGHT
));
2246 dc
.FrameRect(&rcItem
, ::GetSysColorBrush(COLOR_HIGHLIGHT
));
2250 dc
.FillRect(&rcItem
, ::GetSysColorBrush(COLOR_MENU
));
2254 if(pmd
->fType
& MFT_SEPARATOR
)
2258 rc
.top
+= (rc
.bottom
- rc
.top
) / 2; // vertical center
2259 dc
.DrawEdge(&rc
, EDGE_ETCHED
, BF_TOP
); // draw separator line
2261 else // not a separator
2263 if(LOWORD(lpDrawItemStruct
->itemID
) == (WORD
)-1)
2265 RECT rcButn
= { rcItem
.left
, rcItem
.top
, rcItem
.left
+ m_szButton
.cx
, rcItem
.top
+ m_szButton
.cy
}; // button rect
2266 ::OffsetRect(&rcButn
, 0, ((rcItem
.bottom
- rcItem
.top
) - (rcButn
.bottom
- rcButn
.top
)) / 2); // center vertically
2268 // draw background and border for checked items
2271 RECT rcCheck
= rcButn
;
2272 ::InflateRect(&rcCheck
, -1, -1);
2274 dc
.FillRect(&rcCheck
, ::GetSysColorBrush(COLOR_MENU
));
2275 dc
.FrameRect(&rcCheck
, ::GetSysColorBrush(COLOR_HIGHLIGHT
));
2278 int iButton
= pmd
->iButton
;
2281 // calc drawing point
2282 SIZE sz
= { rcButn
.right
- rcButn
.left
- m_szBitmap
.cx
, rcButn
.bottom
- rcButn
.top
- m_szBitmap
.cy
};
2285 POINT point
= { rcButn
.left
+ sz
.cx
, rcButn
.top
+ sz
.cy
};
2287 // draw disabled or normal
2290 ::ImageList_Draw(m_hImageList
, iButton
, dc
, point
.x
, point
.y
, ILD_TRANSPARENT
);
2294 HBRUSH hBrushBackground
= ::GetSysColorBrush((bSelected
&& !(bDisabled
&& bChecked
)) ? COLOR_MENUHILIGHT
: COLOR_MENU
);
2295 HBRUSH hBrushDisabledImage
= ::GetSysColorBrush(COLOR_3DSHADOW
);
2296 pT
->DrawBitmapDisabled(dc
, iButton
, point
, hBrushBackground
, hBrushBackground
, hBrushDisabledImage
);
2301 // no image - look for custom checked/unchecked bitmaps
2303 info
.fMask
= MIIM_CHECKMARKS
| MIIM_TYPE
;
2304 ::GetMenuItemInfo((HMENU
)lpDrawItemStruct
->hwndItem
, lpDrawItemStruct
->itemID
, MF_BYCOMMAND
, &info
);
2305 if(bChecked
|| info
.hbmpUnchecked
!= NULL
)
2307 BOOL bRadio
= ((info
.fType
& MFT_RADIOCHECK
) != 0);
2308 pT
->DrawCheckmark(dc
, rcButn
, bSelected
, bDisabled
, bRadio
, bChecked
? info
.hbmpChecked
: info
.hbmpUnchecked
);
2313 int cxButn
= m_szButton
.cx
;
2314 // calc text rectangle and colors
2315 RECT rcText
= rcItem
;
2316 rcText
.left
+= cxButn
+ s_kcxGap
+ s_kcxTextMargin
;
2317 rcText
.right
-= cxButn
;
2318 dc
.SetBkMode(TRANSPARENT
);
2319 COLORREF colorText
= ::GetSysColor(bDisabled
? (bSelected
? COLOR_GRAYTEXT
: COLOR_3DSHADOW
) : (bSelected
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
));
2321 pT
->DrawMenuText(dc
, rcText
, pmd
->lpstrText
, colorText
); // finally!
2325 void DrawMenuText(CDCHandle
& dc
, RECT
& rc
, LPCTSTR lpstrText
, COLORREF color
)
2328 for(int i
= 0; i
< lstrlen(lpstrText
); i
++)
2330 if(lpstrText
[i
] == _T('\t'))
2336 dc
.SetTextColor(color
);
2337 dc
.DrawText(lpstrText
, nTab
, &rc
, DT_SINGLELINE
| DT_LEFT
| DT_VCENTER
| (m_bShowKeyboardCues
? 0 : DT_HIDEPREFIX
));
2339 dc
.DrawText(&lpstrText
[nTab
+ 1], -1, &rc
, DT_SINGLELINE
| DT_RIGHT
| DT_VCENTER
| (m_bShowKeyboardCues
? 0 : DT_HIDEPREFIX
));
2342 void DrawBitmapDisabled(CDCHandle
& dc
, int nImage
, POINT point
,
2343 HBRUSH hBrushBackground
= ::GetSysColorBrush(COLOR_3DFACE
),
2344 HBRUSH hBrush3DEffect
= ::GetSysColorBrush(COLOR_3DHILIGHT
),
2345 HBRUSH hBrushDisabledImage
= ::GetSysColorBrush(COLOR_3DSHADOW
))
2347 #if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
2350 IMAGELISTDRAWPARAMS ildp
= { 0 };
2351 ildp
.cbSize
= sizeof(IMAGELISTDRAWPARAMS
);
2352 ildp
.himl
= m_hImageList
;
2361 ildp
.fStyle
= ILD_TRANSPARENT
;
2362 ildp
.fState
= ILS_SATURATE
;
2364 ::ImageList_DrawIndirect(&ildp
);
2367 #endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
2371 dcMem
.CreateCompatibleDC(dc
);
2372 // create mono or color bitmap
2374 bmp
.CreateCompatibleBitmap(dc
, m_szBitmap
.cx
, m_szBitmap
.cy
);
2375 ATLASSERT(bmp
.m_hBitmap
!= NULL
);
2376 // draw image into memory DC--fill BG white first
2377 HBITMAP hBmpOld
= dcMem
.SelectBitmap(bmp
);
2378 dcMem
.PatBlt(0, 0, m_szBitmap
.cx
, m_szBitmap
.cy
, WHITENESS
);
2379 // If white is the text color, we can't use the normal painting since
2380 // it would blend with the WHITENESS, but the mask is OK
2381 UINT uDrawStyle
= (::GetSysColor(COLOR_BTNTEXT
) == RGB(255, 255, 255)) ? ILD_MASK
: ILD_NORMAL
;
2382 ::ImageList_Draw(m_hImageList
, nImage
, dcMem
, 0, 0, uDrawStyle
);
2383 dc
.DitherBlt(point
.x
, point
.y
, m_szBitmap
.cx
, m_szBitmap
.cy
, dcMem
, NULL
, 0, 0, hBrushBackground
, hBrush3DEffect
, hBrushDisabledImage
);
2384 dcMem
.SelectBitmap(hBmpOld
); // restore
2389 BOOL
Draw3DCheckmark(CDCHandle
& dc
, const RECT
& rc
, BOOL bSelected
, BOOL bDisabled
, BOOL bRadio
, HBITMAP hBmpCheck
)
2391 return DrawCheckmark(dc
, rc
, bSelected
, bDisabled
, bRadio
, hBmpCheck
);
2394 BOOL
DrawCheckmark(CDCHandle
& dc
, const RECT
& rc
, BOOL bSelected
, BOOL bDisabled
, BOOL bRadio
, HBITMAP hBmpCheck
)
2396 // get checkmark bitmap, if none, use Windows standard
2397 SIZE size
= { 0, 0 };
2398 CBitmapHandle bmp
= hBmpCheck
;
2399 if(hBmpCheck
!= NULL
)
2405 size
.cx
= ::GetSystemMetrics(SM_CXMENUCHECK
);
2406 size
.cy
= ::GetSystemMetrics(SM_CYMENUCHECK
);
2407 bmp
.CreateCompatibleBitmap(dc
, size
.cx
, size
.cy
);
2408 ATLASSERT(bmp
.m_hBitmap
!= NULL
);
2410 // center bitmap in caller's rectangle
2412 if((rc
.right
- rc
.left
) > size
.cx
)
2414 rcDest
.left
= rc
.left
+ (rc
.right
- rc
.left
- size
.cx
) / 2;
2415 rcDest
.right
= rcDest
.left
+ size
.cx
;
2417 if((rc
.bottom
- rc
.top
) > size
.cy
)
2419 rcDest
.top
= rc
.top
+ (rc
.bottom
- rc
.top
- size
.cy
) / 2;
2420 rcDest
.bottom
= rcDest
.top
+ size
.cy
;
2425 if(bSelected
&& !bDisabled
)
2427 dc
.FillRect(&rcDest
, COLOR_MENU
);
2431 COLORREF clrTextOld
= dc
.SetTextColor(::GetSysColor(COLOR_BTNFACE
));
2432 COLORREF clrBkOld
= dc
.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT
));
2433 CBrush
hbr(CDCHandle::GetHalftoneBrush());
2434 dc
.SetBrushOrg(rcDest
.left
, rcDest
.top
);
2435 dc
.FillRect(&rcDest
, hbr
);
2436 dc
.SetTextColor(clrTextOld
);
2437 dc
.SetBkColor(clrBkOld
);
2441 // create source image
2443 dcSource
.CreateCompatibleDC(dc
);
2444 HBITMAP hBmpOld
= dcSource
.SelectBitmap(bmp
);
2446 const COLORREF clrBlack
= RGB(0, 0, 0);
2447 const COLORREF clrWhite
= RGB(255, 255, 255);
2448 COLORREF clrTextOld
= dc
.SetTextColor(clrBlack
);
2449 COLORREF clrBkOld
= dc
.SetBkColor(clrWhite
);
2452 dcMask
.CreateCompatibleDC(dc
);
2454 bmpMask
.CreateBitmap(size
.cx
, size
.cy
, 1, 1, NULL
);
2455 HBITMAP hBmpOld1
= dcMask
.SelectBitmap(bmpMask
);
2457 // draw the checkmark transparently
2458 int cx
= rcDest
.right
- rcDest
.left
;
2459 int cy
= rcDest
.bottom
- rcDest
.top
;
2460 if(hBmpCheck
!= NULL
)
2462 // build mask based on transparent color
2463 dcSource
.SetBkColor(m_clrMask
);
2464 dcMask
.SetBkColor(clrBlack
);
2465 dcMask
.SetTextColor(clrWhite
);
2466 dcMask
.BitBlt(0, 0, size
.cx
, size
.cy
, dcSource
, 0, 0, SRCCOPY
);
2467 // draw bitmap using the mask
2468 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcSource
, 0, 0, SRCINVERT
);
2469 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcMask
, 0, 0, SRCAND
);
2470 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcSource
, 0, 0, SRCINVERT
);
2474 const DWORD ROP_DSno
= 0x00BB0226L
;
2475 const DWORD ROP_DSa
= 0x008800C6L
;
2476 const DWORD ROP_DSo
= 0x00EE0086L
;
2477 const DWORD ROP_DSna
= 0x00220326L
;
2480 RECT rcSource
= { 0, 0, __min(size
.cx
, rc
.right
- rc
.left
), __min(size
.cy
, rc
.bottom
- rc
.top
) };
2481 dcMask
.DrawFrameControl(&rcSource
, DFC_MENU
, bRadio
? DFCS_MENUBULLET
: DFCS_MENUCHECK
);
2483 // draw shadow if disabled
2484 if(!m_bFlatMenus
&& bDisabled
)
2486 // offset by one pixel
2487 int x
= rcDest
.left
+ 1;
2488 int y
= rcDest
.top
+ 1;
2489 // paint source bitmap
2490 const int nColor
= COLOR_3DHILIGHT
;
2491 dcSource
.FillRect(&rcSource
, nColor
);
2492 // draw checkmark - special case black and white colors
2493 COLORREF clrCheck
= ::GetSysColor(nColor
);
2494 if(clrCheck
== clrWhite
)
2496 dc
.BitBlt(x
, y
, cx
, cy
, dcMask
, 0, 0, ROP_DSno
);
2497 dc
.BitBlt(x
, y
, cx
, cy
, dcSource
, 0, 0, ROP_DSa
);
2501 if(clrCheck
!= clrBlack
)
2503 ATLASSERT(dcSource
.GetTextColor() == clrBlack
);
2504 ATLASSERT(dcSource
.GetBkColor() == clrWhite
);
2505 dcSource
.BitBlt(0, 0, size
.cx
, size
.cy
, dcMask
, 0, 0, ROP_DSna
);
2507 dc
.BitBlt(x
, y
, cx
, cy
, dcMask
, 0, 0, ROP_DSa
);
2508 dc
.BitBlt(x
, y
, cx
, cy
, dcSource
, 0, 0, ROP_DSo
);
2512 // paint source bitmap
2513 const int nColor
= bDisabled
? COLOR_BTNSHADOW
: COLOR_MENUTEXT
;
2514 dcSource
.FillRect(&rcSource
, nColor
);
2515 // draw checkmark - special case black and white colors
2516 COLORREF clrCheck
= ::GetSysColor(nColor
);
2517 if(clrCheck
== clrWhite
)
2519 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcMask
, 0, 0, ROP_DSno
);
2520 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcSource
, 0, 0, ROP_DSa
);
2524 if(clrCheck
!= clrBlack
)
2526 ATLASSERT(dcSource
.GetTextColor() == clrBlack
);
2527 ATLASSERT(dcSource
.GetBkColor() == clrWhite
);
2528 dcSource
.BitBlt(0, 0, size
.cx
, size
.cy
, dcMask
, 0, 0, ROP_DSna
);
2530 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcMask
, 0, 0, ROP_DSa
);
2531 dc
.BitBlt(rcDest
.left
, rcDest
.top
, cx
, cy
, dcSource
, 0, 0, ROP_DSo
);
2535 dc
.SetTextColor(clrTextOld
);
2536 dc
.SetBkColor(clrBkOld
);
2537 dcSource
.SelectBitmap(hBmpOld
);
2538 dcMask
.SelectBitmap(hBmpOld1
);
2539 if(hBmpCheck
== NULL
)
2541 // draw pushed-in hilight
2542 if(!m_bFlatMenus
&& !bDisabled
)
2544 if(rc
.right
- rc
.left
> size
.cx
)
2545 ::InflateRect(&rcDest
, 1,1); // inflate checkmark by one pixel all around
2546 dc
.DrawEdge(&rcDest
, BDR_SUNKENOUTER
, BF_RECT
);
2552 void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct
)
2554 _MenuItemData
* pmd
= (_MenuItemData
*)lpMeasureItemStruct
->itemData
;
2556 if(pmd
->fType
& MFT_SEPARATOR
) // separator - use half system height and zero width
2558 lpMeasureItemStruct
->itemHeight
= ::GetSystemMetrics(SM_CYMENU
) / 2;
2559 lpMeasureItemStruct
->itemWidth
= 0;
2563 // compute size of text - use DrawText with DT_CALCRECT
2566 HFONT hOldFont
= NULL
;
2567 if(pmd
->fState
& MFS_DEFAULT
)
2569 // need bold version of font
2571 m_fontMenu
.GetLogFont(lf
);
2573 fontBold
.CreateFontIndirect(&lf
);
2574 ATLASSERT(fontBold
.m_hFont
!= NULL
);
2575 hOldFont
= dc
.SelectFont(fontBold
);
2579 hOldFont
= dc
.SelectFont(m_fontMenu
);
2582 RECT rcText
= { 0, 0, 0, 0 };
2583 dc
.DrawText(pmd
->lpstrText
, -1, &rcText
, DT_SINGLELINE
| DT_LEFT
| DT_VCENTER
| DT_CALCRECT
);
2584 int cx
= rcText
.right
- rcText
.left
;
2585 dc
.SelectFont(hOldFont
);
2588 m_fontMenu
.GetLogFont(lf
);
2589 int cy
= lf
.lfHeight
;
2592 const int cyMargin
= 8;
2595 // height of item is the bigger of these two
2596 lpMeasureItemStruct
->itemHeight
= __max(cy
, (int)m_szButton
.cy
);
2598 // width is width of text plus a bunch of stuff
2599 cx
+= 2 * s_kcxTextMargin
; // L/R margin for readability
2600 cx
+= s_kcxGap
; // space between button and menu text
2601 cx
+= 2 * m_szButton
.cx
; // button width (L=button; R=empty margin)
2602 cx
+= m_cxExtraSpacing
; // extra between item text and accelerator keys
2604 // Windows adds 1 to returned value
2605 cx
-= ::GetSystemMetrics(SM_CXMENUCHECK
) - 1;
2606 lpMeasureItemStruct
->itemWidth
= cx
; // done deal
2610 // Implementation - Hook procs
2611 static LRESULT CALLBACK
CreateHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
2613 const int cchClassName
= 7;
2614 TCHAR szClassName
[cchClassName
] = { 0 };
2616 if(nCode
== HCBT_CREATEWND
)
2618 HWND hWndMenu
= (HWND
)wParam
;
2619 #ifdef _CMDBAR_EXTRA_TRACE
2620 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu
);
2623 ::GetClassName(hWndMenu
, szClassName
, cchClassName
);
2624 if(!lstrcmp(_T("#32768"), szClassName
))
2625 s_pCurrentBar
->m_stackMenuWnd
.Push(hWndMenu
);
2627 else if(nCode
== HCBT_DESTROYWND
)
2629 HWND hWndMenu
= (HWND
)wParam
;
2630 #ifdef _CMDBAR_EXTRA_TRACE
2631 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu
);
2634 ::GetClassName(hWndMenu
, szClassName
, cchClassName
);
2635 if(!lstrcmp(_T("#32768"), szClassName
))
2637 ATLASSERT(hWndMenu
== s_pCurrentBar
->m_stackMenuWnd
.GetCurrent());
2638 s_pCurrentBar
->m_stackMenuWnd
.Pop();
2642 return ::CallNextHookEx(s_hCreateHook
, nCode
, wParam
, lParam
);
2645 static LRESULT CALLBACK
MessageHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
2647 LPMSG pMsg
= (LPMSG
)lParam
;
2649 if(nCode
== HC_ACTION
&& wParam
== PM_REMOVE
&& pMsg
->message
!= GetGetBarMessage() && pMsg
->message
!= WM_FORWARDMSG
)
2651 CCommandBarCtrlBase
* pCmdBar
= NULL
;
2652 HWND hWnd
= pMsg
->hwnd
;
2654 while(pCmdBar
== NULL
&& hWnd
!= NULL
)
2656 pCmdBar
= (CCommandBarCtrlBase
*)::SendMessage(hWnd
, GetGetBarMessage(), (WPARAM
)&dwPID
, 0L);
2657 hWnd
= ::GetParent(hWnd
);
2660 if(pCmdBar
!= NULL
&& dwPID
== GetCurrentProcessId())
2662 pCmdBar
->m_hWndHook
= pMsg
->hwnd
;
2663 ATLASSERT(pCmdBar
->IsCommandBarBase());
2665 if(::IsWindow(pCmdBar
->m_hWnd
))
2666 pCmdBar
->SendMessage(WM_FORWARDMSG
, 0, (LPARAM
)pMsg
);
2668 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n"));
2673 ATLASSERT(s_pmapMsgHook
!= NULL
);
2674 if(s_pmapMsgHook
!= NULL
)
2676 DWORD dwThreadID
= ::GetCurrentThreadId();
2677 _MsgHookData
* pData
= s_pmapMsgHook
->Lookup(dwThreadID
);
2680 lRet
= ::CallNextHookEx(pData
->hMsgHook
, nCode
, wParam
, lParam
);
2687 void DoPopupMenu(int nIndex
, bool bAnimate
)
2689 #ifdef _CMDBAR_EXTRA_TRACE
2690 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate
? "true" : "false");
2693 // Menu animation flags
2694 #ifndef TPM_VERPOSANIMATION
2695 const UINT TPM_VERPOSANIMATION
= 0x1000L
;
2697 #ifndef TPM_NOANIMATION
2698 const UINT TPM_NOANIMATION
= 0x4000L
;
2700 T
* pT
= static_cast<T
*>(this);
2702 // get popup menu and it's position
2704 GetItemRect(nIndex
, &rect
);
2705 POINT pt
= { rect
.left
, rect
.bottom
};
2706 MapWindowPoints(NULL
, &pt
, 1);
2707 MapWindowPoints(NULL
, &rect
);
2708 TPMPARAMS TPMParams
= { 0 };
2709 TPMParams
.cbSize
= sizeof(TPMPARAMS
);
2710 TPMParams
.rcExclude
= rect
;
2711 HMENU hMenuPopup
= ::GetSubMenu(m_hMenu
, nIndex
);
2712 ATLASSERT(hMenuPopup
!= NULL
);
2715 TBBUTTON tbb
= { 0 };
2716 GetButton(nIndex
, &tbb
);
2717 int nCmdID
= tbb
.idCommand
;
2719 m_nPopBtn
= nIndex
; // remember current button's index
2721 // press button and display popup menu
2722 PressButton(nCmdID
, TRUE
);
2724 pT
->DoTrackPopupMenu(hMenuPopup
, TPM_LEFTBUTTON
| TPM_VERTICAL
| TPM_LEFTALIGN
| TPM_TOPALIGN
|
2725 (s_bW2K
? (bAnimate
? TPM_VERPOSANIMATION
: TPM_NOANIMATION
) : 0), pt
.x
, pt
.y
, &TPMParams
);
2726 PressButton(nCmdID
, FALSE
);
2727 if(::GetFocus() != m_hWnd
)
2730 m_nPopBtn
= -1; // restore
2732 // eat next message if click is on the same button
2734 if(::PeekMessage(&msg
, m_hWnd
, WM_LBUTTONDOWN
, WM_LBUTTONDOWN
, PM_NOREMOVE
) && ::PtInRect(&rect
, msg
.pt
))
2735 ::PeekMessage(&msg
, m_hWnd
, WM_LBUTTONDOWN
, WM_LBUTTONDOWN
, PM_REMOVE
);
2737 // check if another popup menu should be displayed
2738 if(m_nNextPopBtn
!= -1)
2740 PostMessage(GetAutoPopupMessage(), m_nNextPopBtn
& 0xFFFF);
2741 if(!(m_nNextPopBtn
& 0xFFFF0000) && !m_bPopupItem
)
2742 PostMessage(WM_KEYDOWN
, VK_DOWN
, 0);
2747 m_bContextMenu
= false;
2748 // If user didn't hit escape, give focus back
2749 if(!m_bEscapePressed
)
2751 if(m_bUseKeyboardCues
&& m_bShowKeyboardCues
)
2752 m_bAllowKeyboardCues
= false;
2753 pT
->GiveFocusBack();
2758 SetAnchorHighlight(TRUE
);
2763 BOOL
DoTrackPopupMenu(HMENU hMenu
, UINT uFlags
, int x
, int y
, LPTPMPARAMS lpParams
= NULL
)
2765 CMenuHandle menuPopup
= hMenu
;
2767 CWindowCreateCriticalSectionLock lock
;
2768 if(FAILED(lock
.Lock()))
2770 ATLTRACE2(atlTraceUI
, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n"));
2775 ATLASSERT(s_hCreateHook
== NULL
);
2777 s_pCurrentBar
= static_cast<CCommandBarCtrlBase
*>(this);
2779 s_hCreateHook
= ::SetWindowsHookEx(WH_CBT
, CreateHookProc
, ModuleHelper::GetModuleInstance(), GetCurrentThreadId());
2780 ATLASSERT(s_hCreateHook
!= NULL
);
2782 m_bPopupItem
= false;
2783 m_bMenuActive
= true;
2785 BOOL bTrackRet
= menuPopup
.TrackPopupMenuEx(uFlags
, x
, y
, m_hWnd
, lpParams
);
2786 m_bMenuActive
= false;
2788 ::UnhookWindowsHookEx(s_hCreateHook
);
2790 s_hCreateHook
= NULL
;
2791 s_pCurrentBar
= NULL
;
2795 // cleanup - convert menus back to original state
2796 #ifdef _CMDBAR_EXTRA_TRACE
2797 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - TrackPopupMenu - cleanup\n"));
2800 ATLASSERT(m_stackMenuWnd
.GetSize() == 0);
2803 ATL::CWindow wndTL
= GetTopLevelParent();
2804 wndTL
.UpdateWindow();
2806 // restore the menu items to the previous state for all menus that were converted
2807 if(m_bImagesVisible
)
2809 HMENU hMenuSav
= NULL
;
2810 while((hMenuSav
= m_stackMenuHandle
.Pop()) != NULL
)
2812 menuPopup
= hMenuSav
;
2814 // restore state and delete menu item data
2815 for(int i
= 0; i
< menuPopup
.GetMenuItemCount(); i
++)
2818 mii
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_ID
;
2819 bRet
= menuPopup
.GetMenuItemInfo(i
, TRUE
, &mii
);
2822 _MenuItemData
* pMI
= (_MenuItemData
*)mii
.dwItemData
;
2823 if(pMI
!= NULL
&& pMI
->IsCmdBarMenuItem())
2825 mii
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_STATE
;
2826 mii
.fType
= pMI
->fType
;
2827 mii
.fState
= pMI
->fState
;
2828 mii
.dwTypeData
= pMI
->lpstrText
;
2829 mii
.cch
= lstrlen(pMI
->lpstrText
);
2830 mii
.dwItemData
= NULL
;
2832 bRet
= menuPopup
.SetMenuItemInfo(i
, TRUE
, &mii
);
2833 // this one triggers WM_MEASUREITEM
2834 menuPopup
.ModifyMenu(i
, MF_BYPOSITION
| mii
.fType
| mii
.fState
, mii
.wID
, pMI
->lpstrText
);
2837 delete [] pMI
->lpstrText
;
2846 int GetPreviousMenuItem(int nBtn
) const
2850 #if (_WIN32_IE >= 0x0500)
2852 GetClientRect(&rcClient
);
2853 #endif // (_WIN32_IE >= 0x0500)
2855 for(nNextBtn
= nBtn
- 1; nNextBtn
!= nBtn
; nNextBtn
--)
2858 nNextBtn
= ::GetMenuItemCount(m_hMenu
) - 1;
2859 TBBUTTON tbb
= { 0 };
2860 GetButton(nNextBtn
, &tbb
);
2861 #if (_WIN32_IE >= 0x0500)
2863 GetItemRect(nNextBtn
, &rcBtn
);
2864 if(rcBtn
.right
> rcClient
.right
)
2866 nNextBtn
= -2; // chevron
2869 #endif // (_WIN32_IE >= 0x0500)
2870 if((tbb
.fsState
& TBSTATE_ENABLED
) != 0 && (tbb
.fsState
& TBSTATE_HIDDEN
) == 0)
2873 return (nNextBtn
!= nBtn
) ? nNextBtn
: -1;
2876 int GetNextMenuItem(int nBtn
) const
2880 #if (_WIN32_IE >= 0x0500)
2881 RECT rcClient
= { 0 };
2882 GetClientRect(&rcClient
);
2883 #endif // (_WIN32_IE >= 0x0500)
2885 int nCount
= ::GetMenuItemCount(m_hMenu
);
2886 for(nNextBtn
= nBtn
+ 1; nNextBtn
!= nBtn
; nNextBtn
++)
2888 if(nNextBtn
>= nCount
)
2890 TBBUTTON tbb
= { 0 };
2891 GetButton(nNextBtn
, &tbb
);
2892 #if (_WIN32_IE >= 0x0500)
2894 GetItemRect(nNextBtn
, &rcBtn
);
2895 if(rcBtn
.right
> rcClient
.right
)
2897 nNextBtn
= -2; // chevron
2900 #endif // (_WIN32_IE >= 0x0500)
2901 if((tbb
.fsState
& TBSTATE_ENABLED
) != 0 && (tbb
.fsState
& TBSTATE_HIDDEN
) == 0)
2904 return (nNextBtn
!= nBtn
) ? nNextBtn
: -1;
2907 #if (_WIN32_IE >= 0x0500)
2908 bool DisplayChevronMenu()
2910 // assume we are in a rebar
2911 HWND hWndReBar
= GetParent();
2912 int nCount
= (int)::SendMessage(hWndReBar
, RB_GETBANDCOUNT
, 0, 0L);
2914 for(int i
= 0; i
< nCount
; i
++)
2916 REBARBANDINFO rbbi
= { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD
| RBBIM_STYLE
};
2917 BOOL bRetBandInfo
= (BOOL
)::SendMessage(hWndReBar
, RB_GETBANDINFO
, i
, (LPARAM
)&rbbi
);
2918 if(bRetBandInfo
&& rbbi
.hwndChild
== m_hWnd
)
2920 if((rbbi
.fStyle
& RBBS_USECHEVRON
) != 0)
2922 ::PostMessage(hWndReBar
, RB_PUSHCHEVRON
, i
, 0L);
2923 PostMessage(WM_KEYDOWN
, VK_DOWN
, 0L);
2931 #endif // (_WIN32_IE >= 0x0500)
2933 void GetSystemSettings()
2936 NONCLIENTMETRICS info
= { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
2937 BOOL bRet
= ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(info
), &info
, 0);
2941 LOGFONT logfont
= { 0 };
2942 if(m_fontMenu
.m_hFont
!= NULL
)
2943 m_fontMenu
.GetLogFont(logfont
);
2944 if(logfont
.lfHeight
!= info
.lfMenuFont
.lfHeight
||
2945 logfont
.lfWidth
!= info
.lfMenuFont
.lfWidth
||
2946 logfont
.lfEscapement
!= info
.lfMenuFont
.lfEscapement
||
2947 logfont
.lfOrientation
!= info
.lfMenuFont
.lfOrientation
||
2948 logfont
.lfWeight
!= info
.lfMenuFont
.lfWeight
||
2949 logfont
.lfItalic
!= info
.lfMenuFont
.lfItalic
||
2950 logfont
.lfUnderline
!= info
.lfMenuFont
.lfUnderline
||
2951 logfont
.lfStrikeOut
!= info
.lfMenuFont
.lfStrikeOut
||
2952 logfont
.lfCharSet
!= info
.lfMenuFont
.lfCharSet
||
2953 logfont
.lfOutPrecision
!= info
.lfMenuFont
.lfOutPrecision
||
2954 logfont
.lfClipPrecision
!= info
.lfMenuFont
.lfClipPrecision
||
2955 logfont
.lfQuality
!= info
.lfMenuFont
.lfQuality
||
2956 logfont
.lfPitchAndFamily
!= info
.lfMenuFont
.lfPitchAndFamily
||
2957 lstrcmp(logfont
.lfFaceName
, info
.lfMenuFont
.lfFaceName
) != 0)
2959 HFONT hFontMenu
= ::CreateFontIndirect(&info
.lfMenuFont
);
2960 ATLASSERT(hFontMenu
!= NULL
);
2961 if(hFontMenu
!= NULL
)
2963 if(m_fontMenu
.m_hFont
!= NULL
)
2964 m_fontMenu
.DeleteObject();
2965 m_fontMenu
.Attach(hFontMenu
);
2966 SetFont(m_fontMenu
);
2967 AddStrings(_T("NS\0")); // for proper item height
2973 // check if we need extra spacing for menu item text
2974 CWindowDC
dc(m_hWnd
);
2975 HFONT hFontOld
= dc
.SelectFont(m_fontMenu
);
2976 RECT rcText
= { 0, 0, 0, 0 };
2977 dc
.DrawText(_T("\t"), -1, &rcText
, DT_SINGLELINE
| DT_LEFT
| DT_VCENTER
| DT_CALCRECT
);
2978 if((rcText
.right
- rcText
.left
) < 4)
2980 ::SetRectEmpty(&rcText
);
2981 dc
.DrawText(_T("x"), -1, &rcText
, DT_SINGLELINE
| DT_LEFT
| DT_VCENTER
| DT_CALCRECT
);
2982 m_cxExtraSpacing
= rcText
.right
- rcText
.left
;
2986 m_cxExtraSpacing
= 0;
2988 dc
.SelectFont(hFontOld
);
2990 // get Windows version
2991 OSVERSIONINFO ovi
= { sizeof(OSVERSIONINFO
) };
2992 ::GetVersionEx(&ovi
);
2994 // query keyboard cues mode (Windows 2000 or later)
2995 if(ovi
.dwMajorVersion
>= 5)
2997 #ifndef SPI_GETKEYBOARDCUES
2998 const UINT SPI_GETKEYBOARDCUES
= 0x100A;
2999 #endif // !SPI_GETKEYBOARDCUES
3000 BOOL bRetVal
= TRUE
;
3001 bRet
= ::SystemParametersInfo(SPI_GETKEYBOARDCUES
, 0, &bRetVal
, 0);
3002 m_bUseKeyboardCues
= (bRet
&& !bRetVal
);
3003 m_bAllowKeyboardCues
= true;
3004 ShowKeyboardCues(!m_bUseKeyboardCues
);
3007 // query flat menu mode (Windows XP or later)
3008 if((ovi
.dwMajorVersion
== 5 && ovi
.dwMinorVersion
>= 1) || (ovi
.dwMajorVersion
> 5))
3010 #ifndef SPI_GETFLATMENU
3011 const UINT SPI_GETFLATMENU
= 0x1022;
3012 #endif // !SPI_GETFLATMENU
3013 BOOL bRetVal
= FALSE
;
3014 bRet
= ::SystemParametersInfo(SPI_GETFLATMENU
, 0, &bRetVal
, 0);
3015 m_bFlatMenus
= (bRet
&& bRetVal
);
3018 #if _WTL_CMDBAR_VISTA_MENUS
3019 // check if we should use Vista menus
3020 bool bVistaMenus
= (RunTimeHelper::IsVista() && RunTimeHelper::IsCommCtrl6() && ((m_dwExtendedStyle
& CBR_EX_NOVISTAMENUS
) == 0));
3024 HMODULE hThemeDLL
= ::LoadLibrary(_T("uxtheme.dll"));
3025 if(hThemeDLL
!= NULL
)
3027 typedef BOOL (STDAPICALLTYPE
*PFN_IsThemeActive
)();
3028 PFN_IsThemeActive pfnIsThemeActive
= (PFN_IsThemeActive
)::GetProcAddress(hThemeDLL
, "IsThemeActive");
3029 ATLASSERT(pfnIsThemeActive
!= NULL
);
3030 bVistaMenus
= bVistaMenus
&& (pfnIsThemeActive
!= NULL
) && (pfnIsThemeActive() != FALSE
);
3032 typedef BOOL (STDAPICALLTYPE
*PFN_IsAppThemed
)();
3033 PFN_IsAppThemed pfnIsAppThemed
= (PFN_IsAppThemed
)::GetProcAddress(hThemeDLL
, "IsAppThemed");
3034 ATLASSERT(pfnIsAppThemed
!= NULL
);
3035 bVistaMenus
= bVistaMenus
&& (pfnIsAppThemed
!= NULL
) && (pfnIsAppThemed() != FALSE
);
3037 ::FreeLibrary(hThemeDLL
);
3041 if(!bVistaMenus
&& m_bVistaMenus
&& (m_hMenu
!= NULL
) && (m_arrCommand
.GetSize() > 0))
3043 T
* pT
= static_cast<T
*>(this);
3044 pT
->_RemoveVistaBitmapsFromMenu();
3047 m_bVistaMenus
= bVistaMenus
;
3048 #endif // _WTL_CMDBAR_VISTA_MENUS
3050 #ifdef _CMDBAR_EXTRA_TRACE
3051 ATLTRACE2(atlTraceUI
, 0, _T("CmdBar - GetSystemSettings:\n m_bFlatMenus = %s\n m_bUseKeyboardCues = %s m_bVistaMenus = %s\n"),
3052 m_bFlatMenus
? "true" : "false", m_bUseKeyboardCues
? "true" : "false", m_bVistaMenus
? "true" : "false");
3056 // Implementation - alternate focus mode support
3059 if((m_dwExtendedStyle
& CBR_EX_ALTFOCUSMODE
) && m_hWndFocus
== NULL
)
3060 m_hWndFocus
= ::GetFocus();
3064 void GiveFocusBack()
3068 if((m_dwExtendedStyle
& CBR_EX_ALTFOCUSMODE
) && ::IsWindow(m_hWndFocus
))
3069 ::SetFocus(m_hWndFocus
);
3070 else if(!(m_dwExtendedStyle
& CBR_EX_ALTFOCUSMODE
) && m_wndParent
.IsWindow())
3071 m_wndParent
.SetFocus();
3074 SetAnchorHighlight(FALSE
);
3075 if(m_bUseKeyboardCues
&& m_bShowKeyboardCues
)
3076 ShowKeyboardCues(false);
3077 m_bSkipPostDown
= false;
3080 void ShowKeyboardCues(bool bShow
)
3082 m_bShowKeyboardCues
= bShow
;
3083 SetDrawTextFlags(DT_HIDEPREFIX
, m_bShowKeyboardCues
? 0 : DT_HIDEPREFIX
);
3088 // Implementation - internal message helpers
3089 static UINT
GetAutoPopupMessage()
3091 static UINT uAutoPopupMessage
= 0;
3092 if(uAutoPopupMessage
== 0)
3094 CStaticDataInitCriticalSectionLock lock
;
3095 if(FAILED(lock
.Lock()))
3097 ATLTRACE2(atlTraceUI
, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n"));
3102 if(uAutoPopupMessage
== 0)
3103 uAutoPopupMessage
= ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg"));
3107 ATLASSERT(uAutoPopupMessage
!= 0);
3108 return uAutoPopupMessage
;
3111 static UINT
GetGetBarMessage()
3113 static UINT uGetBarMessage
= 0;
3114 if(uGetBarMessage
== 0)
3116 CStaticDataInitCriticalSectionLock lock
;
3117 if(FAILED(lock
.Lock()))
3119 ATLTRACE2(atlTraceUI
, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n"));
3124 if(uGetBarMessage
== 0)
3125 uGetBarMessage
= ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg"));
3129 ATLASSERT(uGetBarMessage
!= 0);
3130 return uGetBarMessage
;
3134 bool CreateInternalImageList(int cImages
)
3136 UINT uFlags
= (m_bAlphaImages
? ILC_COLOR32
: ILC_COLOR24
) | ILC_MASK
;
3137 m_hImageList
= ::ImageList_Create(m_szBitmap
.cx
, m_szBitmap
.cy
, uFlags
, cImages
, 1);
3138 ATLASSERT(m_hImageList
!= NULL
);
3139 return (m_hImageList
!= NULL
);
3142 // Implementation - support for Vista menus
3143 #if _WTL_CMDBAR_VISTA_MENUS
3144 void _AddVistaBitmapsFromImageList(int nStartIndex
, int nCount
)
3146 // Create display compatible memory DC
3147 HDC hDC
= ::GetDC(NULL
);
3149 dcMem
.CreateCompatibleDC(hDC
);
3150 HBITMAP hBitmapSave
= dcMem
.GetCurrentBitmap();
3152 T
* pT
= static_cast<T
*>(this);
3153 // Create bitmaps for all menu items
3154 for(int i
= 0; i
< nCount
; i
++)
3156 HBITMAP hBitmap
= pT
->_CreateVistaBitmapHelper(nStartIndex
+ i
, hDC
, dcMem
);
3157 dcMem
.SelectBitmap(hBitmapSave
);
3158 m_arrVistaBitmap
.Add(hBitmap
);
3162 void _AddVistaBitmapFromImageList(int nIndex
)
3164 // Create display compatible memory DC
3165 HDC hDC
= ::GetDC(NULL
);
3167 dcMem
.CreateCompatibleDC(hDC
);
3168 HBITMAP hBitmapSave
= dcMem
.GetCurrentBitmap();
3170 // Create bitmap for menu item
3171 T
* pT
= static_cast<T
*>(this);
3172 HBITMAP hBitmap
= pT
->_CreateVistaBitmapHelper(nIndex
, hDC
, dcMem
);
3174 // Select saved bitmap back and add bitmap to the array
3175 dcMem
.SelectBitmap(hBitmapSave
);
3176 m_arrVistaBitmap
.Add(hBitmap
);
3179 void _ReplaceVistaBitmapFromImageList(int nIndex
)
3181 // Delete existing bitmap
3182 if(m_arrVistaBitmap
[nIndex
] != NULL
)
3183 ::DeleteObject(m_arrVistaBitmap
[nIndex
]);
3185 // Create display compatible memory DC
3186 HDC hDC
= ::GetDC(NULL
);
3188 dcMem
.CreateCompatibleDC(hDC
);
3189 HBITMAP hBitmapSave
= dcMem
.GetCurrentBitmap();
3191 // Create bitmap for menu item
3192 T
* pT
= static_cast<T
*>(this);
3193 HBITMAP hBitmap
= pT
->_CreateVistaBitmapHelper(nIndex
, hDC
, dcMem
);
3195 // Select saved bitmap back and replace bitmap in the array
3196 dcMem
.SelectBitmap(hBitmapSave
);
3197 m_arrVistaBitmap
.SetAtIndex(nIndex
, hBitmap
);
3200 HBITMAP
_CreateVistaBitmapHelper(int nIndex
, HDC hDCSource
, HDC hDCTarget
)
3202 // Create 32-bit bitmap
3203 BITMAPINFO bi
= { 0 };
3204 bi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
3205 bi
.bmiHeader
.biWidth
= m_szBitmap
.cx
;
3206 bi
.bmiHeader
.biHeight
= m_szBitmap
.cy
;
3207 bi
.bmiHeader
.biPlanes
= 1;
3208 bi
.bmiHeader
.biBitCount
= 32;
3209 bi
.bmiHeader
.biCompression
= BI_RGB
;
3210 bi
.bmiHeader
.biSizeImage
= 0;
3211 bi
.bmiHeader
.biXPelsPerMeter
= 0;
3212 bi
.bmiHeader
.biYPelsPerMeter
= 0;
3213 bi
.bmiHeader
.biClrUsed
= 0;
3214 bi
.bmiHeader
.biClrImportant
= 0;
3215 HBITMAP hBitmap
= ::CreateDIBSection(hDCSource
, &bi
, DIB_RGB_COLORS
, NULL
, NULL
, 0);
3216 ATLASSERT(hBitmap
!= NULL
);
3218 // Select bitmap into target DC and draw from image list to it
3221 ::SelectObject(hDCTarget
, hBitmap
);
3223 IMAGELISTDRAWPARAMS ildp
= { 0 };
3224 ildp
.cbSize
= sizeof(IMAGELISTDRAWPARAMS
);
3225 ildp
.himl
= m_hImageList
;
3227 ildp
.hdcDst
= hDCTarget
;
3234 ildp
.fStyle
= ILD_TRANSPARENT
;
3235 ildp
.fState
= ILS_ALPHA
;
3237 ::ImageList_DrawIndirect(&ildp
);
3243 void _RemoveVistaBitmapsFromMenu()
3245 CMenuHandle menu
= m_hMenu
;
3246 for(int i
= 0; i
< m_arrCommand
.GetSize(); i
++)
3249 mii
.fMask
= MIIM_BITMAP
;
3250 mii
.hbmpItem
= NULL
;
3251 menu
.SetMenuItemInfo(m_arrCommand
[i
], FALSE
, &mii
);
3254 #endif // _WTL_CMDBAR_VISTA_MENUS
3258 class CCommandBarCtrl
: public CCommandBarCtrlImpl
<CCommandBarCtrl
>
3261 DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName())
3265 ///////////////////////////////////////////////////////////////////////////////
3266 // CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps
3268 template <class T
, class TBase
= CCommandBarCtrlBase
, class TWinTraits
= ATL::CControlWinTraits
>
3269 class ATL_NO_VTABLE CMDICommandBarCtrlImpl
: public CCommandBarCtrlImpl
< T
, TBase
, TWinTraits
>
3273 ATL::CContainedWindow m_wndMDIClient
;
3274 bool m_bChildMaximized
;
3275 HWND m_hWndChildMaximized
;
3276 HICON m_hIconChildMaximized
;
3278 int m_nBtnWasPressed
;
3280 int m_cxyOffset
; // offset between nonclient elements
3281 int m_cxIconWidth
; // small icon width
3282 int m_cyIconHeight
; // small icon height
3283 int m_cxBtnWidth
; // nonclient button width
3284 int m_cyBtnHeight
; // nonclient button height
3285 int m_cxLeft
; // left nonclient area width
3286 int m_cxRight
; // right nonclient area width
3288 // Theme declarations and data members
3289 #ifndef _WTL_NO_AUTO_THEME
3291 typedef HANDLE HTHEME
;
3292 #endif // !_UXTHEME_H_
3293 typedef HTHEME (STDAPICALLTYPE
*PFN_OpenThemeData
)(HWND hwnd
, LPCWSTR pszClassList
);
3294 typedef HRESULT (STDAPICALLTYPE
*PFN_CloseThemeData
)(HTHEME hTheme
);
3295 typedef HRESULT (STDAPICALLTYPE
*PFN_DrawThemeBackground
)(HTHEME hTheme
, HDC hdc
, int iPartId
, int iStateId
, const RECT
*pRect
, OPTIONAL
const RECT
*pClipRect
);
3296 typedef HRESULT (STDAPICALLTYPE
*PFN_DrawThemeParentBackground
)(HWND hwnd
, HDC hdc
, OPTIONAL RECT
* prc
);
3298 HMODULE m_hThemeDLL
;
3300 PFN_DrawThemeBackground m_pfnDrawThemeBackground
;
3301 PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground
;
3302 #endif // !_WTL_NO_AUTO_THEME
3304 // Constructor/destructor
3305 CMDICommandBarCtrlImpl() :
3306 m_wndMDIClient(this, 2), m_bChildMaximized(false),
3307 m_hWndChildMaximized(NULL
), m_hIconChildMaximized(NULL
),
3308 m_nBtnPressed(-1), m_nBtnWasPressed(-1),
3309 #ifndef _WTL_NO_AUTO_THEME
3310 m_hThemeDLL(NULL
), m_hTheme(NULL
), m_pfnDrawThemeBackground(NULL
), m_pfnDrawThemeParentBackground(NULL
),
3311 #endif // !_WTL_NO_AUTO_THEME
3313 m_cxIconWidth(16), m_cyIconHeight(16),
3314 m_cxBtnWidth(16), m_cyBtnHeight(14),
3315 m_cxLeft(20), m_cxRight(55)
3318 ~CMDICommandBarCtrlImpl()
3320 if(m_wndMDIClient
.IsWindow())
3321 /*scary!*/ m_wndMDIClient
.UnsubclassWindow();
3325 BOOL
SetMDIClient(HWND hWndMDIClient
)
3327 ATLASSERT(::IsWindow(m_hWnd
));
3328 ATLASSERT(::IsWindow(hWndMDIClient
));
3329 if(!::IsWindow(hWndMDIClient
))
3333 // BLOCK: Test if the passed window is MDICLIENT
3335 LPCTSTR lpszMDIClientClass
= _T("MDICLIENT");
3336 const int nNameLen
= 9 + 1; // "MDICLIENT" + NULL
3337 TCHAR szClassName
[nNameLen
] = { 0 };
3338 ::GetClassName(hWndMDIClient
, szClassName
, nNameLen
);
3339 ATLASSERT(lstrcmpi(szClassName
, lpszMDIClientClass
) == 0);
3343 if(m_wndMDIClient
.IsWindow())
3344 /*scary!*/ m_wndMDIClient
.UnsubclassWindow();
3346 return m_wndMDIClient
.SubclassWindow(hWndMDIClient
);
3350 typedef CCommandBarCtrlImpl
< T
, TBase
, TWinTraits
> _baseClass
;
3351 BEGIN_MSG_MAP(CMDICommandBarCtrlImpl
)
3352 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
3353 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
3354 #ifndef _WTL_NO_AUTO_THEME
3355 MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged
)
3356 #endif // !_WTL_NO_AUTO_THEME
3357 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
3358 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
3359 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
3360 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
3361 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
3362 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
3363 MESSAGE_HANDLER(WM_LBUTTONUP
, OnLButtonUp
)
3364 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClk
)
3365 MESSAGE_HANDLER(WM_CAPTURECHANGED
, OnCaptureChanged
)
3366 CHAIN_MSG_MAP(_baseClass
)
3367 ALT_MSG_MAP(1) // Parent window messages
3368 MESSAGE_HANDLER(WM_ACTIVATE
, OnParentActivate
)
3369 CHAIN_MSG_MAP_ALT(_baseClass
, 1)
3370 ALT_MSG_MAP(2) // MDI client window messages
3371 MESSAGE_HANDLER(WM_MDISETMENU
, OnMDISetMenu
)
3372 // no chaining needed since this was moved from the base class here
3373 ALT_MSG_MAP(3) // Message hook messages
3374 MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages
)
3375 CHAIN_MSG_MAP_ALT(_baseClass
, 3)
3378 // Additional MDI message handlers
3379 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
3381 LRESULT lRet
= _baseClass::OnCreate(uMsg
, wParam
, lParam
, bHandled
);
3382 if(lRet
== (LRESULT
)-1)
3385 #ifndef _WTL_NO_AUTO_THEME
3386 // this will fail if theming is not supported
3387 m_hThemeDLL
= ::LoadLibrary(_T("uxtheme.dll"));
3388 if(m_hThemeDLL
!= NULL
)
3390 m_pfnDrawThemeBackground
= (PFN_DrawThemeBackground
)::GetProcAddress(m_hThemeDLL
, "DrawThemeBackground");
3391 ATLASSERT(m_pfnDrawThemeBackground
!= NULL
);
3392 if(m_pfnDrawThemeBackground
!= NULL
)
3394 T
* pT
= static_cast<T
*>(this);
3395 pT
->_OpenThemeData();
3399 ::FreeLibrary(m_hThemeDLL
);
3402 m_pfnDrawThemeParentBackground
= (PFN_DrawThemeParentBackground
)::GetProcAddress(m_hThemeDLL
, "DrawThemeParentBackground");
3403 ATLASSERT(m_pfnDrawThemeParentBackground
!= NULL
);
3405 #endif // !_WTL_NO_AUTO_THEME
3410 LRESULT
OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
3412 LRESULT lRet
= _baseClass::OnDestroy(uMsg
, wParam
, lParam
, bHandled
);
3414 #ifndef _WTL_NO_AUTO_THEME
3415 if(m_hThemeDLL
!= NULL
)
3417 T
* pT
= static_cast<T
*>(this);
3418 pT
->_CloseThemeData();
3419 ::FreeLibrary(m_hThemeDLL
);
3422 #endif // !_WTL_NO_AUTO_THEME
3427 #ifndef _WTL_NO_AUTO_THEME
3428 LRESULT
OnThemeChanged(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
3430 if(m_hThemeDLL
!= NULL
)
3432 T
* pT
= static_cast<T
*>(this);
3433 pT
->_CloseThemeData();
3434 pT
->_OpenThemeData();
3438 #endif // !_WTL_NO_AUTO_THEME
3440 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3442 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
3443 T
* pT
= static_cast<T
*>(this);
3444 pT
->_AdjustBtnSize(GET_Y_LPARAM(lParam
));
3448 LRESULT
OnNcCalcSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3450 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
3452 if(m_bChildMaximized
&& (BOOL
)wParam
)
3454 LPNCCALCSIZE_PARAMS lpParams
= (LPNCCALCSIZE_PARAMS
)lParam
;
3457 lpParams
->rgrc
[0].left
+= m_cxRight
;
3458 lpParams
->rgrc
[0].right
-= m_cxLeft
;
3462 lpParams
->rgrc
[0].left
+= m_cxLeft
;
3463 lpParams
->rgrc
[0].right
-= m_cxRight
;
3470 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3472 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
3474 if(!m_bChildMaximized
)
3477 ATLASSERT(m_hWndChildMaximized
!= NULL
&& m_hIconChildMaximized
!= NULL
);
3479 // get DC and window rectangle
3480 CWindowDC
dc(m_hWnd
);
3482 GetWindowRect(&rect
);
3483 int cxWidth
= rect
.right
- rect
.left
;
3484 int cyHeight
= rect
.bottom
- rect
.top
;
3486 // paint left side nonclient background and draw icon
3487 ::SetRect(&rect
, 0, 0, m_cxLeft
, cyHeight
);
3488 #ifndef _WTL_NO_AUTO_THEME
3489 if(m_hTheme
!= NULL
)
3491 if(m_pfnDrawThemeParentBackground
!= NULL
)
3492 m_pfnDrawThemeParentBackground(m_hWnd
, dc
, &rect
);
3494 dc
.FillRect(&rect
, COLOR_WINDOW
);
3497 #endif // !_WTL_NO_AUTO_THEME
3499 if((m_dwExtendedStyle
& CBR_EX_TRANSPARENT
) != 0)
3500 dc
.FillRect(&rect
, COLOR_3DFACE
);
3502 dc
.FillRect(&rect
, COLOR_MENU
);
3505 RECT rcIcon
= { 0 };
3506 T
* pT
= static_cast<T
*>(this);
3507 pT
->_CalcIconRect(cxWidth
, cyHeight
, rcIcon
);
3508 dc
.DrawIconEx(rcIcon
.left
, rcIcon
.top
, m_hIconChildMaximized
, m_cxIconWidth
, m_cyIconHeight
);
3510 // paint right side nonclient background
3511 ::SetRect(&rect
, cxWidth
- m_cxRight
, 0, cxWidth
, cyHeight
);
3512 #ifndef _WTL_NO_AUTO_THEME
3513 if(m_hTheme
!= NULL
)
3515 if(m_pfnDrawThemeParentBackground
!= NULL
)
3517 // this is to account for the left non-client area
3518 POINT ptOrg
= { 0, 0 };
3519 dc
.GetViewportOrg(&ptOrg
);
3520 dc
.SetViewportOrg(ptOrg
.x
+ m_cxLeft
, ptOrg
.y
);
3521 ::OffsetRect(&rect
, -m_cxLeft
, 0);
3523 m_pfnDrawThemeParentBackground(m_hWnd
, dc
, &rect
);
3526 dc
.SetViewportOrg(ptOrg
);
3527 ::OffsetRect(&rect
, m_cxLeft
, 0);
3531 dc
.FillRect(&rect
, COLOR_3DFACE
);
3535 #endif // !_WTL_NO_AUTO_THEME
3537 if((m_dwExtendedStyle
& CBR_EX_TRANSPARENT
) != 0)
3538 dc
.FillRect(&rect
, COLOR_3DFACE
);
3540 dc
.FillRect(&rect
, COLOR_MENU
);
3544 RECT arrRect
[3] = { 0 };
3545 pT
->_CalcBtnRects(cxWidth
, cyHeight
, arrRect
);
3546 pT
->_DrawMDIButton(dc
, arrRect
, -1); // draw all buttons
3551 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3553 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
3554 if(m_bChildMaximized
)
3557 GetWindowRect(&rect
);
3558 POINT pt
= { GET_X_LPARAM(lParam
) - rect
.left
, GET_Y_LPARAM(lParam
) - rect
.top
};
3561 if((pt
.x
< m_cxRight
) || (pt
.x
> ((rect
.right
- rect
.left
) - m_cxLeft
)))
3566 if((pt
.x
< m_cxLeft
) || (pt
.x
> ((rect
.right
- rect
.left
) - m_cxRight
)))
3573 LRESULT
OnNcLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
3575 if(!m_bChildMaximized
)
3581 ATLASSERT(_DebugCheckChild());
3583 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
3585 GetWindowRect(&rect
);
3589 RECT rcIcon
= { 0 };
3590 T
* pT
= static_cast<T
*>(this);
3591 pT
->_CalcIconRect(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, rcIcon
, m_bLayoutRTL
);
3592 RECT arrRect
[3] = { 0 };
3593 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
, m_bLayoutRTL
);
3595 if(::PtInRect(&rcIcon
, pt
))
3597 #ifdef _CMDBAR_EXTRA_TRACE
3598 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonDown: icon\n"));
3600 #ifndef TPM_VERPOSANIMATION
3601 const UINT TPM_VERPOSANIMATION
= 0x1000L
; // Menu animation flag
3603 CMenuHandle menu
= ::GetSystemMenu(m_hWndChildMaximized
, FALSE
);
3604 UINT uRet
= (UINT
)menu
.TrackPopupMenu(TPM_LEFTBUTTON
| TPM_VERTICAL
| TPM_LEFTALIGN
| TPM_TOPALIGN
| TPM_RETURNCMD
|
3605 (s_bW2K
? TPM_VERPOSANIMATION
: 0), m_bLayoutRTL
? rect
.right
: rect
.left
, rect
.bottom
, m_hWndChildMaximized
);
3607 // eat next message if click is on the same button
3608 ::OffsetRect(&rcIcon
, rect
.left
, rect
.top
);
3610 if(::PeekMessage(&msg
, m_hWnd
, WM_NCLBUTTONDOWN
, WM_NCLBUTTONDOWN
, PM_NOREMOVE
) && ::PtInRect(&rcIcon
, msg
.pt
))
3611 ::PeekMessage(&msg
, m_hWnd
, WM_NCLBUTTONDOWN
, WM_NCLBUTTONDOWN
, PM_REMOVE
);
3614 ::SendMessage(m_hWndChildMaximized
, WM_SYSCOMMAND
, uRet
, 0L);
3616 else if(::PtInRect(&arrRect
[0], pt
))
3618 #ifdef _CMDBAR_EXTRA_TRACE
3619 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonDown: close button\n"));
3621 m_nBtnWasPressed
= m_nBtnPressed
= 0;
3623 else if(::PtInRect(&arrRect
[1], pt
))
3625 #ifdef _CMDBAR_EXTRA_TRACE
3626 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonDown: restore button\n"));
3628 m_nBtnWasPressed
= m_nBtnPressed
= 1;
3630 else if(::PtInRect(&arrRect
[2], pt
))
3632 #ifdef _CMDBAR_EXTRA_TRACE
3633 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonDown: minimize button\n"));
3635 m_nBtnWasPressed
= m_nBtnPressed
= 2;
3642 // draw the button state if it was pressed
3643 if(m_nBtnPressed
!= -1)
3646 CWindowDC
dc(m_hWnd
);
3647 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
);
3648 pT
->_DrawMDIButton(dc
, arrRect
, m_nBtnPressed
);
3654 LRESULT
OnMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
3656 if(!m_bChildMaximized
|| ::GetCapture() != m_hWnd
|| m_nBtnWasPressed
== -1)
3662 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
3663 ClientToScreen(&pt
);
3665 GetWindowRect(&rect
);
3668 RECT arrRect
[3] = { 0 };
3669 T
* pT
= static_cast<T
*>(this);
3670 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
, m_bLayoutRTL
);
3671 int nOldBtnPressed
= m_nBtnPressed
;
3672 m_nBtnPressed
= ::PtInRect(&arrRect
[m_nBtnWasPressed
], pt
) ? m_nBtnWasPressed
: -1;
3673 if(nOldBtnPressed
!= m_nBtnPressed
)
3675 CWindowDC
dc(m_hWnd
);
3676 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
);
3677 pT
->_DrawMDIButton(dc
, arrRect
, (m_nBtnPressed
!= -1) ? m_nBtnPressed
: nOldBtnPressed
);
3683 LRESULT
OnLButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
3685 if(!m_bChildMaximized
|| ::GetCapture() != m_hWnd
|| m_nBtnWasPressed
== -1)
3691 ATLASSERT(_DebugCheckChild());
3693 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
3694 ClientToScreen(&pt
);
3696 GetWindowRect(&rect
);
3700 int nBtn
= m_nBtnWasPressed
;
3703 RECT arrRect
[3] = { 0 };
3704 T
* pT
= static_cast<T
*>(this);
3705 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
, m_bLayoutRTL
);
3706 if(::PtInRect(&arrRect
[nBtn
], pt
))
3711 #ifdef _CMDBAR_EXTRA_TRACE
3712 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonUp: close button\n"));
3714 ::SendMessage(m_hWndChildMaximized
, WM_SYSCOMMAND
, SC_CLOSE
, 0L);
3717 #ifdef _CMDBAR_EXTRA_TRACE
3718 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonUp: restore button\n"));
3720 ::SendMessage(m_hWndChildMaximized
, WM_SYSCOMMAND
, SC_RESTORE
, 0L);
3723 #ifdef _CMDBAR_EXTRA_TRACE
3724 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - LButtonUp: minimize button\n"));
3726 ::SendMessage(m_hWndChildMaximized
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0L);
3736 LRESULT
OnNcLButtonDblClk(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
3738 if(!m_bChildMaximized
|| m_nBtnWasPressed
!= -1)
3744 ATLASSERT(_DebugCheckChild());
3746 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
3748 GetWindowRect(&rect
);
3752 RECT rcIcon
= { 0 };
3753 T
* pT
= static_cast<T
*>(this);
3754 pT
->_CalcIconRect(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, rcIcon
, m_bLayoutRTL
);
3755 RECT arrRect
[3] = { 0 };
3756 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
, m_bLayoutRTL
);
3758 if(::PtInRect(&rcIcon
, pt
))
3760 CMenuHandle menu
= ::GetSystemMenu(m_hWndChildMaximized
, FALSE
);
3761 UINT uDefID
= menu
.GetMenuDefaultItem();
3762 if(uDefID
== (UINT
)-1)
3764 ::SendMessage(m_hWndChildMaximized
, WM_SYSCOMMAND
, uDefID
, 0L);
3770 LRESULT
OnCaptureChanged(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
3772 if(m_bChildMaximized
)
3774 if(m_nBtnPressed
!= -1)
3776 ATLASSERT(m_nBtnPressed
== m_nBtnWasPressed
); // must be
3779 GetWindowRect(&rect
);
3780 RECT arrRect
[3] = { 0 };
3781 T
* pT
= static_cast<T
*>(this);
3782 pT
->_CalcBtnRects(rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, arrRect
);
3783 CWindowDC
dc(m_hWnd
);
3784 pT
->_DrawMDIButton(dc
, arrRect
, m_nBtnWasPressed
);
3786 m_nBtnWasPressed
= -1;
3795 // Parent window message handlers
3796 LRESULT
OnParentActivate(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
3798 m_bParentActive
= (LOWORD(wParam
) != WA_INACTIVE
);
3799 RedrawWindow(NULL
, NULL
, RDW_INVALIDATE
| RDW_FRAME
| RDW_UPDATENOW
);
3804 // MDI client window message handlers
3805 LRESULT
OnMDISetMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3807 m_wndMDIClient
.DefWindowProc(uMsg
, NULL
, lParam
);
3808 HMENU hOldMenu
= GetMenu();
3809 BOOL bRet
= AttachMenu((HMENU
)wParam
);
3810 bRet
; // avoid level 4 warning
3813 #if (_WIN32_IE >= 0x0400)
3814 T
* pT
= static_cast<T
*>(this);
3815 pT
->UpdateRebarBandIdealSize();
3816 #endif // (_WIN32_IE >= 0x0400)
3818 return (LRESULT
)hOldMenu
;
3821 // All messages from the message hook
3822 LRESULT
OnAllHookMessages(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
3824 T
* pT
= static_cast<T
*>(this);
3825 pT
->_ProcessAllHookMessages(uMsg
, wParam
, lParam
);
3832 // override this to provide different ideal size
3833 void UpdateRebarBandIdealSize()
3835 // assuming we are in a rebar, change ideal size to our size
3836 // we hope that if we are not in a rebar, nCount will be 0
3837 int nCount
= (int)::SendMessage(GetParent(), RB_GETBANDCOUNT
, 0, 0L);
3838 for(int i
= 0; i
< nCount
; i
++)
3840 REBARBANDINFO rbi
= { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD
| RBBIM_CHILDSIZE
| RBBIM_IDEALSIZE
};
3841 ::SendMessage(GetParent(), RB_GETBANDINFO
, i
, (LPARAM
)&rbi
);
3842 if(rbi
.hwndChild
== m_hWnd
)
3844 rbi
.fMask
= RBBIM_IDEALSIZE
;
3845 rbi
.cxIdeal
= m_bChildMaximized
? m_cxLeft
+ m_cxRight
: 0;
3846 int nBtnCount
= GetButtonCount();
3850 GetItemRect(nBtnCount
- 1, &rect
);
3851 rbi
.cxIdeal
+= rect
.right
;
3853 ::SendMessage(GetParent(), RB_SETBANDINFO
, i
, (LPARAM
)&rbi
);
3859 // all hook messages - check for the maximized MDI child window change
3860 void _ProcessAllHookMessages(UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/)
3862 if(uMsg
== WM_MDIGETACTIVE
|| uMsg
== WM_MDISETMENU
)
3865 BOOL bMaximized
= FALSE
;
3866 HWND hWndChild
= (HWND
)::SendMessage(m_wndMDIClient
, WM_MDIGETACTIVE
, 0, (LPARAM
)&bMaximized
);
3867 bool bMaxOld
= m_bChildMaximized
;
3868 m_bChildMaximized
= (hWndChild
!= NULL
&& bMaximized
);
3869 HICON hIconOld
= m_hIconChildMaximized
;
3871 if(m_bChildMaximized
)
3873 if(m_hWndChildMaximized
!= hWndChild
)
3875 ATL::CWindow wnd
= m_hWndChildMaximized
= hWndChild
;
3876 m_hIconChildMaximized
= wnd
.GetIcon(FALSE
);
3877 if(m_hIconChildMaximized
== NULL
)
3879 m_hIconChildMaximized
= wnd
.GetIcon(TRUE
);
3880 if(m_hIconChildMaximized
== NULL
)
3882 // no icon set with WM_SETICON, get the class one
3883 // need conditional code because types don't match in winuser.h
3885 m_hIconChildMaximized
= (HICON
)::GetClassLongPtr(wnd
, GCLP_HICONSM
);
3887 m_hIconChildMaximized
= (HICON
)LongToHandle(::GetClassLongPtr(wnd
, GCLP_HICONSM
));
3895 m_hWndChildMaximized
= NULL
;
3896 m_hIconChildMaximized
= NULL
;
3899 if(bMaxOld
!= m_bChildMaximized
)
3901 #ifdef _CMDBAR_EXTRA_TRACE
3902 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized
? "true" : "false");
3904 // assuming we are in a rebar, change our size to accomodate new state
3905 // we hope that if we are not in a rebar, nCount will be 0
3906 int nCount
= (int)::SendMessage(GetParent(), RB_GETBANDCOUNT
, 0, 0L);
3907 int cxDiff
= (m_bChildMaximized
? 1 : -1) * (m_cxLeft
+ m_cxRight
);
3908 for(int i
= 0; i
< nCount
; i
++)
3910 #if (_WIN32_IE >= 0x0500)
3911 REBARBANDINFO rbi
= { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD
| RBBIM_CHILDSIZE
| RBBIM_IDEALSIZE
| RBBIM_STYLE
};
3912 ::SendMessage(GetParent(), RB_GETBANDINFO
, i
, (LPARAM
)&rbi
);
3913 if(rbi
.hwndChild
== m_hWnd
)
3915 if((rbi
.fStyle
& RBBS_USECHEVRON
) != 0)
3917 rbi
.fMask
= RBBIM_CHILDSIZE
| RBBIM_IDEALSIZE
;
3918 rbi
.cxMinChild
+= cxDiff
;
3919 rbi
.cxIdeal
+= cxDiff
;
3920 ::SendMessage(GetParent(), RB_SETBANDINFO
, i
, (LPARAM
)&rbi
);
3924 #elif (_WIN32_IE >= 0x0400)
3925 REBARBANDINFO rbi
= { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD
| RBBIM_CHILDSIZE
| RBBIM_IDEALSIZE
};
3926 ::SendMessage(GetParent(), RB_GETBANDINFO
, i
, (LPARAM
)&rbi
);
3927 if(rbi
.hwndChild
== m_hWnd
)
3929 rbi
.fMask
= RBBIM_CHILDSIZE
| RBBIM_IDEALSIZE
;
3930 rbi
.cxMinChild
+= cxDiff
;
3931 rbi
.cxIdeal
+= cxDiff
;
3932 ::SendMessage(GetParent(), RB_SETBANDINFO
, i
, (LPARAM
)&rbi
);
3935 #else // (_WIN32_IE < 0x0400)
3936 REBARBANDINFO rbi
= { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD
| RBBIM_CHILDSIZE
};
3937 ::SendMessage(GetParent(), RB_GETBANDINFO
, i
, (LPARAM
)&rbi
);
3938 if(rbi
.hwndChild
== m_hWnd
)
3940 rbi
.fMask
= RBBIM_CHILDSIZE
;
3941 rbi
.cxMinChild
+= cxDiff
;
3942 ::SendMessage(GetParent(), RB_SETBANDINFO
, i
, (LPARAM
)&rbi
);
3945 #endif // (_WIN32_IE < 0x0400)
3949 if(bMaxOld
!= m_bChildMaximized
|| hIconOld
!= m_hIconChildMaximized
)
3951 // force size change and redraw everything
3953 GetWindowRect(&rect
);
3954 ::MapWindowPoints(NULL
, GetParent(), (LPPOINT
)&rect
, 2);
3956 SetWindowPos(NULL
, 0, 0, 1, 1, SWP_NOZORDER
| SWP_NOMOVE
);
3957 SetWindowPos(NULL
, &rect
, SWP_NOZORDER
| SWP_NOMOVE
);
3959 RedrawWindow(NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
| RDW_UPDATENOW
);
3964 void GetSystemSettings()
3966 #ifdef _CMDBAR_EXTRA_TRACE
3967 ATLTRACE2(atlTraceUI
, 0, _T("MDI CmdBar - GetSystemSettings\n"));
3969 _baseClass::GetSystemSettings();
3971 NONCLIENTMETRICS info
= { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
3972 BOOL bRet
= ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(info
), &info
, 0);
3976 m_cxIconWidth
= ::GetSystemMetrics(SM_CXSMICON
);
3977 m_cyIconHeight
= ::GetSystemMetrics(SM_CYSMICON
);
3978 m_cxLeft
= m_cxIconWidth
;
3980 #ifndef _WTL_NO_AUTO_THEME
3981 if(m_hTheme
!= NULL
)
3983 m_cxBtnWidth
= info
.iCaptionWidth
- 2 * m_cxyOffset
;
3984 m_cyBtnHeight
= info
.iCaptionHeight
- 2 * m_cxyOffset
;
3985 m_cxRight
= 3 * m_cxBtnWidth
;
3988 #endif // !_WTL_NO_AUTO_THEME
3990 m_cxBtnWidth
= info
.iCaptionWidth
- m_cxyOffset
;
3991 m_cyBtnHeight
= info
.iCaptionHeight
- 2 * m_cxyOffset
;
3992 m_cxRight
= 3 * m_cxBtnWidth
+ m_cxyOffset
;
3997 GetClientRect(&rect
);
3998 T
* pT
= static_cast<T
*>(this);
3999 pT
->_AdjustBtnSize(rect
.bottom
);
4002 void _AdjustBtnSize(int cyHeight
)
4004 if(cyHeight
> 1 && m_cyBtnHeight
> cyHeight
)
4006 #ifndef _WTL_NO_AUTO_THEME
4007 if(m_hTheme
!= NULL
)
4009 m_cyBtnHeight
= cyHeight
;
4010 m_cxBtnWidth
= cyHeight
;
4011 m_cxRight
= 3 * m_cxBtnWidth
;
4014 #endif // !_WTL_NO_AUTO_THEME
4016 m_cyBtnHeight
= cyHeight
;
4017 m_cxBtnWidth
= cyHeight
+ m_cxyOffset
;
4018 m_cxRight
= 3 * m_cxBtnWidth
+ m_cxyOffset
;
4023 void _CalcIconRect(int cxWidth
, int cyHeight
, RECT
& rect
, bool bInvertX
= false) const
4025 int xStart
= (m_cxLeft
- m_cxIconWidth
) / 2;
4028 int yStart
= (cyHeight
- m_cyIconHeight
) / 2;
4033 ::SetRect(&rect
, cxWidth
- (xStart
+ m_cxBtnWidth
), yStart
, cxWidth
- xStart
, yStart
+ m_cyBtnHeight
);
4035 ::SetRect(&rect
, xStart
, yStart
, xStart
+ m_cxBtnWidth
, yStart
+ m_cyBtnHeight
);
4038 void _CalcBtnRects(int cxWidth
, int cyHeight
, RECT arrRect
[3], bool bInvertX
= false) const
4040 int yStart
= (cyHeight
- m_cyBtnHeight
) / 2;
4044 RECT rcBtn
= { cxWidth
- m_cxBtnWidth
, yStart
, cxWidth
, yStart
+ m_cyBtnHeight
};
4045 int nDirection
= -1;
4048 ::SetRect(&rcBtn
, 0, yStart
, m_cxBtnWidth
, yStart
+ m_cyBtnHeight
);
4053 #ifndef _WTL_NO_AUTO_THEME
4054 if(m_hTheme
!= NULL
)
4055 ::OffsetRect(&rcBtn
, nDirection
* m_cxBtnWidth
, 0);
4057 #endif // !_WTL_NO_AUTO_THEME
4058 ::OffsetRect(&rcBtn
, nDirection
* (m_cxBtnWidth
+ m_cxyOffset
), 0);
4060 ::OffsetRect(&rcBtn
, nDirection
* m_cxBtnWidth
, 0);
4064 void _DrawMDIButton(CWindowDC
& dc
, LPRECT pRects
, int nBtn
)
4066 #ifndef _WTL_NO_AUTO_THEME
4067 if(m_hTheme
!= NULL
)
4070 const int WP_MDICLOSEBUTTON
= 20;
4071 const int CBS_NORMAL
= 1;
4072 const int CBS_PUSHED
= 3;
4073 const int CBS_DISABLED
= 4;
4074 const int WP_MDIRESTOREBUTTON
= 22;
4075 const int RBS_NORMAL
= 1;
4076 const int RBS_PUSHED
= 3;
4077 const int RBS_DISABLED
= 4;
4078 const int WP_MDIMINBUTTON
= 16;
4079 const int MINBS_NORMAL
= 1;
4080 const int MINBS_PUSHED
= 3;
4081 const int MINBS_DISABLED
= 4;
4082 #endif // TMSCHEMA_H
4083 if(nBtn
== -1 || nBtn
== 0)
4084 m_pfnDrawThemeBackground(m_hTheme
, dc
, WP_MDICLOSEBUTTON
, m_bParentActive
? ((m_nBtnPressed
== 0) ? CBS_PUSHED
: CBS_NORMAL
) : CBS_DISABLED
, &pRects
[0], NULL
);
4085 if(nBtn
== -1 || nBtn
== 1)
4086 m_pfnDrawThemeBackground(m_hTheme
, dc
, WP_MDIRESTOREBUTTON
, m_bParentActive
? ((m_nBtnPressed
== 1) ? RBS_PUSHED
: RBS_NORMAL
) : RBS_DISABLED
, &pRects
[1], NULL
);
4087 if(nBtn
== -1 || nBtn
== 2)
4088 m_pfnDrawThemeBackground(m_hTheme
, dc
, WP_MDIMINBUTTON
, m_bParentActive
? ((m_nBtnPressed
== 2) ? MINBS_PUSHED
: MINBS_NORMAL
) : MINBS_DISABLED
, &pRects
[2], NULL
);
4091 #endif // !_WTL_NO_AUTO_THEME
4093 if(nBtn
== -1 || nBtn
== 0)
4094 dc
.DrawFrameControl(&pRects
[0], DFC_CAPTION
, DFCS_CAPTIONCLOSE
| ((m_nBtnPressed
== 0) ? DFCS_PUSHED
: 0));
4095 if(nBtn
== -1 || nBtn
== 1)
4096 dc
.DrawFrameControl(&pRects
[1], DFC_CAPTION
, DFCS_CAPTIONRESTORE
| ((m_nBtnPressed
== 1) ? DFCS_PUSHED
: 0));
4097 if(nBtn
== -1 || nBtn
== 2)
4098 dc
.DrawFrameControl(&pRects
[2], DFC_CAPTION
, DFCS_CAPTIONMIN
| ((m_nBtnPressed
== 2) ? DFCS_PUSHED
: 0));
4102 #ifndef _WTL_NO_AUTO_THEME
4103 static UINT
_GetThemeChangedMsg()
4105 #ifndef WM_THEMECHANGED
4106 static const UINT WM_THEMECHANGED
= 0x031A;
4107 #endif // !WM_THEMECHANGED
4108 return WM_THEMECHANGED
;
4111 void _OpenThemeData()
4113 ATLASSERT(m_hThemeDLL
!= NULL
);
4115 PFN_OpenThemeData pfnOpenThemeData
= (PFN_OpenThemeData
)::GetProcAddress(m_hThemeDLL
, "OpenThemeData");
4116 ATLASSERT(pfnOpenThemeData
!= NULL
);
4117 if(pfnOpenThemeData
!= NULL
)
4118 m_hTheme
= pfnOpenThemeData(m_hWnd
, L
"Window");
4121 void _CloseThemeData()
4123 ATLASSERT(m_hThemeDLL
!= NULL
);
4125 if(m_hTheme
== NULL
)
4126 return; // nothing to do
4128 PFN_CloseThemeData pfnCloseThemeData
= (PFN_CloseThemeData
)::GetProcAddress(m_hThemeDLL
, "CloseThemeData");
4129 ATLASSERT(pfnCloseThemeData
!= NULL
);
4130 if(pfnCloseThemeData
!= NULL
)
4132 pfnCloseThemeData(m_hTheme
);
4136 #endif // !_WTL_NO_AUTO_THEME
4138 bool _DebugCheckChild()
4141 BOOL bMaximized
= FALSE
;
4142 HWND hWndChild
= (HWND
)::SendMessage(m_wndMDIClient
, WM_MDIGETACTIVE
, 0, (LPARAM
)&bMaximized
);
4143 return (bMaximized
&& hWndChild
== m_hWndChildMaximized
);
4150 class CMDICommandBarCtrl
: public CMDICommandBarCtrlImpl
<CMDICommandBarCtrl
>
4153 DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName())
4158 #endif // __ATLCTRLW_H__