]> git.sesse.net Git - casparcg/blob - WTL80/include/atlctrlw.h
2.0.2: INFO TEMPLATE works on both compressed and uncompressed templates.
[casparcg] / WTL80 / include / atlctrlw.h
1 // Windows Template Library - WTL version 8.0\r
2 // Copyright (C) Microsoft Corporation. All rights reserved.\r
3 //\r
4 // This file is a part of the Windows Template Library.\r
5 // The use and distribution terms for this software are covered by the\r
6 // Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php)\r
7 // which can be found in the file CPL.TXT at the root of this distribution.\r
8 // By using this software in any fashion, you are agreeing to be bound by\r
9 // the terms of this license. You must not remove this notice, or\r
10 // any other, from this software.\r
11 \r
12 #ifndef __ATLCTRLW_H__\r
13 #define __ATLCTRLW_H__\r
14 \r
15 #pragma once\r
16 \r
17 #ifndef __cplusplus\r
18         #error ATL requires C++ compilation (use a .cpp suffix)\r
19 #endif\r
20 \r
21 #ifdef _WIN32_WCE\r
22         #error atlctrlw.h is not supported on Windows CE\r
23 #endif\r
24 \r
25 #ifndef __ATLAPP_H__\r
26         #error atlctrlw.h requires atlapp.h to be included first\r
27 #endif\r
28 \r
29 #ifndef __ATLCTRLS_H__\r
30         #error atlctrlw.h requires atlctrls.h to be included first\r
31 #endif\r
32 \r
33 #if (_WIN32_IE < 0x0400)\r
34         #error atlctrlw.h requires _WIN32_IE >= 0x0400\r
35 #endif\r
36 \r
37 // Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support\r
38 #if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\r
39   #define _WTL_CMDBAR_VISTA_MENUS 1\r
40 #endif\r
41 \r
42 #if _WTL_CMDBAR_VISTA_MENUS\r
43   #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501))\r
44         #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\r
45   #endif\r
46 #endif\r
47 \r
48 \r
49 ///////////////////////////////////////////////////////////////////////////////\r
50 // Classes in this file:\r
51 //\r
52 // CCommandBarCtrlImpl<T, TBase, TWinTraits>\r
53 // CCommandBarCtrl\r
54 // CMDICommandBarCtrlImpl<T, TBase, TWinTraits>\r
55 // CMDICommandBarCtrl\r
56 \r
57 \r
58 namespace WTL\r
59 {\r
60 \r
61 ///////////////////////////////////////////////////////////////////////////////\r
62 // Command Bars\r
63 \r
64 // Window Styles:\r
65 #define CBRWS_TOP               CCS_TOP\r
66 #define CBRWS_BOTTOM            CCS_BOTTOM\r
67 #define CBRWS_NORESIZE          CCS_NORESIZE\r
68 #define CBRWS_NOPARENTALIGN     CCS_NOPARENTALIGN\r
69 #define CBRWS_NODIVIDER         CCS_NODIVIDER\r
70 \r
71 // Extended styles\r
72 #define CBR_EX_TRANSPARENT      0x00000001L\r
73 #define CBR_EX_SHAREMENU        0x00000002L\r
74 #define CBR_EX_ALTFOCUSMODE     0x00000004L\r
75 #define CBR_EX_TRACKALWAYS      0x00000008L\r
76 #define CBR_EX_NOVISTAMENUS     0x00000010L\r
77 \r
78 // standard command bar styles\r
79 #define ATL_SIMPLE_CMDBAR_PANE_STYLE \\r
80         (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)\r
81 \r
82 // Messages - support chevrons for frame windows\r
83 #define CBRM_GETCMDBAR                  (WM_USER + 301) // returns command bar HWND\r
84 #define CBRM_GETMENU                    (WM_USER + 302) // returns loaded or attached menu\r
85 #define CBRM_TRACKPOPUPMENU             (WM_USER + 303) // displays a popup menu\r
86 \r
87 typedef struct tagCBRPOPUPMENU\r
88 {\r
89         int cbSize;\r
90         HMENU hMenu;         // popup menu do display\r
91         UINT uFlags;         // TPM_* flags for ::TrackPopupMenuEx\r
92         int x;\r
93         int y;\r
94         LPTPMPARAMS lptpm;   // ptr to TPMPARAMS for ::TrackPopupMenuEx\r
95 } CBRPOPUPMENU, *LPCBRPOPUPMENU;\r
96 \r
97 // helper class\r
98 template <class T>\r
99 class CSimpleStack : public ATL::CSimpleArray< T >\r
100 {\r
101 public:\r
102         BOOL Push(T t)\r
103         {\r
104 #ifdef _CMDBAR_EXTRA_TRACE\r
105                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t, GetSize());\r
106 #endif\r
107                 return Add(t);\r
108         }\r
109 \r
110         T Pop()\r
111         {\r
112                 int nLast = GetSize() - 1;\r
113                 if(nLast < 0)\r
114                         return NULL;   // must be able to convert to NULL\r
115                 T t = m_aT[nLast];\r
116 #ifdef _CMDBAR_EXTRA_TRACE\r
117                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t, GetSize());\r
118 #endif\r
119                 if(!RemoveAt(nLast))\r
120                         return NULL;\r
121                 return t;\r
122         }\r
123 \r
124         T GetCurrent()\r
125         {\r
126                 int nLast = GetSize() - 1;\r
127                 if(nLast < 0)\r
128                         return NULL;   // must be able to convert to NULL\r
129                 return m_aT[nLast];\r
130         }\r
131 };\r
132 \r
133 \r
134 ///////////////////////////////////////////////////////////////////////////////\r
135 // CCommandBarCtrlBase - base class for the Command Bar implementation\r
136 \r
137 class CCommandBarCtrlBase : public CToolBarCtrl\r
138 {\r
139 public:\r
140         struct _MsgHookData\r
141         {\r
142                 HHOOK hMsgHook;\r
143                 DWORD dwUsage;\r
144 \r
145                 _MsgHookData() : hMsgHook(NULL), dwUsage(0)\r
146                 { }\r
147         };\r
148 \r
149         typedef ATL::CSimpleMap<DWORD, _MsgHookData*>   CMsgHookMap;\r
150         static CMsgHookMap* s_pmapMsgHook;\r
151 \r
152         static HHOOK s_hCreateHook;\r
153         static bool s_bW2K;  // For animation flag\r
154         static CCommandBarCtrlBase* s_pCurrentBar;\r
155         static bool s_bStaticInit;\r
156 \r
157         CSimpleStack<HWND> m_stackMenuWnd;\r
158         CSimpleStack<HMENU> m_stackMenuHandle;\r
159 \r
160         HWND m_hWndHook;\r
161         DWORD m_dwMagic;\r
162 \r
163 \r
164         CCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314)\r
165         {\r
166                 // init static variables\r
167                 if(!s_bStaticInit)\r
168                 {\r
169                         CStaticDataInitCriticalSectionLock lock;\r
170                         if(FAILED(lock.Lock()))\r
171                         {\r
172                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n"));\r
173                                 ATLASSERT(FALSE);\r
174                                 return;\r
175                         }\r
176 \r
177                         if(!s_bStaticInit)\r
178                         {\r
179                                 // Just in case...\r
180                                 AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);\r
181                                 // Animation on Win2000 only\r
182                                 s_bW2K = !AtlIsOldWindows();\r
183                                 // done\r
184                                 s_bStaticInit = true;\r
185                         }\r
186 \r
187                         lock.Unlock();\r
188                 }\r
189         }\r
190 \r
191         bool IsCommandBarBase() const { return m_dwMagic == 1314; }\r
192 };\r
193 \r
194 __declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL;\r
195 __declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL;\r
196 __declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL;\r
197 __declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false;\r
198 __declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false;\r
199 \r
200 \r
201 ///////////////////////////////////////////////////////////////////////////////\r
202 // CCommandBarCtrl - ATL implementation of Command Bars\r
203 \r
204 template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>\r
205 class ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >\r
206 {\r
207 public:\r
208         DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())\r
209 \r
210 // Declarations\r
211         struct _MenuItemData    // menu item data\r
212         {\r
213                 DWORD dwMagic;\r
214                 LPTSTR lpstrText;\r
215                 UINT fType;\r
216                 UINT fState;\r
217                 int iButton;\r
218 \r
219                 _MenuItemData() { dwMagic = 0x1313; }\r
220                 bool IsCmdBarMenuItem() { return (dwMagic == 0x1313); }\r
221         };\r
222 \r
223         struct _ToolBarData     // toolbar resource data\r
224         {\r
225                 WORD wVersion;\r
226                 WORD wWidth;\r
227                 WORD wHeight;\r
228                 WORD wItemCount;\r
229                 //WORD aItems[wItemCount]\r
230 \r
231                 WORD* items()\r
232                         { return (WORD*)(this+1); }\r
233         };\r
234 \r
235 // Constants\r
236         enum _CmdBarDrawConstants\r
237         {\r
238                 s_kcxGap = 1,\r
239                 s_kcxTextMargin = 2,\r
240                 s_kcxButtonMargin = 3,\r
241                 s_kcyButtonMargin = 3\r
242         };\r
243 \r
244         enum\r
245         {\r
246                 _nMaxMenuItemTextLength = 100,\r
247                 _chChevronShortcut = _T('/')\r
248         };\r
249 \r
250 #ifndef DT_HIDEPREFIX\r
251         enum { DT_HIDEPREFIX = 0x00100000 };\r
252 #endif // !DT_HIDEPREFIX\r
253 \r
254 // Data members\r
255         HMENU m_hMenu;\r
256         HIMAGELIST m_hImageList;\r
257         ATL::CSimpleValArray<WORD> m_arrCommand;\r
258 \r
259         DWORD m_dwExtendedStyle;   // Command Bar specific extended styles\r
260 \r
261         ATL::CContainedWindow m_wndParent;\r
262 \r
263         bool m_bMenuActive:1;\r
264         bool m_bAttachedMenu:1;\r
265         bool m_bImagesVisible:1;\r
266         bool m_bPopupItem:1;\r
267         bool m_bContextMenu:1;\r
268         bool m_bEscapePressed:1;\r
269         bool m_bSkipMsg:1;\r
270         bool m_bParentActive:1;\r
271         bool m_bFlatMenus:1;\r
272         bool m_bUseKeyboardCues:1;\r
273         bool m_bShowKeyboardCues:1;\r
274         bool m_bAllowKeyboardCues:1;\r
275         bool m_bKeyboardInput:1;\r
276         bool m_bAlphaImages:1;\r
277         bool m_bLayoutRTL:1;\r
278         bool m_bSkipPostDown:1;\r
279         bool m_bVistaMenus:1;\r
280 \r
281         int m_nPopBtn;\r
282         int m_nNextPopBtn;\r
283 \r
284         SIZE m_szBitmap;\r
285         SIZE m_szButton;\r
286 \r
287         COLORREF m_clrMask;\r
288         CFont m_fontMenu;   // used internally, only to measure text\r
289 \r
290         UINT m_uSysKey;\r
291 \r
292         HWND m_hWndFocus;   // Alternate focus mode\r
293 \r
294         int m_cxExtraSpacing;\r
295 \r
296 #if _WTL_CMDBAR_VISTA_MENUS\r
297         ATL::CSimpleValArray<HBITMAP> m_arrVistaBitmap;   // Bitmaps for Vista menus\r
298 #endif // _WTL_CMDBAR_VISTA_MENUS\r
299 \r
300 // Constructor/destructor\r
301         CCommandBarCtrlImpl() : \r
302                         m_hMenu(NULL), \r
303                         m_hImageList(NULL), \r
304                         m_wndParent(this, 1), \r
305                         m_bMenuActive(false), \r
306                         m_bAttachedMenu(false), \r
307                         m_nPopBtn(-1), \r
308                         m_nNextPopBtn(-1), \r
309                         m_bPopupItem(false),\r
310                         m_bImagesVisible(true),\r
311                         m_bSkipMsg(false),\r
312                         m_uSysKey(0),\r
313                         m_hWndFocus(NULL),\r
314                         m_bContextMenu(false),\r
315                         m_bEscapePressed(false),\r
316                         m_clrMask(RGB(192, 192, 192)),\r
317                         m_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS),\r
318                         m_bParentActive(true),\r
319                         m_bFlatMenus(false),\r
320                         m_bUseKeyboardCues(false),\r
321                         m_bShowKeyboardCues(false),\r
322                         m_bAllowKeyboardCues(true),\r
323                         m_bKeyboardInput(false),\r
324                         m_cxExtraSpacing(0),\r
325                         m_bAlphaImages(false),\r
326                         m_bLayoutRTL(false),\r
327                         m_bSkipPostDown(false),\r
328                         m_bVistaMenus(false)\r
329         {\r
330                 SetImageSize(16, 15);   // default\r
331         }\r
332 \r
333         ~CCommandBarCtrlImpl()\r
334         {\r
335                 if(m_wndParent.IsWindow())\r
336 /*scary!*/                      m_wndParent.UnsubclassWindow();\r
337 \r
338                 if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)\r
339                         ::DestroyMenu(m_hMenu);\r
340 \r
341                 if(m_hImageList != NULL)\r
342                         ::ImageList_Destroy(m_hImageList);\r
343         }\r
344 \r
345 // Attributes\r
346         DWORD GetCommandBarExtendedStyle() const\r
347         {\r
348                 return m_dwExtendedStyle;\r
349         }\r
350 \r
351         DWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\r
352         {\r
353                 DWORD dwPrevStyle = m_dwExtendedStyle;\r
354                 if(dwMask == 0)\r
355                         m_dwExtendedStyle = dwExtendedStyle;\r
356                 else\r
357                         m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\r
358                 return dwPrevStyle;\r
359         }\r
360 \r
361         CMenuHandle GetMenu() const\r
362         {\r
363                 ATLASSERT(::IsWindow(m_hWnd));\r
364                 return m_hMenu;\r
365         }\r
366 \r
367         COLORREF GetImageMaskColor() const\r
368         {\r
369                 return m_clrMask;\r
370         }\r
371 \r
372         COLORREF SetImageMaskColor(COLORREF clrMask)\r
373         {\r
374                 COLORREF clrOld = m_clrMask;\r
375                 m_clrMask = clrMask;\r
376                 return clrOld;\r
377         }\r
378 \r
379         bool GetImagesVisible() const\r
380         {\r
381                 return m_bImagesVisible;\r
382         }\r
383 \r
384         bool SetImagesVisible(bool bVisible)\r
385         {\r
386                 bool bOld = m_bImagesVisible;\r
387                 m_bImagesVisible = bVisible;\r
388                 return bOld;\r
389         }\r
390 \r
391         void GetImageSize(SIZE& size) const\r
392         {\r
393                 size = m_szBitmap;\r
394         }\r
395 \r
396         bool SetImageSize(SIZE& size)\r
397         {\r
398                 return SetImageSize(size.cx, size.cy);\r
399         }\r
400 \r
401         bool SetImageSize(int cx, int cy)\r
402         {\r
403                 if(m_hImageList != NULL)\r
404                 {\r
405                         if(::ImageList_GetImageCount(m_hImageList) == 0)   // empty\r
406                         {\r
407                                 ::ImageList_Destroy(m_hImageList);\r
408                                 m_hImageList = NULL;\r
409                         }\r
410                         else\r
411                         {\r
412                                 return false;   // can't set, image list exists\r
413                         }\r
414                 }\r
415 \r
416                 if(cx == 0 || cy == 0)\r
417                         return false;\r
418 \r
419                 m_szBitmap.cx = cx;\r
420                 m_szBitmap.cy = cy;\r
421                 m_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin;\r
422                 m_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin;\r
423 \r
424                 return true;\r
425         }\r
426 \r
427         bool GetAlphaImages() const\r
428         {\r
429                 return m_bAlphaImages;\r
430         }\r
431 \r
432         bool SetAlphaImages(bool bAlphaImages)\r
433         {\r
434                 if(m_hImageList != NULL)\r
435                 {\r
436                         if(::ImageList_GetImageCount(m_hImageList) == 0)   // empty\r
437                         {\r
438                                 ::ImageList_Destroy(m_hImageList);\r
439                                 m_hImageList = NULL;\r
440                         }\r
441                         else\r
442                         {\r
443                                 return false;   // can't set, image list exists\r
444                         }\r
445                 }\r
446 \r
447                 m_bAlphaImages = bAlphaImages;\r
448                 return true;\r
449         }\r
450 \r
451         HWND GetCmdBar() const\r
452         {\r
453                 ATLASSERT(::IsWindow(m_hWnd));\r
454                 return (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);\r
455         }\r
456 \r
457 // Methods\r
458         HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,\r
459                         DWORD dwStyle = 0, DWORD dwExStyle = 0,\r
460                         UINT nID = 0, LPVOID lpCreateParam = NULL)\r
461         {\r
462                 // These styles are required for command bars\r
463                 dwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT;\r
464 #if (_MSC_VER >= 1300)\r
465                 return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);\r
466 #else // !(_MSC_VER >= 1300)\r
467                 typedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\r
468                 return _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);\r
469 #endif // !(_MSC_VER >= 1300)\r
470         }\r
471 \r
472         BOOL AttachToWindow(HWND hWnd)\r
473         {\r
474                 ATLASSERT(m_hWnd == NULL);\r
475                 ATLASSERT(::IsWindow(hWnd));\r
476                 BOOL bRet = SubclassWindow(hWnd);\r
477                 if(bRet)\r
478                 {\r
479                         m_bAttachedMenu = true;\r
480                         T* pT = static_cast<T*>(this);\r
481                         pT->GetSystemSettings();\r
482                 }\r
483                 return bRet;\r
484         }\r
485 \r
486         BOOL LoadMenu(ATL::_U_STRINGorID menu)\r
487         {\r
488                 ATLASSERT(::IsWindow(m_hWnd));\r
489 \r
490                 if(m_bAttachedMenu)   // doesn't work in this mode\r
491                         return FALSE;\r
492                 if(menu.m_lpstr == NULL)\r
493                         return FALSE;\r
494 \r
495                 HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);\r
496                 if(hMenu == NULL)\r
497                         return FALSE;\r
498 \r
499                 return AttachMenu(hMenu);\r
500         }\r
501 \r
502         BOOL AttachMenu(HMENU hMenu)\r
503         {\r
504                 ATLASSERT(::IsWindow(m_hWnd));\r
505                 ATLASSERT(hMenu == NULL || ::IsMenu(hMenu));\r
506                 if(hMenu != NULL && !::IsMenu(hMenu))\r
507                         return FALSE;\r
508 \r
509 #if _WTL_CMDBAR_VISTA_MENUS\r
510                 // remove Vista bitmaps if used\r
511                 if(m_bVistaMenus && (m_hMenu != NULL))\r
512                 {\r
513                         T* pT = static_cast<T*>(this);\r
514                         pT->_RemoveVistaBitmapsFromMenu();\r
515                 }\r
516 #endif // _WTL_CMDBAR_VISTA_MENUS\r
517 \r
518                 // destroy old menu, if needed, and set new one\r
519                 if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)\r
520                         ::DestroyMenu(m_hMenu);\r
521 \r
522                 m_hMenu = hMenu;\r
523 \r
524                 if(m_bAttachedMenu)   // Nothing else in this mode\r
525                         return TRUE;\r
526 \r
527                 // Build buttons according to menu\r
528                 SetRedraw(FALSE);\r
529 \r
530                 // Clear all buttons\r
531                 int nCount = GetButtonCount();\r
532                 for(int i = 0; i < nCount; i++)\r
533                         ATLVERIFY(DeleteButton(0) != FALSE);\r
534 \r
535                 // Add buttons for each menu item\r
536                 if(m_hMenu != NULL)\r
537                 {\r
538                         int nItems = ::GetMenuItemCount(m_hMenu);\r
539 \r
540                         T* pT = static_cast<T*>(this);\r
541                         pT;   // avoid level 4 warning\r
542                         TCHAR szString[pT->_nMaxMenuItemTextLength];\r
543                         for(int i = 0; i < nItems; i++)\r
544                         {\r
545                                 CMenuItemInfo mii;\r
546                                 mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU;\r
547                                 mii.fType = MFT_STRING;\r
548                                 mii.dwTypeData = szString;\r
549                                 mii.cch = pT->_nMaxMenuItemTextLength;\r
550                                 BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii);\r
551                                 ATLASSERT(bRet);\r
552                                 // If we have more than the buffer, we assume we have bitmaps bits\r
553                                 if(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1)\r
554                                 {\r
555                                         mii.fType = MFT_BITMAP;\r
556                                         ::SetMenuItemInfo(m_hMenu, i, TRUE, &mii);\r
557                                         szString[0] = 0;\r
558                                 }\r
559 \r
560                                 // NOTE: Command Bar currently supports only drop-down menu items\r
561                                 ATLASSERT(mii.hSubMenu != NULL);\r
562 \r
563                                 TBBUTTON btn = { 0 };\r
564                                 btn.iBitmap = 0;\r
565                                 btn.idCommand = i;\r
566                                 btn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0);\r
567                                 btn.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN;\r
568                                 btn.dwData = 0;\r
569                                 btn.iString = 0;\r
570 \r
571                                 bRet = InsertButton(-1, &btn);\r
572                                 ATLASSERT(bRet);\r
573 \r
574                                 TBBUTTONINFO bi = { 0 };\r
575                                 bi.cbSize = sizeof(TBBUTTONINFO);\r
576                                 bi.dwMask = TBIF_TEXT;\r
577                                 bi.pszText = szString;\r
578 \r
579                                 bRet = SetButtonInfo(i, &bi);\r
580                                 ATLASSERT(bRet);\r
581                         }\r
582                 }\r
583 \r
584                 SetRedraw(TRUE);\r
585                 Invalidate();\r
586                 UpdateWindow();\r
587 \r
588                 return TRUE;\r
589         }\r
590 \r
591         BOOL LoadImages(ATL::_U_STRINGorID image)\r
592         {\r
593                 return _LoadImagesHelper(image, false);\r
594         }\r
595 \r
596         BOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)\r
597         {\r
598                 return _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize);\r
599         }\r
600 \r
601         BOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)\r
602         {\r
603                 ATLASSERT(::IsWindow(m_hWnd));\r
604                 HINSTANCE hInstance = ModuleHelper::GetResourceInstance();\r
605 \r
606                 HRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR);\r
607                 if(hRsrc == NULL)\r
608                         return FALSE;\r
609 \r
610                 HGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc);\r
611                 if(hGlobal == NULL)\r
612                         return FALSE;\r
613 \r
614                 _ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal);\r
615                 if(pData == NULL)\r
616                         return FALSE;\r
617                 ATLASSERT(pData->wVersion == 1);\r
618 \r
619                 WORD* pItems = pData->items();\r
620                 int nItems = pData->wItemCount;\r
621 \r
622                 // Set internal data\r
623                 SetImageSize(pData->wWidth, pData->wHeight);\r
624 \r
625                 // Create image list if needed\r
626                 if(m_hImageList == NULL)\r
627                 {\r
628                         // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only)\r
629                         T* pT = static_cast<T*>(this);\r
630                         m_bAlphaImages = AtlIsAlphaBitmapResource(image);\r
631 \r
632                         if(!pT->CreateInternalImageList(pData->wItemCount))\r
633                                 return FALSE;\r
634                 }\r
635 \r
636 #if _WTL_CMDBAR_VISTA_MENUS\r
637                 int nOldImageCount = ::ImageList_GetImageCount(m_hImageList);\r
638 #endif // _WTL_CMDBAR_VISTA_MENUS\r
639 \r
640                 // Add bitmap to our image list\r
641                 CBitmap bmp;\r
642                 if(bMapped)\r
643                 {\r
644                         ATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0);   // if mapped, must be a numeric ID\r
645                         int nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr));\r
646                         bmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize);\r
647                 }\r
648                 else\r
649                 {\r
650                         if(m_bAlphaImages)\r
651                                 bmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);\r
652                         else\r
653                                 bmp.LoadBitmap(image.m_lpstr);\r
654                 }\r
655                 ATLASSERT(bmp.m_hBitmap != NULL);\r
656                 if(bmp.m_hBitmap == NULL)\r
657                         return FALSE;\r
658                 if(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1)\r
659                         return FALSE;\r
660 \r
661                 // Fill the array with command IDs\r
662                 for(int i = 0; i < nItems; i++)\r
663                 {\r
664                         if(pItems[i] != 0)\r
665                                 m_arrCommand.Add(pItems[i]);\r
666                 }\r
667 \r
668                 int nImageCount = ::ImageList_GetImageCount(m_hImageList);\r
669                 ATLASSERT(nImageCount == m_arrCommand.GetSize());\r
670                 if(nImageCount != m_arrCommand.GetSize())\r
671                         return FALSE;\r
672 \r
673 #if _WTL_CMDBAR_VISTA_MENUS\r
674                 if(RunTimeHelper::IsVista())\r
675                 {\r
676                         T* pT = static_cast<T*>(this);\r
677                         pT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount);\r
678                         ATLASSERT(nImageCount == m_arrVistaBitmap.GetSize());\r
679                 }\r
680 #endif // _WTL_CMDBAR_VISTA_MENUS\r
681 \r
682                 return TRUE;\r
683         }\r
684 \r
685         BOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)\r
686         {\r
687                 ATLASSERT(::IsWindow(m_hWnd));\r
688                 CBitmap bmp;\r
689                 bmp.LoadBitmap(bitmap.m_lpstr);\r
690                 if(bmp.m_hBitmap == NULL)\r
691                         return FALSE;\r
692                 return AddBitmap(bmp, nCommandID);\r
693         }\r
694 \r
695         BOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID)\r
696         {\r
697                 ATLASSERT(::IsWindow(m_hWnd));\r
698                 T* pT = static_cast<T*>(this);\r
699                 // Create image list if it doesn't exist\r
700                 if(m_hImageList == NULL)\r
701                 {\r
702                         if(!pT->CreateInternalImageList(1))\r
703                                 return FALSE;\r
704                 }\r
705                 // check bitmap size\r
706                 CBitmapHandle bmp = hBitmap;\r
707                 SIZE size = { 0, 0 };\r
708                 bmp.GetSize(size);\r
709                 if(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy)\r
710                 {\r
711                         ATLASSERT(FALSE);   // must match size!\r
712                         return FALSE;\r
713                 }\r
714                 // add bitmap\r
715                 int nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask);\r
716                 if(nRet == -1)\r
717                         return FALSE;\r
718                 BOOL bRet = m_arrCommand.Add((WORD)nCommandID);\r
719                 ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());\r
720 #if _WTL_CMDBAR_VISTA_MENUS\r
721                 if(RunTimeHelper::IsVista())\r
722                 {\r
723                         pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);\r
724                         ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());\r
725                 }\r
726 #endif // _WTL_CMDBAR_VISTA_MENUS\r
727                 return bRet;\r
728         }\r
729 \r
730         BOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID)\r
731         {\r
732                 ATLASSERT(::IsWindow(m_hWnd));\r
733                 HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);\r
734                 if(hIcon == NULL)\r
735                         return FALSE;\r
736                 return AddIcon(hIcon, nCommandID);\r
737         }\r
738 \r
739         BOOL AddIcon(HICON hIcon, UINT nCommandID)\r
740         {\r
741                 ATLASSERT(::IsWindow(m_hWnd));\r
742                 T* pT = static_cast<T*>(this);\r
743                 // create image list if it doesn't exist\r
744                 if(m_hImageList == NULL)\r
745                 {\r
746                         if(!pT->CreateInternalImageList(1))\r
747                                 return FALSE;\r
748                 }\r
749 \r
750                 int nRet = ::ImageList_AddIcon(m_hImageList, hIcon);\r
751                 if(nRet == -1)\r
752                         return FALSE;\r
753                 BOOL bRet = m_arrCommand.Add((WORD)nCommandID);\r
754                 ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());\r
755 #if _WTL_CMDBAR_VISTA_MENUS\r
756                 if(RunTimeHelper::IsVista())\r
757                 {\r
758                         pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);\r
759                         ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());\r
760                 }\r
761 #endif // _WTL_CMDBAR_VISTA_MENUS\r
762                 return bRet;\r
763         }\r
764 \r
765         BOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)\r
766         {\r
767                 ATLASSERT(::IsWindow(m_hWnd));\r
768                 CBitmap bmp;\r
769                 bmp.LoadBitmap(bitmap.m_lpstr);\r
770                 if(bmp.m_hBitmap == NULL)\r
771                         return FALSE;\r
772                 return ReplaceBitmap(bmp, nCommandID);\r
773         }\r
774 \r
775         BOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID)\r
776         {\r
777                 ATLASSERT(::IsWindow(m_hWnd));\r
778                 BOOL bRet = FALSE;\r
779                 for(int i = 0; i < m_arrCommand.GetSize(); i++)\r
780                 {\r
781                         if(m_arrCommand[i] == nCommandID)\r
782                         {\r
783                                 bRet = ::ImageList_Remove(m_hImageList, i);\r
784                                 if(bRet)\r
785                                 {\r
786                                         m_arrCommand.RemoveAt(i);\r
787 #if _WTL_CMDBAR_VISTA_MENUS\r
788                                         if(RunTimeHelper::IsVista())\r
789                                         {\r
790                                                 if(m_arrVistaBitmap[i] != NULL)\r
791                                                         ::DeleteObject(m_arrVistaBitmap[i]);\r
792                                                 m_arrVistaBitmap.RemoveAt(i);\r
793                                         }\r
794 #endif // _WTL_CMDBAR_VISTA_MENUS\r
795                                 }\r
796                                 break;\r
797                         }\r
798                 }\r
799                 if(bRet)\r
800                         bRet = AddBitmap(hBitmap, nCommandID);\r
801                 return bRet;\r
802         }\r
803 \r
804         BOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID)\r
805         {\r
806                 ATLASSERT(::IsWindow(m_hWnd));\r
807                 HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);\r
808                 if(hIcon == NULL)\r
809                         return FALSE;\r
810                 return ReplaceIcon(hIcon, nCommandID);\r
811         }\r
812 \r
813         BOOL ReplaceIcon(HICON hIcon, UINT nCommandID)\r
814         {\r
815                 ATLASSERT(::IsWindow(m_hWnd));\r
816                 BOOL bRet = FALSE;\r
817                 for(int i = 0; i < m_arrCommand.GetSize(); i++)\r
818                 {\r
819                         if(m_arrCommand[i] == nCommandID)\r
820                         {\r
821                                 bRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1);\r
822 #if _WTL_CMDBAR_VISTA_MENUS\r
823                                 if(RunTimeHelper::IsVista() && bRet != FALSE)\r
824                                 {\r
825                                         T* pT = static_cast<T*>(this);\r
826                                         pT->_ReplaceVistaBitmapFromImageList(i);\r
827                                 }\r
828 #endif // _WTL_CMDBAR_VISTA_MENUS\r
829                                 break;\r
830                         }\r
831                 }\r
832                 return bRet;\r
833         }\r
834 \r
835         BOOL RemoveImage(int nCommandID)\r
836         {\r
837                 ATLASSERT(::IsWindow(m_hWnd));\r
838 \r
839                 BOOL bRet = FALSE;\r
840                 for(int i = 0; i < m_arrCommand.GetSize(); i++)\r
841                 {\r
842                         if(m_arrCommand[i] == nCommandID)\r
843                         {\r
844                                 bRet = ::ImageList_Remove(m_hImageList, i);\r
845                                 if(bRet)\r
846                                 {\r
847                                         m_arrCommand.RemoveAt(i);\r
848 #if _WTL_CMDBAR_VISTA_MENUS\r
849                                         if(RunTimeHelper::IsVista())\r
850                                         {\r
851                                                 if(m_arrVistaBitmap[i] != NULL)\r
852                                                         ::DeleteObject(m_arrVistaBitmap[i]);\r
853                                                 m_arrVistaBitmap.RemoveAt(i);\r
854                                         }\r
855 #endif // _WTL_CMDBAR_VISTA_MENUS\r
856                                 }\r
857                                 break;\r
858                         }\r
859                 }\r
860                 return bRet;\r
861         }\r
862 \r
863         BOOL RemoveAllImages()\r
864         {\r
865                 ATLASSERT(::IsWindow(m_hWnd));\r
866 \r
867                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Removing all images\n"));\r
868                 BOOL bRet = ::ImageList_RemoveAll(m_hImageList);\r
869                 if(bRet)\r
870                 {\r
871                         m_arrCommand.RemoveAll();\r
872 #if _WTL_CMDBAR_VISTA_MENUS\r
873                         for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)\r
874                         {\r
875                                 if(m_arrVistaBitmap[i] != NULL)\r
876                                         ::DeleteObject(m_arrVistaBitmap[i]);\r
877                         }\r
878                         m_arrVistaBitmap.RemoveAll();\r
879 #endif // _WTL_CMDBAR_VISTA_MENUS\r
880                 }\r
881                 return bRet;\r
882         }\r
883 \r
884         BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)\r
885         {\r
886                 ATLASSERT(::IsWindow(m_hWnd));\r
887                 ATLASSERT(::IsMenu(hMenu));\r
888                 if(!::IsMenu(hMenu))\r
889                         return FALSE;\r
890                 m_bContextMenu = true;\r
891                 if(m_bUseKeyboardCues)\r
892                         m_bShowKeyboardCues = m_bKeyboardInput;\r
893                 T* pT = static_cast<T*>(this);\r
894                 return pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams);\r
895         }\r
896 \r
897         BOOL SetMDIClient(HWND /*hWndMDIClient*/)\r
898         {\r
899                 // Use CMDICommandBarCtrl for MDI support\r
900                 ATLASSERT(FALSE);\r
901                 return FALSE;\r
902         }\r
903 \r
904 // Message map and handlers\r
905         BEGIN_MSG_MAP(CCommandBarCtrlImpl)\r
906                 MESSAGE_HANDLER(WM_CREATE, OnCreate)\r
907                 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)\r
908                 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\r
909                 MESSAGE_HANDLER(WM_INITMENU, OnInitMenu)\r
910                 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)\r
911                 MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)\r
912                 MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup)\r
913                 MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar)\r
914                 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\r
915                 MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar)\r
916 \r
917                 MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\r
918                 MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)\r
919                 MESSAGE_HANDLER(WM_CHAR, OnChar)\r
920                 MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown)\r
921                 MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp)\r
922                 MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar)\r
923 // public API handlers - these stay to support chevrons in atlframe.h\r
924                 MESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu)\r
925                 MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu)\r
926                 MESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar)\r
927 \r
928                 MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)\r
929                 MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)\r
930 \r
931                 MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg)\r
932         ALT_MSG_MAP(1)   // Parent window messages\r
933                 NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange)\r
934                 NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown)\r
935                 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup)\r
936                 MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar)\r
937                 MESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand)\r
938                 MESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu)\r
939                 MESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar)\r
940                 MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu)\r
941                 MESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar)\r
942                 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange)\r
943 \r
944                 MESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem)\r
945                 MESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem)\r
946 \r
947                 MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)\r
948                 NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw)\r
949         ALT_MSG_MAP(2)   // MDI client window messages\r
950                 // Use CMDICommandBarCtrl for MDI support\r
951         ALT_MSG_MAP(3)   // Message hook messages\r
952                 MESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove)\r
953                 MESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown)\r
954                 MESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp)\r
955                 MESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar)\r
956                 MESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown)\r
957                 MESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu)\r
958                 MESSAGE_HANDLER(WM_CHAR, OnHookChar)\r
959         END_MSG_MAP()\r
960 \r
961         LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\r
962         {\r
963                 LPMSG pMsg = (LPMSG)lParam;\r
964                 if(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)\r
965                         m_bKeyboardInput = false;\r
966                 else if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)\r
967                         m_bKeyboardInput = true;\r
968                 LRESULT lRet = 0;\r
969                 ProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3);\r
970                 return lRet;\r
971         }\r
972 \r
973         LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
974         {\r
975                 // Let the toolbar initialize itself\r
976                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
977                 // get and use system settings\r
978                 T* pT = static_cast<T*>(this);\r
979                 pT->GetSystemSettings();\r
980                 // Parent init\r
981                 ATL::CWindow wndParent = GetParent();\r
982                 ATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent();\r
983                 m_wndParent.SubclassWindow(wndTopLevelParent);\r
984                 // Toolbar Init\r
985                 SetButtonStructSize();\r
986                 SetImageList(NULL);\r
987 \r
988                 // Create message hook if needed\r
989                 CWindowCreateCriticalSectionLock lock;\r
990                 if(FAILED(lock.Lock()))\r
991                 {\r
992                         ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n"));\r
993                         ATLASSERT(FALSE);\r
994                         return -1;\r
995                 }\r
996 \r
997                 if(s_pmapMsgHook == NULL)\r
998                 {\r
999                         ATLTRY(s_pmapMsgHook = new CMsgHookMap);\r
1000                         ATLASSERT(s_pmapMsgHook != NULL);\r
1001                 }\r
1002 \r
1003                 if(s_pmapMsgHook != NULL)\r
1004                 {\r
1005                         DWORD dwThreadID = ::GetCurrentThreadId();\r
1006                         _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);\r
1007                         if(pData == NULL)\r
1008                         {\r
1009                                 ATLTRY(pData = new _MsgHookData);\r
1010                                 ATLASSERT(pData != NULL);\r
1011                                 HHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID);\r
1012                                 ATLASSERT(hMsgHook != NULL);\r
1013                                 if(pData != NULL && hMsgHook != NULL)\r
1014                                 {\r
1015                                         pData->hMsgHook = hMsgHook;\r
1016                                         pData->dwUsage = 1;\r
1017                                         BOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData);\r
1018                                         bRet;\r
1019                                         ATLASSERT(bRet);\r
1020                                 }\r
1021                         }\r
1022                         else\r
1023                         {\r
1024                                 (pData->dwUsage)++;\r
1025                         }\r
1026                 }\r
1027                 lock.Unlock();\r
1028 \r
1029                 // Get layout\r
1030 #if (WINVER >= 0x0500)\r
1031                 m_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0);\r
1032 #endif // (WINVER >= 0x0500)\r
1033 \r
1034                 return lRet;\r
1035         }\r
1036 \r
1037         LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
1038         {\r
1039                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
1040 \r
1041 #if _WTL_CMDBAR_VISTA_MENUS\r
1042                 if(m_bVistaMenus && (m_hMenu != NULL))\r
1043                 {\r
1044                         T* pT = static_cast<T*>(this);\r
1045                         pT->_RemoveVistaBitmapsFromMenu();\r
1046                 }\r
1047 \r
1048                 for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)\r
1049                 {\r
1050                         if(m_arrVistaBitmap[i] != NULL)\r
1051                                 ::DeleteObject(m_arrVistaBitmap[i]);\r
1052                 }\r
1053 #endif // _WTL_CMDBAR_VISTA_MENUS\r
1054 \r
1055                 if(m_bAttachedMenu)   // nothing to do in this mode\r
1056                         return lRet;\r
1057 \r
1058                 CWindowCreateCriticalSectionLock lock;\r
1059                 if(FAILED(lock.Lock()))\r
1060                 {\r
1061                         ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n"));\r
1062                         ATLASSERT(FALSE);\r
1063                         return lRet;\r
1064                 }\r
1065 \r
1066                 if(s_pmapMsgHook != NULL)\r
1067                 {\r
1068                         DWORD dwThreadID = ::GetCurrentThreadId();\r
1069                         _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);\r
1070                         if(pData != NULL)\r
1071                         {\r
1072                                 (pData->dwUsage)--;\r
1073                                 if(pData->dwUsage == 0)\r
1074                                 {\r
1075                                         BOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook);\r
1076                                         ATLASSERT(bRet);\r
1077                                         bRet = s_pmapMsgHook->Remove(dwThreadID);\r
1078                                         ATLASSERT(bRet);\r
1079                                         if(bRet)\r
1080                                                 delete pData;\r
1081                                 }\r
1082 \r
1083                                 if(s_pmapMsgHook->GetSize() == 0)\r
1084                                 {\r
1085                                         delete s_pmapMsgHook;\r
1086                                         s_pmapMsgHook = NULL;\r
1087                                 }\r
1088                         }\r
1089                 }\r
1090 \r
1091                 lock.Unlock();\r
1092 \r
1093                 return lRet;\r
1094         }\r
1095 \r
1096         LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1097         {\r
1098 #ifdef _CMDBAR_EXTRA_TRACE\r
1099                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyDown\n"));\r
1100 #endif\r
1101                 bHandled = FALSE;\r
1102                 // Simulate Alt+Space for the parent\r
1103                 if(wParam == VK_SPACE)\r
1104                 {\r
1105                         m_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29));\r
1106                         bHandled = TRUE;\r
1107                 }\r
1108 #if (_WIN32_IE >= 0x0500)\r
1109                 else if(wParam == VK_LEFT || wParam == VK_RIGHT)\r
1110                 {\r
1111                         WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;\r
1112 \r
1113                         if(!m_bMenuActive)\r
1114                         {\r
1115                                 T* pT = static_cast<T*>(this);\r
1116                                 int nBtn = GetHotItem();\r
1117                                 int nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn);\r
1118                                 if(nNextBtn == -2)\r
1119                                 {\r
1120                                         SetHotItem(-1);\r
1121                                         if(pT->DisplayChevronMenu())\r
1122                                                 bHandled = TRUE;\r
1123                                 }\r
1124                         }\r
1125                 }\r
1126 #endif // (_WIN32_IE >= 0x0500)\r
1127                 return 0;\r
1128         }\r
1129 \r
1130         LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1131         {\r
1132 #ifdef _CMDBAR_EXTRA_TRACE\r
1133                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyUp\n"));\r
1134 #endif\r
1135                 if(wParam != VK_SPACE)\r
1136                         bHandled = FALSE;\r
1137                 return 0;\r
1138         }\r
1139 \r
1140         LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1141         {\r
1142 #ifdef _CMDBAR_EXTRA_TRACE\r
1143                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnChar\n"));\r
1144 #endif\r
1145                 if(wParam != VK_SPACE)\r
1146                         bHandled = FALSE;\r
1147                 else\r
1148                         return 0;\r
1149                 // Security\r
1150                 if(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd)\r
1151                         return 0;\r
1152 \r
1153                 // Handle mnemonic press when we have focus\r
1154                 int nBtn = 0;\r
1155                 if(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn))\r
1156                 {\r
1157 #if (_WIN32_IE >= 0x0500)\r
1158                         if((TCHAR)LOWORD(wParam) != _chChevronShortcut)\r
1159 #endif // (_WIN32_IE >= 0x0500)\r
1160                                 ::MessageBeep(0);\r
1161                 }\r
1162                 else\r
1163                 {\r
1164 #if (_WIN32_IE >= 0x0500)\r
1165                         RECT rcClient = { 0 };\r
1166                         GetClientRect(&rcClient);\r
1167                         RECT rcBtn = { 0 };\r
1168                         GetItemRect(nBtn, &rcBtn);\r
1169                         TBBUTTON tbb = { 0 };\r
1170                         GetButton(nBtn, &tbb);\r
1171                         if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)\r
1172                         {\r
1173 #endif // (_WIN32_IE >= 0x0500)\r
1174                                 PostMessage(WM_KEYDOWN, VK_DOWN, 0L);\r
1175                                 if(wParam != VK_RETURN)\r
1176                                         SetHotItem(nBtn);\r
1177 #if (_WIN32_IE >= 0x0500)\r
1178                         }\r
1179                         else\r
1180                         {\r
1181                                 ::MessageBeep(0);\r
1182                                 bHandled = TRUE;\r
1183                         }\r
1184 #endif // (_WIN32_IE >= 0x0500)\r
1185                 }\r
1186                 return 0;\r
1187         }\r
1188 \r
1189         LRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
1190         {\r
1191 #ifdef _CMDBAR_EXTRA_TRACE\r
1192                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyDown\n"));\r
1193 #endif\r
1194                 bHandled = FALSE;\r
1195                 return 0;\r
1196         }\r
1197 \r
1198         LRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
1199         {\r
1200 #ifdef _CMDBAR_EXTRA_TRACE\r
1201                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyUp\n"));\r
1202 #endif\r
1203                 bHandled = FALSE;\r
1204                 return 0;\r
1205         }\r
1206 \r
1207         LRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
1208         {\r
1209 #ifdef _CMDBAR_EXTRA_TRACE\r
1210                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysChar\n"));\r
1211 #endif\r
1212                 bHandled = FALSE;\r
1213                 return 0;\r
1214         }\r
1215 \r
1216         LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1217         {\r
1218                 if(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT))\r
1219                 {\r
1220                         bHandled = FALSE;\r
1221                         return 0;\r
1222                 }\r
1223 \r
1224                 CDCHandle dc = (HDC)wParam;\r
1225                 RECT rect = { 0 };\r
1226                 GetClientRect(&rect);\r
1227                 dc.FillRect(&rect, COLOR_MENU);\r
1228 \r
1229                 return 1;   // don't do the default erase\r
1230         }\r
1231 \r
1232         LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
1233         {\r
1234                 int nIndex = GetHotItem();\r
1235                 SendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu);\r
1236                 bHandled = FALSE;\r
1237                 return 1;\r
1238         }\r
1239 \r
1240         LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1241         {\r
1242                 if((BOOL)HIWORD(lParam))   // System menu, do nothing\r
1243                 {\r
1244                         bHandled = FALSE;\r
1245                         return 1;\r
1246                 }\r
1247 \r
1248                 if(!(m_bAttachedMenu || m_bMenuActive))   // Not attached or ours, do nothing\r
1249                 {\r
1250                         bHandled = FALSE;\r
1251                         return 1;\r
1252                 }\r
1253 \r
1254 #ifdef _CMDBAR_EXTRA_TRACE\r
1255                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnInitMenuPopup\n"));\r
1256 #endif\r
1257                 // forward to the parent or subclassed window, so it can handle update UI\r
1258                 LRESULT lRet = 0;\r
1259                 if(m_bAttachedMenu)\r
1260                         lRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());\r
1261                 else\r
1262                         lRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());\r
1263 \r
1264 #if _WTL_CMDBAR_VISTA_MENUS\r
1265                 // If Vista menus are active, just set bitmaps and return\r
1266                 if(m_bVistaMenus)\r
1267                 {\r
1268                         CMenuHandle menu = (HMENU)wParam;\r
1269                         ATLASSERT(menu.m_hMenu != NULL);\r
1270 \r
1271                         for(int i = 0; i < menu.GetMenuItemCount(); i++)\r
1272                         {\r
1273                                 WORD nID = (WORD)menu.GetMenuItemID(i);\r
1274                                 int nIndex = m_arrCommand.Find(nID);\r
1275 \r
1276                                 CMenuItemInfo mii;\r
1277                                 mii.fMask = MIIM_BITMAP;\r
1278                                 mii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL;\r
1279                                 menu.SetMenuItemInfo(i, TRUE, &mii);\r
1280                         }\r
1281 \r
1282                         return lRet;\r
1283                 }\r
1284 #endif // _WTL_CMDBAR_VISTA_MENUS\r
1285 \r
1286                 // Convert menu items to ownerdraw, add our data\r
1287                 if(m_bImagesVisible)\r
1288                 {\r
1289                         CMenuHandle menuPopup = (HMENU)wParam;\r
1290                         ATLASSERT(menuPopup.m_hMenu != NULL);\r
1291 \r
1292                         T* pT = static_cast<T*>(this);\r
1293                         pT;   // avoid level 4 warning\r
1294                         TCHAR szString[pT->_nMaxMenuItemTextLength];\r
1295                         BOOL bRet = FALSE;\r
1296                         for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)\r
1297                         {\r
1298                                 CMenuItemInfo mii;\r
1299                                 mii.cch = pT->_nMaxMenuItemTextLength;\r
1300                                 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;\r
1301                                 mii.dwTypeData = szString;\r
1302                                 bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);\r
1303                                 ATLASSERT(bRet);\r
1304 \r
1305                                 if(!(mii.fType & MFT_OWNERDRAW))   // Not already an ownerdraw item\r
1306                                 {\r
1307                                         mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;\r
1308                                         _MenuItemData* pMI = NULL;\r
1309                                         ATLTRY(pMI = new _MenuItemData);\r
1310                                         ATLASSERT(pMI != NULL);\r
1311                                         if(pMI != NULL)\r
1312                                         {\r
1313                                                 pMI->fType = mii.fType;\r
1314                                                 pMI->fState = mii.fState;\r
1315                                                 mii.fType |= MFT_OWNERDRAW;\r
1316                                                 pMI->iButton = -1;\r
1317                                                 for(int j = 0; j < m_arrCommand.GetSize(); j++)\r
1318                                                 {\r
1319                                                         if(m_arrCommand[j] == mii.wID)\r
1320                                                         {\r
1321                                                                 pMI->iButton = j;\r
1322                                                                 break;\r
1323                                                         }\r
1324                                                 }\r
1325                                                 int cchLen = lstrlen(szString) + 1;\r
1326                                                 pMI->lpstrText = NULL;\r
1327                                                 ATLTRY(pMI->lpstrText = new TCHAR[cchLen]);\r
1328                                                 ATLASSERT(pMI->lpstrText != NULL);\r
1329                                                 if(pMI->lpstrText != NULL)\r
1330                                                         SecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString);\r
1331                                                 mii.dwItemData = (ULONG_PTR)pMI;\r
1332                                                 bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);\r
1333                                                 ATLASSERT(bRet);\r
1334                                         }\r
1335                                 }\r
1336                         }\r
1337 \r
1338                         // Add it to the list\r
1339                         m_stackMenuHandle.Push(menuPopup.m_hMenu);\r
1340                 }\r
1341 \r
1342                 return lRet;\r
1343         }\r
1344 \r
1345         LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1346         {\r
1347                 if(!m_bAttachedMenu)   // Not attached, do nothing, forward to parent\r
1348                 {\r
1349                         m_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP);\r
1350                         if(m_wndParent.IsWindow())\r
1351                                 m_wndParent.SendMessage(uMsg, wParam, lParam);\r
1352                         bHandled = FALSE;\r
1353                         return 1;\r
1354                 }\r
1355 \r
1356                 // Check if a menu is closing, do a cleanup\r
1357                 if(HIWORD(wParam) == 0xFFFF && lParam == NULL)   // Menu closing\r
1358                 {\r
1359 #ifdef _CMDBAR_EXTRA_TRACE\r
1360                         ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n"));\r
1361 #endif\r
1362                         ATLASSERT(m_stackMenuWnd.GetSize() == 0);\r
1363                         // Restore the menu items to the previous state for all menus that were converted\r
1364                         if(m_bImagesVisible)\r
1365                         {\r
1366                                 HMENU hMenu = NULL;\r
1367                                 while((hMenu = m_stackMenuHandle.Pop()) != NULL)\r
1368                                 {\r
1369                                         CMenuHandle menuPopup = hMenu;\r
1370                                         ATLASSERT(menuPopup.m_hMenu != NULL);\r
1371                                         // Restore state and delete menu item data\r
1372                                         BOOL bRet = FALSE;\r
1373                                         for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)\r
1374                                         {\r
1375                                                 CMenuItemInfo mii;\r
1376                                                 mii.fMask = MIIM_DATA | MIIM_TYPE;\r
1377                                                 bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);\r
1378                                                 ATLASSERT(bRet);\r
1379 \r
1380                                                 _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;\r
1381                                                 if(pMI != NULL && pMI->IsCmdBarMenuItem())\r
1382                                                 {\r
1383                                                         mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;\r
1384                                                         mii.fType = pMI->fType;\r
1385                                                         mii.dwTypeData = pMI->lpstrText;\r
1386                                                         mii.cch = lstrlen(pMI->lpstrText);\r
1387                                                         mii.dwItemData = NULL;\r
1388 \r
1389                                                         bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);\r
1390                                                         ATLASSERT(bRet);\r
1391 \r
1392                                                         delete [] pMI->lpstrText;\r
1393                                                         pMI->dwMagic = 0x6666;\r
1394                                                         delete pMI;\r
1395                                                 }\r
1396                                         }\r
1397                                 }\r
1398                         }\r
1399                 }\r
1400 \r
1401                 bHandled = FALSE;\r
1402                 return 1;\r
1403         }\r
1404 \r
1405         LRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1406         {\r
1407                 int nIndex = (int)wParam;\r
1408                 T* pT = static_cast<T*>(this);\r
1409                 pT->DoPopupMenu(nIndex, false);\r
1410                 return 0;\r
1411         }\r
1412 \r
1413         LRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1414         {\r
1415                 // Let's make sure we're not embedded in another process\r
1416                 if((LPVOID)wParam != NULL)\r
1417                         *((DWORD*)wParam) = GetCurrentProcessId();\r
1418                 if(IsWindowVisible())\r
1419                         return (LRESULT)static_cast<CCommandBarCtrlBase*>(this);\r
1420                 else\r
1421                         return NULL;\r
1422         }\r
1423 \r
1424         LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1425         {\r
1426 #ifndef SPI_GETKEYBOARDCUES\r
1427                 const UINT SPI_SETKEYBOARDCUES = 0x100B;\r
1428 #endif // !SPI_GETKEYBOARDCUES\r
1429 #ifndef SPI_GETFLATMENU\r
1430                 const UINT SPI_SETFLATMENU = 0x1023;\r
1431 #endif // !SPI_GETFLATMENU\r
1432 \r
1433                 if(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU)\r
1434                 {\r
1435                         T* pT = static_cast<T*>(this);\r
1436                         pT->GetSystemSettings();\r
1437                 }\r
1438 \r
1439                 return 0;\r
1440         }\r
1441 \r
1442         LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
1443         {\r
1444                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
1445 \r
1446                 LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;\r
1447                 int cyMin = ::GetSystemMetrics(SM_CYMENU);\r
1448                 if(lpWP->cy < cyMin)\r
1449                 lpWP->cy = cyMin;\r
1450 \r
1451                 return lRet;\r
1452         }\r
1453 \r
1454         LRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1455         {\r
1456 #ifdef _CMDBAR_EXTRA_TRACE\r
1457                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuChar\n"));\r
1458 #endif\r
1459                 bHandled = TRUE;\r
1460                 T* pT = static_cast<T*>(this);\r
1461 \r
1462                 LRESULT lRet;\r
1463                 if(m_bMenuActive && LOWORD(wParam) != 0x0D)\r
1464                         lRet = 0;\r
1465                 else\r
1466                         lRet = MAKELRESULT(1, 1);\r
1467 \r
1468                 if(m_bMenuActive && HIWORD(wParam) == MF_POPUP)\r
1469                 {\r
1470                         // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout\r
1471                         TCHAR ch = (TCHAR)LOWORD(wParam);\r
1472                         CMenuHandle menu = (HMENU)lParam;\r
1473                         int nCount = ::GetMenuItemCount(menu);\r
1474                         int nRetCode = MNC_EXECUTE;\r
1475                         BOOL bRet = FALSE;\r
1476                         TCHAR szString[pT->_nMaxMenuItemTextLength];\r
1477                         WORD wMnem = 0;\r
1478                         bool bFound = false;\r
1479                         for(int i = 0; i < nCount; i++)\r
1480                         {\r
1481                                 CMenuItemInfo mii;\r
1482                                 mii.cch = pT->_nMaxMenuItemTextLength;\r
1483                                 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;\r
1484                                 mii.dwTypeData = szString;\r
1485                                 bRet = menu.GetMenuItemInfo(i, TRUE, &mii);\r
1486                                 if(!bRet || (mii.fType & MFT_SEPARATOR))\r
1487                                         continue;\r
1488                                 _MenuItemData* pmd = (_MenuItemData*)mii.dwItemData;\r
1489                                 if(pmd != NULL && pmd->IsCmdBarMenuItem())\r
1490                                 {\r
1491                                         LPTSTR p = pmd->lpstrText;\r
1492 \r
1493                                         if(p != NULL)\r
1494                                         {\r
1495                                                 while(*p && *p != _T('&'))\r
1496                                                         p = ::CharNext(p);\r
1497                                                 if(p != NULL && *p)\r
1498                                                 {\r
1499                                                         DWORD dwP = MAKELONG(*(++p), 0);\r
1500                                                         DWORD dwC = MAKELONG(ch, 0);\r
1501                                                         if(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC)))\r
1502                                                         {\r
1503                                                                 if(!bFound)\r
1504                                                                 {\r
1505                                                                         wMnem = (WORD)i;\r
1506                                                                         bFound = true;\r
1507                                                                 }\r
1508                                                                 else\r
1509                                                                 {\r
1510                                                                         nRetCode = MNC_SELECT;\r
1511                                                                         break;\r
1512                                                                 }\r
1513                                                         }\r
1514                                                 }\r
1515                                         }\r
1516                                 }\r
1517                         }\r
1518                         if(bFound)\r
1519                         {\r
1520                                 if(nRetCode == MNC_EXECUTE)\r
1521                                 {\r
1522                                         PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\r
1523                                         pT->GiveFocusBack();\r
1524                                 }\r
1525                                 bHandled = TRUE;\r
1526                                 lRet = MAKELRESULT(wMnem, nRetCode);\r
1527                         }\r
1528                 } \r
1529                 else if(!m_bMenuActive)\r
1530                 {\r
1531                         int nBtn = 0;\r
1532                         if(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn))\r
1533                         {\r
1534                                 bHandled = FALSE;\r
1535                                 PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\r
1536                                 pT->GiveFocusBack();\r
1537 \r
1538 #if (_WIN32_IE >= 0x0500)\r
1539                                 // check if we should display chevron menu\r
1540                                 if((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut)\r
1541                                 {\r
1542                                         if(pT->DisplayChevronMenu())\r
1543                                                 bHandled = TRUE;\r
1544                                 }\r
1545 #endif // (_WIN32_IE >= 0x0500)\r
1546                         }\r
1547                         else if(m_wndParent.IsWindowEnabled())\r
1548                         {\r
1549 #if (_WIN32_IE >= 0x0500)\r
1550                                 RECT rcClient = { 0 };\r
1551                                 GetClientRect(&rcClient);\r
1552                                 RECT rcBtn = { 0 };\r
1553                                 GetItemRect(nBtn, &rcBtn);\r
1554                                 TBBUTTON tbb = { 0 };\r
1555                                 GetButton(nBtn, &tbb);\r
1556                                 if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)\r
1557                                 {\r
1558 #endif // (_WIN32_IE >= 0x0500)\r
1559                                         if(m_bUseKeyboardCues && !m_bShowKeyboardCues)\r
1560                                         {\r
1561                                                 m_bAllowKeyboardCues = true;\r
1562                                                 ShowKeyboardCues(true);\r
1563                                         }\r
1564                                         pT->TakeFocus();\r
1565                                         PostMessage(WM_KEYDOWN, VK_DOWN, 0L);\r
1566                                         SetHotItem(nBtn);\r
1567 #if (_WIN32_IE >= 0x0500)\r
1568                                 }\r
1569                                 else\r
1570                                 {\r
1571                                         ::MessageBeep(0);\r
1572                                 }\r
1573 #endif // (_WIN32_IE >= 0x0500)\r
1574                         }\r
1575                 }\r
1576 \r
1577                 return lRet;\r
1578         }\r
1579 \r
1580         LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
1581         {\r
1582                 LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam;\r
1583                 _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;\r
1584                 if(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())\r
1585                 {\r
1586                         T* pT = static_cast<T*>(this);\r
1587                         pT->DrawItem(lpDrawItemStruct);\r
1588                 }\r
1589                 else\r
1590                 {\r
1591                         bHandled = FALSE;\r
1592                 }\r
1593                 return (LRESULT)TRUE;\r
1594         }\r
1595 \r
1596         LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
1597         {\r
1598                 LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam;\r
1599                 _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;\r
1600                 if(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())\r
1601                 {\r
1602                         T* pT = static_cast<T*>(this);\r
1603                         pT->MeasureItem(lpMeasureItemStruct);\r
1604                 }\r
1605                 else\r
1606                 {\r
1607                         bHandled = FALSE;\r
1608                 }\r
1609                 return (LRESULT)TRUE;\r
1610         }\r
1611 \r
1612 // API message handlers\r
1613         LRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1614         {\r
1615                 return (LRESULT)m_hMenu;\r
1616         }\r
1617 \r
1618         LRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\r
1619         {\r
1620                 if(lParam == NULL)\r
1621                         return FALSE;\r
1622                 LPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam;\r
1623                 if(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU))\r
1624                         return FALSE;\r
1625 \r
1626                 T* pT = static_cast<T*>(this);\r
1627                 return pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm);\r
1628         }\r
1629 \r
1630         LRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1631         {\r
1632                 return (LRESULT)m_hWnd;\r
1633         }\r
1634 \r
1635 // Parent window message handlers\r
1636         LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\r
1637         {\r
1638                 LPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh;\r
1639 \r
1640                 // Check if this comes from us\r
1641                 if(pnmh->hwndFrom != m_hWnd)\r
1642                 {\r
1643                         bHandled = FALSE;\r
1644                         return 0;\r
1645                 }\r
1646 \r
1647                 bool bBlockTracking = false;\r
1648                 if((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0)\r
1649                 {\r
1650                         DWORD dwProcessID;\r
1651                         ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID);\r
1652                         bBlockTracking = (::GetCurrentProcessId() != dwProcessID);\r
1653                 }\r
1654 \r
1655                 if((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE))\r
1656                 {\r
1657                         return 1;\r
1658                 }\r
1659                 else\r
1660                 {\r
1661 #ifndef HICF_LMOUSE\r
1662                         const DWORD HICF_LMOUSE = 0x00000080;   // left mouse button selected\r
1663 #endif\r
1664                         bHandled = FALSE;\r
1665 \r
1666                         // Send WM_MENUSELECT to the app if it needs to display a status text\r
1667                         if(!(lpNMHT->dwFlags & HICF_MOUSE)\r
1668                                 && !(lpNMHT->dwFlags & HICF_ACCELERATOR)\r
1669                                 && !(lpNMHT->dwFlags & HICF_LMOUSE))\r
1670                         {\r
1671                                 if(lpNMHT->dwFlags & HICF_ENTERING)\r
1672                                         m_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu);\r
1673                                 if(lpNMHT->dwFlags & HICF_LEAVING)\r
1674                                         m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL);\r
1675                         }\r
1676 \r
1677                         return 0;\r
1678                 }\r
1679         }\r
1680 \r
1681         LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\r
1682         {\r
1683                 // Check if this comes from us\r
1684                 if(pnmh->hwndFrom != m_hWnd)\r
1685                 {\r
1686                         bHandled = FALSE;\r
1687                         return 1;\r
1688                 }\r
1689 \r
1690                 T* pT = static_cast<T*>(this);\r
1691                 if(::GetFocus() != m_hWnd)\r
1692                         pT->TakeFocus();\r
1693                 LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh;\r
1694                 int nIndex = CommandToIndex(pNMToolBar->iItem);\r
1695                 m_bContextMenu = false;\r
1696                 m_bEscapePressed = false;\r
1697                 pT->DoPopupMenu(nIndex, true);\r
1698 \r
1699                 return TBDDRET_DEFAULT;\r
1700         }\r
1701 \r
1702         LRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1703         {\r
1704                 return OnInitMenuPopup(uMsg, wParam, lParam, bHandled);\r
1705         }\r
1706 \r
1707         LRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1708         {\r
1709                 return OnInternalGetBar(uMsg, wParam, lParam, bHandled);\r
1710         }\r
1711 \r
1712         LRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1713         {\r
1714                 bHandled = FALSE;\r
1715                 if((m_uSysKey == VK_MENU \r
1716                         || (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80))\r
1717                         || m_uSysKey == VK_SPACE) \r
1718                         && wParam == SC_KEYMENU)\r
1719                 {\r
1720                         T* pT = static_cast<T*>(this);\r
1721                         if(::GetFocus() == m_hWnd)\r
1722                         {\r
1723                                 pT->GiveFocusBack();   // exit menu "loop"\r
1724                                 PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\r
1725                         }\r
1726                         else if(m_uSysKey != VK_SPACE && !m_bSkipMsg)\r
1727                         {\r
1728                                 if(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)\r
1729                                         ShowKeyboardCues(true);\r
1730 \r
1731                                 pT->TakeFocus();      // enter menu "loop"\r
1732                                 bHandled = TRUE;\r
1733                         }\r
1734                         else if(m_uSysKey != VK_SPACE)\r
1735                         {\r
1736                                 bHandled = TRUE;\r
1737                         }\r
1738                 }\r
1739                 m_bSkipMsg = false;\r
1740                 return 0;\r
1741         }\r
1742 \r
1743         LRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1744         {\r
1745                 return OnAPIGetMenu(uMsg, wParam, lParam, bHandled);\r
1746         }\r
1747 \r
1748         LRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1749         {\r
1750                 return OnMenuChar(uMsg, wParam, lParam, bHandled);\r
1751         }\r
1752 \r
1753         LRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1754         {\r
1755                 return OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled);\r
1756         }\r
1757 \r
1758         LRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1759         {\r
1760                 return OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled);\r
1761         }\r
1762 \r
1763         LRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1764         {\r
1765                 OnSettingChange(uMsg, wParam, lParam, bHandled);\r
1766                 bHandled = FALSE;\r
1767                 return 1;\r
1768         }\r
1769 \r
1770         LRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1771         {\r
1772                 return OnDrawItem(uMsg, wParam, lParam, bHandled);\r
1773         }\r
1774 \r
1775         LRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1776         {\r
1777                 return OnMeasureItem(uMsg, wParam, lParam, bHandled);\r
1778         }\r
1779 \r
1780         LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1781         {\r
1782                 m_bParentActive = (LOWORD(wParam) != WA_INACTIVE);\r
1783                 if(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues)\r
1784                 {\r
1785                         ShowKeyboardCues(false);   // this will repaint our window\r
1786                 }\r
1787                 else\r
1788                 {\r
1789                         Invalidate();\r
1790                         UpdateWindow();\r
1791                 }\r
1792                 bHandled = FALSE;\r
1793                 return 1;\r
1794         }\r
1795 \r
1796         LRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\r
1797         {\r
1798                 LRESULT lRet = CDRF_DODEFAULT;\r
1799                 bHandled = FALSE;\r
1800                 if(pnmh->hwndFrom == m_hWnd)\r
1801                 {\r
1802                         LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh;\r
1803                         if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)\r
1804                         {\r
1805                                 lRet = CDRF_NOTIFYITEMDRAW;\r
1806                                 bHandled = TRUE;\r
1807                         }\r
1808                         else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)\r
1809                         {\r
1810                                 if(m_bFlatMenus)\r
1811                                 {\r
1812 #ifndef COLOR_MENUHILIGHT\r
1813                                         const int COLOR_MENUHILIGHT = 29;\r
1814 #endif // !COLOR_MENUHILIGHT\r
1815                                         bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED);\r
1816                                         if(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT || \r
1817                                                 (lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED))\r
1818                                         {\r
1819                                                 ::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT));\r
1820                                                 ::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));\r
1821                                                 lpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT);\r
1822                                         }\r
1823                                         else if(bDisabled || !m_bParentActive)\r
1824                                         {\r
1825                                                 lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);\r
1826                                         }\r
1827                                         CDCHandle dc = lpTBCustomDraw->nmcd.hdc;\r
1828                                         dc.SetTextColor(lpTBCustomDraw->clrText);\r
1829                                         dc.SetBkMode(lpTBCustomDraw->nStringBkMode);\r
1830                                         HFONT hFont = GetFont();\r
1831                                         HFONT hFontOld = NULL;\r
1832                                         if(hFont != NULL)\r
1833                                                 hFontOld = dc.SelectFont(hFont);\r
1834                                         const int cchText = 200;\r
1835                                         TCHAR szText[cchText] = { 0 };\r
1836                                         TBBUTTONINFO tbbi = { 0 };\r
1837                                         tbbi.cbSize = sizeof(TBBUTTONINFO);\r
1838                                         tbbi.dwMask = TBIF_TEXT;\r
1839                                         tbbi.pszText = szText;\r
1840                                         tbbi.cchText = cchText;\r
1841                                         GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi);\r
1842                                         dc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));\r
1843                                         if(hFont != NULL)\r
1844                                                 dc.SelectFont(hFontOld);\r
1845                                         lRet = CDRF_SKIPDEFAULT;\r
1846                                         bHandled = TRUE;\r
1847                                 }\r
1848                                 else if(!m_bParentActive)\r
1849                                 {\r
1850                                         lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);\r
1851                                         bHandled = TRUE;\r
1852                                 }\r
1853                         }\r
1854                 }\r
1855                 return lRet;\r
1856         }\r
1857 \r
1858 // Message hook handlers\r
1859         LRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
1860         {\r
1861                 static POINT s_point = { -1, -1 };\r
1862                 DWORD dwPoint = ::GetMessagePos();\r
1863                 POINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) };\r
1864 \r
1865                 bHandled = FALSE;\r
1866                 if(m_bMenuActive)\r
1867                 {\r
1868                         if(::WindowFromPoint(point) == m_hWnd)\r
1869                         {\r
1870                                 ScreenToClient(&point);\r
1871                                 int nHit = HitTest(&point);\r
1872 \r
1873                                 if((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1)\r
1874                                 {\r
1875                                         TBBUTTON tbb = { 0 };\r
1876                                         GetButton(nHit, &tbb);\r
1877                                         if((tbb.fsState & TBSTATE_ENABLED) != 0)\r
1878                                         {\r
1879                                                 m_nNextPopBtn = nHit | 0xFFFF0000;\r
1880                                                 HWND hWndMenu = m_stackMenuWnd.GetCurrent();\r
1881                                                 ATLASSERT(hWndMenu != NULL);\r
1882 \r
1883                                                 // this one is needed to close a menu if mouse button was down\r
1884                                                 ::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y));\r
1885                                                 // this one closes a popup menu\r
1886                                                 ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);\r
1887 \r
1888                                                 bHandled = TRUE;\r
1889                                         }\r
1890                                 }\r
1891                         }\r
1892                 }\r
1893                 else\r
1894                 {\r
1895                         ScreenToClient(&point);\r
1896                 }\r
1897 \r
1898                 s_point = point;\r
1899                 return 0;\r
1900         }\r
1901 \r
1902         LRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1903         {\r
1904                 bHandled = FALSE;\r
1905 #ifdef _CMDBAR_EXTRA_TRACE\r
1906                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam);\r
1907 #endif\r
1908 \r
1909                 if(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)\r
1910                         ShowKeyboardCues(true);\r
1911 \r
1912                 if(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd)\r
1913                 {\r
1914                         m_bAllowKeyboardCues = false;\r
1915                         PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\r
1916                         T* pT = static_cast<T*>(this);\r
1917                         pT->GiveFocusBack();\r
1918                         m_bSkipMsg = true;\r
1919                 }\r
1920                 else\r
1921                 {\r
1922                         if(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues)\r
1923                         {\r
1924                                 m_bAllowKeyboardCues = true;\r
1925                                 ShowKeyboardCues(false);\r
1926                         }\r
1927                         m_uSysKey = (UINT)wParam;\r
1928                 }\r
1929                 return 0;\r
1930         }\r
1931 \r
1932         LRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1933         {\r
1934                 if(!m_bAllowKeyboardCues)\r
1935                         m_bAllowKeyboardCues = true;\r
1936                 bHandled = FALSE;\r
1937                 wParam;\r
1938 #ifdef _CMDBAR_EXTRA_TRACE\r
1939                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam);\r
1940 #endif\r
1941                 return 0;\r
1942         }\r
1943 \r
1944         LRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1945         {\r
1946                 bHandled = FALSE;\r
1947 #ifdef _CMDBAR_EXTRA_TRACE\r
1948                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam);\r
1949 #endif\r
1950 \r
1951                 if(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE)\r
1952                         bHandled = TRUE;\r
1953                 return 0;\r
1954         }\r
1955 \r
1956         LRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
1957         {\r
1958 #ifdef _CMDBAR_EXTRA_TRACE\r
1959                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam);\r
1960 #endif\r
1961                 bHandled = FALSE;\r
1962                 T* pT = static_cast<T*>(this);\r
1963 \r
1964                 if(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1)\r
1965                 {\r
1966                         if(m_bMenuActive && !m_bContextMenu)\r
1967                         {\r
1968                                 int nHot = GetHotItem();\r
1969                                 if(nHot == -1)\r
1970                                         nHot = m_nPopBtn;\r
1971                                 if(nHot == -1)\r
1972                                         nHot = 0;\r
1973                                 SetHotItem(nHot);\r
1974                                 bHandled = TRUE;\r
1975                                 pT->TakeFocus();\r
1976                                 m_bEscapePressed = true; // To keep focus\r
1977                                 m_bSkipPostDown = false;\r
1978                         }\r
1979                         else if(::GetFocus() == m_hWnd && m_wndParent.IsWindow())\r
1980                         {\r
1981                                 SetHotItem(-1);\r
1982                                 pT->GiveFocusBack();\r
1983                                 bHandled = TRUE;\r
1984                         }\r
1985                 }\r
1986                 else if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN)\r
1987                 {\r
1988                         if(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow())\r
1989                         {\r
1990                                 int nHot = GetHotItem();\r
1991                                 if(nHot != -1)\r
1992                                 {\r
1993                                         if(wParam != VK_RETURN)\r
1994                                         {\r
1995                                                 if(!m_bSkipPostDown)\r
1996                                                 {\r
1997 // IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click\r
1998 #if (_WIN32_IE < 0x0500)\r
1999                                                         DWORD dwMajor = 0, dwMinor = 0;\r
2000                                                         ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);\r
2001                                                         if(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80))\r
2002                                                         {\r
2003                                                                 RECT rect;\r
2004                                                                 GetItemRect(nHot, &rect);\r
2005                                                                 PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top));\r
2006                                                         }\r
2007 #endif // (_WIN32_IE < 0x0500)\r
2008                                                         PostMessage(WM_KEYDOWN, VK_DOWN, 0L);\r
2009                                                         m_bSkipPostDown = true;\r
2010                                                 }\r
2011                                                 else\r
2012                                                 {\r
2013                                                         ATLTRACE2(atlTraceUI, 0, _T("CmdBar - skipping posting another VK_DOWN\n"));\r
2014                                                         m_bSkipPostDown = false;\r
2015                                                 }\r
2016                                         }\r
2017                                 }\r
2018                                 else\r
2019                                 {\r
2020                                         ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Can't find hot button\n"));\r
2021                                 }\r
2022                         }\r
2023                         if(wParam == VK_RETURN && m_bMenuActive)\r
2024                         {\r
2025                                 PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\r
2026                                 m_nNextPopBtn = -1;\r
2027                                 pT->GiveFocusBack();\r
2028                         }\r
2029                 }\r
2030                 else if(wParam == VK_LEFT || wParam == VK_RIGHT)\r
2031                 {\r
2032                         WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;\r
2033                         WPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT;\r
2034 \r
2035                         if(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem))\r
2036                         {\r
2037                                 bool bAction = false;\r
2038                                 if(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1)\r
2039                                 {\r
2040                                         m_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn);\r
2041                                         if(m_nNextPopBtn != -1)\r
2042                                                 bAction = true;\r
2043                                 }\r
2044                                 else if(wParam == wpNext)\r
2045                                 {\r
2046                                         m_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn);\r
2047                                         if(m_nNextPopBtn != -1)\r
2048                                                 bAction = true;\r
2049                                 }\r
2050                                 HWND hWndMenu = m_stackMenuWnd.GetCurrent();\r
2051                                 ATLASSERT(hWndMenu != NULL);\r
2052 \r
2053                                 // Close the popup menu\r
2054                                 if(bAction)\r
2055                                 {\r
2056                                         ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);\r
2057                                         if(wParam == wpNext)\r
2058                                         {\r
2059                                                 int cItem = m_stackMenuWnd.GetSize() - 1;\r
2060                                                 while(cItem >= 0)\r
2061                                                 {\r
2062                                                         hWndMenu = m_stackMenuWnd[cItem];\r
2063                                                         if(hWndMenu != NULL)\r
2064                                                                 ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);\r
2065                                                         cItem--;\r
2066                                                 }\r
2067                                         }\r
2068 #if (_WIN32_IE >= 0x0500)\r
2069                                         if(m_nNextPopBtn == -2)\r
2070                                         {\r
2071                                                 m_nNextPopBtn = -1;\r
2072                                                 pT->DisplayChevronMenu();\r
2073                                         }\r
2074 #endif // (_WIN32_IE >= 0x0500)\r
2075                                         bHandled = TRUE;\r
2076                                 }\r
2077                         }\r
2078                 }\r
2079                 return 0;\r
2080         }\r
2081 \r
2082         LRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
2083         {\r
2084 #ifdef _CMDBAR_EXTRA_TRACE\r
2085                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_NEXTMENU\n"));\r
2086 #endif\r
2087                 bHandled = FALSE;\r
2088                 return 1;\r
2089         }\r
2090 \r
2091         LRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
2092         {\r
2093 #ifdef _CMDBAR_EXTRA_TRACE\r
2094                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam);\r
2095 #endif\r
2096                 bHandled = (wParam == VK_ESCAPE);\r
2097                 return 0;\r
2098         }\r
2099 \r
2100 // Implementation - ownerdraw overrideables and helpers\r
2101         void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)\r
2102         {\r
2103                 T* pT = static_cast<T*>(this);\r
2104                 if(m_bFlatMenus)\r
2105                         pT->DrawItemFlat(lpDrawItemStruct);\r
2106                 else\r
2107                         pT->DrawItem3D(lpDrawItemStruct);\r
2108 \r
2109         }\r
2110 \r
2111         void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct)\r
2112         {\r
2113                 _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;\r
2114                 CDCHandle dc = lpDrawItemStruct->hDC;\r
2115                 const RECT& rcItem = lpDrawItemStruct->rcItem;\r
2116                 T* pT = static_cast<T*>(this);\r
2117 \r
2118                 if(pmd->fType & MFT_SEPARATOR)\r
2119                 {\r
2120                         // draw separator\r
2121                         RECT rc = rcItem;\r
2122                         rc.top += (rc.bottom - rc.top) / 2;      // vertical center\r
2123                         dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP);   // draw separator line\r
2124                 }\r
2125                 else            // not a separator\r
2126                 {\r
2127                         BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;\r
2128                         BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;\r
2129                         BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;\r
2130                         BOOL bHasImage = FALSE;\r
2131 \r
2132                         if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)\r
2133                                 bSelected = FALSE;\r
2134                         RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy };   // button rect\r
2135                         ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2);          // center vertically\r
2136 \r
2137                         int iButton = pmd->iButton;\r
2138                         if(iButton >= 0)\r
2139                         {\r
2140                                 bHasImage = TRUE;\r
2141 \r
2142                                 // calc drawing point\r
2143                                 SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };\r
2144                                 sz.cx /= 2;\r
2145                                 sz.cy /= 2;\r
2146                                 POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };\r
2147 \r
2148                                 // fill background depending on state\r
2149                                 if(!bChecked || (bSelected && !bDisabled))\r
2150                                 {\r
2151                                         if(!bDisabled)\r
2152                                                 dc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU);\r
2153                                         else\r
2154                                                 dc.FillRect(&rcButn, COLOR_MENU);\r
2155                                 }\r
2156                                 else\r
2157                                 {\r
2158                                         COLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));\r
2159                                         COLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));\r
2160                                         CBrush hbr(CDCHandle::GetHalftoneBrush());\r
2161                                         dc.SetBrushOrg(rcButn.left, rcButn.top);\r
2162                                         dc.FillRect(&rcButn, hbr);\r
2163                                         dc.SetTextColor(crTxt);\r
2164                                         dc.SetBkColor(crBk);\r
2165                                 }\r
2166 \r
2167                                 // draw disabled or normal\r
2168                                 if(!bDisabled)\r
2169                                 {\r
2170                                         // draw pushed-in or popped-out edge\r
2171                                         if(bSelected || bChecked)\r
2172                                         {\r
2173                                                 RECT rc2 = rcButn;\r
2174                                                 dc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT);\r
2175                                         }\r
2176                                         // draw the image\r
2177                                         ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);\r
2178                                 }\r
2179                                 else\r
2180                                 {\r
2181                                         HBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU);\r
2182                                         pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground);\r
2183                                 }\r
2184                         }\r
2185                         else\r
2186                         {\r
2187                                 // no image - look for custom checked/unchecked bitmaps\r
2188                                 CMenuItemInfo info;\r
2189                                 info.fMask = MIIM_CHECKMARKS | MIIM_TYPE;\r
2190                                 ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);\r
2191                                 if(bChecked || info.hbmpUnchecked != NULL)\r
2192                                 {\r
2193                                         BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);\r
2194                                         bHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);\r
2195                                 }\r
2196                         }\r
2197 \r
2198                         // draw item text\r
2199                         int cxButn = m_szButton.cx;\r
2200                         COLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);\r
2201                         if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)\r
2202                         {\r
2203                                 RECT rcBG = rcItem;\r
2204                                 if(bHasImage)\r
2205                                         rcBG.left += cxButn + s_kcxGap;\r
2206                                 dc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);\r
2207                         }\r
2208 \r
2209                         // calc text rectangle and colors\r
2210                         RECT rcText = rcItem;\r
2211                         rcText.left += cxButn + s_kcxGap + s_kcxTextMargin;\r
2212                         rcText.right -= cxButn;\r
2213                         dc.SetBkMode(TRANSPARENT);\r
2214                         COLORREF colorText = ::GetSysColor(bDisabled ?  (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));\r
2215 \r
2216                         // font already selected by Windows\r
2217                         if(bDisabled && (!bSelected || colorText == colorBG))\r
2218                         {\r
2219                                 // disabled - draw shadow text shifted down and right 1 pixel (unles selected)\r
2220                                 RECT rcDisabled = rcText;\r
2221                                 ::OffsetRect(&rcDisabled, 1, 1);\r
2222                                 pT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT));\r
2223                         }\r
2224                         pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!\r
2225                 }\r
2226         }\r
2227 \r
2228         void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct)\r
2229         {\r
2230                 _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;\r
2231                 CDCHandle dc = lpDrawItemStruct->hDC;\r
2232                 const RECT& rcItem = lpDrawItemStruct->rcItem;\r
2233                 T* pT = static_cast<T*>(this);\r
2234 \r
2235 #ifndef COLOR_MENUHILIGHT\r
2236                 const int COLOR_MENUHILIGHT = 29;\r
2237 #endif // !COLOR_MENUHILIGHT\r
2238 \r
2239                 BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;\r
2240                 BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;\r
2241                 BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;\r
2242 \r
2243                 // paint background\r
2244                 if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)\r
2245                 {\r
2246                         if(bSelected)\r
2247                         {\r
2248                                 dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT));\r
2249                                 dc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT));\r
2250                         }\r
2251                         else\r
2252                         {\r
2253                                 dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU));\r
2254                         }\r
2255                 }\r
2256 \r
2257                 if(pmd->fType & MFT_SEPARATOR)\r
2258                 {\r
2259                         // draw separator\r
2260                         RECT rc = rcItem;\r
2261                         rc.top += (rc.bottom - rc.top) / 2;      // vertical center\r
2262                         dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP);   // draw separator line\r
2263                 }\r
2264                 else            // not a separator\r
2265                 {\r
2266                         if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)\r
2267                                 bSelected = FALSE;\r
2268                         RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy };   // button rect\r
2269                         ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2);          // center vertically\r
2270 \r
2271                         // draw background and border for checked items\r
2272                         if(bChecked)\r
2273                         {\r
2274                                 RECT rcCheck = rcButn;\r
2275                                 ::InflateRect(&rcCheck, -1, -1);\r
2276                                 if(bSelected)\r
2277                                         dc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU));\r
2278                                 dc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT));\r
2279                         }\r
2280 \r
2281                         int iButton = pmd->iButton;\r
2282                         if(iButton >= 0)\r
2283                         {\r
2284                                 // calc drawing point\r
2285                                 SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };\r
2286                                 sz.cx /= 2;\r
2287                                 sz.cy /= 2;\r
2288                                 POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };\r
2289 \r
2290                                 // draw disabled or normal\r
2291                                 if(!bDisabled)\r
2292                                 {\r
2293                                         ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);\r
2294                                 }\r
2295                                 else\r
2296                                 {\r
2297                                         HBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU);\r
2298                                         HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW);\r
2299                                         pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage);\r
2300                                 }\r
2301                         }\r
2302                         else\r
2303                         {\r
2304                                 // no image - look for custom checked/unchecked bitmaps\r
2305                                 CMenuItemInfo info;\r
2306                                 info.fMask = MIIM_CHECKMARKS | MIIM_TYPE;\r
2307                                 ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);\r
2308                                 if(bChecked || info.hbmpUnchecked != NULL)\r
2309                                 {\r
2310                                         BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);\r
2311                                         pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);\r
2312                                 }\r
2313                         }\r
2314 \r
2315                         // draw item text\r
2316                         int cxButn = m_szButton.cx;\r
2317                         // calc text rectangle and colors\r
2318                         RECT rcText = rcItem;\r
2319                         rcText.left += cxButn + s_kcxGap + s_kcxTextMargin;\r
2320                         rcText.right -= cxButn;\r
2321                         dc.SetBkMode(TRANSPARENT);\r
2322                         COLORREF colorText = ::GetSysColor(bDisabled ?  (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));\r
2323 \r
2324                         pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!\r
2325                 }\r
2326         }\r
2327 \r
2328         void DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color)\r
2329         {\r
2330                 int nTab = -1;\r
2331                 for(int i = 0; i < lstrlen(lpstrText); i++)\r
2332                 {\r
2333                         if(lpstrText[i] == _T('\t'))\r
2334                         {\r
2335                                 nTab = i;\r
2336                                 break;\r
2337                         }\r
2338                 }\r
2339                 dc.SetTextColor(color);\r
2340                 dc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));\r
2341                 if(nTab != -1)\r
2342                         dc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));\r
2343         }\r
2344 \r
2345         void DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point,\r
2346                         HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE),\r
2347                         HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),\r
2348                         HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))\r
2349         {\r
2350 #if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\r
2351                 if(m_bAlphaImages)\r
2352                 {\r
2353                         IMAGELISTDRAWPARAMS ildp = { 0 };\r
2354                         ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);\r
2355                         ildp.himl = m_hImageList;\r
2356                         ildp.i = nImage;\r
2357                         ildp.hdcDst = dc;\r
2358                         ildp.x = point.x;\r
2359                         ildp.y = point.y;\r
2360                         ildp.cx = 0;\r
2361                         ildp.cy = 0;\r
2362                         ildp.xBitmap = 0;\r
2363                         ildp.yBitmap = 0;\r
2364                         ildp.fStyle = ILD_TRANSPARENT;\r
2365                         ildp.fState = ILS_SATURATE;\r
2366                         ildp.Frame = 0;\r
2367                         ::ImageList_DrawIndirect(&ildp);\r
2368                 }\r
2369                 else\r
2370 #endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\r
2371                 {\r
2372                         // create memory DC\r
2373                         CDC dcMem;\r
2374                         dcMem.CreateCompatibleDC(dc);\r
2375                         // create mono or color bitmap\r
2376                         CBitmap bmp;\r
2377                         bmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy);\r
2378                         ATLASSERT(bmp.m_hBitmap != NULL);\r
2379                         // draw image into memory DC--fill BG white first\r
2380                         HBITMAP hBmpOld = dcMem.SelectBitmap(bmp);\r
2381                         dcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS);\r
2382                         // If white is the text color, we can't use the normal painting since\r
2383                         // it would blend with the WHITENESS, but the mask is OK\r
2384                         UINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL;\r
2385                         ::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle);\r
2386                         dc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage);\r
2387                         dcMem.SelectBitmap(hBmpOld);   // restore\r
2388                 }\r
2389         }\r
2390 \r
2391         // old name\r
2392         BOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)\r
2393         {\r
2394                 return DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck);\r
2395         }\r
2396 \r
2397         BOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)\r
2398         {\r
2399                 // get checkmark bitmap, if none, use Windows standard\r
2400                 SIZE size = { 0, 0 };\r
2401                 CBitmapHandle bmp = hBmpCheck;\r
2402                 if(hBmpCheck != NULL)\r
2403                 {\r
2404                         bmp.GetSize(size);\r
2405                 }\r
2406                 else\r
2407                 {\r
2408                         size.cx = ::GetSystemMetrics(SM_CXMENUCHECK); \r
2409                         size.cy = ::GetSystemMetrics(SM_CYMENUCHECK); \r
2410                         bmp.CreateCompatibleBitmap(dc, size.cx, size.cy);\r
2411                         ATLASSERT(bmp.m_hBitmap != NULL);\r
2412                 }\r
2413                 // center bitmap in caller's rectangle\r
2414                 RECT rcDest = rc;\r
2415                 if((rc.right - rc.left) > size.cx)\r
2416                 {\r
2417                         rcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2;\r
2418                         rcDest.right = rcDest.left + size.cx;\r
2419                 }\r
2420                 if((rc.bottom - rc.top) > size.cy)\r
2421                 {\r
2422                         rcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2;\r
2423                         rcDest.bottom = rcDest.top + size.cy;\r
2424                 }\r
2425                 // paint background\r
2426                 if(!m_bFlatMenus)\r
2427                 {\r
2428                         if(bSelected && !bDisabled)\r
2429                         {\r
2430                                 dc.FillRect(&rcDest, COLOR_MENU);\r
2431                         }\r
2432                         else\r
2433                         {\r
2434                                 COLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));\r
2435                                 COLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));\r
2436                                 CBrush hbr(CDCHandle::GetHalftoneBrush());\r
2437                                 dc.SetBrushOrg(rcDest.left, rcDest.top);\r
2438                                 dc.FillRect(&rcDest, hbr);\r
2439                                 dc.SetTextColor(clrTextOld);\r
2440                                 dc.SetBkColor(clrBkOld);\r
2441                         }\r
2442                 }\r
2443 \r
2444                 // create source image\r
2445                 CDC dcSource;\r
2446                 dcSource.CreateCompatibleDC(dc);\r
2447                 HBITMAP hBmpOld = dcSource.SelectBitmap(bmp);\r
2448                 // set colors\r
2449                 const COLORREF clrBlack = RGB(0, 0, 0);\r
2450                 const COLORREF clrWhite = RGB(255, 255, 255);\r
2451                 COLORREF clrTextOld = dc.SetTextColor(clrBlack);\r
2452                 COLORREF clrBkOld = dc.SetBkColor(clrWhite);\r
2453                 // create mask\r
2454                 CDC dcMask;\r
2455                 dcMask.CreateCompatibleDC(dc);\r
2456                 CBitmap bmpMask;\r
2457                 bmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL);\r
2458                 HBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask);\r
2459 \r
2460                 // draw the checkmark transparently\r
2461                 int cx = rcDest.right - rcDest.left;\r
2462                 int cy = rcDest.bottom - rcDest.top;\r
2463                 if(hBmpCheck != NULL)\r
2464                 {\r
2465                         // build mask based on transparent color        \r
2466                         dcSource.SetBkColor(m_clrMask);\r
2467                         dcMask.SetBkColor(clrBlack);\r
2468                         dcMask.SetTextColor(clrWhite);\r
2469                         dcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY);\r
2470                         // draw bitmap using the mask\r
2471                         dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);\r
2472                         dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND);\r
2473                         dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);\r
2474                 }\r
2475                 else\r
2476                 {\r
2477                         const DWORD ROP_DSno = 0x00BB0226L;\r
2478                         const DWORD ROP_DSa = 0x008800C6L;\r
2479                         const DWORD ROP_DSo = 0x00EE0086L;\r
2480                         const DWORD ROP_DSna = 0x00220326L;\r
2481 \r
2482                         // draw mask\r
2483                         RECT rcSource = { 0, 0, min(size.cx, rc.right - rc.left), min(size.cy, rc.bottom - rc.top) };\r
2484                         dcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK);\r
2485 \r
2486                         // draw shadow if disabled\r
2487                         if(!m_bFlatMenus && bDisabled)\r
2488                         {\r
2489                                 // offset by one pixel\r
2490                                 int x = rcDest.left + 1;\r
2491                                 int y = rcDest.top + 1;\r
2492                                 // paint source bitmap\r
2493                                 const int nColor = COLOR_3DHILIGHT;\r
2494                                 dcSource.FillRect(&rcSource, nColor);\r
2495                                 // draw checkmark - special case black and white colors\r
2496                                 COLORREF clrCheck = ::GetSysColor(nColor);\r
2497                                 if(clrCheck == clrWhite)\r
2498                                 {\r
2499                                         dc.BitBlt(x, y, cx, cy, dcMask,  0, 0,   ROP_DSno);\r
2500                                         dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa);\r
2501                                 }\r
2502                                 else\r
2503                                 {\r
2504                                         if(clrCheck != clrBlack)\r
2505                                         {\r
2506                                                 ATLASSERT(dcSource.GetTextColor() == clrBlack);\r
2507                                                 ATLASSERT(dcSource.GetBkColor() == clrWhite);\r
2508                                                 dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);\r
2509                                         }\r
2510                                         dc.BitBlt(x, y, cx, cy, dcMask,  0,  0,  ROP_DSa);\r
2511                                         dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo);\r
2512                                 }\r
2513                         }\r
2514 \r
2515                         // paint source bitmap\r
2516                         const int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT;\r
2517                         dcSource.FillRect(&rcSource, nColor);\r
2518                         // draw checkmark - special case black and white colors\r
2519                         COLORREF clrCheck = ::GetSysColor(nColor);\r
2520                         if(clrCheck == clrWhite)\r
2521                         {\r
2522                                 dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask,  0, 0,   ROP_DSno);\r
2523                                 dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa);\r
2524                         }\r
2525                         else\r
2526                         {\r
2527                                 if(clrCheck != clrBlack)\r
2528                                 {\r
2529                                         ATLASSERT(dcSource.GetTextColor() == clrBlack);\r
2530                                         ATLASSERT(dcSource.GetBkColor() == clrWhite);\r
2531                                         dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);\r
2532                                 }\r
2533                                 dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask,  0,  0,  ROP_DSa);\r
2534                                 dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo);\r
2535                         }\r
2536                 }\r
2537                 // restore all\r
2538                 dc.SetTextColor(clrTextOld);\r
2539                 dc.SetBkColor(clrBkOld);\r
2540                 dcSource.SelectBitmap(hBmpOld);\r
2541                 dcMask.SelectBitmap(hBmpOld1);\r
2542                 if(hBmpCheck == NULL)\r
2543                         bmp.DeleteObject();\r
2544                 // draw pushed-in hilight\r
2545                 if(!m_bFlatMenus && !bDisabled)\r
2546                 {\r
2547                         if(rc.right - rc.left > size.cx)\r
2548                                 ::InflateRect(&rcDest, 1,1);   // inflate checkmark by one pixel all around\r
2549                         dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);\r
2550                 }\r
2551 \r
2552                 return TRUE;\r
2553         }\r
2554 \r
2555         void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)\r
2556         {\r
2557                 _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;\r
2558 \r
2559                 if(pmd->fType & MFT_SEPARATOR)   // separator - use half system height and zero width\r
2560                 {\r
2561                         lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2;\r
2562                         lpMeasureItemStruct->itemWidth  = 0;\r
2563                 }\r
2564                 else\r
2565                 {\r
2566                         // compute size of text - use DrawText with DT_CALCRECT\r
2567                         CWindowDC dc(NULL);\r
2568                         CFont fontBold;\r
2569                         HFONT hOldFont = NULL;\r
2570                         if(pmd->fState & MFS_DEFAULT)\r
2571                         {\r
2572                                 // need bold version of font\r
2573                                 LOGFONT lf = { 0 };\r
2574                                 m_fontMenu.GetLogFont(lf);\r
2575                                 lf.lfWeight += 200;\r
2576                                 fontBold.CreateFontIndirect(&lf);\r
2577                                 ATLASSERT(fontBold.m_hFont != NULL);\r
2578                                 hOldFont = dc.SelectFont(fontBold);\r
2579                         }\r
2580                         else\r
2581                         {\r
2582                                 hOldFont = dc.SelectFont(m_fontMenu);\r
2583                         }\r
2584 \r
2585                         RECT rcText = { 0, 0, 0, 0 };\r
2586                         dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);\r
2587                         int cx = rcText.right - rcText.left;\r
2588                         dc.SelectFont(hOldFont);\r
2589 \r
2590                         LOGFONT lf = { 0 };\r
2591                         m_fontMenu.GetLogFont(lf);\r
2592                         int cy = lf.lfHeight;\r
2593                         if(cy < 0)\r
2594                                 cy = -cy;\r
2595                         const int cyMargin = 8;\r
2596                         cy += cyMargin;\r
2597 \r
2598                         // height of item is the bigger of these two\r
2599                         lpMeasureItemStruct->itemHeight = max(cy, (int)m_szButton.cy);\r
2600 \r
2601                         // width is width of text plus a bunch of stuff\r
2602                         cx += 2 * s_kcxTextMargin;   // L/R margin for readability\r
2603                         cx += s_kcxGap;              // space between button and menu text\r
2604                         cx += 2 * m_szButton.cx;     // button width (L=button; R=empty margin)\r
2605                         cx += m_cxExtraSpacing;      // extra between item text and accelerator keys\r
2606 \r
2607                         // Windows adds 1 to returned value\r
2608                         cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1;\r
2609                         lpMeasureItemStruct->itemWidth = cx;   // done deal\r
2610                 }\r
2611         }\r
2612 \r
2613 // Implementation - Hook procs\r
2614         static LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam)\r
2615         {\r
2616                 const int cchClassName = 7;\r
2617                 TCHAR szClassName[cchClassName] = { 0 };\r
2618 \r
2619                 if(nCode == HCBT_CREATEWND)\r
2620                 {\r
2621                         HWND hWndMenu = (HWND)wParam;\r
2622 #ifdef _CMDBAR_EXTRA_TRACE\r
2623                         ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu);\r
2624 #endif\r
2625 \r
2626                         ::GetClassName(hWndMenu, szClassName, cchClassName);\r
2627                         if(!lstrcmp(_T("#32768"), szClassName))\r
2628                                 s_pCurrentBar->m_stackMenuWnd.Push(hWndMenu);\r
2629                 }\r
2630                 else if(nCode == HCBT_DESTROYWND)\r
2631                 {\r
2632                         HWND hWndMenu = (HWND)wParam;\r
2633 #ifdef _CMDBAR_EXTRA_TRACE\r
2634                         ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu);\r
2635 #endif\r
2636 \r
2637                         ::GetClassName(hWndMenu, szClassName, cchClassName);\r
2638                         if(!lstrcmp(_T("#32768"), szClassName))\r
2639                         {\r
2640                                 ATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent());\r
2641                                 s_pCurrentBar->m_stackMenuWnd.Pop();\r
2642                         }\r
2643                 }\r
2644 \r
2645                 return ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam);\r
2646         }\r
2647 \r
2648         static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)\r
2649         {\r
2650                 LPMSG pMsg = (LPMSG)lParam;\r
2651 \r
2652                 if(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG)\r
2653                 {\r
2654                         CCommandBarCtrlBase* pCmdBar = NULL;\r
2655                         HWND hWnd = pMsg->hwnd;\r
2656                         DWORD dwPID = 0;\r
2657                         while(pCmdBar == NULL && hWnd != NULL)\r
2658                         {\r
2659                                 pCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L);\r
2660                                 hWnd = ::GetParent(hWnd);\r
2661                         }\r
2662 \r
2663                         if(pCmdBar != NULL && dwPID == GetCurrentProcessId())\r
2664                         {\r
2665                                 pCmdBar->m_hWndHook = pMsg->hwnd;\r
2666                                 ATLASSERT(pCmdBar->IsCommandBarBase());\r
2667 \r
2668                                 if(::IsWindow(pCmdBar->m_hWnd))\r
2669                                         pCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);\r
2670                                 else\r
2671                                         ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n"));\r
2672                         }\r
2673                 }\r
2674 \r
2675                 LRESULT lRet = 0;\r
2676                 ATLASSERT(s_pmapMsgHook != NULL);\r
2677                 if(s_pmapMsgHook != NULL)\r
2678                 {\r
2679                         DWORD dwThreadID = ::GetCurrentThreadId();\r
2680                         _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);\r
2681                         if(pData != NULL)\r
2682                         {\r
2683                                 lRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam);\r
2684                         }\r
2685                 }\r
2686                 return lRet;\r
2687         }\r
2688 \r
2689 // Implementation\r
2690         void DoPopupMenu(int nIndex, bool bAnimate)\r
2691         {\r
2692 #ifdef _CMDBAR_EXTRA_TRACE\r
2693                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate ? "true" : "false");\r
2694 #endif\r
2695 \r
2696                 // Menu animation flags\r
2697 #ifndef TPM_VERPOSANIMATION\r
2698                 const UINT TPM_VERPOSANIMATION = 0x1000L;\r
2699 #endif\r
2700 #ifndef TPM_NOANIMATION\r
2701                 const UINT TPM_NOANIMATION = 0x4000L;\r
2702 #endif\r
2703                 T* pT = static_cast<T*>(this);\r
2704 \r
2705                 // get popup menu and it's position\r
2706                 RECT rect = { 0 };\r
2707                 GetItemRect(nIndex, &rect);\r
2708                 POINT pt = { rect.left, rect.bottom };\r
2709                 MapWindowPoints(NULL, &pt, 1);\r
2710                 MapWindowPoints(NULL, &rect);\r
2711                 TPMPARAMS TPMParams = { 0 };\r
2712                 TPMParams.cbSize = sizeof(TPMPARAMS);\r
2713                 TPMParams.rcExclude = rect;\r
2714                 HMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex);\r
2715                 ATLASSERT(hMenuPopup != NULL);\r
2716 \r
2717                 // get button ID\r
2718                 TBBUTTON tbb = { 0 };\r
2719                 GetButton(nIndex, &tbb);\r
2720                 int nCmdID = tbb.idCommand;\r
2721 \r
2722                 m_nPopBtn = nIndex;   // remember current button's index\r
2723 \r
2724                 // press button and display popup menu\r
2725                 PressButton(nCmdID, TRUE);\r
2726                 SetHotItem(nCmdID);\r
2727                 pT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN |\r
2728                         (s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams);\r
2729                 PressButton(nCmdID, FALSE);\r
2730                 if(::GetFocus() != m_hWnd)\r
2731                         SetHotItem(-1);\r
2732 \r
2733                 m_nPopBtn = -1;   // restore\r
2734 \r
2735                 // eat next message if click is on the same button\r
2736                 MSG msg = { 0 };\r
2737                 if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt))\r
2738                         ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);\r
2739 \r
2740                 // check if another popup menu should be displayed\r
2741                 if(m_nNextPopBtn != -1)\r
2742                 {\r
2743                         PostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF);\r
2744                         if(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem)\r
2745                                 PostMessage(WM_KEYDOWN, VK_DOWN, 0);\r
2746                         m_nNextPopBtn = -1;\r
2747                 }\r
2748                 else\r
2749                 {\r
2750                         m_bContextMenu = false;\r
2751                         // If user didn't hit escape, give focus back\r
2752                         if(!m_bEscapePressed)\r
2753                         {\r
2754                                 if(m_bUseKeyboardCues && m_bShowKeyboardCues)\r
2755                                         m_bAllowKeyboardCues = false;\r
2756                                 pT->GiveFocusBack();\r
2757                         }\r
2758                         else\r
2759                         {\r
2760                                 SetHotItem(nCmdID);\r
2761                                 SetAnchorHighlight(TRUE);\r
2762                         }\r
2763                 }\r
2764         }\r
2765 \r
2766         BOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)\r
2767         {\r
2768                 CMenuHandle menuPopup = hMenu;\r
2769 \r
2770                 CWindowCreateCriticalSectionLock lock;\r
2771                 if(FAILED(lock.Lock()))\r
2772                 {\r
2773                         ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n"));\r
2774                         ATLASSERT(FALSE);\r
2775                         return FALSE;\r
2776                 }\r
2777 \r
2778                 ATLASSERT(s_hCreateHook == NULL);\r
2779 \r
2780                 s_pCurrentBar = static_cast<CCommandBarCtrlBase*>(this);\r
2781 \r
2782                 s_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId());\r
2783                 ATLASSERT(s_hCreateHook != NULL);\r
2784 \r
2785                 m_bPopupItem = false;\r
2786                 m_bMenuActive = true;\r
2787 \r
2788                 BOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams);\r
2789                 m_bMenuActive = false;\r
2790 \r
2791                 ::UnhookWindowsHookEx(s_hCreateHook);\r
2792 \r
2793                 s_hCreateHook = NULL;\r
2794                 s_pCurrentBar = NULL;\r
2795 \r
2796                 lock.Unlock();\r
2797 \r
2798                 // cleanup - convert menus back to original state\r
2799 #ifdef _CMDBAR_EXTRA_TRACE\r
2800                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - TrackPopupMenu - cleanup\n"));\r
2801 #endif\r
2802 \r
2803                 ATLASSERT(m_stackMenuWnd.GetSize() == 0);\r
2804 \r
2805                 UpdateWindow();\r
2806                 ATL::CWindow wndTL = GetTopLevelParent();\r
2807                 wndTL.UpdateWindow();\r
2808 \r
2809                 // restore the menu items to the previous state for all menus that were converted\r
2810                 if(m_bImagesVisible)\r
2811                 {\r
2812                         HMENU hMenuSav = NULL;\r
2813                         while((hMenuSav = m_stackMenuHandle.Pop()) != NULL)\r
2814                         {\r
2815                                 menuPopup = hMenuSav;\r
2816                                 BOOL bRet = FALSE;\r
2817                                 // restore state and delete menu item data\r
2818                                 for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)\r
2819                                 {\r
2820                                         CMenuItemInfo mii;\r
2821                                         mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;\r
2822                                         bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);\r
2823                                         ATLASSERT(bRet);\r
2824 \r
2825                                         _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;\r
2826                                         if(pMI != NULL && pMI->IsCmdBarMenuItem())\r
2827                                         {\r
2828                                                 mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;\r
2829                                                 mii.fType = pMI->fType;\r
2830                                                 mii.fState = pMI->fState;\r
2831                                                 mii.dwTypeData = pMI->lpstrText;\r
2832                                                 mii.cch = lstrlen(pMI->lpstrText);\r
2833                                                 mii.dwItemData = NULL;\r
2834 \r
2835                                                 bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);\r
2836                                                 // this one triggers WM_MEASUREITEM\r
2837                                                 menuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText);\r
2838                                                 ATLASSERT(bRet);\r
2839 \r
2840                                                 delete [] pMI->lpstrText;\r
2841                                                 delete pMI;\r
2842                                         }\r
2843                                 }\r
2844                         }\r
2845                 }\r
2846                 return bTrackRet;\r
2847         }\r
2848 \r
2849         int GetPreviousMenuItem(int nBtn) const\r
2850         {\r
2851                 if(nBtn == -1)\r
2852                         return -1;\r
2853 #if (_WIN32_IE >= 0x0500)\r
2854                 RECT rcClient;\r
2855                 GetClientRect(&rcClient);\r
2856 #endif // (_WIN32_IE >= 0x0500)\r
2857                 int nNextBtn;\r
2858                 for(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--)\r
2859                 {\r
2860                         if(nNextBtn < 0)\r
2861                                 nNextBtn = ::GetMenuItemCount(m_hMenu) - 1;\r
2862                         TBBUTTON tbb = { 0 };\r
2863                         GetButton(nNextBtn, &tbb);\r
2864 #if (_WIN32_IE >= 0x0500)\r
2865                         RECT rcBtn;\r
2866                         GetItemRect(nNextBtn, &rcBtn);\r
2867                         if(rcBtn.right > rcClient.right)\r
2868                         {\r
2869                                 nNextBtn = -2;   // chevron\r
2870                                 break;\r
2871                         }\r
2872 #endif // (_WIN32_IE >= 0x0500)\r
2873                         if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)\r
2874                                 break;\r
2875                 }\r
2876                 return (nNextBtn != nBtn) ? nNextBtn : -1;\r
2877         }\r
2878 \r
2879         int GetNextMenuItem(int nBtn) const\r
2880         {\r
2881                 if(nBtn == -1)\r
2882                         return -1;\r
2883 #if (_WIN32_IE >= 0x0500)\r
2884                 RECT rcClient = { 0 };\r
2885                 GetClientRect(&rcClient);\r
2886 #endif // (_WIN32_IE >= 0x0500)\r
2887                 int nNextBtn = 0;\r
2888                 int nCount = ::GetMenuItemCount(m_hMenu);\r
2889                 for(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++)\r
2890                 {\r
2891                         if(nNextBtn >= nCount)\r
2892                                 nNextBtn = 0;\r
2893                         TBBUTTON tbb = { 0 };\r
2894                         GetButton(nNextBtn, &tbb);\r
2895 #if (_WIN32_IE >= 0x0500)\r
2896                         RECT rcBtn = { 0 };\r
2897                         GetItemRect(nNextBtn, &rcBtn);\r
2898                         if(rcBtn.right > rcClient.right)\r
2899                         {\r
2900                                 nNextBtn = -2;   // chevron\r
2901                                 break;\r
2902                         }\r
2903 #endif // (_WIN32_IE >= 0x0500)\r
2904                         if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)\r
2905                                 break;\r
2906                 }\r
2907                 return (nNextBtn != nBtn) ? nNextBtn : -1;\r
2908         }\r
2909 \r
2910 #if (_WIN32_IE >= 0x0500)\r
2911         bool DisplayChevronMenu()\r
2912         {\r
2913                 // assume we are in a rebar\r
2914                 HWND hWndReBar = GetParent();\r
2915                 int nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);\r
2916                 bool bRet = false;\r
2917                 for(int i = 0; i < nCount; i++)\r
2918                 {\r
2919                         REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE };\r
2920                         BOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi);\r
2921                         if(bRetBandInfo && rbbi.hwndChild == m_hWnd)\r
2922                         {\r
2923                                 if((rbbi.fStyle & RBBS_USECHEVRON) != 0)\r
2924                                 {\r
2925                                         ::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L);\r
2926                                         PostMessage(WM_KEYDOWN, VK_DOWN, 0L);\r
2927                                         bRet = true;\r
2928                                 }\r
2929                                 break;\r
2930                         }\r
2931                 }\r
2932                 return bRet;\r
2933         }\r
2934 #endif // (_WIN32_IE >= 0x0500)\r
2935 \r
2936         void GetSystemSettings()\r
2937         {\r
2938                 // refresh our font\r
2939                 NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\r
2940                 BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);\r
2941                 ATLASSERT(bRet);\r
2942                 if(bRet)\r
2943                 {\r
2944                         LOGFONT logfont = { 0 };\r
2945                         if(m_fontMenu.m_hFont != NULL)\r
2946                                 m_fontMenu.GetLogFont(logfont);\r
2947                         if(logfont.lfHeight != info.lfMenuFont.lfHeight ||\r
2948                            logfont.lfWidth != info.lfMenuFont.lfWidth ||\r
2949                            logfont.lfEscapement != info.lfMenuFont.lfEscapement ||\r
2950                            logfont.lfOrientation != info.lfMenuFont.lfOrientation ||\r
2951                            logfont.lfWeight != info.lfMenuFont.lfWeight ||\r
2952                            logfont.lfItalic != info.lfMenuFont.lfItalic ||\r
2953                            logfont.lfUnderline != info.lfMenuFont.lfUnderline ||\r
2954                            logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut ||\r
2955                            logfont.lfCharSet != info.lfMenuFont.lfCharSet ||\r
2956                            logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision ||\r
2957                            logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision ||\r
2958                            logfont.lfQuality != info.lfMenuFont.lfQuality ||\r
2959                            logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily ||\r
2960                            lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0)\r
2961                         {\r
2962                                 HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);\r
2963                                 ATLASSERT(hFontMenu != NULL);\r
2964                                 if(hFontMenu != NULL)\r
2965                                 {\r
2966                                         if(m_fontMenu.m_hFont != NULL)\r
2967                                                 m_fontMenu.DeleteObject();\r
2968                                         m_fontMenu.Attach(hFontMenu);\r
2969                                         SetFont(m_fontMenu);\r
2970                                         AddStrings(_T("NS\0"));   // for proper item height\r
2971                                         AutoSize();\r
2972                                 }\r
2973                         }\r
2974                 }\r
2975 \r
2976                 // check if we need extra spacing for menu item text\r
2977                 CWindowDC dc(m_hWnd);\r
2978                 HFONT hFontOld = dc.SelectFont(m_fontMenu);\r
2979                 RECT rcText = { 0, 0, 0, 0 };\r
2980                 dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);\r
2981                 if((rcText.right - rcText.left) < 4)\r
2982                 {\r
2983                         ::SetRectEmpty(&rcText);\r
2984                         dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);\r
2985                         m_cxExtraSpacing = rcText.right - rcText.left;\r
2986                 }\r
2987                 else\r
2988                 {\r
2989                         m_cxExtraSpacing = 0;\r
2990                 }\r
2991                 dc.SelectFont(hFontOld);\r
2992 \r
2993                 // get Windows version\r
2994                 OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\r
2995                 ::GetVersionEx(&ovi);\r
2996 \r
2997                 // query keyboard cues mode (Windows 2000 or later)\r
2998                 if(ovi.dwMajorVersion >= 5)\r
2999                 {\r
3000 #ifndef SPI_GETKEYBOARDCUES\r
3001                         const UINT SPI_GETKEYBOARDCUES = 0x100A;\r
3002 #endif // !SPI_GETKEYBOARDCUES\r
3003                         BOOL bRetVal = TRUE;\r
3004                         bRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0);\r
3005                         m_bUseKeyboardCues = (bRet && !bRetVal);\r
3006                         m_bAllowKeyboardCues = true;\r
3007                         ShowKeyboardCues(!m_bUseKeyboardCues);\r
3008                 }\r
3009 \r
3010                 // query flat menu mode (Windows XP or later)\r
3011                 if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5))\r
3012                 {\r
3013 #ifndef SPI_GETFLATMENU\r
3014                         const UINT SPI_GETFLATMENU = 0x1022;\r
3015 #endif // !SPI_GETFLATMENU\r
3016                         BOOL bRetVal = FALSE;\r
3017                         bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0);\r
3018                         m_bFlatMenus = (bRet && bRetVal);\r
3019                 }\r
3020 \r
3021 #if _WTL_CMDBAR_VISTA_MENUS\r
3022                 // check if we should use Vista menus\r
3023                 bool bVistaMenus = (RunTimeHelper::IsVista() && RunTimeHelper::IsCommCtrl6() && ((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0));\r
3024 \r
3025                 if(bVistaMenus)\r
3026                 {\r
3027                         HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));\r
3028                         if(hThemeDLL != NULL)\r
3029                         {\r
3030                                 typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)();\r
3031                                 PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive");\r
3032                                 ATLASSERT(pfnIsThemeActive != NULL);\r
3033                                 bVistaMenus = bVistaMenus && (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE);\r
3034 \r
3035                                 typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)();\r
3036                                 PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed");\r
3037                                 ATLASSERT(pfnIsAppThemed != NULL);\r
3038                                 bVistaMenus = bVistaMenus && (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE);\r
3039 \r
3040                                 ::FreeLibrary(hThemeDLL);\r
3041                         }\r
3042                 }\r
3043 \r
3044                 if(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0))\r
3045                 {\r
3046                         T* pT = static_cast<T*>(this);\r
3047                         pT->_RemoveVistaBitmapsFromMenu();\r
3048                 }\r
3049 \r
3050                 m_bVistaMenus = bVistaMenus;\r
3051 #endif // _WTL_CMDBAR_VISTA_MENUS\r
3052 \r
3053 #ifdef _CMDBAR_EXTRA_TRACE\r
3054                 ATLTRACE2(atlTraceUI, 0, _T("CmdBar - GetSystemSettings:\n     m_bFlatMenus = %s\n     m_bUseKeyboardCues = %s     m_bVistaMenus = %s\n"),\r
3055                         m_bFlatMenus ? "true" : "false", m_bUseKeyboardCues ? "true" : "false", m_bVistaMenus ? "true" : "false");\r
3056 #endif\r
3057         }\r
3058 \r
3059 // Implementation - alternate focus mode support\r
3060         void TakeFocus()\r
3061         {\r
3062                 if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL)\r
3063                         m_hWndFocus = ::GetFocus();\r
3064                 SetFocus();\r
3065         }\r
3066 \r
3067         void GiveFocusBack()\r
3068         {\r
3069                 if(m_bParentActive)\r
3070                 {\r
3071                         if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus))\r
3072                                 ::SetFocus(m_hWndFocus);\r
3073                         else if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow())\r
3074                                 m_wndParent.SetFocus();\r
3075                 }\r
3076                 m_hWndFocus = NULL;\r
3077                 SetAnchorHighlight(FALSE);\r
3078                 if(m_bUseKeyboardCues && m_bShowKeyboardCues)\r
3079                         ShowKeyboardCues(false);\r
3080                 m_bSkipPostDown = false;\r
3081         }\r
3082 \r
3083         void ShowKeyboardCues(bool bShow)\r
3084         {\r
3085                 m_bShowKeyboardCues = bShow;\r
3086                 SetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX);\r
3087                 Invalidate();\r
3088                 UpdateWindow();\r
3089         }\r
3090 \r
3091 // Implementation - internal message helpers\r
3092         static UINT GetAutoPopupMessage()\r
3093         {\r
3094                 static UINT uAutoPopupMessage = 0;\r
3095                 if(uAutoPopupMessage == 0)\r
3096                 {\r
3097                         CStaticDataInitCriticalSectionLock lock;\r
3098                         if(FAILED(lock.Lock()))\r
3099                         {\r
3100                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n"));\r
3101                                 ATLASSERT(FALSE);\r
3102                                 return 0;\r
3103                         }\r
3104 \r
3105                         if(uAutoPopupMessage == 0)\r
3106                                 uAutoPopupMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg"));\r
3107 \r
3108                         lock.Unlock();\r
3109                 }\r
3110                 ATLASSERT(uAutoPopupMessage != 0);\r
3111                 return uAutoPopupMessage;\r
3112         }\r
3113 \r
3114         static UINT GetGetBarMessage()\r
3115         {\r
3116                 static UINT uGetBarMessage = 0;\r
3117                 if(uGetBarMessage == 0)\r
3118                 {\r
3119                         CStaticDataInitCriticalSectionLock lock;\r
3120                         if(FAILED(lock.Lock()))\r
3121                         {\r
3122                                 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n"));\r
3123                                 ATLASSERT(FALSE);\r
3124                                 return 0;\r
3125                         }\r
3126 \r
3127                         if(uGetBarMessage == 0)\r
3128                                 uGetBarMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg"));\r
3129 \r
3130                         lock.Unlock();\r
3131                 }\r
3132                 ATLASSERT(uGetBarMessage != 0);\r
3133                 return uGetBarMessage;\r
3134         }\r
3135 \r
3136 // Implementation\r
3137         bool CreateInternalImageList(int cImages)\r
3138         {\r
3139                 UINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK;\r
3140                 m_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1);\r
3141                 ATLASSERT(m_hImageList != NULL);\r
3142                 return (m_hImageList != NULL);\r
3143         }\r
3144 \r
3145 // Implementation - support for Vista menus\r
3146 #if _WTL_CMDBAR_VISTA_MENUS\r
3147         void _AddVistaBitmapsFromImageList(int nStartIndex, int nCount)\r
3148         {\r
3149                 // Create display compatible memory DC\r
3150                 HDC hDC = ::GetDC(NULL);\r
3151                 CDC dcMem;\r
3152                 dcMem.CreateCompatibleDC(hDC);\r
3153                 HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();\r
3154 \r
3155                 T* pT = static_cast<T*>(this);\r
3156                 // Create bitmaps for all menu items\r
3157                 for(int i = 0; i < nCount; i++)\r
3158                 {\r
3159                         HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, hDC, dcMem);\r
3160                         dcMem.SelectBitmap(hBitmapSave);\r
3161                         m_arrVistaBitmap.Add(hBitmap);\r
3162                 }\r
3163         }\r
3164 \r
3165         void _AddVistaBitmapFromImageList(int nIndex)\r
3166         {\r
3167                 // Create display compatible memory DC\r
3168                 HDC hDC = ::GetDC(NULL);\r
3169                 CDC dcMem;\r
3170                 dcMem.CreateCompatibleDC(hDC);\r
3171                 HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();\r
3172 \r
3173                 // Create bitmap for menu item\r
3174                 T* pT = static_cast<T*>(this);\r
3175                 HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, hDC, dcMem);\r
3176 \r
3177                 // Select saved bitmap back and add bitmap to the array\r
3178                 dcMem.SelectBitmap(hBitmapSave);\r
3179                 m_arrVistaBitmap.Add(hBitmap);\r
3180         }\r
3181 \r
3182         void _ReplaceVistaBitmapFromImageList(int nIndex)\r
3183         {\r
3184                 // Delete existing bitmap\r
3185                 if(m_arrVistaBitmap[nIndex] != NULL)\r
3186                         ::DeleteObject(m_arrVistaBitmap[nIndex]);\r
3187 \r
3188                 // Create display compatible memory DC\r
3189                 HDC hDC = ::GetDC(NULL);\r
3190                 CDC dcMem;\r
3191                 dcMem.CreateCompatibleDC(hDC);\r
3192                 HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();\r
3193 \r
3194                 // Create bitmap for menu item\r
3195                 T* pT = static_cast<T*>(this);\r
3196                 HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, hDC, dcMem);\r
3197 \r
3198                 // Select saved bitmap back and replace bitmap in the array\r
3199                 dcMem.SelectBitmap(hBitmapSave);\r
3200                 m_arrVistaBitmap.SetAtIndex(nIndex, hBitmap);\r
3201         }\r
3202 \r
3203         HBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget)\r
3204         {\r
3205                 // Create 32-bit bitmap\r
3206                 BITMAPINFO bi = { 0 };\r
3207                 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
3208                 bi.bmiHeader.biWidth = m_szBitmap.cx;\r
3209                 bi.bmiHeader.biHeight = m_szBitmap.cy;\r
3210                 bi.bmiHeader.biPlanes = 1;\r
3211                 bi.bmiHeader.biBitCount = 32;\r
3212                 bi.bmiHeader.biCompression = BI_RGB;\r
3213                 bi.bmiHeader.biSizeImage = 0;\r
3214                 bi.bmiHeader.biXPelsPerMeter = 0;\r
3215                 bi.bmiHeader.biYPelsPerMeter = 0;\r
3216                 bi.bmiHeader.biClrUsed = 0;\r
3217                 bi.bmiHeader.biClrImportant = 0;\r
3218                 HBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0);\r
3219                 ATLASSERT(hBitmap != NULL);\r
3220 \r
3221                 // Select bitmap into target DC and draw from image list to it\r
3222                 if(hBitmap != NULL)\r
3223                 {\r
3224                         ::SelectObject(hDCTarget, hBitmap);\r
3225 \r
3226                         IMAGELISTDRAWPARAMS ildp = { 0 };\r
3227                         ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);\r
3228                         ildp.himl = m_hImageList;\r
3229                         ildp.i = nIndex;\r
3230                         ildp.hdcDst = hDCTarget;\r
3231                         ildp.x = 0;\r
3232                         ildp.y = 0;\r
3233                         ildp.cx = 0;\r
3234                         ildp.cy = 0;\r
3235                         ildp.xBitmap = 0;\r
3236                         ildp.yBitmap = 0;\r
3237                         ildp.fStyle = ILD_TRANSPARENT;\r
3238                         ildp.fState = ILS_ALPHA;\r
3239                         ildp.Frame = 255;\r
3240                         ::ImageList_DrawIndirect(&ildp);\r
3241                 }\r
3242 \r
3243                 return hBitmap;\r
3244         }\r
3245 \r
3246         void _RemoveVistaBitmapsFromMenu()\r
3247         {\r
3248                 CMenuHandle menu = m_hMenu;\r
3249                 for(int i = 0; i < m_arrCommand.GetSize(); i++)\r
3250                 {\r
3251                         CMenuItemInfo mii;\r
3252                         mii.fMask = MIIM_BITMAP;\r
3253                         mii.hbmpItem = NULL;\r
3254                         menu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii);\r
3255                 }\r
3256         }\r
3257 #endif // _WTL_CMDBAR_VISTA_MENUS\r
3258 };\r
3259 \r
3260 \r
3261 class CCommandBarCtrl : public CCommandBarCtrlImpl<CCommandBarCtrl>\r
3262 {\r
3263 public:\r
3264         DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName())\r
3265 };\r
3266 \r
3267 \r
3268 ///////////////////////////////////////////////////////////////////////////////\r
3269 // CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps\r
3270 \r
3271 template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>\r
3272 class ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits>\r
3273 {\r
3274 public:\r
3275 // Data members\r
3276         ATL::CContainedWindow m_wndMDIClient;\r
3277         bool m_bChildMaximized;\r
3278         HWND m_hWndChildMaximized;\r
3279         HICON m_hIconChildMaximized;\r
3280         int m_nBtnPressed;\r
3281         int m_nBtnWasPressed;\r
3282 \r
3283         int m_cxyOffset;      // offset between nonclient elements\r
3284         int m_cxIconWidth;    // small icon width\r
3285         int m_cyIconHeight;   // small icon height\r
3286         int m_cxBtnWidth;     // nonclient button width\r
3287         int m_cyBtnHeight;    // nonclient button height\r
3288         int m_cxLeft;         // left nonclient area width\r
3289         int m_cxRight;        // right nonclient area width\r
3290 \r
3291 // Theme declarations and data members\r
3292 #ifndef _WTL_NO_AUTO_THEME\r
3293 #ifndef _UXTHEME_H_\r
3294         typedef HANDLE HTHEME;\r
3295 #endif // !_UXTHEME_H_\r
3296         typedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList);\r
3297         typedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme);\r
3298         typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);\r
3299         typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc);\r
3300 \r
3301         HMODULE m_hThemeDLL;\r
3302         HTHEME m_hTheme;\r
3303         PFN_DrawThemeBackground m_pfnDrawThemeBackground;\r
3304         PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground;\r
3305 #endif // !_WTL_NO_AUTO_THEME\r
3306 \r
3307 // Constructor/destructor\r
3308         CMDICommandBarCtrlImpl() : \r
3309                         m_wndMDIClient(this, 2), m_bChildMaximized(false), \r
3310                         m_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL), \r
3311                         m_nBtnPressed(-1), m_nBtnWasPressed(-1),\r
3312 #ifndef _WTL_NO_AUTO_THEME\r
3313                         m_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL), \r
3314 #endif // !_WTL_NO_AUTO_THEME\r
3315                         m_cxyOffset(2),\r
3316                         m_cxIconWidth(16), m_cyIconHeight(16),\r
3317                         m_cxBtnWidth(16), m_cyBtnHeight(14),\r
3318                         m_cxLeft(20), m_cxRight(55)\r
3319         { }\r
3320 \r
3321         ~CMDICommandBarCtrlImpl()\r
3322         {\r
3323                 if(m_wndMDIClient.IsWindow())\r
3324 /*scary!*/                      m_wndMDIClient.UnsubclassWindow();\r
3325         }\r
3326 \r
3327 // Operations\r
3328         BOOL SetMDIClient(HWND hWndMDIClient)\r
3329         {\r
3330                 ATLASSERT(::IsWindow(m_hWnd));\r
3331                 ATLASSERT(::IsWindow(hWndMDIClient));\r
3332                 if(!::IsWindow(hWndMDIClient))\r
3333                         return FALSE;\r
3334 \r
3335 #ifdef _DEBUG\r
3336                 // BLOCK: Test if the passed window is MDICLIENT\r
3337                 {\r
3338                         LPCTSTR lpszMDIClientClass = _T("MDICLIENT");\r
3339                         const int nNameLen = 9 + 1;   // "MDICLIENT" + NULL\r
3340                         TCHAR szClassName[nNameLen] = { 0 };\r
3341                         ::GetClassName(hWndMDIClient, szClassName, nNameLen);\r
3342                         ATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0);\r
3343                 }\r
3344 #endif // _DEBUG\r
3345 \r
3346                 if(m_wndMDIClient.IsWindow())\r
3347 /*scary!*/              m_wndMDIClient.UnsubclassWindow();\r
3348 \r
3349                 return m_wndMDIClient.SubclassWindow(hWndMDIClient);\r
3350         }\r
3351 \r
3352 // Message maps\r
3353         typedef CCommandBarCtrlImpl< T, TBase, TWinTraits >   _baseClass;\r
3354         BEGIN_MSG_MAP(CMDICommandBarCtrlImpl)\r
3355                 MESSAGE_HANDLER(WM_CREATE, OnCreate)\r
3356                 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)\r
3357 #ifndef _WTL_NO_AUTO_THEME\r
3358                 MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged)\r
3359 #endif // !_WTL_NO_AUTO_THEME\r
3360                 MESSAGE_HANDLER(WM_SIZE, OnSize)\r
3361                 MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)\r
3362                 MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)\r
3363                 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)\r
3364                 MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)\r
3365                 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\r
3366                 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\r
3367                 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)\r
3368                 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)\r
3369                 CHAIN_MSG_MAP(_baseClass)\r
3370         ALT_MSG_MAP(1)   // Parent window messages\r
3371                 MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)\r
3372                 CHAIN_MSG_MAP_ALT(_baseClass, 1)\r
3373         ALT_MSG_MAP(2)   // MDI client window messages\r
3374                 MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)\r
3375                 // no chaining needed since this was moved from the base class here\r
3376         ALT_MSG_MAP(3)   // Message hook messages\r
3377                 MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages)\r
3378                 CHAIN_MSG_MAP_ALT(_baseClass, 3)\r
3379         END_MSG_MAP()\r
3380 \r
3381 // Additional MDI message handlers\r
3382         LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
3383         {\r
3384                 LRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled);\r
3385                 if(lRet == (LRESULT)-1)\r
3386                         return lRet;\r
3387 \r
3388 #ifndef _WTL_NO_AUTO_THEME\r
3389                 // this will fail if theming is not supported\r
3390                 m_hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));\r
3391                 if(m_hThemeDLL != NULL)\r
3392                 {\r
3393                         m_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeBackground");\r
3394                         ATLASSERT(m_pfnDrawThemeBackground != NULL);\r
3395                         if(m_pfnDrawThemeBackground != NULL)\r
3396                         {\r
3397                                 T* pT = static_cast<T*>(this);\r
3398                                 pT->_OpenThemeData();\r
3399                         }\r
3400                         else\r
3401                         {\r
3402                                 ::FreeLibrary(m_hThemeDLL);\r
3403                                 m_hThemeDLL = NULL;\r
3404                         }\r
3405                         m_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeParentBackground");\r
3406                         ATLASSERT(m_pfnDrawThemeParentBackground != NULL);\r
3407                 }\r
3408 #endif // !_WTL_NO_AUTO_THEME\r
3409 \r
3410                 return lRet;\r
3411         }\r
3412 \r
3413         LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
3414         {\r
3415                 LRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled);\r
3416 \r
3417 #ifndef _WTL_NO_AUTO_THEME\r
3418                 if(m_hThemeDLL != NULL)\r
3419                 {\r
3420                         T* pT = static_cast<T*>(this);\r
3421                         pT->_CloseThemeData();\r
3422                         ::FreeLibrary(m_hThemeDLL);\r
3423                         m_hThemeDLL = NULL;\r
3424                 }\r
3425 #endif // !_WTL_NO_AUTO_THEME\r
3426 \r
3427                 return lRet;\r
3428         }\r
3429 \r
3430 #ifndef _WTL_NO_AUTO_THEME\r
3431         LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
3432         {\r
3433                 if(m_hThemeDLL != NULL)\r
3434                 {\r
3435                         T* pT = static_cast<T*>(this);\r
3436                         pT->_CloseThemeData();\r
3437                         pT->_OpenThemeData();\r
3438                 }\r
3439                 return 0;\r
3440         }\r
3441 #endif // !_WTL_NO_AUTO_THEME\r
3442 \r
3443         LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
3444         {\r
3445                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
3446                 T* pT = static_cast<T*>(this);\r
3447                 pT->_AdjustBtnSize(GET_Y_LPARAM(lParam));\r
3448                 return lRet;\r
3449         }\r
3450 \r
3451         LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
3452         {\r
3453                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
3454 \r
3455                 if(m_bChildMaximized && (BOOL)wParam)\r
3456                 {\r
3457                         LPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam;\r
3458                         if(m_bLayoutRTL)\r
3459                         {\r
3460                                 lpParams->rgrc[0].left += m_cxRight;\r
3461                                 lpParams->rgrc[0].right -= m_cxLeft;\r
3462                         }\r
3463                         else\r
3464                         {\r
3465                                 lpParams->rgrc[0].left += m_cxLeft;\r
3466                                 lpParams->rgrc[0].right -= m_cxRight;\r
3467                         }\r
3468                 }\r
3469 \r
3470                 return lRet;\r
3471         }\r
3472 \r
3473         LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
3474         {\r
3475                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
3476 \r
3477                 if(!m_bChildMaximized)\r
3478                         return lRet;\r
3479 \r
3480                 ATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL);\r
3481 \r
3482                 // get DC and window rectangle\r
3483                 CWindowDC dc(m_hWnd);\r
3484                 RECT rect;\r
3485                 GetWindowRect(&rect);\r
3486                 int cxWidth = rect.right - rect.left;\r
3487                 int cyHeight = rect.bottom - rect.top;\r
3488 \r
3489                 // paint left side nonclient background and draw icon\r
3490                 ::SetRect(&rect, 0, 0, m_cxLeft, cyHeight);\r
3491 #ifndef _WTL_NO_AUTO_THEME\r
3492                 if(m_hTheme != NULL)\r
3493                 {\r
3494                         if(m_pfnDrawThemeParentBackground != NULL)\r
3495                                 m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);\r
3496                         else\r
3497                                 dc.FillRect(&rect, COLOR_WINDOW);\r
3498                 }\r
3499                 else\r
3500 #endif // !_WTL_NO_AUTO_THEME\r
3501                 {\r
3502                         if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)\r
3503                                 dc.FillRect(&rect, COLOR_3DFACE);\r
3504                         else\r
3505                                 dc.FillRect(&rect, COLOR_MENU);\r
3506                 }\r
3507 \r
3508                 RECT rcIcon = { 0 };\r
3509                 T* pT = static_cast<T*>(this);\r
3510                 pT->_CalcIconRect(cxWidth, cyHeight, rcIcon);\r
3511                 dc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight);\r
3512 \r
3513                 // paint right side nonclient background\r
3514                 ::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight);\r
3515 #ifndef _WTL_NO_AUTO_THEME\r
3516                 if(m_hTheme != NULL)\r
3517                 {\r
3518                         if(m_pfnDrawThemeParentBackground != NULL)\r
3519                         {\r
3520                                 // this is to account for the left non-client area\r
3521                                 POINT ptOrg = { 0, 0 };\r
3522                                 dc.GetViewportOrg(&ptOrg);\r
3523                                 dc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y);\r
3524                                 ::OffsetRect(&rect, -m_cxLeft, 0);\r
3525 \r
3526                                 m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);\r
3527 \r
3528                                 // restore\r
3529                                 dc.SetViewportOrg(ptOrg);\r
3530                                 ::OffsetRect(&rect, m_cxLeft, 0);\r
3531                         }\r
3532                         else\r
3533                         {\r
3534                                 dc.FillRect(&rect, COLOR_3DFACE);\r
3535                         }\r
3536                 }\r
3537                 else\r
3538 #endif // !_WTL_NO_AUTO_THEME\r
3539                 {\r
3540                         if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)\r
3541                                 dc.FillRect(&rect, COLOR_3DFACE);\r
3542                         else\r
3543                                 dc.FillRect(&rect, COLOR_MENU);\r
3544                 }\r
3545 \r
3546                 // draw buttons\r
3547                 RECT arrRect[3] = { 0 };\r
3548                 pT->_CalcBtnRects(cxWidth, cyHeight, arrRect);\r
3549                 pT->_DrawMDIButton(dc, arrRect, -1);   // draw all buttons\r
3550 \r
3551                 return lRet;\r
3552         }\r
3553 \r
3554         LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
3555         {\r
3556                 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\r
3557                 if(m_bChildMaximized)\r
3558                 {\r
3559                         RECT rect = { 0 };\r
3560                         GetWindowRect(&rect);\r
3561                         POINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top };\r
3562                         if(m_bLayoutRTL)\r
3563                         {\r
3564                                 if((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft)))\r
3565                                         lRet = HTBORDER;\r
3566                         }\r
3567                         else\r
3568                         {\r
3569                                 if((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight)))\r
3570                                         lRet = HTBORDER;\r
3571                         }\r
3572                 }\r
3573                 return lRet;\r
3574         }\r
3575 \r
3576         LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
3577         {\r
3578                 if(!m_bChildMaximized)\r
3579                 {\r
3580                         bHandled = FALSE;\r
3581                         return 1;\r
3582                 }\r
3583 \r
3584                 ATLASSERT(_DebugCheckChild());\r
3585 \r
3586                 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\r
3587                 RECT rect = { 0 };\r
3588                 GetWindowRect(&rect);\r
3589                 pt.x -= rect.left;\r
3590                 pt.y -= rect.top;\r
3591 \r
3592                 RECT rcIcon = { 0 };\r
3593                 T* pT = static_cast<T*>(this);\r
3594                 pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);\r
3595                 RECT arrRect[3] = { 0 };\r
3596                 pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\r
3597 \r
3598                 if(::PtInRect(&rcIcon, pt))\r
3599                 {\r
3600 #ifdef _CMDBAR_EXTRA_TRACE\r
3601                         ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: icon\n"));\r
3602 #endif\r
3603 #ifndef TPM_VERPOSANIMATION\r
3604                         const UINT TPM_VERPOSANIMATION = 0x1000L;   // Menu animation flag\r
3605 #endif\r
3606                         CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);\r
3607                         UINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD |  \r
3608                                 (s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized);\r
3609 \r
3610                         // eat next message if click is on the same button\r
3611                         ::OffsetRect(&rcIcon, rect.left, rect.top);\r
3612                         MSG msg = { 0 };\r
3613                         if(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt))\r
3614                                 ::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE);\r
3615 \r
3616                         if(uRet != 0)\r
3617                                 ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L);\r
3618                 }\r
3619                 else if(::PtInRect(&arrRect[0], pt))\r
3620                 {\r
3621 #ifdef _CMDBAR_EXTRA_TRACE\r
3622                         ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: close button\n"));\r
3623 #endif\r
3624                         m_nBtnWasPressed = m_nBtnPressed = 0;\r
3625                 }\r
3626                 else if(::PtInRect(&arrRect[1], pt))\r
3627                 {\r
3628 #ifdef _CMDBAR_EXTRA_TRACE\r
3629                         ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: restore button\n"));\r
3630 #endif\r
3631                         m_nBtnWasPressed = m_nBtnPressed = 1;\r
3632                 }\r
3633                 else if(::PtInRect(&arrRect[2], pt))\r
3634                 {\r
3635 #ifdef _CMDBAR_EXTRA_TRACE\r
3636                         ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: minimize button\n"));\r
3637 #endif\r
3638                         m_nBtnWasPressed = m_nBtnPressed = 2;\r
3639                 }\r
3640                 else\r
3641                 {\r
3642                         bHandled = FALSE;\r
3643                 }\r
3644 \r
3645                 // draw the button state if it was pressed\r
3646                 if(m_nBtnPressed != -1)\r
3647                 {\r
3648                         SetCapture();\r
3649                         CWindowDC dc(m_hWnd);\r
3650                         pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);\r
3651                         pT->_DrawMDIButton(dc, arrRect, m_nBtnPressed);\r
3652                 }\r
3653 \r
3654                 return 0;\r
3655         }\r
3656 \r
3657         LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
3658         {\r
3659                 if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)\r
3660                 {\r
3661                         bHandled = FALSE;\r
3662                         return 1;\r
3663                 }\r
3664 \r
3665                 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\r
3666                 ClientToScreen(&pt);\r
3667                 RECT rect = { 0 };\r
3668                 GetWindowRect(&rect);\r
3669                 pt.x -= rect.left;\r
3670                 pt.y -= rect.top;\r
3671                 RECT arrRect[3] = { 0 };\r
3672                 T* pT = static_cast<T*>(this);\r
3673                 pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\r
3674                 int nOldBtnPressed = m_nBtnPressed;\r
3675                 m_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1;\r
3676                 if(nOldBtnPressed != m_nBtnPressed)\r
3677                 {\r
3678                         CWindowDC dc(m_hWnd);\r
3679                         pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);\r
3680                         pT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed);\r
3681                 }\r
3682 \r
3683                 return 0;\r
3684         }\r
3685 \r
3686         LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
3687         {\r
3688                 if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)\r
3689                 {\r
3690                         bHandled = FALSE;\r
3691                         return 1;\r
3692                 }\r
3693 \r
3694                 ATLASSERT(_DebugCheckChild());\r
3695 \r
3696                 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\r
3697                 ClientToScreen(&pt);\r
3698                 RECT rect = { 0 };\r
3699                 GetWindowRect(&rect);\r
3700                 pt.x -= rect.left;\r
3701                 pt.y -= rect.top;\r
3702 \r
3703                 int nBtn = m_nBtnWasPressed;\r
3704                 ReleaseCapture();\r
3705 \r
3706                 RECT arrRect[3] = { 0 };\r
3707                 T* pT = static_cast<T*>(this);\r
3708                 pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\r
3709                 if(::PtInRect(&arrRect[nBtn], pt))\r
3710                 {\r
3711                         switch(nBtn)\r
3712                         {\r
3713                         case 0:         // close\r
3714 #ifdef _CMDBAR_EXTRA_TRACE\r
3715                                 ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: close button\n"));\r
3716 #endif\r
3717                                 ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L);\r
3718                                 break;\r
3719                         case 1:         // restore\r
3720 #ifdef _CMDBAR_EXTRA_TRACE\r
3721                                 ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: restore button\n"));\r
3722 #endif\r
3723                                 ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L);\r
3724                                 break;\r
3725                         case 2:         // minimize\r
3726 #ifdef _CMDBAR_EXTRA_TRACE\r
3727                                 ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: minimize button\n"));\r
3728 #endif\r
3729                                 ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L);\r
3730                                 break;\r
3731                         default:\r
3732                                 break;\r
3733                         }\r
3734                 }\r
3735 \r
3736                 return 0;\r
3737         }\r
3738 \r
3739         LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
3740         {\r
3741                 if(!m_bChildMaximized || m_nBtnWasPressed != -1)\r
3742                 {\r
3743                         bHandled = FALSE;\r
3744                         return 1;\r
3745                 }\r
3746 \r
3747                 ATLASSERT(_DebugCheckChild());\r
3748 \r
3749                 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\r
3750                 RECT rect = { 0 };\r
3751                 GetWindowRect(&rect);\r
3752                 pt.x -= rect.left;\r
3753                 pt.y -= rect.top;\r
3754 \r
3755                 RECT rcIcon = { 0 };\r
3756                 T* pT = static_cast<T*>(this);\r
3757                 pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);\r
3758                 RECT arrRect[3] = { 0 };\r
3759                 pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\r
3760 \r
3761                 if(::PtInRect(&rcIcon, pt))\r
3762                 {\r
3763                         CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);\r
3764                         UINT uDefID = menu.GetMenuDefaultItem();\r
3765                         if(uDefID == (UINT)-1)\r
3766                                 uDefID = SC_CLOSE;\r
3767                         ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L);\r
3768                 }\r
3769 \r
3770                 return 0;\r
3771         }\r
3772 \r
3773         LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
3774         {\r
3775                 if(m_bChildMaximized)\r
3776                 {\r
3777                         if(m_nBtnPressed != -1)\r
3778                         {\r
3779                                 ATLASSERT(m_nBtnPressed == m_nBtnWasPressed);   // must be\r
3780                                 m_nBtnPressed = -1;\r
3781                                 RECT rect = { 0 };\r
3782                                 GetWindowRect(&rect);\r
3783                                 RECT arrRect[3] = { 0 };\r
3784                                 T* pT = static_cast<T*>(this);\r
3785                                 pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);\r
3786                                 CWindowDC dc(m_hWnd);\r
3787                                 pT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed);\r
3788                         }\r
3789                         m_nBtnWasPressed = -1;\r
3790                 }\r
3791                 else\r
3792                 {\r
3793                         bHandled = FALSE;\r
3794                 }\r
3795                 return 0;\r
3796         }\r
3797 \r
3798 // Parent window message handlers\r
3799         LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\r
3800         {\r
3801                 m_bParentActive = (LOWORD(wParam) != WA_INACTIVE);\r
3802                 RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW);\r
3803                 bHandled = FALSE;\r
3804                 return 1;\r
3805         }\r
3806 \r
3807 // MDI client window message handlers\r
3808         LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
3809         {\r
3810                 m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam);\r
3811                 HMENU hOldMenu = GetMenu();\r
3812                 BOOL bRet = AttachMenu((HMENU)wParam);\r
3813                 bRet;   // avoid level 4 warning\r
3814                 ATLASSERT(bRet);\r
3815 \r
3816 #if (_WIN32_IE >= 0x0400)\r
3817                 T* pT = static_cast<T*>(this);\r
3818                 pT->UpdateRebarBandIdealSize();\r
3819 #endif // (_WIN32_IE >= 0x0400)\r
3820 \r
3821                 return (LRESULT)hOldMenu;\r
3822         }\r
3823 \r
3824 // All messages from the message hook\r
3825         LRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
3826         {\r
3827                 T* pT = static_cast<T*>(this);\r
3828                 pT->_ProcessAllHookMessages(uMsg, wParam, lParam);\r
3829 \r
3830                 bHandled = FALSE;\r
3831                 return 1;\r
3832         }\r
3833 \r
3834 // Overrideables\r
3835         // override this to provide different ideal size\r
3836         void UpdateRebarBandIdealSize()\r
3837         {\r
3838                 // assuming we are in a rebar, change ideal size to our size\r
3839                 // we hope that if we are not in a rebar, nCount will be 0\r
3840                 int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);\r
3841                 for(int i = 0; i < nCount; i++)\r
3842                 {\r
3843                         REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };\r
3844                         ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\r
3845                         if(rbi.hwndChild == m_hWnd)\r
3846                         {\r
3847                                 rbi.fMask = RBBIM_IDEALSIZE;\r
3848                                 rbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0;\r
3849                                 int nBtnCount = GetButtonCount();\r
3850                                 if(nBtnCount > 0)\r
3851                                 {\r
3852                                         RECT rect = { 0 };\r
3853                                         GetItemRect(nBtnCount - 1, &rect);\r
3854                                         rbi.cxIdeal += rect.right;\r
3855                                 }\r
3856                                 ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\r
3857                                 break;\r
3858                         }\r
3859                 }\r
3860         }\r
3861 \r
3862         // all hook messages - check for the maximized MDI child window change\r
3863         void _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)\r
3864         {\r
3865                 if(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU)\r
3866                         return;\r
3867 \r
3868                 BOOL bMaximized = FALSE;\r
3869                 HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);\r
3870                 bool bMaxOld = m_bChildMaximized;\r
3871                 m_bChildMaximized = (hWndChild != NULL && bMaximized);\r
3872                 HICON hIconOld = m_hIconChildMaximized;\r
3873 \r
3874                 if(m_bChildMaximized)\r
3875                 {\r
3876                         if(m_hWndChildMaximized != hWndChild)\r
3877                         {\r
3878                                 ATL::CWindow wnd = m_hWndChildMaximized = hWndChild;\r
3879                                 m_hIconChildMaximized = wnd.GetIcon(FALSE);\r
3880                                 if(m_hIconChildMaximized == NULL)\r
3881                                 {\r
3882                                         m_hIconChildMaximized = wnd.GetIcon(TRUE);\r
3883                                         if(m_hIconChildMaximized == NULL)\r
3884                                         {\r
3885                                                 // no icon set with WM_SETICON, get the class one\r
3886 // need conditional code because types don't match in winuser.h\r
3887 #ifdef _WIN64\r
3888                                                 m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM);\r
3889 #else\r
3890                                                 m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM));\r
3891 #endif\r
3892                                         }\r
3893                                 }\r
3894                         }\r
3895                 }\r
3896                 else\r
3897                 {\r
3898                         m_hWndChildMaximized = NULL;\r
3899                         m_hIconChildMaximized = NULL;\r
3900                 }\r
3901 \r
3902                 if(bMaxOld != m_bChildMaximized)\r
3903                 {\r
3904 #ifdef _CMDBAR_EXTRA_TRACE\r
3905                         ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized ? "true" : "false");\r
3906 #endif\r
3907                         // assuming we are in a rebar, change our size to accomodate new state\r
3908                         // we hope that if we are not in a rebar, nCount will be 0\r
3909                         int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);\r
3910                         int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight);\r
3911                         for(int i = 0; i < nCount; i++)\r
3912                         {\r
3913 #if (_WIN32_IE >= 0x0500)\r
3914                                 REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE };\r
3915                                 ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\r
3916                                 if(rbi.hwndChild == m_hWnd)\r
3917                                 {\r
3918                                         if((rbi.fStyle & RBBS_USECHEVRON) != 0)\r
3919                                         {\r
3920                                                 rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;\r
3921                                                 rbi.cxMinChild += cxDiff;\r
3922                                                 rbi.cxIdeal += cxDiff;\r
3923                                                 ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\r
3924                                         }\r
3925                                         break;\r
3926                                 }\r
3927 #elif (_WIN32_IE >= 0x0400)\r
3928                                 REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };\r
3929                                 ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\r
3930                                 if(rbi.hwndChild == m_hWnd)\r
3931                                 {\r
3932                                         rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;\r
3933                                         rbi.cxMinChild += cxDiff;\r
3934                                         rbi.cxIdeal += cxDiff;\r
3935                                         ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\r
3936                                         break;\r
3937                                 }\r
3938 #else // (_WIN32_IE < 0x0400)\r
3939                                 REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE };\r
3940                                 ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\r
3941                                 if(rbi.hwndChild == m_hWnd)\r
3942                                 {\r
3943                                         rbi.fMask = RBBIM_CHILDSIZE;\r
3944                                         rbi.cxMinChild += cxDiff;\r
3945                                         ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\r
3946                                         break;\r
3947                                 }\r
3948 #endif // (_WIN32_IE < 0x0400)\r
3949                         }\r
3950                 }\r
3951 \r
3952                 if(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized)\r
3953                 {\r
3954                         // force size change and redraw everything\r
3955                         RECT rect = { 0 };\r
3956                         GetWindowRect(&rect);\r
3957                         ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2);\r
3958                         SetRedraw(FALSE);\r
3959                         SetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE);\r
3960                         SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);\r
3961                         SetRedraw(TRUE);\r
3962                         RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);\r
3963                 }\r
3964         }\r
3965 \r
3966 // Implementation\r
3967         void GetSystemSettings()\r
3968         {\r
3969 #ifdef _CMDBAR_EXTRA_TRACE\r
3970                 ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - GetSystemSettings\n"));\r
3971 #endif\r
3972                 _baseClass::GetSystemSettings();\r
3973 \r
3974                 NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\r
3975                 BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);\r
3976                 ATLASSERT(bRet);\r
3977                 if(bRet)\r
3978                 {\r
3979                         m_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON);\r
3980                         m_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON);\r
3981                         m_cxLeft = m_cxIconWidth;\r
3982 \r
3983 #ifndef _WTL_NO_AUTO_THEME\r
3984                         if(m_hTheme != NULL)\r
3985                         {\r
3986                                 m_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset;\r
3987                                 m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;\r
3988                                 m_cxRight = 3 * m_cxBtnWidth;\r
3989                         }\r
3990                         else\r
3991 #endif // !_WTL_NO_AUTO_THEME\r
3992                         {\r
3993                                 m_cxBtnWidth = info.iCaptionWidth - m_cxyOffset;\r
3994                                 m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;\r
3995                                 m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;\r
3996                         }\r
3997                 }\r
3998 \r
3999                 RECT rect = { 0 };\r
4000                 GetClientRect(&rect);\r
4001                 T* pT = static_cast<T*>(this);\r
4002                 pT->_AdjustBtnSize(rect.bottom);\r
4003         }\r
4004 \r
4005         void _AdjustBtnSize(int cyHeight)\r
4006         {\r
4007                 if(cyHeight > 1 && m_cyBtnHeight > cyHeight)\r
4008                 {\r
4009 #ifndef _WTL_NO_AUTO_THEME\r
4010                         if(m_hTheme != NULL)\r
4011                         {\r
4012                                 m_cyBtnHeight = cyHeight;\r
4013                                 m_cxBtnWidth = cyHeight;\r
4014                                 m_cxRight = 3 * m_cxBtnWidth;\r
4015                         }\r
4016                         else\r
4017 #endif // !_WTL_NO_AUTO_THEME\r
4018                         {\r
4019                                 m_cyBtnHeight = cyHeight;\r
4020                                 m_cxBtnWidth = cyHeight + m_cxyOffset;\r
4021                                 m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;\r
4022                         }\r
4023                 }\r
4024         }\r
4025 \r
4026         void _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const\r
4027         {\r
4028                 int xStart = (m_cxLeft - m_cxIconWidth) / 2;\r
4029                 if(xStart < 0)\r
4030                         xStart = 0;\r
4031                 int yStart = (cyHeight - m_cyIconHeight) / 2;\r
4032                 if(yStart < 0)\r
4033                         yStart = 0;\r
4034 \r
4035                 if(bInvertX)\r
4036                         ::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight);\r
4037                 else\r
4038                         ::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight);\r
4039         }\r
4040 \r
4041         void _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const\r
4042         {\r
4043                 int yStart = (cyHeight - m_cyBtnHeight) / 2;\r
4044                 if(yStart < 0)\r
4045                         yStart = 0;\r
4046 \r
4047                 RECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight };\r
4048                 int nDirection = -1;\r
4049                 if(bInvertX)\r
4050                 {\r
4051                         ::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight);\r
4052                         nDirection = 1;\r
4053                 }\r
4054 \r
4055                 arrRect[0] = rcBtn;\r
4056 #ifndef _WTL_NO_AUTO_THEME\r
4057                 if(m_hTheme != NULL)\r
4058                         ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);\r
4059                 else\r
4060 #endif // !_WTL_NO_AUTO_THEME\r
4061                         ::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0);\r
4062                 arrRect[1] = rcBtn;\r
4063                 ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);\r
4064                 arrRect[2] = rcBtn;\r
4065         }\r
4066 \r
4067         void _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn)\r
4068         {\r
4069 #ifndef _WTL_NO_AUTO_THEME\r
4070                 if(m_hTheme != NULL)\r
4071                 {\r
4072 #ifndef TMSCHEMA_H\r
4073                         const int WP_MDICLOSEBUTTON = 20;\r
4074                         const int CBS_NORMAL = 1;\r
4075                         const int CBS_PUSHED = 3;\r
4076                         const int CBS_DISABLED = 4;\r
4077                         const int WP_MDIRESTOREBUTTON = 22;\r
4078                         const int RBS_NORMAL = 1;\r
4079                         const int RBS_PUSHED = 3;\r
4080                         const int RBS_DISABLED = 4;\r
4081                         const int WP_MDIMINBUTTON = 16;\r
4082                         const int MINBS_NORMAL = 1;\r
4083                         const int MINBS_PUSHED = 3;\r
4084                         const int MINBS_DISABLED = 4;\r
4085 #endif // TMSCHEMA_H\r
4086                         if(nBtn == -1 || nBtn == 0)\r
4087                                 m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL);\r
4088                         if(nBtn == -1 || nBtn == 1)\r
4089                                 m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL);\r
4090                         if(nBtn == -1 || nBtn == 2)\r
4091                                 m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL);\r
4092                 }\r
4093                 else\r
4094 #endif // !_WTL_NO_AUTO_THEME\r
4095                 {\r
4096                         if(nBtn == -1 || nBtn == 0)\r
4097                                 dc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0));\r
4098                         if(nBtn == -1 || nBtn == 1)\r
4099                                 dc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0));\r
4100                         if(nBtn == -1 || nBtn == 2)\r
4101                                 dc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0));\r
4102                 }\r
4103         }\r
4104 \r
4105 #ifndef _WTL_NO_AUTO_THEME\r
4106         static UINT _GetThemeChangedMsg()\r
4107         {\r
4108 #ifndef WM_THEMECHANGED\r
4109                 static const UINT WM_THEMECHANGED = 0x031A;\r
4110 #endif // !WM_THEMECHANGED\r
4111                 return WM_THEMECHANGED;\r
4112         }\r
4113 \r
4114         void _OpenThemeData()\r
4115         {\r
4116                 ATLASSERT(m_hThemeDLL != NULL);\r
4117 \r
4118                 PFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, "OpenThemeData");\r
4119                 ATLASSERT(pfnOpenThemeData != NULL);\r
4120                 if(pfnOpenThemeData != NULL)\r
4121                         m_hTheme = pfnOpenThemeData(m_hWnd, L"Window");\r
4122         }\r
4123 \r
4124         void _CloseThemeData()\r
4125         {\r
4126                 ATLASSERT(m_hThemeDLL != NULL);\r
4127 \r
4128                 if(m_hTheme == NULL)\r
4129                         return;   // nothing to do\r
4130 \r
4131                 PFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, "CloseThemeData");\r
4132                 ATLASSERT(pfnCloseThemeData != NULL);\r
4133                 if(pfnCloseThemeData != NULL)\r
4134                 {\r
4135                         pfnCloseThemeData(m_hTheme);\r
4136                         m_hTheme = NULL;\r
4137                 }\r
4138         }\r
4139 #endif // !_WTL_NO_AUTO_THEME\r
4140 \r
4141         bool _DebugCheckChild()\r
4142         {\r
4143 #ifdef _DEBUG\r
4144                 BOOL bMaximized = FALSE;\r
4145                 HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);\r
4146                 return (bMaximized && hWndChild == m_hWndChildMaximized);\r
4147 #else // !_DEBUG\r
4148                 return true;\r
4149 #endif // !_DEBUG\r
4150         }\r
4151 };\r
4152 \r
4153 class CMDICommandBarCtrl : public CMDICommandBarCtrlImpl<CMDICommandBarCtrl>\r
4154 {\r
4155 public:\r
4156         DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName())\r
4157 };\r
4158 \r
4159 }; // namespace WTL\r
4160 \r
4161 #endif // __ATLCTRLW_H__\r