|
1
|
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__
|