Mercurial > foo_out_sdl
comparison foosdk/wtl/Include/atlframe.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 __ATLFRAME_H__ | |
| 10 #define __ATLFRAME_H__ | |
| 11 | |
| 12 #pragma once | |
| 13 | |
| 14 #ifndef __ATLAPP_H__ | |
| 15 #error atlframe.h requires atlapp.h to be included first | |
| 16 #endif | |
| 17 | |
| 18 #ifndef __ATLWIN_H__ | |
| 19 #error atlframe.h requires atlwin.h to be included first | |
| 20 #endif | |
| 21 | |
| 22 | |
| 23 /////////////////////////////////////////////////////////////////////////////// | |
| 24 // Classes in this file: | |
| 25 // | |
| 26 // CFrameWindowImpl<T, TBase, TWinTraits> | |
| 27 // CMDIWindow | |
| 28 // CMDIFrameWindowImpl<T, TBase, TWinTraits> | |
| 29 // CMDIChildWindowImpl<T, TBase, TWinTraits> | |
| 30 // COwnerDraw<T> | |
| 31 // CUpdateUIBase | |
| 32 // CUpdateUI<T> | |
| 33 // CDynamicUpdateUI<T> | |
| 34 // CAutoUpdateUI<T> | |
| 35 // CDialogResize<T> | |
| 36 // CDynamicDialogLayout<T> | |
| 37 // CDoubleBufferImpl<T> | |
| 38 // CDoubleBufferWindowImpl<T, TBase, TWinTraits> | |
| 39 // | |
| 40 // Global functions: | |
| 41 // AtlCreateSimpleToolBar() | |
| 42 | |
| 43 | |
| 44 namespace WTL | |
| 45 { | |
| 46 | |
| 47 /////////////////////////////////////////////////////////////////////////////// | |
| 48 // CFrameWndClassInfo - Manages frame window Windows class information | |
| 49 | |
| 50 class CFrameWndClassInfo | |
| 51 { | |
| 52 public: | |
| 53 enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs | |
| 54 WNDCLASSEX m_wc; | |
| 55 LPCTSTR m_lpszOrigName; | |
| 56 WNDPROC pWndProc; | |
| 57 LPCTSTR m_lpszCursorID; | |
| 58 BOOL m_bSystemCursor; | |
| 59 ATOM m_atom; | |
| 60 TCHAR m_szAutoName[cchAutoName]; | |
| 61 UINT m_uCommonResourceID; | |
| 62 | |
| 63 ATOM Register(WNDPROC* pProc) | |
| 64 { | |
| 65 if (m_atom == 0) | |
| 66 { | |
| 67 CWindowCreateCriticalSectionLock lock; | |
| 68 if(FAILED(lock.Lock())) | |
| 69 { | |
| 70 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); | |
| 71 ATLASSERT(FALSE); | |
| 72 return 0; | |
| 73 } | |
| 74 | |
| 75 if(m_atom == 0) | |
| 76 { | |
| 77 HINSTANCE hInst = ModuleHelper::GetModuleInstance(); | |
| 78 | |
| 79 if (m_lpszOrigName != NULL) | |
| 80 { | |
| 81 ATLASSERT(pProc != NULL); | |
| 82 LPCTSTR lpsz = m_wc.lpszClassName; | |
| 83 WNDPROC proc = m_wc.lpfnWndProc; | |
| 84 | |
| 85 WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; | |
| 86 // try process local class first | |
| 87 if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) | |
| 88 { | |
| 89 // try global class | |
| 90 if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc)) | |
| 91 { | |
| 92 lock.Unlock(); | |
| 93 return 0; | |
| 94 } | |
| 95 } | |
| 96 m_wc = wc; | |
| 97 pWndProc = m_wc.lpfnWndProc; | |
| 98 m_wc.lpszClassName = lpsz; | |
| 99 m_wc.lpfnWndProc = proc; | |
| 100 } | |
| 101 else | |
| 102 { | |
| 103 m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); | |
| 104 } | |
| 105 | |
| 106 m_wc.hInstance = hInst; | |
| 107 m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes | |
| 108 if (m_wc.lpszClassName == NULL) | |
| 109 { | |
| 110 _stprintf_s(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc); | |
| 111 m_wc.lpszClassName = m_szAutoName; | |
| 112 } | |
| 113 | |
| 114 WNDCLASSEX wcTemp = m_wc; | |
| 115 m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); | |
| 116 if (m_atom == 0) | |
| 117 { | |
| 118 if(m_uCommonResourceID != 0) // use it if not zero | |
| 119 { | |
| 120 m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), | |
| 121 MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, | |
| 122 ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); | |
| 123 m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), | |
| 124 MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, | |
| 125 ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); | |
| 126 } | |
| 127 m_atom = ::RegisterClassEx(&m_wc); | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 lock.Unlock(); | |
| 132 } | |
| 133 | |
| 134 if (m_lpszOrigName != NULL) | |
| 135 { | |
| 136 ATLASSERT(pProc != NULL); | |
| 137 ATLASSERT(pWndProc != NULL); | |
| 138 *pProc = pWndProc; | |
| 139 } | |
| 140 | |
| 141 return m_atom; | |
| 142 } | |
| 143 }; | |
| 144 | |
| 145 | |
| 146 /////////////////////////////////////////////////////////////////////////////// | |
| 147 // Macros for declaring frame window WNDCLASS | |
| 148 | |
| 149 #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ | |
| 150 static WTL::CFrameWndClassInfo& GetWndClassInfo() \ | |
| 151 { \ | |
| 152 static WTL::CFrameWndClassInfo wc = \ | |
| 153 { \ | |
| 154 { sizeof(WNDCLASSEX), 0, StartWindowProc, \ | |
| 155 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ | |
| 156 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ | |
| 157 }; \ | |
| 158 return wc; \ | |
| 159 } | |
| 160 | |
| 161 #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ | |
| 162 static WTL::CFrameWndClassInfo& GetWndClassInfo() \ | |
| 163 { \ | |
| 164 static WTL::CFrameWndClassInfo wc = \ | |
| 165 { \ | |
| 166 { sizeof(WNDCLASSEX), style, StartWindowProc, \ | |
| 167 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ | |
| 168 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ | |
| 169 }; \ | |
| 170 return wc; \ | |
| 171 } | |
| 172 | |
| 173 #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ | |
| 174 static WTL::CFrameWndClassInfo& GetWndClassInfo() \ | |
| 175 { \ | |
| 176 static WTL::CFrameWndClassInfo wc = \ | |
| 177 { \ | |
| 178 { sizeof(WNDCLASSEX), 0, StartWindowProc, \ | |
| 179 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ | |
| 180 OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ | |
| 181 }; \ | |
| 182 return wc; \ | |
| 183 } | |
| 184 | |
| 185 // These are for templated classes | |
| 186 #define DECLARE_FRAME_WND_CLASS2(WndClassName, EnclosingClass, uCommonResourceID) \ | |
| 187 static WTL::CFrameWndClassInfo& GetWndClassInfo() \ | |
| 188 { \ | |
| 189 static WTL::CFrameWndClassInfo wc = \ | |
| 190 { \ | |
| 191 { sizeof(WNDCLASSEX), 0, EnclosingClass::StartWindowProc, \ | |
| 192 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ | |
| 193 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ | |
| 194 }; \ | |
| 195 return wc; \ | |
| 196 } | |
| 197 | |
| 198 #define DECLARE_FRAME_WND_CLASS_EX2(WndClassName, EnclosingClass, uCommonResourceID, style, bkgnd) \ | |
| 199 static WTL::CFrameWndClassInfo& GetWndClassInfo() \ | |
| 200 { \ | |
| 201 static WTL::CFrameWndClassInfo wc = \ | |
| 202 { \ | |
| 203 { sizeof(WNDCLASSEX), style, EnclosingClass::StartWindowProc, \ | |
| 204 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ | |
| 205 NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ | |
| 206 }; \ | |
| 207 return wc; \ | |
| 208 } | |
| 209 | |
| 210 #define DECLARE_FRAME_WND_SUPERCLASS2(WndClassName, EnclosingClass, OrigWndClassName, uCommonResourceID) \ | |
| 211 static WTL::CFrameWndClassInfo& GetWndClassInfo() \ | |
| 212 { \ | |
| 213 static WTL::CFrameWndClassInfo wc = \ | |
| 214 { \ | |
| 215 { sizeof(WNDCLASSEX), 0, EnclosingClass::StartWindowProc, \ | |
| 216 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ | |
| 217 OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ | |
| 218 }; \ | |
| 219 return wc; \ | |
| 220 } | |
| 221 | |
| 222 | |
| 223 /////////////////////////////////////////////////////////////////////////////// | |
| 224 // CFrameWindowImpl | |
| 225 | |
| 226 // Client window command chaining macro (only for frame windows) | |
| 227 #define CHAIN_CLIENT_COMMANDS() \ | |
| 228 if((uMsg == WM_COMMAND) && (this->m_hWndClient != NULL)) \ | |
| 229 ::SendMessage(this->m_hWndClient, uMsg, wParam, lParam); | |
| 230 | |
| 231 // standard toolbar styles | |
| 232 #define ATL_SIMPLE_TOOLBAR_STYLE \ | |
| 233 (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS) | |
| 234 // toolbar in a rebar pane | |
| 235 #define ATL_SIMPLE_TOOLBAR_PANE_STYLE \ | |
| 236 (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT) | |
| 237 // standard rebar styles | |
| 238 #define ATL_SIMPLE_REBAR_STYLE \ | |
| 239 (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE) | |
| 240 // rebar without borders | |
| 241 #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ | |
| 242 (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER) | |
| 243 | |
| 244 // command bar support | |
| 245 #if !defined(__ATLCTRLW_H__) | |
| 246 | |
| 247 #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND | |
| 248 #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu | |
| 249 #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu | |
| 250 | |
| 251 struct _AtlFrameWnd_CmdBarPopupMenu | |
| 252 { | |
| 253 int cbSize; | |
| 254 HMENU hMenu; | |
| 255 UINT uFlags; | |
| 256 int x; | |
| 257 int y; | |
| 258 LPTPMPARAMS lptpm; | |
| 259 }; | |
| 260 | |
| 261 #define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu | |
| 262 | |
| 263 #endif // !defined(__ATLCTRLW_H__) | |
| 264 | |
| 265 | |
| 266 template <class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits> | |
| 267 class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits > | |
| 268 { | |
| 269 public: | |
| 270 typedef CFrameWindowImplBase<TBase, TWinTraits > _thisClass; | |
| 271 DECLARE_FRAME_WND_CLASS2(NULL, _thisClass, 0) | |
| 272 | |
| 273 struct _ChevronMenuInfo | |
| 274 { | |
| 275 HMENU hMenu; | |
| 276 LPNMREBARCHEVRON lpnm; | |
| 277 bool bCmdBar; | |
| 278 }; | |
| 279 | |
| 280 // Data members | |
| 281 HWND m_hWndToolBar; | |
| 282 HWND m_hWndStatusBar; | |
| 283 HWND m_hWndClient; | |
| 284 | |
| 285 HACCEL m_hAccel; | |
| 286 | |
| 287 // Constructor | |
| 288 CFrameWindowImplBase() : | |
| 289 m_hWndToolBar(NULL), | |
| 290 m_hWndStatusBar(NULL), | |
| 291 m_hWndClient(NULL), | |
| 292 m_hAccel(NULL) | |
| 293 { } | |
| 294 | |
| 295 // Methods | |
| 296 HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam) | |
| 297 { | |
| 298 ATLASSERT(this->m_hWnd == NULL); | |
| 299 | |
| 300 // Allocate the thunk structure here, where we can fail gracefully. | |
| 301 BOOL bRet = this->m_thunk.Init(NULL, NULL); | |
| 302 if(bRet == FALSE) | |
| 303 { | |
| 304 ::SetLastError(ERROR_OUTOFMEMORY); | |
| 305 return NULL; | |
| 306 } | |
| 307 | |
| 308 if(atom == 0) | |
| 309 return NULL; | |
| 310 | |
| 311 ModuleHelper::AddCreateWndData(&this->m_thunk.cd, this); | |
| 312 | |
| 313 if((MenuOrID.m_hMenu == NULL) && (dwStyle & WS_CHILD)) | |
| 314 MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this; | |
| 315 if(rect.m_lpRect == NULL) | |
| 316 rect.m_lpRect = &TBase::rcDefault; | |
| 317 | |
| 318 HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName, | |
| 319 dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left, | |
| 320 rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu, | |
| 321 ModuleHelper::GetModuleInstance(), lpCreateParam); | |
| 322 | |
| 323 ATLASSERT((hWnd == NULL) || (this->m_hWnd == hWnd)); | |
| 324 | |
| 325 return hWnd; | |
| 326 } | |
| 327 | |
| 328 static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, | |
| 329 DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 330 { | |
| 331 HINSTANCE hInst = ModuleHelper::GetResourceInstance(); | |
| 332 HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR); | |
| 333 if (hRsrc == NULL) | |
| 334 return NULL; | |
| 335 | |
| 336 HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc); | |
| 337 if (hGlobal == NULL) | |
| 338 return NULL; | |
| 339 | |
| 340 _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal); | |
| 341 if (pData == NULL) | |
| 342 return NULL; | |
| 343 ATLASSERT(pData->wVersion == 1); | |
| 344 | |
| 345 WORD* pItems = pData->items(); | |
| 346 int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0); | |
| 347 ATL::CTempBuffer<TBBUTTON, _WTL_STACK_ALLOC_THRESHOLD> buff; | |
| 348 TBBUTTON* pTBBtn = buff.Allocate(nItems); | |
| 349 ATLASSERT(pTBBtn != NULL); | |
| 350 if(pTBBtn == NULL) | |
| 351 return NULL; | |
| 352 | |
| 353 const int cxSeparator = 8; | |
| 354 | |
| 355 // set initial separator (half width) | |
| 356 if(bInitialSeparator) | |
| 357 { | |
| 358 pTBBtn[0].iBitmap = cxSeparator / 2; | |
| 359 pTBBtn[0].idCommand = 0; | |
| 360 pTBBtn[0].fsState = 0; | |
| 361 pTBBtn[0].fsStyle = BTNS_SEP; | |
| 362 pTBBtn[0].dwData = 0; | |
| 363 pTBBtn[0].iString = 0; | |
| 364 } | |
| 365 | |
| 366 int nBmp = 0; | |
| 367 for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++) | |
| 368 { | |
| 369 if(pItems[i] != 0) | |
| 370 { | |
| 371 pTBBtn[j].iBitmap = nBmp++; | |
| 372 pTBBtn[j].idCommand = pItems[i]; | |
| 373 pTBBtn[j].fsState = TBSTATE_ENABLED; | |
| 374 pTBBtn[j].fsStyle = BTNS_BUTTON; | |
| 375 pTBBtn[j].dwData = 0; | |
| 376 pTBBtn[j].iString = 0; | |
| 377 } | |
| 378 else | |
| 379 { | |
| 380 pTBBtn[j].iBitmap = cxSeparator; | |
| 381 pTBBtn[j].idCommand = 0; | |
| 382 pTBBtn[j].fsState = 0; | |
| 383 pTBBtn[j].fsStyle = BTNS_SEP; | |
| 384 pTBBtn[j].dwData = 0; | |
| 385 pTBBtn[j].iString = 0; | |
| 386 } | |
| 387 } | |
| 388 | |
| 389 HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); | |
| 390 if(hWnd == NULL) | |
| 391 { | |
| 392 ATLASSERT(FALSE); | |
| 393 return NULL; | |
| 394 } | |
| 395 | |
| 396 ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L); | |
| 397 | |
| 398 // check if font is taller than our bitmaps | |
| 399 CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); | |
| 400 if(font.IsNull()) | |
| 401 font = (HFONT)::GetStockObject(SYSTEM_FONT); | |
| 402 LOGFONT lf = {}; | |
| 403 font.GetLogFont(lf); | |
| 404 WORD cyFontHeight = (WORD)abs(lf.lfHeight); | |
| 405 | |
| 406 WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID); | |
| 407 if(bitsPerPixel > 4) | |
| 408 { | |
| 409 COLORREF crMask = CLR_DEFAULT; | |
| 410 if(bitsPerPixel == 32) | |
| 411 { | |
| 412 // 32-bit color bitmap with alpha channel (valid for Windows XP and later) | |
| 413 crMask = CLR_NONE; | |
| 414 } | |
| 415 HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); | |
| 416 ATLASSERT(hImageList != NULL); | |
| 417 ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList); | |
| 418 } | |
| 419 else | |
| 420 { | |
| 421 TBADDBITMAP tbab = {}; | |
| 422 tbab.hInst = hInst; | |
| 423 tbab.nID = nResourceID; | |
| 424 ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab); | |
| 425 } | |
| 426 | |
| 427 ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn); | |
| 428 ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, __max(pData->wHeight, cyFontHeight))); | |
| 429 const int cxyButtonMargin = 7; | |
| 430 ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, __max(pData->wHeight, cyFontHeight) + cxyButtonMargin)); | |
| 431 | |
| 432 return hWnd; | |
| 433 } | |
| 434 | |
| 435 static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 436 { | |
| 437 // Ensure style combinations for proper rebar painting | |
| 438 if(dwStyle & CCS_NODIVIDER && (dwStyle & WS_BORDER)) | |
| 439 dwStyle &= ~WS_BORDER; | |
| 440 else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER)) | |
| 441 dwStyle |= CCS_NODIVIDER; | |
| 442 | |
| 443 // Create rebar window | |
| 444 HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); | |
| 445 if(hWndReBar == NULL) | |
| 446 { | |
| 447 ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n")); | |
| 448 return NULL; | |
| 449 } | |
| 450 | |
| 451 // Initialize and send the REBARINFO structure | |
| 452 REBARINFO rbi = { sizeof(REBARINFO), 0 }; | |
| 453 if(::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi) == 0) | |
| 454 { | |
| 455 ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n")); | |
| 456 ::DestroyWindow(hWndReBar); | |
| 457 return NULL; | |
| 458 } | |
| 459 | |
| 460 return hWndReBar; | |
| 461 } | |
| 462 | |
| 463 BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 464 { | |
| 465 ATLASSERT(!::IsWindow(m_hWndToolBar)); | |
| 466 m_hWndToolBar = CreateSimpleReBarCtrl(this->m_hWnd, dwStyle, nID); | |
| 467 return (m_hWndToolBar != NULL); | |
| 468 } | |
| 469 | |
| 470 static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) | |
| 471 { | |
| 472 ATLASSERT(::IsWindow(hWndReBar)); // must be already created | |
| 473 #ifdef _DEBUG | |
| 474 // block - check if this is really a rebar | |
| 475 { | |
| 476 TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = {}; | |
| 477 ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME)); | |
| 478 ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0); | |
| 479 } | |
| 480 #endif // _DEBUG | |
| 481 ATLASSERT(::IsWindow(hWndBand)); // must be already created | |
| 482 | |
| 483 // Get number of buttons on the toolbar | |
| 484 int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L); | |
| 485 | |
| 486 // Set band info structure | |
| 487 REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; | |
| 488 rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE; | |
| 489 if(lpstrTitle != NULL) | |
| 490 rbBand.fMask |= RBBIM_TEXT; | |
| 491 rbBand.fStyle = RBBS_CHILDEDGE; | |
| 492 if(nBtnCount > 0) // add chevron style for toolbar with buttons | |
| 493 rbBand.fStyle |= RBBS_USECHEVRON; | |
| 494 if(bNewRow) | |
| 495 rbBand.fStyle |= RBBS_BREAK; | |
| 496 | |
| 497 rbBand.lpText = (LPTSTR)lpstrTitle; | |
| 498 rbBand.hwndChild = hWndBand; | |
| 499 if(nID == 0) // calc band ID | |
| 500 nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); | |
| 501 rbBand.wID = nID; | |
| 502 | |
| 503 // Calculate the size of the band | |
| 504 BOOL bRet = FALSE; | |
| 505 RECT rcTmp = {}; | |
| 506 if(nBtnCount > 0) | |
| 507 { | |
| 508 bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp); | |
| 509 ATLASSERT(bRet); | |
| 510 rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right; | |
| 511 rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; | |
| 512 if(bFullWidthAlways) | |
| 513 { | |
| 514 rbBand.cxMinChild = rbBand.cx; | |
| 515 } | |
| 516 else if(lpstrTitle == NULL) | |
| 517 { | |
| 518 bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp); | |
| 519 ATLASSERT(bRet); | |
| 520 rbBand.cxMinChild = rcTmp.right; | |
| 521 } | |
| 522 else | |
| 523 { | |
| 524 rbBand.cxMinChild = 0; | |
| 525 } | |
| 526 } | |
| 527 else // no buttons, either not a toolbar or really has no buttons | |
| 528 { | |
| 529 bRet = ::GetWindowRect(hWndBand, &rcTmp); | |
| 530 ATLASSERT(bRet); | |
| 531 rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left); | |
| 532 rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0; | |
| 533 rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; | |
| 534 } | |
| 535 | |
| 536 rbBand.cxIdeal = rbBand.cx; | |
| 537 | |
| 538 // Add the band | |
| 539 LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); | |
| 540 if(lRes == 0) | |
| 541 { | |
| 542 ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n")); | |
| 543 return FALSE; | |
| 544 } | |
| 545 | |
| 546 DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L); | |
| 547 ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS); | |
| 548 | |
| 549 return TRUE; | |
| 550 } | |
| 551 | |
| 552 BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) | |
| 553 { | |
| 554 ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar | |
| 555 ATLASSERT(::IsWindow(hWndBand)); // must be created | |
| 556 return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways); | |
| 557 } | |
| 558 | |
| 559 void SizeSimpleReBarBands() | |
| 560 { | |
| 561 ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar | |
| 562 | |
| 563 int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L); | |
| 564 | |
| 565 for(int i = 0; i < nCount; i++) | |
| 566 { | |
| 567 REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; | |
| 568 rbBand.fMask = RBBIM_SIZE; | |
| 569 BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand); | |
| 570 ATLASSERT(bRet); | |
| 571 RECT rect = {}; | |
| 572 ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect); | |
| 573 rbBand.cx += rect.left + rect.right; | |
| 574 bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand); | |
| 575 ATLASSERT(bRet); | |
| 576 } | |
| 577 } | |
| 578 | |
| 579 BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) | |
| 580 { | |
| 581 ATLASSERT(!::IsWindow(m_hWndStatusBar)); | |
| 582 m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, this->m_hWnd, nID); | |
| 583 return (m_hWndStatusBar != NULL); | |
| 584 } | |
| 585 | |
| 586 BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) | |
| 587 { | |
| 588 const int cchMax = 128; // max text length is 127 for status bars (+1 for null) | |
| 589 TCHAR szText[cchMax] = {}; | |
| 590 ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); | |
| 591 return CreateSimpleStatusBar(szText, dwStyle, nID); | |
| 592 } | |
| 593 | |
| 594 void UpdateLayout(BOOL bResizeBars = TRUE) | |
| 595 { | |
| 596 RECT rect = {}; | |
| 597 this->GetClientRect(&rect); | |
| 598 | |
| 599 // position bars and offset their dimensions | |
| 600 UpdateBarsPosition(rect, bResizeBars); | |
| 601 | |
| 602 // resize client window | |
| 603 if(m_hWndClient != NULL) | |
| 604 ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, | |
| 605 rect.right - rect.left, rect.bottom - rect.top, | |
| 606 SWP_NOZORDER | SWP_NOACTIVATE); | |
| 607 } | |
| 608 | |
| 609 void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) | |
| 610 { | |
| 611 // resize toolbar | |
| 612 if((m_hWndToolBar != NULL) && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) | |
| 613 { | |
| 614 if(bResizeBars != FALSE) | |
| 615 { | |
| 616 ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); | |
| 617 ::InvalidateRect(m_hWndToolBar, NULL, TRUE); | |
| 618 } | |
| 619 RECT rectTB = {}; | |
| 620 ::GetWindowRect(m_hWndToolBar, &rectTB); | |
| 621 rect.top += rectTB.bottom - rectTB.top; | |
| 622 } | |
| 623 | |
| 624 // resize status bar | |
| 625 if((m_hWndStatusBar != NULL) && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) | |
| 626 { | |
| 627 if(bResizeBars != FALSE) | |
| 628 ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0); | |
| 629 RECT rectSB = {}; | |
| 630 ::GetWindowRect(m_hWndStatusBar, &rectSB); | |
| 631 rect.bottom -= rectSB.bottom - rectSB.top; | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 BOOL PreTranslateMessage(MSG* pMsg) | |
| 636 { | |
| 637 if((m_hAccel != NULL) && ::TranslateAccelerator(this->m_hWnd, m_hAccel, pMsg)) | |
| 638 return TRUE; | |
| 639 return FALSE; | |
| 640 } | |
| 641 | |
| 642 BEGIN_MSG_MAP(CFrameWindowImplBase) | |
| 643 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) | |
| 644 MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) | |
| 645 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) | |
| 646 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) | |
| 647 NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA) | |
| 648 NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW) | |
| 649 END_MSG_MAP() | |
| 650 | |
| 651 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | |
| 652 { | |
| 653 if(m_hWndClient != NULL) // view will paint itself instead | |
| 654 return 1; | |
| 655 | |
| 656 bHandled = FALSE; | |
| 657 return 0; | |
| 658 } | |
| 659 | |
| 660 LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) | |
| 661 { | |
| 662 bHandled = FALSE; | |
| 663 | |
| 664 if(m_hWndStatusBar == NULL) | |
| 665 return 1; | |
| 666 | |
| 667 WORD wFlags = HIWORD(wParam); | |
| 668 if((wFlags == 0xFFFF) && (lParam == NULL)) // menu closing | |
| 669 { | |
| 670 ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L); | |
| 671 } | |
| 672 else | |
| 673 { | |
| 674 const int cchBuff = 256; | |
| 675 TCHAR szBuff[cchBuff] = {}; | |
| 676 if(!(wFlags & MF_POPUP)) | |
| 677 { | |
| 678 WORD wID = LOWORD(wParam); | |
| 679 // check for special cases | |
| 680 if((wID >= 0xF000) && (wID < 0xF1F0)) // system menu IDs | |
| 681 wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST); | |
| 682 else if((wID >= ID_FILE_MRU_FIRST) && (wID <= ID_FILE_MRU_LAST)) // MRU items | |
| 683 wID = ATL_IDS_MRU_FILE; | |
| 684 else if((wID >= ATL_IDM_FIRST_MDICHILD) && (wID <= ATL_IDM_LAST_MDICHILD)) // MDI child windows | |
| 685 wID = ATL_IDS_MDICHILD; | |
| 686 | |
| 687 int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff); | |
| 688 for(int i = 0; i < nRet; i++) | |
| 689 { | |
| 690 if(szBuff[i] == _T('\n')) | |
| 691 { | |
| 692 szBuff[i] = 0; | |
| 693 break; | |
| 694 } | |
| 695 } | |
| 696 } | |
| 697 ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); | |
| 698 ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff); | |
| 699 } | |
| 700 | |
| 701 return 1; | |
| 702 } | |
| 703 | |
| 704 LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled) | |
| 705 { | |
| 706 if(m_hWndClient != NULL) | |
| 707 ::SetFocus(m_hWndClient); | |
| 708 | |
| 709 bHandled = FALSE; | |
| 710 return 1; | |
| 711 } | |
| 712 | |
| 713 LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) | |
| 714 { | |
| 715 if((this->GetStyle() & (WS_CHILD | WS_POPUP)) == 0) | |
| 716 ::PostQuitMessage(1); | |
| 717 | |
| 718 bHandled = FALSE; | |
| 719 return 1; | |
| 720 } | |
| 721 | |
| 722 LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) | |
| 723 { | |
| 724 LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh; | |
| 725 if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) | |
| 726 { | |
| 727 const int cchBuff = 256; | |
| 728 char szBuff[cchBuff] = {}; | |
| 729 int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); | |
| 730 for(int i = 0; i < nRet; i++) | |
| 731 { | |
| 732 if(szBuff[i] == '\n') | |
| 733 { | |
| 734 ATL::Checked::strncpy_s(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); | |
| 735 break; | |
| 736 } | |
| 737 } | |
| 738 if(nRet > 0) // string was loaded, save it | |
| 739 pDispInfo->uFlags |= TTF_DI_SETITEM; | |
| 740 } | |
| 741 | |
| 742 return 0; | |
| 743 } | |
| 744 | |
| 745 LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) | |
| 746 { | |
| 747 LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh; | |
| 748 if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) | |
| 749 { | |
| 750 const int cchBuff = 256; | |
| 751 wchar_t szBuff[cchBuff] = {}; | |
| 752 int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); | |
| 753 for(int i = 0; i < nRet; i++) | |
| 754 { | |
| 755 if(szBuff[i] == L'\n') | |
| 756 { | |
| 757 ATL::Checked::wcsncpy_s(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); | |
| 758 break; | |
| 759 } | |
| 760 } | |
| 761 if(nRet > 0) // string was loaded, save it | |
| 762 pDispInfo->uFlags |= TTF_DI_SETITEM; | |
| 763 } | |
| 764 | |
| 765 return 0; | |
| 766 } | |
| 767 | |
| 768 // Implementation - chevron menu support | |
| 769 bool PrepareChevronMenu(_ChevronMenuInfo& cmi) | |
| 770 { | |
| 771 // get rebar and toolbar | |
| 772 REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; | |
| 773 rbbi.fMask = RBBIM_CHILD; | |
| 774 BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi); | |
| 775 ATLASSERT(bRet); | |
| 776 | |
| 777 // assume the band is a toolbar | |
| 778 ATL::CWindow wnd = rbbi.hwndChild; | |
| 779 int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT); | |
| 780 if(nCount <= 0) // probably not a toolbar | |
| 781 return false; | |
| 782 | |
| 783 // check if it's a command bar | |
| 784 CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU); | |
| 785 cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL); | |
| 786 | |
| 787 // build a menu from hidden items | |
| 788 CMenuHandle menu; | |
| 789 bRet = menu.CreatePopupMenu(); | |
| 790 ATLASSERT(bRet); | |
| 791 RECT rcClient = {}; | |
| 792 bRet = wnd.GetClientRect(&rcClient); | |
| 793 ATLASSERT(bRet); | |
| 794 for(int i = 0; i < nCount; i++) | |
| 795 { | |
| 796 TBBUTTON tbb = {}; | |
| 797 bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb); | |
| 798 ATLASSERT(bRet); | |
| 799 // skip hidden buttons | |
| 800 if((tbb.fsState & TBSTATE_HIDDEN) != 0) | |
| 801 continue; | |
| 802 RECT rcButton = {}; | |
| 803 bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton); | |
| 804 ATLASSERT(bRet); | |
| 805 bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0); | |
| 806 if((rcButton.right > rcClient.right) || (rcButton.bottom > rcClient.bottom)) | |
| 807 { | |
| 808 if(tbb.fsStyle & BTNS_SEP) | |
| 809 { | |
| 810 if(menu.GetMenuItemCount() > 0) | |
| 811 menu.AppendMenu(MF_SEPARATOR); | |
| 812 } | |
| 813 else if(cmi.bCmdBar) | |
| 814 { | |
| 815 const int cchBuff = 200; | |
| 816 TCHAR szBuff[cchBuff] = {}; | |
| 817 CMenuItemInfo mii; | |
| 818 mii.fMask = MIIM_TYPE | MIIM_SUBMENU; | |
| 819 mii.dwTypeData = szBuff; | |
| 820 mii.cch = cchBuff; | |
| 821 bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii); | |
| 822 ATLASSERT(bRet); | |
| 823 // Note: CmdBar currently supports only drop-down items | |
| 824 ATLASSERT(::IsMenu(mii.hSubMenu)); | |
| 825 bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData); | |
| 826 ATLASSERT(bRet); | |
| 827 } | |
| 828 else | |
| 829 { | |
| 830 // get button's text | |
| 831 const int cchBuff = 200; | |
| 832 TCHAR szBuff[cchBuff] = {}; | |
| 833 LPCTSTR lpstrText = szBuff; | |
| 834 TBBUTTONINFO tbbi = {}; | |
| 835 tbbi.cbSize = sizeof(TBBUTTONINFO); | |
| 836 tbbi.dwMask = TBIF_TEXT; | |
| 837 tbbi.pszText = szBuff; | |
| 838 tbbi.cchText = cchBuff; | |
| 839 if((wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1) || (szBuff[0] == 0)) | |
| 840 { | |
| 841 // no text for this button, try a resource string | |
| 842 lpstrText = _T(""); | |
| 843 int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff); | |
| 844 for(int n = 0; n < nRet; n++) | |
| 845 { | |
| 846 if(szBuff[n] == _T('\n')) | |
| 847 { | |
| 848 lpstrText = &szBuff[n + 1]; | |
| 849 break; | |
| 850 } | |
| 851 } | |
| 852 } | |
| 853 bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText); | |
| 854 ATLASSERT(bRet); | |
| 855 } | |
| 856 } | |
| 857 } | |
| 858 | |
| 859 if(menu.GetMenuItemCount() == 0) // no hidden buttons after all | |
| 860 { | |
| 861 menu.DestroyMenu(); | |
| 862 ::MessageBeep((UINT)-1); | |
| 863 return false; | |
| 864 } | |
| 865 | |
| 866 cmi.hMenu = menu; | |
| 867 return true; | |
| 868 } | |
| 869 | |
| 870 void DisplayChevronMenu(_ChevronMenuInfo& cmi) | |
| 871 { | |
| 872 // convert chevron rect to screen coordinates | |
| 873 ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; | |
| 874 POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom }; | |
| 875 wndFrom.MapWindowPoints(NULL, &pt, 1); | |
| 876 RECT rc = cmi.lpnm->rc; | |
| 877 wndFrom.MapWindowPoints(NULL, &rc); | |
| 878 // set up flags and rect | |
| 879 UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION; | |
| 880 TPMPARAMS TPMParams = {}; | |
| 881 TPMParams.cbSize = sizeof(TPMPARAMS); | |
| 882 TPMParams.rcExclude = rc; | |
| 883 // check if this window has a command bar | |
| 884 HWND hWndCmdBar = (HWND)::SendMessage(this->m_hWnd, CBRM_GETCMDBAR, 0, 0L); | |
| 885 if(::IsWindow(hWndCmdBar)) | |
| 886 { | |
| 887 CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams }; | |
| 888 ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu); | |
| 889 } | |
| 890 else | |
| 891 { | |
| 892 CMenuHandle menu = cmi.hMenu; | |
| 893 menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, this->m_hWnd, &TPMParams); | |
| 894 } | |
| 895 } | |
| 896 | |
| 897 void CleanupChevronMenu(_ChevronMenuInfo& cmi) | |
| 898 { | |
| 899 CMenuHandle menu = cmi.hMenu; | |
| 900 // if menu is from a command bar, detach submenus so they are not destroyed | |
| 901 if(cmi.bCmdBar) | |
| 902 { | |
| 903 for(int i = menu.GetMenuItemCount() - 1; i >=0; i--) | |
| 904 menu.RemoveMenu(i, MF_BYPOSITION); | |
| 905 } | |
| 906 // destroy menu | |
| 907 menu.DestroyMenu(); | |
| 908 // convert chevron rect to screen coordinates | |
| 909 ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; | |
| 910 RECT rc = cmi.lpnm->rc; | |
| 911 wndFrom.MapWindowPoints(NULL, &rc); | |
| 912 // eat next message if click is on the same button | |
| 913 MSG msg = {}; | |
| 914 if(::PeekMessage(&msg, this->m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt)) | |
| 915 ::PeekMessage(&msg, this->m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); | |
| 916 } | |
| 917 }; | |
| 918 | |
| 919 | |
| 920 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits> | |
| 921 class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits > | |
| 922 { | |
| 923 public: | |
| 924 HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, | |
| 925 DWORD dwStyle = 0, DWORD dwExStyle = 0, | |
| 926 HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) | |
| 927 { | |
| 928 ATOM atom = T::GetWndClassInfo().Register(&this->m_pfnSuperWindowProc); | |
| 929 | |
| 930 dwStyle = T::GetWndStyle(dwStyle); | |
| 931 dwExStyle = T::GetWndExStyle(dwExStyle); | |
| 932 | |
| 933 if(rect.m_lpRect == NULL) | |
| 934 rect.m_lpRect = &TBase::rcDefault; | |
| 935 | |
| 936 return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); | |
| 937 } | |
| 938 | |
| 939 HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) | |
| 940 { | |
| 941 const int cchName = 256; | |
| 942 TCHAR szWindowName[cchName] = {}; | |
| 943 ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); | |
| 944 HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); | |
| 945 | |
| 946 T* pT = static_cast<T*>(this); | |
| 947 HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); | |
| 948 | |
| 949 if(hWnd != NULL) | |
| 950 this->m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); | |
| 951 | |
| 952 return hWnd; | |
| 953 } | |
| 954 | |
| 955 BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 956 { | |
| 957 if(nResourceID == 0) | |
| 958 nResourceID = T::GetWndClassInfo().m_uCommonResourceID; | |
| 959 ATLASSERT(!::IsWindow(this->m_hWndToolBar)); | |
| 960 this->m_hWndToolBar = T::CreateSimpleToolBarCtrl(this->m_hWnd, nResourceID, TRUE, dwStyle, nID); | |
| 961 return (this->m_hWndToolBar != NULL); | |
| 962 } | |
| 963 | |
| 964 // message map and handlers | |
| 965 typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass; | |
| 966 | |
| 967 BEGIN_MSG_MAP(CFrameWindowImpl) | |
| 968 MESSAGE_HANDLER(WM_SIZE, OnSize) | |
| 969 #ifndef _ATL_NO_REBAR_SUPPORT | |
| 970 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) | |
| 971 NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) | |
| 972 #endif // !_ATL_NO_REBAR_SUPPORT | |
| 973 CHAIN_MSG_MAP(_baseClass) | |
| 974 END_MSG_MAP() | |
| 975 | |
| 976 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) | |
| 977 { | |
| 978 if(wParam != SIZE_MINIMIZED) | |
| 979 { | |
| 980 T* pT = static_cast<T*>(this); | |
| 981 pT->UpdateLayout(); | |
| 982 } | |
| 983 bHandled = FALSE; | |
| 984 return 1; | |
| 985 } | |
| 986 | |
| 987 #ifndef _ATL_NO_REBAR_SUPPORT | |
| 988 LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) | |
| 989 { | |
| 990 T* pT = static_cast<T*>(this); | |
| 991 pT->UpdateLayout(FALSE); | |
| 992 return 0; | |
| 993 } | |
| 994 | |
| 995 LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) | |
| 996 { | |
| 997 T* pT = static_cast<T*>(this); | |
| 998 typename CFrameWindowImplBase< TBase, TWinTraits >::_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; | |
| 999 if(!pT->PrepareChevronMenu(cmi)) | |
| 1000 { | |
| 1001 bHandled = FALSE; | |
| 1002 return 1; | |
| 1003 } | |
| 1004 // display a popup menu with hidden items | |
| 1005 pT->DisplayChevronMenu(cmi); | |
| 1006 // cleanup | |
| 1007 pT->CleanupChevronMenu(cmi); | |
| 1008 return 0; | |
| 1009 } | |
| 1010 #endif // !_ATL_NO_REBAR_SUPPORT | |
| 1011 }; | |
| 1012 | |
| 1013 | |
| 1014 /////////////////////////////////////////////////////////////////////////////// | |
| 1015 // AtlCreateSimpleToolBar - helper for creating simple toolbars | |
| 1016 | |
| 1017 inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, | |
| 1018 DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 1019 { | |
| 1020 return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID); | |
| 1021 } | |
| 1022 | |
| 1023 | |
| 1024 /////////////////////////////////////////////////////////////////////////////// | |
| 1025 // CMDIWindow | |
| 1026 | |
| 1027 #ifndef _WTL_MDIWINDOWMENU_TEXT | |
| 1028 #define _WTL_MDIWINDOWMENU_TEXT _T("&Window") | |
| 1029 #endif | |
| 1030 | |
| 1031 class CMDIWindow : public ATL::CWindow | |
| 1032 { | |
| 1033 public: | |
| 1034 // Data members | |
| 1035 HWND m_hWndMDIClient; | |
| 1036 HMENU m_hMenu; | |
| 1037 | |
| 1038 // Constructors | |
| 1039 CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) | |
| 1040 { } | |
| 1041 | |
| 1042 CMDIWindow& operator =(HWND hWnd) | |
| 1043 { | |
| 1044 m_hWnd = hWnd; | |
| 1045 return *this; | |
| 1046 } | |
| 1047 | |
| 1048 // Operations | |
| 1049 HWND MDIGetActive(BOOL* lpbMaximized = NULL) | |
| 1050 { | |
| 1051 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1052 return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized); | |
| 1053 } | |
| 1054 | |
| 1055 void MDIActivate(HWND hWndChildToActivate) | |
| 1056 { | |
| 1057 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1058 ATLASSERT(::IsWindow(hWndChildToActivate)); | |
| 1059 ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0); | |
| 1060 } | |
| 1061 | |
| 1062 void MDINext(HWND hWndChild, BOOL bPrevious = FALSE) | |
| 1063 { | |
| 1064 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1065 ATLASSERT((hWndChild == NULL) || ::IsWindow(hWndChild)); | |
| 1066 ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious); | |
| 1067 } | |
| 1068 | |
| 1069 void MDIMaximize(HWND hWndChildToMaximize) | |
| 1070 { | |
| 1071 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1072 ATLASSERT(::IsWindow(hWndChildToMaximize)); | |
| 1073 ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0); | |
| 1074 } | |
| 1075 | |
| 1076 void MDIRestore(HWND hWndChildToRestore) | |
| 1077 { | |
| 1078 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1079 ATLASSERT(::IsWindow(hWndChildToRestore)); | |
| 1080 ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0); | |
| 1081 } | |
| 1082 | |
| 1083 void MDIDestroy(HWND hWndChildToDestroy) | |
| 1084 { | |
| 1085 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1086 ATLASSERT(::IsWindow(hWndChildToDestroy)); | |
| 1087 ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0); | |
| 1088 } | |
| 1089 | |
| 1090 BOOL MDICascade(UINT uFlags = 0) | |
| 1091 { | |
| 1092 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1093 return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0); | |
| 1094 } | |
| 1095 | |
| 1096 BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL) | |
| 1097 { | |
| 1098 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1099 return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0); | |
| 1100 } | |
| 1101 | |
| 1102 void MDIIconArrange() | |
| 1103 { | |
| 1104 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1105 ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0); | |
| 1106 } | |
| 1107 | |
| 1108 HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow) | |
| 1109 { | |
| 1110 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1111 return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow); | |
| 1112 } | |
| 1113 | |
| 1114 HMENU MDIRefreshMenu() | |
| 1115 { | |
| 1116 ATLASSERT(::IsWindow(m_hWndMDIClient)); | |
| 1117 return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0); | |
| 1118 } | |
| 1119 | |
| 1120 // Additional operations | |
| 1121 static HMENU GetStandardWindowMenu(HMENU hMenu) | |
| 1122 { | |
| 1123 int nCount = ::GetMenuItemCount(hMenu); | |
| 1124 if(nCount == -1) | |
| 1125 return NULL; | |
| 1126 int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION); | |
| 1127 if(nLen == 0) | |
| 1128 return NULL; | |
| 1129 ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; | |
| 1130 LPTSTR lpszText = buff.Allocate(nLen + 1); | |
| 1131 if(lpszText == NULL) | |
| 1132 return NULL; | |
| 1133 if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen) | |
| 1134 return NULL; | |
| 1135 if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0) | |
| 1136 return NULL; | |
| 1137 return ::GetSubMenu(hMenu, nCount - 2); | |
| 1138 } | |
| 1139 | |
| 1140 void SetMDIFrameMenu() | |
| 1141 { | |
| 1142 HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu); | |
| 1143 MDISetMenu(m_hMenu, hWindowMenu); | |
| 1144 MDIRefreshMenu(); | |
| 1145 ::DrawMenuBar(GetMDIFrame()); | |
| 1146 } | |
| 1147 | |
| 1148 HWND GetMDIFrame() const | |
| 1149 { | |
| 1150 return ::GetParent(m_hWndMDIClient); | |
| 1151 } | |
| 1152 }; | |
| 1153 | |
| 1154 | |
| 1155 /////////////////////////////////////////////////////////////////////////////// | |
| 1156 // CMDIFrameWindowImpl | |
| 1157 | |
| 1158 // MDI child command chaining macro (only for MDI frame windows) | |
| 1159 #define CHAIN_MDI_CHILD_COMMANDS() \ | |
| 1160 if(uMsg == WM_COMMAND) \ | |
| 1161 { \ | |
| 1162 HWND hWndChild = this->MDIGetActive(); \ | |
| 1163 if(hWndChild != NULL) \ | |
| 1164 ::SendMessage(hWndChild, uMsg, wParam, lParam); \ | |
| 1165 } | |
| 1166 | |
| 1167 template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits> | |
| 1168 class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits > | |
| 1169 { | |
| 1170 public: | |
| 1171 HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, | |
| 1172 DWORD dwStyle = 0, DWORD dwExStyle = 0, | |
| 1173 HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) | |
| 1174 { | |
| 1175 this->m_hMenu = hMenu; | |
| 1176 ATOM atom = T::GetWndClassInfo().Register(&this->m_pfnSuperWindowProc); | |
| 1177 | |
| 1178 dwStyle = T::GetWndStyle(dwStyle); | |
| 1179 dwExStyle = T::GetWndExStyle(dwExStyle); | |
| 1180 | |
| 1181 if(rect.m_lpRect == NULL) | |
| 1182 rect.m_lpRect = &TBase::rcDefault; | |
| 1183 | |
| 1184 return CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); | |
| 1185 } | |
| 1186 | |
| 1187 HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) | |
| 1188 { | |
| 1189 const int cchName = 256; | |
| 1190 TCHAR szWindowName[cchName] = {}; | |
| 1191 ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); | |
| 1192 HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); | |
| 1193 | |
| 1194 T* pT = static_cast<T*>(this); | |
| 1195 HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); | |
| 1196 | |
| 1197 if(hWnd != NULL) | |
| 1198 this->m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); | |
| 1199 | |
| 1200 return hWnd; | |
| 1201 } | |
| 1202 | |
| 1203 BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 1204 { | |
| 1205 ATLASSERT(!::IsWindow(this->m_hWndToolBar)); | |
| 1206 if(nResourceID == 0) | |
| 1207 nResourceID = T::GetWndClassInfo().m_uCommonResourceID; | |
| 1208 this->m_hWndToolBar = T::CreateSimpleToolBarCtrl(this->m_hWnd, nResourceID, TRUE, dwStyle, nID); | |
| 1209 return (this->m_hWndToolBar != NULL); | |
| 1210 } | |
| 1211 | |
| 1212 virtual WNDPROC GetWindowProc() | |
| 1213 { | |
| 1214 return MDIFrameWindowProc; | |
| 1215 } | |
| 1216 | |
| 1217 static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
| 1218 { | |
| 1219 CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd; | |
| 1220 // set a ptr to this message and save the old value | |
| 1221 ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam); | |
| 1222 const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg; | |
| 1223 pThis->m_pCurrentMsg = &msg; | |
| 1224 // pass to the message map to process | |
| 1225 LRESULT lRes = 0; | |
| 1226 BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); | |
| 1227 // restore saved value for the current message | |
| 1228 ATLASSERT(pThis->m_pCurrentMsg == &msg); | |
| 1229 pThis->m_pCurrentMsg = pOldMsg; | |
| 1230 // do the default processing if message was not handled | |
| 1231 if(!bRet) | |
| 1232 { | |
| 1233 if(uMsg != WM_NCDESTROY) | |
| 1234 { | |
| 1235 lRes = pThis->DefWindowProc(uMsg, wParam, lParam); | |
| 1236 } | |
| 1237 else | |
| 1238 { | |
| 1239 // unsubclass, if needed | |
| 1240 LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); | |
| 1241 lRes = pThis->DefWindowProc(uMsg, wParam, lParam); | |
| 1242 if((pThis->m_pfnSuperWindowProc != ::DefWindowProc) && (::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)) | |
| 1243 ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); | |
| 1244 // mark window as destryed | |
| 1245 pThis->m_dwState |= ATL::CWindowImplRoot< TBase >::WINSTATE_DESTROYED; | |
| 1246 } | |
| 1247 } | |
| 1248 if((pThis->m_dwState & ATL::CWindowImplRoot< TBase >::WINSTATE_DESTROYED) && (pThis->m_pCurrentMsg == NULL)) | |
| 1249 { | |
| 1250 // clear out window handle | |
| 1251 HWND hWndThis = pThis->m_hWnd; | |
| 1252 pThis->m_hWnd = NULL; | |
| 1253 pThis->m_dwState &= ~ATL::CWindowImplRoot< TBase >::WINSTATE_DESTROYED; | |
| 1254 // clean up after window is destroyed | |
| 1255 pThis->OnFinalMessage(hWndThis); | |
| 1256 } | |
| 1257 return lRes; | |
| 1258 } | |
| 1259 | |
| 1260 // Overriden to call DefWindowProc which uses DefFrameProc | |
| 1261 LRESULT DefWindowProc() | |
| 1262 { | |
| 1263 const ATL::_ATL_MSG* pMsg = this->m_pCurrentMsg; | |
| 1264 LRESULT lRes = 0; | |
| 1265 if (pMsg != NULL) | |
| 1266 lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); | |
| 1267 return lRes; | |
| 1268 } | |
| 1269 | |
| 1270 LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) | |
| 1271 { | |
| 1272 return ::DefFrameProc(this->m_hWnd, this->m_hWndMDIClient, uMsg, wParam, lParam); | |
| 1273 } | |
| 1274 | |
| 1275 BOOL PreTranslateMessage(MSG* pMsg) | |
| 1276 { | |
| 1277 if(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg)) | |
| 1278 return TRUE; | |
| 1279 return ::TranslateMDISysAccel(this->m_hWndMDIClient, pMsg); | |
| 1280 } | |
| 1281 | |
| 1282 HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD) | |
| 1283 { | |
| 1284 DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES; | |
| 1285 DWORD dwExStyle = WS_EX_CLIENTEDGE; | |
| 1286 | |
| 1287 CLIENTCREATESTRUCT ccs = {}; | |
| 1288 ccs.hWindowMenu = hWindowMenu; | |
| 1289 ccs.idFirstChild = nFirstChildID; | |
| 1290 | |
| 1291 if((this->GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0) | |
| 1292 { | |
| 1293 // parent MDI frame's scroll styles move to the MDICLIENT | |
| 1294 dwStyle |= (this->GetStyle() & (WS_HSCROLL | WS_VSCROLL)); | |
| 1295 | |
| 1296 // fast way to turn off the scrollbar bits (without a resize) | |
| 1297 this->ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED); | |
| 1298 } | |
| 1299 | |
| 1300 // Create MDICLIENT window | |
| 1301 this->m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL, | |
| 1302 dwStyle, 0, 0, 1, 1, this->m_hWnd, (HMENU)LongToHandle(nID), | |
| 1303 ModuleHelper::GetModuleInstance(), (LPVOID)&ccs); | |
| 1304 if (this->m_hWndClient == NULL) | |
| 1305 { | |
| 1306 ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n")); | |
| 1307 return NULL; | |
| 1308 } | |
| 1309 | |
| 1310 // Move it to the top of z-order | |
| 1311 ::BringWindowToTop(this->m_hWndClient); | |
| 1312 | |
| 1313 // set as MDI client window | |
| 1314 this->m_hWndMDIClient = this->m_hWndClient; | |
| 1315 | |
| 1316 // update to proper size | |
| 1317 T* pT = static_cast<T*>(this); | |
| 1318 pT->UpdateLayout(); | |
| 1319 | |
| 1320 return this->m_hWndClient; | |
| 1321 } | |
| 1322 | |
| 1323 typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass; | |
| 1324 | |
| 1325 BEGIN_MSG_MAP(CMDIFrameWindowImpl) | |
| 1326 MESSAGE_HANDLER(WM_SIZE, OnSize) | |
| 1327 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) | |
| 1328 MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) | |
| 1329 #ifndef _ATL_NO_REBAR_SUPPORT | |
| 1330 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) | |
| 1331 NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) | |
| 1332 #endif // !_ATL_NO_REBAR_SUPPORT | |
| 1333 CHAIN_MSG_MAP(_baseClass) | |
| 1334 END_MSG_MAP() | |
| 1335 | |
| 1336 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | |
| 1337 { | |
| 1338 if(wParam != SIZE_MINIMIZED) | |
| 1339 { | |
| 1340 T* pT = static_cast<T*>(this); | |
| 1341 pT->UpdateLayout(); | |
| 1342 } | |
| 1343 // message must be handled, otherwise DefFrameProc would resize the client again | |
| 1344 return 0; | |
| 1345 } | |
| 1346 | |
| 1347 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) | |
| 1348 { | |
| 1349 // don't allow CFrameWindowImplBase to handle this one | |
| 1350 return DefWindowProc(uMsg, wParam, lParam); | |
| 1351 } | |
| 1352 | |
| 1353 LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | |
| 1354 { | |
| 1355 this->SetMDIFrameMenu(); | |
| 1356 return 0; | |
| 1357 } | |
| 1358 | |
| 1359 #ifndef _ATL_NO_REBAR_SUPPORT | |
| 1360 LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) | |
| 1361 { | |
| 1362 T* pT = static_cast<T*>(this); | |
| 1363 pT->UpdateLayout(FALSE); | |
| 1364 return 0; | |
| 1365 } | |
| 1366 | |
| 1367 LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) | |
| 1368 { | |
| 1369 T* pT = static_cast<T*>(this); | |
| 1370 typename CFrameWindowImplBase<TBase, TWinTraits >::_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; | |
| 1371 if(!pT->PrepareChevronMenu(cmi)) | |
| 1372 { | |
| 1373 bHandled = FALSE; | |
| 1374 return 1; | |
| 1375 } | |
| 1376 // display a popup menu with hidden items | |
| 1377 pT->DisplayChevronMenu(cmi); | |
| 1378 // cleanup | |
| 1379 pT->CleanupChevronMenu(cmi); | |
| 1380 return 0; | |
| 1381 } | |
| 1382 #endif // !_ATL_NO_REBAR_SUPPORT | |
| 1383 }; | |
| 1384 | |
| 1385 | |
| 1386 /////////////////////////////////////////////////////////////////////////////// | |
| 1387 // CMDIChildWindowImpl | |
| 1388 | |
| 1389 template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits> | |
| 1390 class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits > | |
| 1391 { | |
| 1392 public: | |
| 1393 HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, | |
| 1394 DWORD dwStyle = 0, DWORD dwExStyle = 0, | |
| 1395 UINT nMenuID = 0, LPVOID lpCreateParam = NULL) | |
| 1396 { | |
| 1397 ATOM atom = T::GetWndClassInfo().Register(&this->m_pfnSuperWindowProc); | |
| 1398 | |
| 1399 if(nMenuID != 0) | |
| 1400 this->m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID)); | |
| 1401 | |
| 1402 dwStyle = T::GetWndStyle(dwStyle); | |
| 1403 dwExStyle = T::GetWndExStyle(dwExStyle); | |
| 1404 | |
| 1405 dwExStyle |= WS_EX_MDICHILD; // force this one | |
| 1406 this->m_pfnSuperWindowProc = ::DefMDIChildProc; | |
| 1407 this->m_hWndMDIClient = hWndParent; | |
| 1408 ATLASSERT(::IsWindow(this->m_hWndMDIClient)); | |
| 1409 | |
| 1410 if(rect.m_lpRect == NULL) | |
| 1411 rect.m_lpRect = &TBase::rcDefault; | |
| 1412 | |
| 1413 // If the currently active MDI child is maximized, we want to create this one maximized too | |
| 1414 ATL::CWindow wndParent = hWndParent; | |
| 1415 BOOL bMaximized = FALSE; | |
| 1416 wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); | |
| 1417 if(bMaximized) | |
| 1418 wndParent.SetRedraw(FALSE); | |
| 1419 | |
| 1420 HWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam); | |
| 1421 | |
| 1422 if(bMaximized) | |
| 1423 { | |
| 1424 // Maximize and redraw everything | |
| 1425 if(hWnd != NULL) | |
| 1426 this->MDIMaximize(hWnd); | |
| 1427 wndParent.SetRedraw(TRUE); | |
| 1428 wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); | |
| 1429 ::SetFocus(this->GetMDIFrame()); // focus will be set back to this window | |
| 1430 } | |
| 1431 else if((hWnd != NULL) && ::IsWindowVisible(this->m_hWnd) && !::IsChild(hWnd, ::GetFocus())) | |
| 1432 { | |
| 1433 ::SetFocus(hWnd); | |
| 1434 } | |
| 1435 | |
| 1436 return hWnd; | |
| 1437 } | |
| 1438 | |
| 1439 HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) | |
| 1440 { | |
| 1441 const int cchName = 256; | |
| 1442 TCHAR szWindowName[cchName] = {}; | |
| 1443 if(lpcstrWindowName == NULL) | |
| 1444 { | |
| 1445 ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); | |
| 1446 lpcstrWindowName = szWindowName; | |
| 1447 } | |
| 1448 | |
| 1449 T* pT = static_cast<T*>(this); | |
| 1450 HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam); | |
| 1451 | |
| 1452 if(hWnd != NULL) | |
| 1453 this->m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); | |
| 1454 | |
| 1455 return hWnd; | |
| 1456 } | |
| 1457 | |
| 1458 BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) | |
| 1459 { | |
| 1460 ATLASSERT(!::IsWindow(this->m_hWndToolBar)); | |
| 1461 if(nResourceID == 0) | |
| 1462 nResourceID = T::GetWndClassInfo().m_uCommonResourceID; | |
| 1463 this->m_hWndToolBar = T::CreateSimpleToolBarCtrl(this->m_hWnd, nResourceID, TRUE, dwStyle, nID); | |
| 1464 return (this->m_hWndToolBar != NULL); | |
| 1465 } | |
| 1466 | |
| 1467 BOOL UpdateClientEdge(LPRECT lpRect = NULL) | |
| 1468 { | |
| 1469 // only adjust for active MDI child window | |
| 1470 HWND hWndChild = this->MDIGetActive(); | |
| 1471 if((hWndChild != NULL) && (hWndChild != this->m_hWnd)) | |
| 1472 return FALSE; | |
| 1473 | |
| 1474 // need to adjust the client edge style as max/restore happens | |
| 1475 DWORD dwStyle = ::GetWindowLong(this->m_hWndMDIClient, GWL_EXSTYLE); | |
| 1476 DWORD dwNewStyle = dwStyle; | |
| 1477 if((hWndChild != NULL) && ((this->GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((this->GetStyle() & WS_MAXIMIZE) != 0)) | |
| 1478 dwNewStyle &= ~(WS_EX_CLIENTEDGE); | |
| 1479 else | |
| 1480 dwNewStyle |= WS_EX_CLIENTEDGE; | |
| 1481 | |
| 1482 if(dwStyle != dwNewStyle) | |
| 1483 { | |
| 1484 // SetWindowPos will not move invalid bits | |
| 1485 ::RedrawWindow(this->m_hWndMDIClient, NULL, NULL, | |
| 1486 RDW_INVALIDATE | RDW_ALLCHILDREN); | |
| 1487 // remove/add WS_EX_CLIENTEDGE to MDI client area | |
| 1488 ::SetWindowLong(this->m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle); | |
| 1489 ::SetWindowPos(this->m_hWndMDIClient, NULL, 0, 0, 0, 0, | |
| 1490 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | | |
| 1491 SWP_NOZORDER | SWP_NOCOPYBITS); | |
| 1492 | |
| 1493 // return new client area | |
| 1494 if (lpRect != NULL) | |
| 1495 ::GetClientRect(this->m_hWndMDIClient, lpRect); | |
| 1496 | |
| 1497 return TRUE; | |
| 1498 } | |
| 1499 | |
| 1500 return FALSE; | |
| 1501 } | |
| 1502 | |
| 1503 typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass; | |
| 1504 BEGIN_MSG_MAP(CMDIChildWindowImpl) | |
| 1505 MESSAGE_HANDLER(WM_SIZE, OnSize) | |
| 1506 MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged) | |
| 1507 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) | |
| 1508 MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) | |
| 1509 MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate) | |
| 1510 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) | |
| 1511 #ifndef _ATL_NO_REBAR_SUPPORT | |
| 1512 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) | |
| 1513 NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) | |
| 1514 #endif // !_ATL_NO_REBAR_SUPPORT | |
| 1515 CHAIN_MSG_MAP(_baseClass) | |
| 1516 END_MSG_MAP() | |
| 1517 | |
| 1518 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) | |
| 1519 { | |
| 1520 this->DefWindowProc(uMsg, wParam, lParam); // needed for MDI children | |
| 1521 if(wParam != SIZE_MINIMIZED) | |
| 1522 { | |
| 1523 T* pT = static_cast<T*>(this); | |
| 1524 pT->UpdateLayout(); | |
| 1525 } | |
| 1526 return 0; | |
| 1527 } | |
| 1528 | |
| 1529 LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | |
| 1530 { | |
| 1531 // update MDI client edge and adjust MDI child rect | |
| 1532 LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam; | |
| 1533 | |
| 1534 if(!(lpWndPos->flags & SWP_NOSIZE)) | |
| 1535 { | |
| 1536 RECT rectClient = {}; | |
| 1537 if(UpdateClientEdge(&rectClient) && ((this->GetStyle() & WS_MAXIMIZE) != 0)) | |
| 1538 { | |
| 1539 ::AdjustWindowRectEx(&rectClient, this->GetStyle(), FALSE, this->GetExStyle()); | |
| 1540 lpWndPos->x = rectClient.left; | |
| 1541 lpWndPos->y = rectClient.top; | |
| 1542 lpWndPos->cx = rectClient.right - rectClient.left; | |
| 1543 lpWndPos->cy = rectClient.bottom - rectClient.top; | |
| 1544 } | |
| 1545 } | |
| 1546 | |
| 1547 bHandled = FALSE; | |
| 1548 return 1; | |
| 1549 } | |
| 1550 | |
| 1551 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) | |
| 1552 { | |
| 1553 LRESULT lRes = this->DefWindowProc(uMsg, wParam, lParam); | |
| 1554 | |
| 1555 // Activate this MDI window if needed | |
| 1556 if((lRes == MA_ACTIVATE) || (lRes == MA_ACTIVATEANDEAT)) | |
| 1557 { | |
| 1558 if(this->MDIGetActive() != this->m_hWnd) | |
| 1559 this->MDIActivate(this->m_hWnd); | |
| 1560 } | |
| 1561 | |
| 1562 return lRes; | |
| 1563 } | |
| 1564 | |
| 1565 LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) | |
| 1566 { | |
| 1567 return ::SendMessage(this->GetMDIFrame(), uMsg, wParam, lParam); | |
| 1568 } | |
| 1569 | |
| 1570 LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | |
| 1571 { | |
| 1572 if(((HWND)lParam == this->m_hWnd) && (this->m_hMenu != NULL)) | |
| 1573 this->SetMDIFrameMenu(); | |
| 1574 else if((HWND)lParam == NULL) | |
| 1575 ::SendMessage(this->GetMDIFrame(), WM_MDISETMENU, 0, 0); | |
| 1576 | |
| 1577 bHandled = FALSE; | |
| 1578 return 1; | |
| 1579 } | |
| 1580 | |
| 1581 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | |
| 1582 { | |
| 1583 if(this->m_hMenu != NULL) | |
| 1584 { | |
| 1585 ::DestroyMenu(this->m_hMenu); | |
| 1586 this->m_hMenu = NULL; | |
| 1587 } | |
| 1588 UpdateClientEdge(); | |
| 1589 bHandled = FALSE; | |
| 1590 return 1; | |
| 1591 } | |
| 1592 | |
| 1593 #ifndef _ATL_NO_REBAR_SUPPORT | |
| 1594 LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) | |
| 1595 { | |
| 1596 T* pT = static_cast<T*>(this); | |
| 1597 pT->UpdateLayout(FALSE); | |
| 1598 return 0; | |
| 1599 } | |
| 1600 | |
| 1601 LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) | |
| 1602 { | |
| 1603 T* pT = static_cast<T*>(this); | |
| 1604 typename CFrameWindowImplBase<TBase, TWinTraits >::_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; | |
| 1605 if(!pT->PrepareChevronMenu(cmi)) | |
| 1606 { | |
| 1607 bHandled = FALSE; | |
| 1608 return 1; | |
| 1609 } | |
| 1610 // display a popup menu with hidden items | |
| 1611 pT->DisplayChevronMenu(cmi); | |
| 1612 // cleanup | |
| 1613 pT->CleanupChevronMenu(cmi); | |
| 1614 return 0; | |
| 1615 } | |
| 1616 #endif // !_ATL_NO_REBAR_SUPPORT | |
| 1617 }; | |
| 1618 | |
| 1619 | |
| 1620 /////////////////////////////////////////////////////////////////////////////// | |
| 1621 // COwnerDraw - MI class for owner-draw support | |
| 1622 | |
| 1623 template <class T> | |
| 1624 class COwnerDraw | |
| 1625 { | |
| 1626 public: | |
| 1627 // Message map and handlers | |
| 1628 BEGIN_MSG_MAP(COwnerDraw< T >) | |
| 1629 MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) | |
| 1630 MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) | |
| 1631 MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem) | |
| 1632 MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem) | |
| 1633 ALT_MSG_MAP(1) | |
| 1634 MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem) | |
| 1635 MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem) | |
| 1636 MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem) | |
| 1637 MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem) | |
| 1638 END_MSG_MAP() | |
| 1639 | |
| 1640 LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | |
| 1641 { | |
| 1642 T* pT = static_cast<T*>(this); | |
| 1643 pT->SetMsgHandled(TRUE); | |
| 1644 pT->DrawItem((LPDRAWITEMSTRUCT)lParam); | |
| 1645 bHandled = pT->IsMsgHandled(); | |
| 1646 return (LRESULT)TRUE; | |
| 1647 } | |
| 1648 | |
| 1649 LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | |
| 1650 { | |
| 1651 T* pT = static_cast<T*>(this); | |
| 1652 pT->SetMsgHandled(TRUE); | |
| 1653 pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam); | |
| 1654 bHandled = pT->IsMsgHandled(); | |
| 1655 return (LRESULT)TRUE; | |
| 1656 } | |
| 1657 | |
| 1658 LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | |
| 1659 { | |
| 1660 T* pT = static_cast<T*>(this); | |
| 1661 pT->SetMsgHandled(TRUE); | |
| 1662 bHandled = pT->IsMsgHandled(); | |
| 1663 return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam); | |
| 1664 } | |
| 1665 | |
| 1666 LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | |
| 1667 { | |
| 1668 T* pT = static_cast<T*>(this); | |
| 1669 pT->SetMsgHandled(TRUE); | |
| 1670 pT->DeleteItem((LPDELETEITEMSTRUCT)lParam); | |
| 1671 bHandled = pT->IsMsgHandled(); | |
| 1672 return (LRESULT)TRUE; | |
| 1673 } | |
| 1674 | |
| 1675 // Overrideables | |
| 1676 void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/) | |
| 1677 { | |
| 1678 // must be implemented | |
| 1679 ATLASSERT(FALSE); | |
| 1680 } | |
| 1681 | |
| 1682 void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) | |
| 1683 { | |
| 1684 if(lpMeasureItemStruct->CtlType != ODT_MENU) | |
| 1685 { | |
| 1686 // return default height for a system font | |
| 1687 T* pT = static_cast<T*>(this); | |
| 1688 HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID); | |
| 1689 CClientDC dc(hWnd); | |
| 1690 TEXTMETRIC tm = {}; | |
| 1691 dc.GetTextMetrics(&tm); | |
| 1692 | |
| 1693 lpMeasureItemStruct->itemHeight = tm.tmHeight; | |
| 1694 } | |
| 1695 else | |
| 1696 lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU); | |
| 1697 } | |
| 1698 | |
| 1699 int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/) | |
| 1700 { | |
| 1701 // all items are equal | |
| 1702 return 0; | |
| 1703 } | |
| 1704 | |
| 1705 void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/) | |
| 1706 { | |
| 1707 // default - nothing | |
| 1708 } | |
| 1709 }; | |
| 1710 | |
| 1711 | |
| 1712 /////////////////////////////////////////////////////////////////////////////// | |
| 1713 // Update UI macros | |
| 1714 | |
| 1715 // these build the Update UI map inside a class definition | |
| 1716 #define BEGIN_UPDATE_UI_MAP(thisClass) \ | |
| 1717 static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \ | |
| 1718 { \ | |
| 1719 static const CUpdateUIBase::_AtlUpdateUIMap theMap[] = \ | |
| 1720 { | |
| 1721 | |
| 1722 #define UPDATE_ELEMENT(nID, wType) \ | |
| 1723 { nID, wType }, | |
| 1724 | |
| 1725 #define END_UPDATE_UI_MAP() \ | |
| 1726 { (WORD)-1, 0 } \ | |
| 1727 }; \ | |
| 1728 return theMap; \ | |
| 1729 } | |
| 1730 | |
| 1731 /////////////////////////////////////////////////////////////////////////////// | |
| 1732 // CUpdateUI - manages UI elements updating | |
| 1733 | |
| 1734 class CUpdateUIBase | |
| 1735 { | |
| 1736 public: | |
| 1737 // constants | |
| 1738 enum | |
| 1739 { | |
| 1740 // UI element type | |
| 1741 UPDUI_MENUPOPUP = 0x0001, | |
| 1742 UPDUI_MENUBAR = 0x0002, | |
| 1743 UPDUI_CHILDWINDOW = 0x0004, | |
| 1744 UPDUI_TOOLBAR = 0x0008, | |
| 1745 UPDUI_STATUSBAR = 0x0010, | |
| 1746 // state | |
| 1747 UPDUI_ENABLED = 0x0000, | |
| 1748 UPDUI_DISABLED = 0x0100, | |
| 1749 UPDUI_CHECKED = 0x0200, | |
| 1750 UPDUI_CHECKED2 = 0x0400, | |
| 1751 UPDUI_RADIO = 0x0800, | |
| 1752 UPDUI_DEFAULT = 0x1000, | |
| 1753 UPDUI_TEXT = 0x2000, | |
| 1754 // internal state | |
| 1755 UPDUI_CLEARDEFAULT = 0x4000, | |
| 1756 }; | |
| 1757 | |
| 1758 // element data | |
| 1759 struct _AtlUpdateUIElement | |
| 1760 { | |
| 1761 HWND m_hWnd; | |
| 1762 WORD m_wType; | |
| 1763 | |
| 1764 bool operator ==(const _AtlUpdateUIElement& e) const | |
| 1765 { return ((m_hWnd == e.m_hWnd) && (m_wType == e.m_wType)); } | |
| 1766 }; | |
| 1767 | |
| 1768 // map data | |
| 1769 struct _AtlUpdateUIMap | |
| 1770 { | |
| 1771 WORD m_nID; | |
| 1772 WORD m_wType; | |
| 1773 | |
| 1774 bool operator ==(const _AtlUpdateUIMap& e) const | |
| 1775 { return ((m_nID == e.m_nID) && (m_wType == e.m_wType)); } | |
| 1776 }; | |
| 1777 | |
| 1778 // instance data | |
| 1779 #pragma warning(push) | |
| 1780 #pragma warning(disable: 4201) // nameless unions are part of C++ | |
| 1781 | |
| 1782 struct _AtlUpdateUIData | |
| 1783 { | |
| 1784 WORD m_wState; | |
| 1785 union | |
| 1786 { | |
| 1787 void* m_lpData; | |
| 1788 LPTSTR m_lpstrText; | |
| 1789 struct | |
| 1790 { | |
| 1791 WORD m_nIDFirst; | |
| 1792 WORD m_nIDLast; | |
| 1793 }; | |
| 1794 }; | |
| 1795 | |
| 1796 bool operator ==(const _AtlUpdateUIData& e) const | |
| 1797 { return ((m_wState == e.m_wState) && (m_lpData == e.m_lpData)); } | |
| 1798 }; | |
| 1799 | |
| 1800 #pragma warning(pop) | |
| 1801 | |
| 1802 ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data | |
| 1803 const _AtlUpdateUIMap* m_pUIMap; // static UI data | |
| 1804 _AtlUpdateUIData* m_pUIData; // instance UI data | |
| 1805 WORD m_wDirtyType; // global dirty flag | |
| 1806 | |
| 1807 bool m_bBlockAccelerators; | |
| 1808 | |
| 1809 | |
| 1810 // Constructor, destructor | |
| 1811 CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false) | |
| 1812 { } | |
| 1813 | |
| 1814 ~CUpdateUIBase() | |
| 1815 { | |
| 1816 if((m_pUIMap != NULL) && (m_pUIData != NULL)) | |
| 1817 { | |
| 1818 const _AtlUpdateUIMap* pUIMap = m_pUIMap; | |
| 1819 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 1820 while(pUIMap->m_nID != (WORD)-1) | |
| 1821 { | |
| 1822 if(pUIData->m_wState & UPDUI_TEXT) | |
| 1823 delete [] pUIData->m_lpstrText; | |
| 1824 pUIMap++; | |
| 1825 pUIData++; | |
| 1826 } | |
| 1827 delete [] m_pUIData; | |
| 1828 } | |
| 1829 } | |
| 1830 | |
| 1831 // Check for disabled commands | |
| 1832 bool UIGetBlockAccelerators() const | |
| 1833 { | |
| 1834 return m_bBlockAccelerators; | |
| 1835 } | |
| 1836 | |
| 1837 bool UISetBlockAccelerators(bool bBlock) | |
| 1838 { | |
| 1839 bool bOld = m_bBlockAccelerators; | |
| 1840 m_bBlockAccelerators = bBlock; | |
| 1841 return bOld; | |
| 1842 } | |
| 1843 | |
| 1844 // Add elements | |
| 1845 BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu) | |
| 1846 { | |
| 1847 if(hWnd == NULL) | |
| 1848 return FALSE; | |
| 1849 _AtlUpdateUIElement e; | |
| 1850 e.m_hWnd = hWnd; | |
| 1851 e.m_wType = UPDUI_MENUBAR; | |
| 1852 return m_UIElements.Add(e); | |
| 1853 } | |
| 1854 | |
| 1855 BOOL UIAddToolBar(HWND hWnd) // toolbar | |
| 1856 { | |
| 1857 if(hWnd == NULL) | |
| 1858 return FALSE; | |
| 1859 _AtlUpdateUIElement e; | |
| 1860 e.m_hWnd = hWnd; | |
| 1861 e.m_wType = UPDUI_TOOLBAR; | |
| 1862 return m_UIElements.Add(e); | |
| 1863 } | |
| 1864 | |
| 1865 BOOL UIAddStatusBar(HWND hWnd) // status bar | |
| 1866 { | |
| 1867 if(hWnd == NULL) | |
| 1868 return FALSE; | |
| 1869 _AtlUpdateUIElement e; | |
| 1870 e.m_hWnd = hWnd; | |
| 1871 e.m_wType = UPDUI_STATUSBAR; | |
| 1872 return m_UIElements.Add(e); | |
| 1873 } | |
| 1874 | |
| 1875 BOOL UIAddChildWindowContainer(HWND hWnd) // child window | |
| 1876 { | |
| 1877 if(hWnd == NULL) | |
| 1878 return FALSE; | |
| 1879 _AtlUpdateUIElement e; | |
| 1880 e.m_hWnd = hWnd; | |
| 1881 e.m_wType = UPDUI_CHILDWINDOW; | |
| 1882 return m_UIElements.Add(e); | |
| 1883 } | |
| 1884 | |
| 1885 // Message map for popup menu updates and accelerator blocking | |
| 1886 BEGIN_MSG_MAP(CUpdateUIBase) | |
| 1887 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) | |
| 1888 MESSAGE_HANDLER(WM_COMMAND, OnCommand) | |
| 1889 END_MSG_MAP() | |
| 1890 | |
| 1891 LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) | |
| 1892 { | |
| 1893 bHandled = FALSE; | |
| 1894 HMENU hMenu = (HMENU)wParam; | |
| 1895 if(hMenu == NULL) | |
| 1896 return 1; | |
| 1897 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 1898 if(pUIData == NULL) | |
| 1899 return 1; | |
| 1900 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 1901 while(pMap->m_nID != (WORD)-1) | |
| 1902 { | |
| 1903 if(pMap->m_wType & UPDUI_MENUPOPUP) | |
| 1904 { | |
| 1905 UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); | |
| 1906 | |
| 1907 if((pUIData->m_wState & UPDUI_RADIO) != 0) | |
| 1908 ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND); | |
| 1909 } | |
| 1910 pMap++; | |
| 1911 pUIData++; | |
| 1912 } | |
| 1913 return 0; | |
| 1914 } | |
| 1915 | |
| 1916 LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) | |
| 1917 { | |
| 1918 bHandled = FALSE; | |
| 1919 if(m_bBlockAccelerators && (HIWORD(wParam) == 1)) // accelerators only | |
| 1920 { | |
| 1921 int nID = LOWORD(wParam); | |
| 1922 if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED) | |
| 1923 { | |
| 1924 ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID); | |
| 1925 bHandled = TRUE; // eat the command, UI item is disabled | |
| 1926 } | |
| 1927 } | |
| 1928 return 0; | |
| 1929 } | |
| 1930 | |
| 1931 // methods for setting UI element state | |
| 1932 BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) | |
| 1933 { | |
| 1934 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 1935 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 1936 if(pUIData == NULL) | |
| 1937 return FALSE; | |
| 1938 | |
| 1939 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 1940 { | |
| 1941 if(nID == (int)pMap->m_nID) | |
| 1942 { | |
| 1943 if(bEnable) | |
| 1944 { | |
| 1945 if(pUIData->m_wState & UPDUI_DISABLED) | |
| 1946 { | |
| 1947 pUIData->m_wState |= pMap->m_wType; | |
| 1948 pUIData->m_wState &= ~UPDUI_DISABLED; | |
| 1949 } | |
| 1950 } | |
| 1951 else | |
| 1952 { | |
| 1953 if(!(pUIData->m_wState & UPDUI_DISABLED)) | |
| 1954 { | |
| 1955 pUIData->m_wState |= pMap->m_wType; | |
| 1956 pUIData->m_wState |= UPDUI_DISABLED; | |
| 1957 } | |
| 1958 } | |
| 1959 | |
| 1960 if(bForceUpdate) | |
| 1961 pUIData->m_wState |= pMap->m_wType; | |
| 1962 if(pUIData->m_wState & pMap->m_wType) | |
| 1963 m_wDirtyType |= pMap->m_wType; | |
| 1964 | |
| 1965 break; // found | |
| 1966 } | |
| 1967 } | |
| 1968 | |
| 1969 return TRUE; | |
| 1970 } | |
| 1971 | |
| 1972 BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) | |
| 1973 { | |
| 1974 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 1975 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 1976 if(pUIData == NULL) | |
| 1977 return FALSE; | |
| 1978 | |
| 1979 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 1980 { | |
| 1981 if(nID == (int)pMap->m_nID) | |
| 1982 { | |
| 1983 switch(nCheck) | |
| 1984 { | |
| 1985 case 0: | |
| 1986 if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2)) | |
| 1987 { | |
| 1988 pUIData->m_wState |= pMap->m_wType; | |
| 1989 pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2); | |
| 1990 } | |
| 1991 break; | |
| 1992 case 1: | |
| 1993 if(!(pUIData->m_wState & UPDUI_CHECKED)) | |
| 1994 { | |
| 1995 pUIData->m_wState |= pMap->m_wType; | |
| 1996 pUIData->m_wState &= ~UPDUI_CHECKED2; | |
| 1997 pUIData->m_wState |= UPDUI_CHECKED; | |
| 1998 } | |
| 1999 break; | |
| 2000 case 2: | |
| 2001 if(!(pUIData->m_wState & UPDUI_CHECKED2)) | |
| 2002 { | |
| 2003 pUIData->m_wState |= pMap->m_wType; | |
| 2004 pUIData->m_wState &= ~UPDUI_CHECKED; | |
| 2005 pUIData->m_wState |= UPDUI_CHECKED2; | |
| 2006 } | |
| 2007 break; | |
| 2008 } | |
| 2009 | |
| 2010 if(bForceUpdate) | |
| 2011 pUIData->m_wState |= pMap->m_wType; | |
| 2012 if(pUIData->m_wState & pMap->m_wType) | |
| 2013 m_wDirtyType |= pMap->m_wType; | |
| 2014 | |
| 2015 break; // found | |
| 2016 } | |
| 2017 } | |
| 2018 | |
| 2019 return TRUE; | |
| 2020 } | |
| 2021 | |
| 2022 // variant that supports bool (checked/not-checked, no intermediate state) | |
| 2023 BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) | |
| 2024 { | |
| 2025 return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate); | |
| 2026 } | |
| 2027 | |
| 2028 BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) | |
| 2029 { | |
| 2030 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2031 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2032 if(pUIData == NULL) | |
| 2033 return FALSE; | |
| 2034 | |
| 2035 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 2036 { | |
| 2037 if(nID == (int)pMap->m_nID) | |
| 2038 { | |
| 2039 if(bRadio) | |
| 2040 { | |
| 2041 if(!(pUIData->m_wState & UPDUI_RADIO)) | |
| 2042 { | |
| 2043 pUIData->m_wState |= pMap->m_wType; | |
| 2044 pUIData->m_wState |= UPDUI_RADIO; | |
| 2045 } | |
| 2046 } | |
| 2047 else | |
| 2048 { | |
| 2049 if(pUIData->m_wState & UPDUI_RADIO) | |
| 2050 { | |
| 2051 pUIData->m_wState |= pMap->m_wType; | |
| 2052 pUIData->m_wState &= ~UPDUI_RADIO; | |
| 2053 } | |
| 2054 } | |
| 2055 | |
| 2056 if(bForceUpdate) | |
| 2057 pUIData->m_wState |= pMap->m_wType; | |
| 2058 if(pUIData->m_wState & pMap->m_wType) | |
| 2059 m_wDirtyType |= pMap->m_wType; | |
| 2060 | |
| 2061 break; // found | |
| 2062 } | |
| 2063 } | |
| 2064 | |
| 2065 return TRUE; | |
| 2066 } | |
| 2067 | |
| 2068 // for menu items | |
| 2069 BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE) | |
| 2070 { | |
| 2071 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2072 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2073 if(pUIData == NULL) | |
| 2074 return FALSE; | |
| 2075 | |
| 2076 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 2077 { | |
| 2078 if(nID == (int)pMap->m_nID) | |
| 2079 { | |
| 2080 pUIData->m_wState |= pMap->m_wType; | |
| 2081 pUIData->m_wState |= UPDUI_RADIO; | |
| 2082 pUIData->m_nIDFirst = (WORD)nIDFirst; | |
| 2083 pUIData->m_nIDLast = (WORD)nIDLast; | |
| 2084 | |
| 2085 if(bForceUpdate) | |
| 2086 pUIData->m_wState |= pMap->m_wType; | |
| 2087 if(pUIData->m_wState & pMap->m_wType) | |
| 2088 m_wDirtyType |= pMap->m_wType; | |
| 2089 } | |
| 2090 else if((pMap->m_nID >= nIDFirst) && (pMap->m_nID <= nIDLast)) | |
| 2091 { | |
| 2092 if(pUIData->m_wState & UPDUI_RADIO) | |
| 2093 { | |
| 2094 pUIData->m_wState &= ~pMap->m_wType; | |
| 2095 pUIData->m_wState &= ~UPDUI_RADIO; | |
| 2096 pUIData->m_nIDFirst = 0; | |
| 2097 pUIData->m_nIDLast = 0; | |
| 2098 } | |
| 2099 } | |
| 2100 | |
| 2101 if(pMap->m_nID == nIDLast) | |
| 2102 break; | |
| 2103 } | |
| 2104 | |
| 2105 return TRUE; | |
| 2106 } | |
| 2107 | |
| 2108 BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) | |
| 2109 { | |
| 2110 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2111 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2112 if(pUIData == NULL) | |
| 2113 return FALSE; | |
| 2114 if(lpstrText == NULL) | |
| 2115 lpstrText = _T(""); | |
| 2116 | |
| 2117 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 2118 { | |
| 2119 if(nID == (int)pMap->m_nID) | |
| 2120 { | |
| 2121 if((pUIData->m_lpstrText == NULL) || lstrcmp(pUIData->m_lpstrText, lpstrText)) | |
| 2122 { | |
| 2123 delete [] pUIData->m_lpstrText; | |
| 2124 pUIData->m_lpstrText = NULL; | |
| 2125 int nStrLen = lstrlen(lpstrText); | |
| 2126 ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]); | |
| 2127 if(pUIData->m_lpstrText == NULL) | |
| 2128 { | |
| 2129 ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n")); | |
| 2130 break; | |
| 2131 } | |
| 2132 ATL::Checked::tcscpy_s(pUIData->m_lpstrText, nStrLen + 1, lpstrText); | |
| 2133 pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); | |
| 2134 } | |
| 2135 | |
| 2136 if(bForceUpdate) | |
| 2137 pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); | |
| 2138 if(pUIData->m_wState & pMap->m_wType) | |
| 2139 m_wDirtyType |= pMap->m_wType; | |
| 2140 | |
| 2141 break; // found | |
| 2142 } | |
| 2143 } | |
| 2144 | |
| 2145 return TRUE; | |
| 2146 } | |
| 2147 | |
| 2148 BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE) | |
| 2149 { | |
| 2150 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2151 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2152 if(pUIData == NULL) | |
| 2153 return FALSE; | |
| 2154 | |
| 2155 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 2156 { | |
| 2157 if(nID == (int)pMap->m_nID) | |
| 2158 { | |
| 2159 if(bDefault) | |
| 2160 { | |
| 2161 if((pUIData->m_wState & UPDUI_DEFAULT) == 0) | |
| 2162 { | |
| 2163 pUIData->m_wState |= pMap->m_wType; | |
| 2164 pUIData->m_wState |= UPDUI_DEFAULT; | |
| 2165 } | |
| 2166 } | |
| 2167 else | |
| 2168 { | |
| 2169 if((pUIData->m_wState & UPDUI_DEFAULT) != 0) | |
| 2170 { | |
| 2171 pUIData->m_wState |= pMap->m_wType; | |
| 2172 pUIData->m_wState &= ~UPDUI_DEFAULT; | |
| 2173 pUIData->m_wState |= UPDUI_CLEARDEFAULT; | |
| 2174 } | |
| 2175 } | |
| 2176 | |
| 2177 if(bForceUpdate) | |
| 2178 pUIData->m_wState |= pMap->m_wType; | |
| 2179 if(pUIData->m_wState & pMap->m_wType) | |
| 2180 m_wDirtyType |= pMap->m_wType; | |
| 2181 | |
| 2182 break; // found | |
| 2183 } | |
| 2184 } | |
| 2185 | |
| 2186 return TRUE; | |
| 2187 } | |
| 2188 | |
| 2189 // methods for complete state set/get | |
| 2190 BOOL UISetState(int nID, DWORD dwState) | |
| 2191 { | |
| 2192 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2193 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2194 if(pUIData == NULL) | |
| 2195 return FALSE; | |
| 2196 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 2197 { | |
| 2198 if(nID == (int)pMap->m_nID) | |
| 2199 { | |
| 2200 pUIData->m_wState = (WORD)(dwState | pMap->m_wType); | |
| 2201 m_wDirtyType |= pMap->m_wType; | |
| 2202 break; // found | |
| 2203 } | |
| 2204 } | |
| 2205 return TRUE; | |
| 2206 } | |
| 2207 | |
| 2208 DWORD UIGetState(int nID) | |
| 2209 { | |
| 2210 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2211 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2212 if(pUIData == NULL) | |
| 2213 return 0; | |
| 2214 for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) | |
| 2215 { | |
| 2216 if(nID == (int)pMap->m_nID) | |
| 2217 return pUIData->m_wState; | |
| 2218 } | |
| 2219 return 0; | |
| 2220 } | |
| 2221 | |
| 2222 // methods for updating UI | |
| 2223 BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE) | |
| 2224 { | |
| 2225 if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate) | |
| 2226 return TRUE; | |
| 2227 | |
| 2228 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2229 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2230 if(pUIData == NULL) | |
| 2231 return FALSE; | |
| 2232 | |
| 2233 while(pMap->m_nID != (WORD)-1) | |
| 2234 { | |
| 2235 for(int i = 0; i < m_UIElements.GetSize(); i++) | |
| 2236 { | |
| 2237 if(m_UIElements[i].m_wType == UPDUI_MENUBAR) | |
| 2238 { | |
| 2239 HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd); | |
| 2240 if((hMenu != NULL) && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR)) | |
| 2241 UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); | |
| 2242 } | |
| 2243 if(bMainMenu) | |
| 2244 ::DrawMenuBar(m_UIElements[i].m_hWnd); | |
| 2245 } | |
| 2246 pMap++; | |
| 2247 pUIData->m_wState &= ~UPDUI_MENUBAR; | |
| 2248 if(pUIData->m_wState & UPDUI_TEXT) | |
| 2249 { | |
| 2250 delete [] pUIData->m_lpstrText; | |
| 2251 pUIData->m_lpstrText = NULL; | |
| 2252 pUIData->m_wState &= ~UPDUI_TEXT; | |
| 2253 } | |
| 2254 pUIData++; | |
| 2255 } | |
| 2256 | |
| 2257 m_wDirtyType &= ~UPDUI_MENUBAR; | |
| 2258 return TRUE; | |
| 2259 } | |
| 2260 | |
| 2261 BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE) | |
| 2262 { | |
| 2263 if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate) | |
| 2264 return TRUE; | |
| 2265 | |
| 2266 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2267 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2268 if(pUIData == NULL) | |
| 2269 return FALSE; | |
| 2270 | |
| 2271 while(pMap->m_nID != (WORD)-1) | |
| 2272 { | |
| 2273 for(int i = 0; i < m_UIElements.GetSize(); i++) | |
| 2274 { | |
| 2275 if(m_UIElements[i].m_wType == UPDUI_TOOLBAR) | |
| 2276 { | |
| 2277 if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR)) | |
| 2278 UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); | |
| 2279 } | |
| 2280 } | |
| 2281 pMap++; | |
| 2282 pUIData->m_wState &= ~UPDUI_TOOLBAR; | |
| 2283 pUIData++; | |
| 2284 } | |
| 2285 | |
| 2286 m_wDirtyType &= ~UPDUI_TOOLBAR; | |
| 2287 return TRUE; | |
| 2288 } | |
| 2289 | |
| 2290 BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) | |
| 2291 { | |
| 2292 if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) | |
| 2293 return TRUE; | |
| 2294 | |
| 2295 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2296 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2297 if(pUIData == NULL) | |
| 2298 return FALSE; | |
| 2299 | |
| 2300 while(pMap->m_nID != (WORD)-1) | |
| 2301 { | |
| 2302 for(int i = 0; i < m_UIElements.GetSize(); i++) | |
| 2303 { | |
| 2304 if(m_UIElements[i].m_wType == UPDUI_STATUSBAR) | |
| 2305 { | |
| 2306 if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR)) | |
| 2307 UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); | |
| 2308 } | |
| 2309 } | |
| 2310 pMap++; | |
| 2311 pUIData->m_wState &= ~UPDUI_STATUSBAR; | |
| 2312 if(pUIData->m_wState & UPDUI_TEXT) | |
| 2313 { | |
| 2314 delete [] pUIData->m_lpstrText; | |
| 2315 pUIData->m_lpstrText = NULL; | |
| 2316 pUIData->m_wState &= ~UPDUI_TEXT; | |
| 2317 } | |
| 2318 pUIData++; | |
| 2319 } | |
| 2320 | |
| 2321 m_wDirtyType &= ~UPDUI_STATUSBAR; | |
| 2322 return TRUE; | |
| 2323 } | |
| 2324 | |
| 2325 BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE) | |
| 2326 { | |
| 2327 if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate) | |
| 2328 return TRUE; | |
| 2329 | |
| 2330 const _AtlUpdateUIMap* pMap = m_pUIMap; | |
| 2331 _AtlUpdateUIData* pUIData = m_pUIData; | |
| 2332 if(pUIData == NULL) | |
| 2333 return FALSE; | |
| 2334 | |
| 2335 while(pMap->m_nID != (WORD)-1) | |
| 2336 { | |
| 2337 for(int i = 0; i < m_UIElements.GetSize(); i++) | |
| 2338 { | |
| 2339 if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW) | |
| 2340 { | |
| 2341 if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW)) | |
| 2342 UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); | |
| 2343 } | |
| 2344 } | |
| 2345 pMap++; | |
| 2346 pUIData->m_wState &= ~UPDUI_CHILDWINDOW; | |
| 2347 if(pUIData->m_wState & UPDUI_TEXT) | |
| 2348 { | |
| 2349 delete [] pUIData->m_lpstrText; | |
| 2350 pUIData->m_lpstrText = NULL; | |
| 2351 pUIData->m_wState &= ~UPDUI_TEXT; | |
| 2352 } | |
| 2353 pUIData++; | |
| 2354 } | |
| 2355 | |
| 2356 m_wDirtyType &= ~UPDUI_CHILDWINDOW; | |
| 2357 return TRUE; | |
| 2358 } | |
| 2359 | |
| 2360 // internal element specific methods | |
| 2361 static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu) | |
| 2362 { | |
| 2363 if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0) | |
| 2364 { | |
| 2365 ::SetMenuDefaultItem(hMenu, (UINT)-1, 0); | |
| 2366 pUIData->m_wState &= ~UPDUI_CLEARDEFAULT; | |
| 2367 } | |
| 2368 | |
| 2369 CMenuItemInfo mii; | |
| 2370 mii.fMask = MIIM_STATE; | |
| 2371 mii.wID = nID; | |
| 2372 | |
| 2373 if((pUIData->m_wState & UPDUI_DISABLED) != 0) | |
| 2374 mii.fState |= MFS_DISABLED | MFS_GRAYED; | |
| 2375 else | |
| 2376 mii.fState |= MFS_ENABLED; | |
| 2377 | |
| 2378 if((pUIData->m_wState & UPDUI_CHECKED) != 0) | |
| 2379 mii.fState |= MFS_CHECKED; | |
| 2380 else | |
| 2381 mii.fState |= MFS_UNCHECKED; | |
| 2382 | |
| 2383 if((pUIData->m_wState & UPDUI_DEFAULT) != 0) | |
| 2384 mii.fState |= MFS_DEFAULT; | |
| 2385 | |
| 2386 if((pUIData->m_wState & UPDUI_TEXT) != 0) | |
| 2387 { | |
| 2388 CMenuItemInfo miiNow; | |
| 2389 miiNow.fMask = MIIM_TYPE; | |
| 2390 miiNow.wID = nID; | |
| 2391 if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow)) | |
| 2392 { | |
| 2393 mii.fMask |= MIIM_TYPE; | |
| 2394 // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING | |
| 2395 mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING; | |
| 2396 mii.dwTypeData = pUIData->m_lpstrText; | |
| 2397 } | |
| 2398 } | |
| 2399 | |
| 2400 ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); | |
| 2401 } | |
| 2402 | |
| 2403 static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar) | |
| 2404 { | |
| 2405 // Note: only handles enabled/disabled, checked state, and radio (press) | |
| 2406 ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); | |
| 2407 ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE); | |
| 2408 ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE); | |
| 2409 ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE); | |
| 2410 } | |
| 2411 | |
| 2412 static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar) | |
| 2413 { | |
| 2414 // Note: only handles text | |
| 2415 if(pUIData->m_wState & UPDUI_TEXT) | |
| 2416 ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText); | |
| 2417 } | |
| 2418 | |
| 2419 static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd) | |
| 2420 { | |
| 2421 HWND hChild = ::GetDlgItem(hWnd, nID); | |
| 2422 | |
| 2423 ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); | |
| 2424 // for check and radio, assume that window is a button | |
| 2425 int nCheck = BST_UNCHECKED; | |
| 2426 if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_RADIO)) | |
| 2427 nCheck = BST_CHECKED; | |
| 2428 else if(pUIData->m_wState & UPDUI_CHECKED2) | |
| 2429 nCheck = BST_INDETERMINATE; | |
| 2430 ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L); | |
| 2431 if(pUIData->m_wState & UPDUI_DEFAULT) | |
| 2432 { | |
| 2433 DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L); | |
| 2434 if(HIWORD(dwRet) == DC_HASDEFID) | |
| 2435 { | |
| 2436 HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet)); | |
| 2437 // remove BS_DEFPUSHBUTTON | |
| 2438 ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); | |
| 2439 } | |
| 2440 ::SendMessage(hWnd, DM_SETDEFID, nID, 0L); | |
| 2441 } | |
| 2442 if(pUIData->m_wState & UPDUI_TEXT) | |
| 2443 ::SetWindowText(hChild, pUIData->m_lpstrText); | |
| 2444 } | |
| 2445 }; | |
| 2446 | |
| 2447 template <class T> | |
| 2448 class CUpdateUI : public CUpdateUIBase | |
| 2449 { | |
| 2450 public: | |
| 2451 CUpdateUI() | |
| 2452 { | |
| 2453 T* pT = static_cast<T*>(this); | |
| 2454 (void)pT; // avoid level 4 warning | |
| 2455 const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); | |
| 2456 m_pUIMap = pMap; | |
| 2457 ATLASSERT(m_pUIMap != NULL); | |
| 2458 int nCount = 1; | |
| 2459 for( ; pMap->m_nID != (WORD)-1; nCount++) | |
| 2460 pMap++; | |
| 2461 | |
| 2462 // check for duplicates (debug only) | |
| 2463 #ifdef _DEBUG | |
| 2464 for(int i = 0; i < nCount; i++) | |
| 2465 { | |
| 2466 for(int j = 0; j < nCount; j++) | |
| 2467 { | |
| 2468 // shouldn't have duplicates in the update UI map | |
| 2469 if(i != j) | |
| 2470 ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID); | |
| 2471 } | |
| 2472 } | |
| 2473 #endif // _DEBUG | |
| 2474 | |
| 2475 ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]); | |
| 2476 ATLASSERT(m_pUIData != NULL); | |
| 2477 | |
| 2478 if(m_pUIData != NULL) | |
| 2479 memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount); | |
| 2480 } | |
| 2481 }; | |
| 2482 | |
| 2483 | |
| 2484 /////////////////////////////////////////////////////////////////////////////// | |
| 2485 // CDynamicUpdateUI - allows update elements to dynamically added and removed | |
| 2486 // in addition to a static update UI map | |
| 2487 | |
| 2488 template <class T> | |
| 2489 class CDynamicUpdateUI : public CUpdateUIBase | |
| 2490 { | |
| 2491 public: | |
| 2492 // Data members | |
| 2493 ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data | |
| 2494 ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data | |
| 2495 | |
| 2496 // Constructor/destructor | |
| 2497 CDynamicUpdateUI() | |
| 2498 { | |
| 2499 T* pT = static_cast<T*>(this); | |
| 2500 (void)pT; // avoid level 4 warning | |
| 2501 const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); | |
| 2502 ATLASSERT(pMap != NULL); | |
| 2503 | |
| 2504 for(;;) | |
| 2505 { | |
| 2506 BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap); | |
| 2507 ATLASSERT(bRet); | |
| 2508 | |
| 2509 if(bRet != FALSE) | |
| 2510 { | |
| 2511 _AtlUpdateUIData data = { 0, NULL }; | |
| 2512 bRet = m_arrUIData.Add(data); | |
| 2513 ATLASSERT(bRet); | |
| 2514 } | |
| 2515 | |
| 2516 if(pMap->m_nID == (WORD)-1) | |
| 2517 break; | |
| 2518 | |
| 2519 pMap++; | |
| 2520 } | |
| 2521 | |
| 2522 ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize()); | |
| 2523 | |
| 2524 #ifdef _DEBUG | |
| 2525 // check for duplicates (debug only) | |
| 2526 for(int i = 0; i < m_arrUIMap.GetSize(); i++) | |
| 2527 { | |
| 2528 for(int j = 0; j < m_arrUIMap.GetSize(); j++) | |
| 2529 { | |
| 2530 // shouldn't have duplicates in the update UI map | |
| 2531 if(i != j) | |
| 2532 ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID); | |
| 2533 } | |
| 2534 } | |
| 2535 #endif // _DEBUG | |
| 2536 | |
| 2537 // Set internal data pointers to point to the new data arrays | |
| 2538 m_pUIMap = m_arrUIMap.m_aT; | |
| 2539 m_pUIData = m_arrUIData.m_aT; | |
| 2540 } | |
| 2541 | |
| 2542 ~CDynamicUpdateUI() | |
| 2543 { | |
| 2544 for(int i = 0; i < m_arrUIData.GetSize(); i++) | |
| 2545 { | |
| 2546 if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) | |
| 2547 delete [] m_arrUIData[i].m_lpstrText; | |
| 2548 } | |
| 2549 | |
| 2550 // Reset internal data pointers (memory will be released by CSimpleArray d-tor) | |
| 2551 m_pUIMap = NULL; | |
| 2552 m_pUIData = NULL; | |
| 2553 } | |
| 2554 | |
| 2555 // Methods for dynamically adding and removing update elements | |
| 2556 bool UIAddUpdateElement(WORD nID, WORD wType) | |
| 2557 { | |
| 2558 // check for duplicates | |
| 2559 for(int i = 0; i < m_arrUIMap.GetSize(); i++) | |
| 2560 { | |
| 2561 // shouldn't have duplicates in the update UI map | |
| 2562 ATLASSERT(m_arrUIMap[i].m_nID != nID); | |
| 2563 if(m_arrUIMap[i].m_nID == nID) | |
| 2564 return false; | |
| 2565 } | |
| 2566 | |
| 2567 bool bRetVal = false; | |
| 2568 | |
| 2569 // Add new end element | |
| 2570 _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 }; | |
| 2571 BOOL bRet = m_arrUIMap.Add(uumEnd); | |
| 2572 ATLASSERT(bRet); | |
| 2573 | |
| 2574 if(bRet != FALSE) | |
| 2575 { | |
| 2576 _AtlUpdateUIData uud = { 0, NULL }; | |
| 2577 bRet = m_arrUIData.Add(uud); | |
| 2578 ATLASSERT(bRet); | |
| 2579 | |
| 2580 // Set new data to the previous end element | |
| 2581 if(bRet != FALSE) | |
| 2582 { | |
| 2583 int nSize = m_arrUIMap.GetSize(); | |
| 2584 _AtlUpdateUIMap uum = { nID, wType }; | |
| 2585 m_arrUIMap.SetAtIndex(nSize - 2, uum); | |
| 2586 m_arrUIData.SetAtIndex(nSize - 2, uud); | |
| 2587 | |
| 2588 // Set internal data pointers again, just in case that memory moved | |
| 2589 m_pUIMap = m_arrUIMap.m_aT; | |
| 2590 m_pUIData = m_arrUIData.m_aT; | |
| 2591 | |
| 2592 bRetVal = true; | |
| 2593 } | |
| 2594 } | |
| 2595 | |
| 2596 return bRetVal; | |
| 2597 } | |
| 2598 | |
| 2599 bool UIRemoveUpdateElement(WORD nID) | |
| 2600 { | |
| 2601 bool bRetVal = false; | |
| 2602 | |
| 2603 for(int i = 0; i < m_arrUIMap.GetSize(); i++) | |
| 2604 { | |
| 2605 if(m_arrUIMap[i].m_nID == nID) | |
| 2606 { | |
| 2607 if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) | |
| 2608 delete [] m_arrUIData[i].m_lpstrText; | |
| 2609 | |
| 2610 BOOL bRet = m_arrUIMap.RemoveAt(i); | |
| 2611 ATLASSERT(bRet); | |
| 2612 bRet = m_arrUIData.RemoveAt(i); | |
| 2613 ATLASSERT(bRet); | |
| 2614 | |
| 2615 bRetVal = true; | |
| 2616 break; | |
| 2617 } | |
| 2618 } | |
| 2619 | |
| 2620 return bRetVal; | |
| 2621 } | |
| 2622 }; | |
| 2623 | |
| 2624 | |
| 2625 /////////////////////////////////////////////////////////////////////////////// | |
| 2626 // CAutoUpdateUI : Automatic mapping of UI elements | |
| 2627 | |
| 2628 template <class T> | |
| 2629 class CAutoUpdateUI : public CDynamicUpdateUI<T> | |
| 2630 { | |
| 2631 public: | |
| 2632 LPCTSTR UIGetText(int nID) | |
| 2633 { | |
| 2634 for(int i = 0; i < this->m_arrUIMap.GetSize(); i++) | |
| 2635 { | |
| 2636 if(this->m_arrUIMap[i].m_nID == nID) | |
| 2637 return this->m_arrUIData[i].m_lpstrText; | |
| 2638 } | |
| 2639 | |
| 2640 return NULL; | |
| 2641 } | |
| 2642 | |
| 2643 // Element | |
| 2644 template <WORD t_wType> | |
| 2645 bool UIAddElement(UINT nID) | |
| 2646 { | |
| 2647 // check for existing UI map element | |
| 2648 for(int i = 0; i < this->m_arrUIMap.GetSize(); i++) | |
| 2649 { | |
| 2650 if(this->m_arrUIMap[i].m_nID == nID) | |
| 2651 { | |
| 2652 // set requested type | |
| 2653 this->m_arrUIMap[i].m_wType |= t_wType; | |
| 2654 return true; | |
| 2655 } | |
| 2656 } | |
| 2657 | |
| 2658 // Add element to UI map with requested type | |
| 2659 return this->UIAddUpdateElement((WORD)nID, t_wType); | |
| 2660 } | |
| 2661 | |
| 2662 template <WORD t_wType> | |
| 2663 bool UIRemoveElement(UINT nID) | |
| 2664 { | |
| 2665 for(int i = 0; i < this->m_arrUIMap.GetSize(); i++) | |
| 2666 { | |
| 2667 if(this->m_arrUIMap[i].m_nID == nID) // matching UI map element | |
| 2668 { | |
| 2669 WORD wType = this->m_arrUIMap[i].m_wType & ~t_wType; | |
| 2670 if (wType != 0) // has other types | |
| 2671 { | |
| 2672 this->m_arrUIMap[i].m_wType = wType; // keep other types | |
| 2673 return true; | |
| 2674 } | |
| 2675 else | |
| 2676 { | |
| 2677 return this->UIRemoveUpdateElement((WORD)nID); | |
| 2678 } | |
| 2679 } | |
| 2680 } | |
| 2681 | |
| 2682 return false; | |
| 2683 } | |
| 2684 | |
| 2685 // Menu | |
| 2686 bool UIAddMenu(HMENU hMenu, bool bSetText = false) | |
| 2687 { | |
| 2688 ATLASSERT(::IsMenu(hMenu)); | |
| 2689 MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU}; | |
| 2690 | |
| 2691 // Complete the UI map | |
| 2692 for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++) | |
| 2693 { | |
| 2694 if(mii.hSubMenu) | |
| 2695 { | |
| 2696 // Add submenu to UI map | |
| 2697 UIAddMenu(mii.hSubMenu, bSetText); | |
| 2698 } | |
| 2699 else if (mii.wID != 0) | |
| 2700 { | |
| 2701 // Add element to UI map | |
| 2702 UIAddElement<CDynamicUpdateUI<T>::UPDUI_MENUPOPUP>(mii.wID); | |
| 2703 if (bSetText) | |
| 2704 { | |
| 2705 TCHAR sText[64] = {}; | |
| 2706 if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION)) | |
| 2707 this->UISetText(mii.wID, sText); | |
| 2708 } | |
| 2709 } | |
| 2710 } | |
| 2711 | |
| 2712 return true; | |
| 2713 } | |
| 2714 | |
| 2715 bool UIAddMenu(UINT uID, bool bSetText = false) | |
| 2716 { | |
| 2717 CMenu menu; | |
| 2718 ATLVERIFY(menu.LoadMenu(uID)); | |
| 2719 return UIAddMenu(menu, bSetText); | |
| 2720 } | |
| 2721 | |
| 2722 // ToolBar | |
| 2723 bool UIAddToolBar(HWND hWndToolBar) | |
| 2724 { | |
| 2725 ATLASSERT(::IsWindow(hWndToolBar)); | |
| 2726 TBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX }; | |
| 2727 | |
| 2728 // Add toolbar buttons | |
| 2729 for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++) | |
| 2730 { | |
| 2731 if (tbbi.fsStyle ^ BTNS_SEP) | |
| 2732 UIAddElement<CDynamicUpdateUI<T>::UPDUI_TOOLBAR>(tbbi.idCommand); | |
| 2733 } | |
| 2734 | |
| 2735 // Add embedded controls if any | |
| 2736 if (::GetWindow(hWndToolBar, GW_CHILD)) | |
| 2737 UIAddChildWindowContainer(hWndToolBar); | |
| 2738 | |
| 2739 return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE); | |
| 2740 } | |
| 2741 | |
| 2742 // Container | |
| 2743 bool UIAddChildWindowContainer(HWND hWnd) | |
| 2744 { | |
| 2745 ATLASSERT(::IsWindow(hWnd)); | |
| 2746 | |
| 2747 // Add children controls if any | |
| 2748 for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT)) | |
| 2749 { | |
| 2750 int id = wCtl.GetDlgCtrlID(); | |
| 2751 if(id != 0) | |
| 2752 UIAddElement<CDynamicUpdateUI<T>::UPDUI_CHILDWINDOW>(id); | |
| 2753 } | |
| 2754 | |
| 2755 return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE); | |
| 2756 } | |
| 2757 | |
| 2758 // StatusBar | |
| 2759 BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) | |
| 2760 { | |
| 2761 if(!(this->m_wDirtyType & CDynamicUpdateUI<T>::UPDUI_STATUSBAR) && !bForceUpdate) | |
| 2762 return TRUE; | |
| 2763 | |
| 2764 for(int i = 0; i < this->m_arrUIMap.GetSize(); i++) | |
| 2765 { | |
| 2766 for(int e = 0; e < this->m_UIElements.GetSize(); e++) | |
| 2767 { | |
| 2768 if((this->m_UIElements[e].m_wType == CDynamicUpdateUI<T>::UPDUI_STATUSBAR) && | |
| 2769 (this->m_arrUIMap[i].m_wType & CDynamicUpdateUI<T>::UPDUI_STATUSBAR) && | |
| 2770 (this->m_arrUIData[i].m_wState & CDynamicUpdateUI<T>::UPDUI_STATUSBAR)) | |
| 2771 { | |
| 2772 this->UIUpdateStatusBarElement(this->m_arrUIMap[i].m_nID, &this->m_arrUIData[i], this->m_UIElements[e].m_hWnd); | |
| 2773 this->m_arrUIData[i].m_wState &= ~CDynamicUpdateUI<T>::UPDUI_STATUSBAR; | |
| 2774 if(this->m_arrUIData[i].m_wState & CDynamicUpdateUI<T>::UPDUI_TEXT) | |
| 2775 this->m_arrUIData[i].m_wState &= ~CDynamicUpdateUI<T>::UPDUI_TEXT; | |
| 2776 } | |
| 2777 } | |
| 2778 } | |
| 2779 | |
| 2780 this->m_wDirtyType &= ~CDynamicUpdateUI<T>::UPDUI_STATUSBAR; | |
| 2781 return TRUE; | |
| 2782 } | |
| 2783 | |
| 2784 bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1) | |
| 2785 { | |
| 2786 ATLASSERT(::IsWindow(hWndStatusBar)); | |
| 2787 | |
| 2788 // Add StatusBar panes | |
| 2789 for (int iPane = 0; iPane < nPanes; iPane++) | |
| 2790 UIAddElement<CDynamicUpdateUI<T>::UPDUI_STATUSBAR>(ID_DEFAULT_PANE + iPane); | |
| 2791 | |
| 2792 return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE); | |
| 2793 } | |
| 2794 | |
| 2795 // UI Map used if derived class has none | |
| 2796 BEGIN_UPDATE_UI_MAP(CAutoUpdateUI) | |
| 2797 END_UPDATE_UI_MAP() | |
| 2798 }; | |
| 2799 | |
| 2800 | |
| 2801 /////////////////////////////////////////////////////////////////////////////// | |
| 2802 // CDialogResize - provides support for resizing dialog controls | |
| 2803 // (works for any window that has child controls) | |
| 2804 | |
| 2805 // Put CDialogResize in the list of base classes for a dialog (or even plain window), | |
| 2806 // then implement DLGRESIZE map by specifying controls and groups of control | |
| 2807 // and using DLSZ_* values to specify how are they supposed to be resized. | |
| 2808 // | |
| 2809 // Notes: | |
| 2810 // - Resizeable border (WS_THICKFRAME style) should be set in the dialog template | |
| 2811 // for top level dialogs (popup or overlapped), so that users can resize the dialog. | |
| 2812 // - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X, | |
| 2813 // DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined. | |
| 2814 // - Order of controls is important - group controls are resized and moved based | |
| 2815 // on the position of the previous control in a group. | |
| 2816 | |
| 2817 // dialog resize map macros | |
| 2818 struct _AtlDlgResizeMap | |
| 2819 { | |
| 2820 int m_nCtlID; | |
| 2821 DWORD m_dwResizeFlags; | |
| 2822 }; | |
| 2823 | |
| 2824 #define BEGIN_DLGRESIZE_MAP(thisClass) \ | |
| 2825 static const WTL::_AtlDlgResizeMap* GetDlgResizeMap() \ | |
| 2826 { \ | |
| 2827 static const WTL::_AtlDlgResizeMap theMap[] = \ | |
| 2828 { | |
| 2829 | |
| 2830 #define END_DLGRESIZE_MAP() \ | |
| 2831 { -1, 0 }, \ | |
| 2832 }; \ | |
| 2833 return theMap; \ | |
| 2834 } | |
| 2835 | |
| 2836 #define DLGRESIZE_CONTROL(id, flags) \ | |
| 2837 { id, flags }, | |
| 2838 | |
| 2839 #define BEGIN_DLGRESIZE_GROUP() \ | |
| 2840 { -1, _DLSZ_BEGIN_GROUP }, | |
| 2841 | |
| 2842 #define END_DLGRESIZE_GROUP() \ | |
| 2843 { -1, _DLSZ_END_GROUP }, | |
| 2844 | |
| 2845 | |
| 2846 template <class T> | |
| 2847 class CDialogResize | |
| 2848 { | |
| 2849 public: | |
| 2850 // Data declarations and members | |
| 2851 enum | |
| 2852 { | |
| 2853 DLSZ_SIZE_X = 0x00000001, | |
| 2854 DLSZ_SIZE_Y = 0x00000002, | |
| 2855 DLSZ_MOVE_X = 0x00000004, | |
| 2856 DLSZ_MOVE_Y = 0x00000008, | |
| 2857 DLSZ_REPAINT = 0x00000010, | |
| 2858 DLSZ_CENTER_X = 0x00000020, | |
| 2859 DLSZ_CENTER_Y = 0x00000040, | |
| 2860 | |
| 2861 // internal use only | |
| 2862 _DLSZ_BEGIN_GROUP = 0x00001000, | |
| 2863 _DLSZ_END_GROUP = 0x00002000, | |
| 2864 _DLSZ_GRIPPER = 0x00004000 | |
| 2865 }; | |
| 2866 | |
| 2867 struct _AtlDlgResizeData | |
| 2868 { | |
| 2869 int m_nCtlID; | |
| 2870 DWORD m_dwResizeFlags; | |
| 2871 RECT m_rect; | |
| 2872 | |
| 2873 int GetGroupCount() const | |
| 2874 { | |
| 2875 return (int)LOBYTE(HIWORD(m_dwResizeFlags)); | |
| 2876 } | |
| 2877 | |
| 2878 void SetGroupCount(int nCount) | |
| 2879 { | |
| 2880 ATLASSERT((nCount > 0) && (nCount < 256)); | |
| 2881 DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0)); | |
| 2882 m_dwResizeFlags &= 0xFF00FFFF; | |
| 2883 m_dwResizeFlags |= dwCount; | |
| 2884 } | |
| 2885 | |
| 2886 bool operator ==(const _AtlDlgResizeData& r) const | |
| 2887 { return ((m_nCtlID == r.m_nCtlID) && (m_dwResizeFlags == r.m_dwResizeFlags)); } | |
| 2888 }; | |
| 2889 | |
| 2890 ATL::CSimpleArray<_AtlDlgResizeData> m_arrData; | |
| 2891 SIZE m_sizeDialog; | |
| 2892 POINT m_ptMinTrackSize; | |
| 2893 bool m_bGripper; | |
| 2894 | |
| 2895 | |
| 2896 // Constructor | |
| 2897 CDialogResize() : m_bGripper(false) | |
| 2898 { | |
| 2899 m_sizeDialog.cx = 0; | |
| 2900 m_sizeDialog.cy = 0; | |
| 2901 m_ptMinTrackSize.x = -1; | |
| 2902 m_ptMinTrackSize.y = -1; | |
| 2903 } | |
| 2904 | |
| 2905 // Operations | |
| 2906 void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN) | |
| 2907 { | |
| 2908 T* pT = static_cast<T*>(this); | |
| 2909 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 2910 | |
| 2911 DWORD dwStyle = pT->GetStyle(); | |
| 2912 | |
| 2913 #ifdef _DEBUG | |
| 2914 // Debug only: Check if top level dialogs have a resizeable border. | |
| 2915 if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0)) | |
| 2916 ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n")); | |
| 2917 #endif // _DEBUG | |
| 2918 | |
| 2919 // Force specified styles (default WS_CLIPCHILDREN reduces flicker) | |
| 2920 if((dwStyle & dwForceStyle) != dwForceStyle) | |
| 2921 pT->ModifyStyle(0, dwForceStyle); | |
| 2922 | |
| 2923 // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have. | |
| 2924 // Setting icon to NULL is required when XP themes are active. | |
| 2925 // Note: This will not prevent adding an icon for the dialog using SetIcon() | |
| 2926 if((dwStyle & WS_CHILD) == 0) | |
| 2927 { | |
| 2928 pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME); | |
| 2929 if(pT->GetIcon(FALSE) == NULL) | |
| 2930 pT->SetIcon(NULL, FALSE); | |
| 2931 } | |
| 2932 | |
| 2933 // Cleanup in case of multiple initialization | |
| 2934 // block: first check for the gripper control, destroy it if needed | |
| 2935 { | |
| 2936 ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); | |
| 2937 if(wndGripper.IsWindow() && (m_arrData.GetSize() > 0) && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0) | |
| 2938 wndGripper.DestroyWindow(); | |
| 2939 } | |
| 2940 // clear out everything else | |
| 2941 m_arrData.RemoveAll(); | |
| 2942 m_sizeDialog.cx = 0; | |
| 2943 m_sizeDialog.cy = 0; | |
| 2944 m_ptMinTrackSize.x = -1; | |
| 2945 m_ptMinTrackSize.y = -1; | |
| 2946 | |
| 2947 // Get initial dialog client size | |
| 2948 RECT rectDlg = {}; | |
| 2949 pT->GetClientRect(&rectDlg); | |
| 2950 m_sizeDialog.cx = rectDlg.right; | |
| 2951 m_sizeDialog.cy = rectDlg.bottom; | |
| 2952 | |
| 2953 // Create gripper if requested | |
| 2954 m_bGripper = false; | |
| 2955 if(bAddGripper) | |
| 2956 { | |
| 2957 // shouldn't exist already | |
| 2958 ATLASSERT(!pT->GetDlgItem(ATL_IDW_STATUS_BAR).IsWindow()); | |
| 2959 if(!pT->GetDlgItem(ATL_IDW_STATUS_BAR).IsWindow()) | |
| 2960 { | |
| 2961 ATL::CWindow wndGripper; | |
| 2962 wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR); | |
| 2963 ATLASSERT(wndGripper.IsWindow()); | |
| 2964 if(wndGripper.IsWindow()) | |
| 2965 { | |
| 2966 m_bGripper = true; | |
| 2967 RECT rectCtl = {}; | |
| 2968 wndGripper.GetWindowRect(&rectCtl); | |
| 2969 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); | |
| 2970 _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; | |
| 2971 m_arrData.Add(data); | |
| 2972 } | |
| 2973 } | |
| 2974 } | |
| 2975 | |
| 2976 // Get min track position if requested | |
| 2977 if(bUseMinTrackSize) | |
| 2978 { | |
| 2979 if((dwStyle & WS_CHILD) != 0) | |
| 2980 { | |
| 2981 RECT rect = {}; | |
| 2982 pT->GetClientRect(&rect); | |
| 2983 m_ptMinTrackSize.x = rect.right - rect.left; | |
| 2984 m_ptMinTrackSize.y = rect.bottom - rect.top; | |
| 2985 } | |
| 2986 else | |
| 2987 { | |
| 2988 RECT rect = {}; | |
| 2989 pT->GetWindowRect(&rect); | |
| 2990 m_ptMinTrackSize.x = rect.right - rect.left; | |
| 2991 m_ptMinTrackSize.y = rect.bottom - rect.top; | |
| 2992 } | |
| 2993 } | |
| 2994 | |
| 2995 // Walk the map and initialize data | |
| 2996 const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap(); | |
| 2997 ATLASSERT(pMap != NULL); | |
| 2998 int nGroupStart = -1; | |
| 2999 for(int nCount = 1; !((pMap->m_nCtlID == -1) && (pMap->m_dwResizeFlags == 0)); nCount++, pMap++) | |
| 3000 { | |
| 3001 if(pMap->m_nCtlID == -1) | |
| 3002 { | |
| 3003 switch(pMap->m_dwResizeFlags) | |
| 3004 { | |
| 3005 case _DLSZ_BEGIN_GROUP: | |
| 3006 ATLASSERT(nGroupStart == -1); | |
| 3007 nGroupStart = m_arrData.GetSize(); | |
| 3008 break; | |
| 3009 case _DLSZ_END_GROUP: | |
| 3010 { | |
| 3011 ATLASSERT(nGroupStart != -1); | |
| 3012 int nGroupCount = m_arrData.GetSize() - nGroupStart; | |
| 3013 m_arrData[nGroupStart].SetGroupCount(nGroupCount); | |
| 3014 nGroupStart = -1; | |
| 3015 } | |
| 3016 break; | |
| 3017 default: | |
| 3018 ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry")); | |
| 3019 break; | |
| 3020 } | |
| 3021 } | |
| 3022 else | |
| 3023 { | |
| 3024 // this ID conflicts with the default gripper one | |
| 3025 ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE); | |
| 3026 | |
| 3027 ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID); | |
| 3028 ATLASSERT(ctl.IsWindow()); | |
| 3029 RECT rectCtl = {}; | |
| 3030 ctl.GetWindowRect(&rectCtl); | |
| 3031 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); | |
| 3032 | |
| 3033 DWORD dwGroupFlag = ((nGroupStart != -1) && (m_arrData.GetSize() == nGroupStart)) ? _DLSZ_BEGIN_GROUP : 0; | |
| 3034 _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; | |
| 3035 m_arrData.Add(data); | |
| 3036 } | |
| 3037 } | |
| 3038 ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map")); | |
| 3039 } | |
| 3040 | |
| 3041 void DlgResize_UpdateLayout(int cxWidth, int cyHeight) | |
| 3042 { | |
| 3043 T* pT = static_cast<T*>(this); | |
| 3044 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 3045 | |
| 3046 // Restrict minimum size if requested | |
| 3047 if(((pT->GetStyle() & WS_CHILD) != 0) && (m_ptMinTrackSize.x != -1) && (m_ptMinTrackSize.y != -1)) | |
| 3048 { | |
| 3049 if(cxWidth < m_ptMinTrackSize.x) | |
| 3050 cxWidth = m_ptMinTrackSize.x; | |
| 3051 if(cyHeight < m_ptMinTrackSize.y) | |
| 3052 cyHeight = m_ptMinTrackSize.y; | |
| 3053 } | |
| 3054 | |
| 3055 BOOL bVisible = pT->IsWindowVisible(); | |
| 3056 if(bVisible) | |
| 3057 pT->SetRedraw(FALSE); | |
| 3058 | |
| 3059 for(int i = 0; i < m_arrData.GetSize(); i++) | |
| 3060 { | |
| 3061 if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group | |
| 3062 { | |
| 3063 int nGroupCount = m_arrData[i].GetGroupCount(); | |
| 3064 ATLASSERT((nGroupCount > 0) && ((i + nGroupCount - 1) < m_arrData.GetSize())); | |
| 3065 RECT rectGroup = m_arrData[i].m_rect; | |
| 3066 | |
| 3067 int j = 1; | |
| 3068 for(j = 1; j < nGroupCount; j++) | |
| 3069 { | |
| 3070 rectGroup.left = __min(rectGroup.left, m_arrData[i + j].m_rect.left); | |
| 3071 rectGroup.top = __min(rectGroup.top, m_arrData[i + j].m_rect.top); | |
| 3072 rectGroup.right = __max(rectGroup.right, m_arrData[i + j].m_rect.right); | |
| 3073 rectGroup.bottom = __max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom); | |
| 3074 } | |
| 3075 | |
| 3076 for(j = 0; j < nGroupCount; j++) | |
| 3077 { | |
| 3078 _AtlDlgResizeData* pDataPrev = NULL; | |
| 3079 if(j > 0) | |
| 3080 pDataPrev = &(m_arrData[i + j - 1]); | |
| 3081 pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev); | |
| 3082 } | |
| 3083 | |
| 3084 i += nGroupCount - 1; // increment to skip all group controls | |
| 3085 } | |
| 3086 else // one control entry | |
| 3087 { | |
| 3088 RECT rectGroup = {}; | |
| 3089 pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false); | |
| 3090 } | |
| 3091 } | |
| 3092 | |
| 3093 if(bVisible) | |
| 3094 pT->SetRedraw(TRUE); | |
| 3095 | |
| 3096 pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); | |
| 3097 } | |
| 3098 | |
| 3099 // Message map and handlers | |
| 3100 BEGIN_MSG_MAP(CDialogResize) | |
| 3101 MESSAGE_HANDLER(WM_SIZE, OnSize) | |
| 3102 MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) | |
| 3103 END_MSG_MAP() | |
| 3104 | |
| 3105 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) | |
| 3106 { | |
| 3107 T* pT = static_cast<T*>(this); | |
| 3108 if(m_bGripper) | |
| 3109 { | |
| 3110 ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); | |
| 3111 if(wParam == SIZE_MAXIMIZED) | |
| 3112 wndGripper.ShowWindow(SW_HIDE); | |
| 3113 else if(wParam == SIZE_RESTORED) | |
| 3114 wndGripper.ShowWindow(SW_SHOW); | |
| 3115 } | |
| 3116 if(wParam != SIZE_MINIMIZED) | |
| 3117 { | |
| 3118 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 3119 pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); | |
| 3120 } | |
| 3121 return 0; | |
| 3122 } | |
| 3123 | |
| 3124 LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) | |
| 3125 { | |
| 3126 if((m_ptMinTrackSize.x != -1) && (m_ptMinTrackSize.y != -1)) | |
| 3127 { | |
| 3128 LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; | |
| 3129 lpMMI->ptMinTrackSize = m_ptMinTrackSize; | |
| 3130 } | |
| 3131 return 0; | |
| 3132 } | |
| 3133 | |
| 3134 // Implementation | |
| 3135 bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, | |
| 3136 _AtlDlgResizeData* pDataPrev = NULL) | |
| 3137 { | |
| 3138 T* pT = static_cast<T*>(this); | |
| 3139 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 3140 ATL::CWindow ctl; | |
| 3141 RECT rectCtl = {}; | |
| 3142 | |
| 3143 ctl = pT->GetDlgItem(data.m_nCtlID); | |
| 3144 if(!ctl.GetWindowRect(&rectCtl)) | |
| 3145 return false; | |
| 3146 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); | |
| 3147 | |
| 3148 if(bGroup) | |
| 3149 { | |
| 3150 if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) | |
| 3151 { | |
| 3152 int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx; | |
| 3153 int cxCtl = data.m_rect.right - data.m_rect.left; | |
| 3154 rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2; | |
| 3155 rectCtl.right = rectCtl.left + cxCtl; | |
| 3156 } | |
| 3157 else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) | |
| 3158 { | |
| 3159 rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); | |
| 3160 | |
| 3161 if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0) | |
| 3162 { | |
| 3163 rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); | |
| 3164 | |
| 3165 if(pDataPrev != NULL) | |
| 3166 { | |
| 3167 ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); | |
| 3168 RECT rcPrev = {}; | |
| 3169 ctlPrev.GetWindowRect(&rcPrev); | |
| 3170 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); | |
| 3171 int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right); | |
| 3172 rcPrev.right += dxAdjust; | |
| 3173 ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); | |
| 3174 } | |
| 3175 } | |
| 3176 else | |
| 3177 { | |
| 3178 rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left); | |
| 3179 } | |
| 3180 } | |
| 3181 | |
| 3182 if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) | |
| 3183 { | |
| 3184 int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy; | |
| 3185 int cyCtl = data.m_rect.bottom - data.m_rect.top; | |
| 3186 rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2; | |
| 3187 rectCtl.bottom = rectCtl.top + cyCtl; | |
| 3188 } | |
| 3189 else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) | |
| 3190 { | |
| 3191 rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); | |
| 3192 | |
| 3193 if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0) | |
| 3194 { | |
| 3195 rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); | |
| 3196 | |
| 3197 if(pDataPrev != NULL) | |
| 3198 { | |
| 3199 ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); | |
| 3200 RECT rcPrev = {}; | |
| 3201 ctlPrev.GetWindowRect(&rcPrev); | |
| 3202 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); | |
| 3203 int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom); | |
| 3204 rcPrev.bottom += dxAdjust; | |
| 3205 ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); | |
| 3206 } | |
| 3207 } | |
| 3208 else | |
| 3209 { | |
| 3210 rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top); | |
| 3211 } | |
| 3212 } | |
| 3213 } | |
| 3214 else // no group | |
| 3215 { | |
| 3216 if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) | |
| 3217 { | |
| 3218 int cxCtl = data.m_rect.right - data.m_rect.left; | |
| 3219 rectCtl.left = (cxWidth - cxCtl) / 2; | |
| 3220 rectCtl.right = rectCtl.left + cxCtl; | |
| 3221 } | |
| 3222 else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) | |
| 3223 { | |
| 3224 rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx); | |
| 3225 | |
| 3226 if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0) | |
| 3227 rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left); | |
| 3228 } | |
| 3229 | |
| 3230 if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) | |
| 3231 { | |
| 3232 int cyCtl = data.m_rect.bottom - data.m_rect.top; | |
| 3233 rectCtl.top = (cyHeight - cyCtl) / 2; | |
| 3234 rectCtl.bottom = rectCtl.top + cyCtl; | |
| 3235 } | |
| 3236 else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) | |
| 3237 { | |
| 3238 rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy); | |
| 3239 | |
| 3240 if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0) | |
| 3241 rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top); | |
| 3242 } | |
| 3243 } | |
| 3244 | |
| 3245 if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0) | |
| 3246 ctl.Invalidate(); | |
| 3247 | |
| 3248 if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0) | |
| 3249 ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE); | |
| 3250 | |
| 3251 return true; | |
| 3252 } | |
| 3253 }; | |
| 3254 | |
| 3255 | |
| 3256 /////////////////////////////////////////////////////////////////////////////// | |
| 3257 // CDynamicDialogLayout - support for dialog dynamic layout resource info | |
| 3258 // (AFX_DIALOG_LAYOUT) in VS2015 and higher | |
| 3259 | |
| 3260 #if (_MSC_VER >= 1900) | |
| 3261 | |
| 3262 template<class T> | |
| 3263 class CDynamicDialogLayout | |
| 3264 { | |
| 3265 public: | |
| 3266 // Data declarations | |
| 3267 struct _AtlDynamicLayoutData | |
| 3268 { | |
| 3269 HWND m_hWnd; | |
| 3270 char m_nMoveRatioX; | |
| 3271 char m_nMoveRatioY; | |
| 3272 char m_nSizeRatioX; | |
| 3273 char m_nSizeRatioY; | |
| 3274 RECT m_rcInit; | |
| 3275 }; | |
| 3276 | |
| 3277 // Data members | |
| 3278 ATL::CSimpleArray<_AtlDynamicLayoutData> m_arrLayoutData; | |
| 3279 SIZE m_szParentInit; | |
| 3280 POINT m_ptMinTrackSize; | |
| 3281 bool m_bGripper; | |
| 3282 | |
| 3283 // Constructor | |
| 3284 CDynamicDialogLayout() : m_bGripper(false) | |
| 3285 { | |
| 3286 m_szParentInit.cx = 0; | |
| 3287 m_szParentInit.cy = 0; | |
| 3288 m_ptMinTrackSize.x = -1; | |
| 3289 m_ptMinTrackSize.y = -1; | |
| 3290 } | |
| 3291 | |
| 3292 // Methods | |
| 3293 void InitDynamicLayout(bool bAddGripper = true, bool bMinTrackSize = true) | |
| 3294 { | |
| 3295 T* pT = static_cast<T*>(this); | |
| 3296 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 3297 | |
| 3298 // Cleanup in case of multiple initialization | |
| 3299 // block: first check for the gripper control, destroy it if needed | |
| 3300 { | |
| 3301 ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); | |
| 3302 if(wndGripper.IsWindow() != FALSE) | |
| 3303 wndGripper.DestroyWindow(); | |
| 3304 } | |
| 3305 // clear out everything else | |
| 3306 m_arrLayoutData.RemoveAll(); | |
| 3307 m_ptMinTrackSize.x = -1; | |
| 3308 m_ptMinTrackSize.y = -1; | |
| 3309 m_szParentInit.cx = 0; | |
| 3310 m_szParentInit.cy = 0; | |
| 3311 m_bGripper = false; | |
| 3312 | |
| 3313 CResource rcLayout; | |
| 3314 if(rcLayout.Load(_T("AFX_DIALOG_LAYOUT"), pT->IDD)) | |
| 3315 { | |
| 3316 int nCount = rcLayout.GetSize() / sizeof(WORD); | |
| 3317 if(nCount > 1) | |
| 3318 { | |
| 3319 RECT rcParent = {}; | |
| 3320 pT->GetWindowRect(&rcParent); | |
| 3321 m_szParentInit.cx = rcParent.right - rcParent.left; | |
| 3322 m_szParentInit.cy = rcParent.bottom - rcParent.top; | |
| 3323 | |
| 3324 WORD* pnData = (WORD*)rcLayout.Lock(); | |
| 3325 WORD wVersion = *pnData; // AFX_DIALOG_LAYOUT version | |
| 3326 ATLASSERT(wVersion == 0); | |
| 3327 if(wVersion == 0) | |
| 3328 { | |
| 3329 pnData++; // skip version | |
| 3330 ATL::CWindow wndChild = pT->GetWindow(GW_CHILD); | |
| 3331 for(int i = 0; (i < nCount) && (wndChild.m_hWnd != NULL); i += 4) | |
| 3332 { | |
| 3333 char nMoveRatioX = _GetDataPct(pnData[i]); | |
| 3334 char nMoveRatioY = _GetDataPct(pnData[i + 1]); | |
| 3335 char nSizeRatioX = _GetDataPct(pnData[i + 2]); | |
| 3336 char nSizeRatioY = _GetDataPct(pnData[i + 3]); | |
| 3337 | |
| 3338 bool bValid = ((nMoveRatioX != -1) && (nMoveRatioY != -1) && (nSizeRatioX != -1) && (nSizeRatioY != -1)); | |
| 3339 bool bAction = ((nMoveRatioX != 0) || (nMoveRatioY != 0) || (nSizeRatioX != 0) || (nSizeRatioY != 0)); | |
| 3340 if(bValid && bAction) | |
| 3341 { | |
| 3342 _AtlDynamicLayoutData LayoutData = { wndChild.m_hWnd, nMoveRatioX, nMoveRatioY, nSizeRatioX, nSizeRatioY }; | |
| 3343 wndChild.GetWindowRect(&LayoutData.m_rcInit); | |
| 3344 pT->ScreenToClient(&LayoutData.m_rcInit); | |
| 3345 m_arrLayoutData.Add(LayoutData); | |
| 3346 } | |
| 3347 | |
| 3348 wndChild = wndChild.GetWindow(GW_HWNDNEXT); | |
| 3349 } | |
| 3350 } | |
| 3351 | |
| 3352 rcLayout.Release(); | |
| 3353 } | |
| 3354 } | |
| 3355 | |
| 3356 if(bAddGripper) | |
| 3357 { | |
| 3358 RECT rcDialog = {}; | |
| 3359 pT->GetClientRect(&rcDialog); | |
| 3360 | |
| 3361 ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); | |
| 3362 if(wndGripper.m_hWnd != NULL) | |
| 3363 wndGripper.DestroyWindow(); | |
| 3364 | |
| 3365 wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rcDialog, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR); | |
| 3366 ATLASSERT(wndGripper.m_hWnd != NULL); | |
| 3367 if(wndGripper.m_hWnd != NULL) | |
| 3368 { | |
| 3369 m_bGripper = true; | |
| 3370 _AtlDynamicLayoutData LayoutData = { wndGripper.m_hWnd, 100, 100, 0, 0 }; | |
| 3371 wndGripper.GetWindowRect(&LayoutData.m_rcInit); | |
| 3372 pT->ScreenToClient(&LayoutData.m_rcInit); | |
| 3373 m_arrLayoutData.Add(LayoutData); | |
| 3374 } | |
| 3375 } | |
| 3376 | |
| 3377 if(bMinTrackSize) | |
| 3378 { | |
| 3379 RECT rcMinTrack = {}; | |
| 3380 if((pT->GetStyle() & WS_CHILD) != 0) | |
| 3381 pT->GetClientRect(&rcMinTrack); | |
| 3382 else | |
| 3383 pT->GetWindowRect(&rcMinTrack); | |
| 3384 | |
| 3385 m_ptMinTrackSize.x = rcMinTrack.right - rcMinTrack.left; | |
| 3386 m_ptMinTrackSize.y = rcMinTrack.bottom - rcMinTrack.top; | |
| 3387 } | |
| 3388 } | |
| 3389 | |
| 3390 void UpdateDynamicLayout() | |
| 3391 { | |
| 3392 T* pT = static_cast<T*>(this); | |
| 3393 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 3394 | |
| 3395 int nCount = m_arrLayoutData.GetSize(); | |
| 3396 if(nCount == 0) | |
| 3397 return; | |
| 3398 | |
| 3399 RECT rcParent = {}; | |
| 3400 pT->GetWindowRect(&rcParent); | |
| 3401 | |
| 3402 int nDeltaWidth = rcParent.right - rcParent.left - m_szParentInit.cx; | |
| 3403 int nDeltaHeight = rcParent.bottom - rcParent.top - m_szParentInit.cy; | |
| 3404 | |
| 3405 HDWP hDwp = ::BeginDeferWindowPos(nCount); | |
| 3406 | |
| 3407 for(int i = 0; i < nCount; i++) | |
| 3408 { | |
| 3409 _AtlDynamicLayoutData& LayoutData = m_arrLayoutData[i]; | |
| 3410 | |
| 3411 ATLASSERT(::IsWindow(LayoutData.m_hWnd) != FALSE); | |
| 3412 | |
| 3413 int nID = ::GetDlgCtrlID(LayoutData.m_hWnd); | |
| 3414 UINT nFlags = (SWP_NOMOVE | SWP_NOSIZE); | |
| 3415 RECT rcItem = LayoutData.m_rcInit; | |
| 3416 | |
| 3417 if(((nID == ATL_IDW_STATUS_BAR) || (nDeltaWidth >= 0)) && (LayoutData.m_nMoveRatioX != 0)) | |
| 3418 { | |
| 3419 rcItem.left += ::MulDiv(nDeltaWidth, LayoutData.m_nMoveRatioX, 100); | |
| 3420 rcItem.right += ::MulDiv(nDeltaWidth, LayoutData.m_nMoveRatioX, 100); | |
| 3421 nFlags &= ~SWP_NOMOVE; | |
| 3422 } | |
| 3423 | |
| 3424 if(((nID == ATL_IDW_STATUS_BAR) || (nDeltaHeight >= 0)) && (LayoutData.m_nMoveRatioY != 0)) | |
| 3425 { | |
| 3426 rcItem.top += ::MulDiv(nDeltaHeight, LayoutData.m_nMoveRatioY, 100); | |
| 3427 rcItem.bottom += ::MulDiv(nDeltaHeight, LayoutData.m_nMoveRatioY, 100); | |
| 3428 nFlags &= ~SWP_NOMOVE; | |
| 3429 } | |
| 3430 | |
| 3431 if((nDeltaWidth >= 0) && (LayoutData.m_nSizeRatioX != 0)) | |
| 3432 { | |
| 3433 rcItem.right += ::MulDiv(nDeltaWidth, LayoutData.m_nSizeRatioX, 100); | |
| 3434 nFlags &= ~SWP_NOSIZE; | |
| 3435 } | |
| 3436 | |
| 3437 if((nDeltaHeight >= 0) && (LayoutData.m_nSizeRatioY != 0)) | |
| 3438 { | |
| 3439 rcItem.bottom += ::MulDiv(nDeltaHeight, LayoutData.m_nSizeRatioY, 100); | |
| 3440 nFlags &= ~SWP_NOSIZE; | |
| 3441 } | |
| 3442 | |
| 3443 if(nFlags != (SWP_NOMOVE | SWP_NOSIZE)) | |
| 3444 ::DeferWindowPos(hDwp, LayoutData.m_hWnd, NULL, rcItem.left, rcItem.top, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, nFlags | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOACTIVATE | SWP_NOCOPYBITS); | |
| 3445 } | |
| 3446 | |
| 3447 ::EndDeferWindowPos(hDwp); | |
| 3448 } | |
| 3449 | |
| 3450 // Message map and handlers | |
| 3451 BEGIN_MSG_MAP(CDynamicDialogLayout) | |
| 3452 MESSAGE_HANDLER(WM_SIZE, OnSize) | |
| 3453 MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) | |
| 3454 END_MSG_MAP() | |
| 3455 | |
| 3456 LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | |
| 3457 { | |
| 3458 T* pT = static_cast<T*>(this); | |
| 3459 | |
| 3460 if(m_bGripper) | |
| 3461 { | |
| 3462 ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); | |
| 3463 if(wndGripper.m_hWnd != NULL) | |
| 3464 { | |
| 3465 if(wParam == SIZE_MAXIMIZED) | |
| 3466 wndGripper.ShowWindow(SW_HIDE); | |
| 3467 else if(wParam == SIZE_RESTORED) | |
| 3468 wndGripper.ShowWindow(SW_SHOW); | |
| 3469 } | |
| 3470 } | |
| 3471 | |
| 3472 if(wParam != SIZE_MINIMIZED) | |
| 3473 pT->UpdateDynamicLayout(); | |
| 3474 | |
| 3475 return 0; | |
| 3476 } | |
| 3477 | |
| 3478 LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) | |
| 3479 { | |
| 3480 if((m_ptMinTrackSize.x != -1) && (m_ptMinTrackSize.y != -1)) | |
| 3481 { | |
| 3482 LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; | |
| 3483 lpMMI->ptMinTrackSize = m_ptMinTrackSize; | |
| 3484 } | |
| 3485 | |
| 3486 return 0; | |
| 3487 } | |
| 3488 | |
| 3489 // Implementation | |
| 3490 char _GetDataPct(WORD wResData) | |
| 3491 { | |
| 3492 ATLASSERT((wResData >= 0) && (wResData <= 100)); | |
| 3493 char nPct = (char)LOBYTE(wResData); | |
| 3494 if((nPct < 0) || (nPct > 100)) | |
| 3495 nPct = -1; | |
| 3496 | |
| 3497 return nPct; | |
| 3498 } | |
| 3499 }; | |
| 3500 | |
| 3501 #endif // (_MSC_VER >= 1900) | |
| 3502 | |
| 3503 | |
| 3504 /////////////////////////////////////////////////////////////////////////////// | |
| 3505 // CDoubleBufferImpl - Provides double-buffer painting support to any window | |
| 3506 | |
| 3507 template <class T> | |
| 3508 class CDoubleBufferImpl | |
| 3509 { | |
| 3510 public: | |
| 3511 // Overrideables | |
| 3512 void DoPaint(CDCHandle /*dc*/) | |
| 3513 { | |
| 3514 // must be implemented in a derived class | |
| 3515 ATLASSERT(FALSE); | |
| 3516 } | |
| 3517 | |
| 3518 // Message map and handlers | |
| 3519 BEGIN_MSG_MAP(CDoubleBufferImpl) | |
| 3520 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) | |
| 3521 MESSAGE_HANDLER(WM_PAINT, OnPaint) | |
| 3522 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | |
| 3523 END_MSG_MAP() | |
| 3524 | |
| 3525 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | |
| 3526 { | |
| 3527 return 1; // no background painting needed | |
| 3528 } | |
| 3529 | |
| 3530 LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | |
| 3531 { | |
| 3532 T* pT = static_cast<T*>(this); | |
| 3533 ATLASSERT(::IsWindow(pT->m_hWnd)); | |
| 3534 | |
| 3535 if(wParam != NULL) | |
| 3536 { | |
| 3537 RECT rect = {}; | |
| 3538 pT->GetClientRect(&rect); | |
| 3539 CMemoryDC dcMem((HDC)wParam, rect); | |
| 3540 pT->DoPaint(dcMem.m_hDC); | |
| 3541 } | |
| 3542 else | |
| 3543 { | |
| 3544 CPaintDC dc(pT->m_hWnd); | |
| 3545 CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint); | |
| 3546 pT->DoPaint(dcMem.m_hDC); | |
| 3547 } | |
| 3548 | |
| 3549 return 0; | |
| 3550 } | |
| 3551 }; | |
| 3552 | |
| 3553 | |
| 3554 /////////////////////////////////////////////////////////////////////////////// | |
| 3555 // CDoubleBufferWindowImpl - Implements a double-buffer painting window | |
| 3556 | |
| 3557 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | |
| 3558 class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T > | |
| 3559 { | |
| 3560 public: | |
| 3561 BEGIN_MSG_MAP(CDoubleBufferWindowImpl) | |
| 3562 CHAIN_MSG_MAP(CDoubleBufferImpl< T >) | |
| 3563 END_MSG_MAP() | |
| 3564 }; | |
| 3565 | |
| 3566 | |
| 3567 // command bar support | |
| 3568 #if !defined(__ATLCTRLW_H__) | |
| 3569 #undef CBRM_GETMENU | |
| 3570 #undef CBRM_TRACKPOPUPMENU | |
| 3571 #undef CBRM_GETCMDBAR | |
| 3572 #undef CBRPOPUPMENU | |
| 3573 #endif // !defined(__ATLCTRLW_H__) | |
| 3574 | |
| 3575 } // namespace WTL | |
| 3576 | |
| 3577 #endif // __ATLFRAME_H__ |
