comparison foosdk/wtl/Include/atlctrlw.h @ 1:20d02a178406 default tip

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