Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2690 lines
78 KiB

  1. // WTL Version 3.1
  2. // Copyright (C) 1997-2000 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This file is a part of Windows Template Library.
  6. // The code and information is provided "as-is" without
  7. // warranty of any kind, either expressed or implied.
  8. #ifndef __ATLFRAME_H__
  9. #define __ATLFRAME_H__
  10. #pragma once
  11. #ifndef __cplusplus
  12. #error ATL requires C++ compilation (use a .cpp suffix)
  13. #endif
  14. #ifndef __ATLAPP_H__
  15. #error atlframe.h requires atlapp.h to be included first
  16. #endif
  17. #ifndef __ATLWIN_H__
  18. #error atlframe.h requires atlwin.h to be included first
  19. #endif
  20. namespace WTL
  21. {
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Forward declarations
  24. template <class T, class TBase = CWindow, class TWinTraits = CFrameWinTraits> class CFrameWindowImpl;
  25. class CMDIWindow;
  26. template <class T, class TBase = CMDIWindow, class TWinTraits = CFrameWinTraits> class CMDIFrameWindowImpl;
  27. template <class T, class TBase = CMDIWindow, class TWinTraits = CMDIChildWinTraits> class CMDIChildWindowImpl;
  28. template <class T> class COwnerDraw;
  29. class CUpdateUIBase;
  30. template <class T> class CUpdateUI;
  31. template <class T> class CDialogResize;
  32. /////////////////////////////////////////////////////////////////////////////
  33. // CFrameWndClassInfo - Manages frame window Windows class information
  34. class CFrameWndClassInfo
  35. {
  36. public:
  37. WNDCLASSEX m_wc;
  38. LPCTSTR m_lpszOrigName;
  39. WNDPROC pWndProc;
  40. LPCTSTR m_lpszCursorID;
  41. BOOL m_bSystemCursor;
  42. ATOM m_atom;
  43. TCHAR m_szAutoName[5 + sizeof(void*) * 2]; // sizeof(void*) * 2 is the number of digits %p outputs
  44. UINT m_uCommonResourceID;
  45. ATOM Register(WNDPROC* pProc)
  46. {
  47. if (m_atom == 0)
  48. {
  49. ::EnterCriticalSection(&_Module.m_csWindowCreate);
  50. if(m_atom == 0)
  51. {
  52. HINSTANCE hInst = _Module.GetModuleInstance();
  53. if (m_lpszOrigName != NULL)
  54. {
  55. ATLASSERT(pProc != NULL);
  56. LPCTSTR lpsz = m_wc.lpszClassName;
  57. WNDPROC proc = m_wc.lpfnWndProc;
  58. WNDCLASSEX wc;
  59. wc.cbSize = sizeof(WNDCLASSEX);
  60. if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc))
  61. {
  62. ::LeaveCriticalSection(&_Module.m_csWindowCreate);
  63. return 0;
  64. }
  65. memcpy(&m_wc, &wc, sizeof(WNDCLASSEX));
  66. pWndProc = m_wc.lpfnWndProc;
  67. m_wc.lpszClassName = lpsz;
  68. m_wc.lpfnWndProc = proc;
  69. }
  70. else
  71. {
  72. m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst,
  73. m_lpszCursorID);
  74. }
  75. m_wc.hInstance = hInst;
  76. m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes
  77. if (m_wc.lpszClassName == NULL)
  78. {
  79. wsprintf(m_szAutoName, _T("ATL:%p"), &m_wc);
  80. m_wc.lpszClassName = m_szAutoName;
  81. }
  82. WNDCLASSEX wcTemp;
  83. memcpy(&wcTemp, &m_wc, sizeof(WNDCLASSEX));
  84. m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
  85. if (m_atom == 0)
  86. {
  87. if(m_uCommonResourceID != 0) // use it if not zero
  88. {
  89. m_wc.hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
  90. m_wc.hIconSm = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  91. }
  92. m_atom = ::RegisterClassEx(&m_wc);
  93. }
  94. }
  95. ::LeaveCriticalSection(&_Module.m_csWindowCreate);
  96. }
  97. if (m_lpszOrigName != NULL)
  98. {
  99. ATLASSERT(pProc != NULL);
  100. ATLASSERT(pWndProc != NULL);
  101. *pProc = pWndProc;
  102. }
  103. return m_atom;
  104. }
  105. };
  106. #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
  107. static CFrameWndClassInfo& GetWndClassInfo() \
  108. { \
  109. static CFrameWndClassInfo wc = \
  110. { \
  111. { sizeof(WNDCLASSEX), 0, StartWindowProc, \
  112. 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
  113. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  114. }; \
  115. return wc; \
  116. }
  117. #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
  118. static CFrameWndClassInfo& GetWndClassInfo() \
  119. { \
  120. static CFrameWndClassInfo wc = \
  121. { \
  122. { sizeof(WNDCLASSEX), style, StartWindowProc, \
  123. 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
  124. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  125. }; \
  126. return wc; \
  127. }
  128. #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
  129. static CFrameWndClassInfo& GetWndClassInfo() \
  130. { \
  131. static CFrameWndClassInfo wc = \
  132. { \
  133. { sizeof(WNDCLASSEX), 0, StartWindowProc, \
  134. 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
  135. OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \
  136. }; \
  137. return wc; \
  138. }
  139. // Command Chaining Macros
  140. #define CHAIN_COMMANDS(theChainClass) \
  141. { \
  142. if(uMsg == WM_COMMAND && theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \
  143. return TRUE; \
  144. }
  145. #define CHAIN_COMMANDS_MEMBER(theChainMember) \
  146. { \
  147. if(uMsg == WM_COMMAND && theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \
  148. return TRUE; \
  149. }
  150. #define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \
  151. { \
  152. if(uMsg == WM_COMMAND && theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \
  153. return TRUE; \
  154. }
  155. #define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \
  156. { \
  157. if(uMsg == WM_COMMAND && theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \
  158. return TRUE; \
  159. }
  160. // Client window command chaining macro
  161. #define CHAIN_CLIENT_COMMANDS() \
  162. if(uMsg == WM_COMMAND && m_hWndClient != NULL) \
  163. ::SendMessage(m_hWndClient, uMsg, wParam, lParam);
  164. /////////////////////////////////////////////////////////////////////////////
  165. // CFrameWindowImpl
  166. // standard toolbar styles
  167. #define ATL_SIMPLE_TOOLBAR_STYLE \
  168. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS)
  169. // toolbar in a rebar pane
  170. #define ATL_SIMPLE_TOOLBAR_PANE_STYLE \
  171. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT)
  172. // standard rebar styles
  173. #if (_WIN32_IE >= 0x0400)
  174. #define ATL_SIMPLE_REBAR_STYLE \
  175. (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE)
  176. #else
  177. #define ATL_SIMPLE_REBAR_STYLE \
  178. (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS)
  179. #endif //!(_WIN32_IE >= 0x0400)
  180. // rebar without borders
  181. #if (_WIN32_IE >= 0x0400)
  182. #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
  183. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER)
  184. #else
  185. #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
  186. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER)
  187. #endif //!(_WIN32_IE >= 0x0400)
  188. // command bar support
  189. #ifndef __ATLCTRLW_H__
  190. #define CBRM_GETCMDBAR (WM_USER + 301) // return command bar HWND
  191. #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
  192. #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
  193. // Menu animation flags
  194. #ifndef TPM_VERPOSANIMATION
  195. #define TPM_VERPOSANIMATION 0x1000L
  196. #endif
  197. struct _AtlFrameWnd_CmdBarPopupMenu
  198. {
  199. int cbSize;
  200. HMENU hMenu;
  201. UINT uFlags;
  202. int x;
  203. int y;
  204. LPTPMPARAMS lptpm;
  205. };
  206. #define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu
  207. #endif //!__ATLCTRLW_H__
  208. template <class TBase = CWindow, class TWinTraits = CFrameWinTraits>
  209. class ATL_NO_VTABLE CFrameWindowImplBase : public CWindowImplBaseT< TBase, TWinTraits >
  210. {
  211. public:
  212. DECLARE_FRAME_WND_CLASS(NULL, 0)
  213. // Data members
  214. HWND m_hWndToolBar;
  215. HWND m_hWndStatusBar;
  216. HWND m_hWndClient;
  217. HACCEL m_hAccel;
  218. struct _AtlToolBarData
  219. {
  220. WORD wVersion;
  221. WORD wWidth;
  222. WORD wHeight;
  223. WORD wItemCount;
  224. //WORD aItems[wItemCount]
  225. WORD* items()
  226. { return (WORD*)(this+1); }
  227. };
  228. #if (_WIN32_IE >= 0x0500)
  229. struct _ChevronMenuInfo
  230. {
  231. HMENU hMenu;
  232. LPNMREBARCHEVRON lpnm;
  233. bool bCmdBar;
  234. };
  235. #endif //(_WIN32_IE >= 0x0500)
  236. // Constructor
  237. CFrameWindowImplBase() : m_hWndToolBar(NULL), m_hWndStatusBar(NULL), m_hWndClient(NULL), m_hAccel(NULL)
  238. { }
  239. // Methods
  240. #ifndef _ATL_TMP_IMPL2
  241. HWND Create(HWND hWndParent, _U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, _U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)
  242. {
  243. ATLASSERT(m_hWnd == NULL);
  244. if(atom == 0)
  245. return NULL;
  246. _Module.AddCreateWndData(&m_thunk.cd, this);
  247. if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD))
  248. MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;
  249. if(rect.m_lpRect == NULL)
  250. rect.m_lpRect = &TBase::rcDefault;
  251. HWND hWnd = ::CreateWindowEx(dwExStyle, (LPCTSTR)(LONG_PTR)MAKELONG(atom, 0), szWindowName,
  252. dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,
  253. rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,
  254. _Module.GetModuleInstance(), lpCreateParam);
  255. ATLASSERT(m_hWnd == hWnd);
  256. return hWnd;
  257. }
  258. #endif //!_ATL_TMP_IMPL2
  259. static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
  260. DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  261. {
  262. HINSTANCE hInst = _Module.GetResourceInstance();
  263. HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR);
  264. if (hRsrc == NULL)
  265. return NULL;
  266. HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);
  267. if (hGlobal == NULL)
  268. return NULL;
  269. _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal);
  270. if (pData == NULL)
  271. return NULL;
  272. ATLASSERT(pData->wVersion == 1);
  273. WORD* pItems = pData->items();
  274. int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0);
  275. TBBUTTON* pTBBtn = (TBBUTTON*)_alloca(nItems * sizeof(TBBUTTON));
  276. // set initial separator (half width)
  277. if(bInitialSeparator)
  278. {
  279. pTBBtn[0].iBitmap = 4;
  280. pTBBtn[0].idCommand = 0;
  281. pTBBtn[0].fsState = 0;
  282. pTBBtn[0].fsStyle = TBSTYLE_SEP;
  283. pTBBtn[0].dwData = 0;
  284. pTBBtn[0].iString = 0;
  285. }
  286. int nBmp = 0;
  287. for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++)
  288. {
  289. if(pItems[i] != 0)
  290. {
  291. pTBBtn[j].iBitmap = nBmp++;
  292. pTBBtn[j].idCommand = pItems[i];
  293. pTBBtn[j].fsState = TBSTATE_ENABLED;
  294. pTBBtn[j].fsStyle = TBSTYLE_BUTTON;
  295. pTBBtn[j].dwData = 0;
  296. pTBBtn[j].iString = 0;
  297. }
  298. else
  299. {
  300. pTBBtn[j].iBitmap = 8;
  301. pTBBtn[j].idCommand = 0;
  302. pTBBtn[j].fsState = 0;
  303. pTBBtn[j].fsStyle = TBSTYLE_SEP;
  304. pTBBtn[j].dwData = 0;
  305. pTBBtn[j].iString = 0;
  306. }
  307. }
  308. HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0,0,100,100,
  309. hWndParent, (HMENU)LongToHandle(nID), _Module.GetModuleInstance(), NULL);
  310. ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L);
  311. TBADDBITMAP tbab;
  312. tbab.hInst = hInst;
  313. tbab.nID = nResourceID;
  314. ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab);
  315. ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn);
  316. ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, pData->wHeight));
  317. ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + 7, pData->wHeight + 7));
  318. return hWnd;
  319. }
  320. static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  321. {
  322. // Ensure style combinations for proper rebar painting
  323. if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER)
  324. dwStyle &= ~WS_BORDER;
  325. else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER))
  326. dwStyle |= CCS_NODIVIDER;
  327. // Create rebar window
  328. HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), _Module.GetModuleInstance(), NULL);
  329. if(hWndReBar == NULL)
  330. {
  331. ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n"));
  332. return NULL;
  333. }
  334. // Initialize and send the REBARINFO structure
  335. REBARINFO rbi;
  336. rbi.cbSize = sizeof(REBARINFO);
  337. rbi.fMask = 0;
  338. if(!::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi))
  339. {
  340. ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n"));
  341. ::DestroyWindow(hWndReBar);
  342. return NULL;
  343. }
  344. return hWndReBar;
  345. }
  346. BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  347. {
  348. ATLASSERT(!::IsWindow(m_hWndToolBar));
  349. m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID);
  350. return (m_hWndToolBar != NULL);
  351. }
  352. static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
  353. {
  354. ATLASSERT(::IsWindow(hWndReBar)); // must be already created
  355. #ifdef _DEBUG
  356. // block - check if this is really a rebar
  357. {
  358. TCHAR lpszClassName[sizeof(REBARCLASSNAME)];
  359. ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME));
  360. ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0);
  361. }
  362. #endif //_DEBUG
  363. ATLASSERT(::IsWindow(hWndBand)); // must be already created
  364. // Get number of buttons on the toolbar
  365. int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L);
  366. // Set band info structure
  367. REBARBANDINFO rbBand;
  368. rbBand.cbSize = sizeof(REBARBANDINFO);
  369. #if (_WIN32_IE >= 0x0400)
  370. rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE;
  371. #else
  372. rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE;
  373. #endif //!(_WIN32_IE >= 0x0400)
  374. if(lpstrTitle != NULL)
  375. rbBand.fMask |= RBBIM_TEXT;
  376. rbBand.fStyle = RBBS_CHILDEDGE;
  377. #if (_WIN32_IE >= 0x0500)
  378. if(nBtnCount > 0) // add chevron style for toolbar with buttons
  379. rbBand.fStyle |= RBBS_USECHEVRON;
  380. #endif //(_WIN32_IE >= 0x0500)
  381. if(bNewRow)
  382. rbBand.fStyle |= RBBS_BREAK;
  383. rbBand.lpText = lpstrTitle;
  384. rbBand.hwndChild = hWndBand;
  385. if(nID == 0) // calc band ID
  386. nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
  387. rbBand.wID = nID;
  388. // Calculate the size of the band
  389. BOOL bRet;
  390. RECT rcTmp;
  391. if(nBtnCount > 0)
  392. {
  393. bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp);
  394. ATLASSERT(bRet);
  395. rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right;
  396. rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
  397. if(bFullWidthAlways)
  398. {
  399. rbBand.cxMinChild = rbBand.cx;
  400. }
  401. else if(lpstrTitle == 0)
  402. {
  403. bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp);
  404. ATLASSERT(bRet);
  405. rbBand.cxMinChild = rcTmp.right;
  406. }
  407. else
  408. {
  409. rbBand.cxMinChild = 0;
  410. }
  411. }
  412. else // no buttons, either not a toolbar or really has no buttons
  413. {
  414. bRet = ::GetWindowRect(hWndBand, &rcTmp);
  415. ATLASSERT(bRet);
  416. rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left);
  417. rbBand.cxMinChild = (bFullWidthAlways) ? rbBand.cx : 0;
  418. rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
  419. }
  420. #if (_WIN32_IE >= 0x0400)
  421. rbBand.cxIdeal = rbBand.cx;
  422. #endif //(_WIN32_IE >= 0x0400)
  423. // Add the band
  424. LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
  425. if(lRes == 0)
  426. {
  427. ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n"));
  428. return FALSE;
  429. }
  430. #if (_WIN32_IE >= 0x0501)
  431. ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
  432. #endif //(_WIN32_IE >= 0x0501)
  433. return TRUE;
  434. }
  435. BOOL AddSimpleReBarBand(HWND hWndBand, LPTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
  436. {
  437. ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
  438. ATLASSERT(::IsWindow(hWndBand)); // must be created
  439. return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways);
  440. }
  441. #if (_WIN32_IE >= 0x0400)
  442. void SizeSimpleReBarBands()
  443. {
  444. ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
  445. int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L);
  446. for(int i = 0; i < nCount; i++)
  447. {
  448. REBARBANDINFO rbBand;
  449. rbBand.cbSize = sizeof(REBARBANDINFO);
  450. rbBand.fMask = RBBIM_SIZE;
  451. BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand);
  452. ATLASSERT(bRet);
  453. RECT rect = { 0, 0, 0, 0 };
  454. ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect);
  455. rbBand.cx += rect.left + rect.right;
  456. bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand);
  457. ATLASSERT(bRet);
  458. }
  459. }
  460. #endif //(_WIN32_IE >= 0x0400)
  461. BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
  462. {
  463. ATLASSERT(!::IsWindow(m_hWndStatusBar));
  464. m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID);
  465. return (m_hWndStatusBar != NULL);
  466. }
  467. 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)
  468. {
  469. TCHAR szText[128]; // max text lentgth is 127 for status bars
  470. szText[0] = 0;
  471. ::LoadString(_Module.GetResourceInstance(), nTextID, szText, 128);
  472. return CreateSimpleStatusBar(szText, dwStyle, nID);
  473. }
  474. void UpdateLayout(BOOL bResizeBars = TRUE)
  475. {
  476. RECT rect;
  477. GetClientRect(&rect);
  478. // position bars and offset their dimensions
  479. UpdateBarsPosition(rect, bResizeBars);
  480. // resize client window
  481. if(m_hWndClient != NULL)
  482. ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
  483. rect.right - rect.left, rect.bottom - rect.top,
  484. SWP_NOZORDER | SWP_NOACTIVATE);
  485. }
  486. void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
  487. {
  488. // resize toolbar
  489. if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))
  490. {
  491. if(bResizeBars)
  492. ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
  493. RECT rectTB;
  494. ::GetWindowRect(m_hWndToolBar, &rectTB);
  495. rect.top += rectTB.bottom - rectTB.top;
  496. }
  497. // resize status bar
  498. if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))
  499. {
  500. if(bResizeBars)
  501. ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
  502. RECT rectSB;
  503. ::GetWindowRect(m_hWndStatusBar, &rectSB);
  504. rect.bottom -= rectSB.bottom - rectSB.top;
  505. }
  506. }
  507. BOOL PreTranslateMessage(MSG* pMsg)
  508. {
  509. if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
  510. return TRUE;
  511. return FALSE;
  512. }
  513. typedef CFrameWindowImplBase< TBase, TWinTraits > thisClass;
  514. BEGIN_MSG_MAP(thisClass)
  515. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  516. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  517. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  518. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  519. NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA)
  520. NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW)
  521. END_MSG_MAP()
  522. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  523. {
  524. if(m_hWndClient != NULL) // view will paint itself instead
  525. return 1;
  526. bHandled = FALSE;
  527. return 0;
  528. }
  529. LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  530. {
  531. bHandled = FALSE;
  532. if(m_hWndStatusBar == NULL)
  533. return 1;
  534. WORD wFlags = HIWORD(wParam);
  535. if(wFlags == 0xFFFF && lParam == NULL) // menu closing
  536. ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L);
  537. else
  538. {
  539. TCHAR szBuff[256];
  540. szBuff[0] = 0;
  541. if(!(wFlags & MF_POPUP))
  542. {
  543. WORD wID = LOWORD(wParam);
  544. // check for special cases
  545. if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs
  546. wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST);
  547. else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items
  548. wID = ATL_IDS_MRU_FILE;
  549. else if(wID >= ATL_IDM_FIRST_MDICHILD) // MDI child windows
  550. wID = ATL_IDS_MDICHILD;
  551. int nRet = ::LoadString(_Module.GetResourceInstance(), wID, szBuff, 256);
  552. for(int i = 0; i < nRet; i++)
  553. {
  554. if(szBuff[i] == _T('\n'))
  555. {
  556. szBuff[i] = 0;
  557. break;
  558. }
  559. }
  560. }
  561. ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L);
  562. ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff);
  563. }
  564. return 1;
  565. }
  566. LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled)
  567. {
  568. if(m_hWndClient != NULL && ::IsWindowVisible(m_hWndClient))
  569. ::SetFocus(m_hWndClient);
  570. bHandled = FALSE;
  571. return 1;
  572. }
  573. LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
  574. {
  575. if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0)
  576. ::PostQuitMessage(1);
  577. bHandled = FALSE;
  578. return 1;
  579. }
  580. LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
  581. {
  582. LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh;
  583. pDispInfo->szText[0] = 0;
  584. if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
  585. {
  586. char szBuff[256];
  587. szBuff[0] = 0;
  588. int nRet = ::LoadStringA(_Module.GetResourceInstance(), idCtrl, szBuff, 256);
  589. for(int i = 0; i < nRet; i++)
  590. {
  591. if(szBuff[i] == '\n')
  592. {
  593. lstrcpynA(pDispInfo->szText, &szBuff[i + 1], sizeof(pDispInfo->szText) / sizeof(pDispInfo->szText[0]));
  594. break;
  595. }
  596. }
  597. #if (_WIN32_IE >= 0x0300)
  598. if(nRet > 0) // string was loaded, save it
  599. pDispInfo->uFlags |= TTF_DI_SETITEM;
  600. #endif //(_WIN32_IE >= 0x0300)
  601. }
  602. return 0;
  603. }
  604. LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
  605. {
  606. LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh;
  607. pDispInfo->szText[0] = 0;
  608. if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
  609. {
  610. wchar_t szBuff[256];
  611. szBuff[0] = 0;
  612. int nRet = ::LoadStringW(_Module.GetResourceInstance(), idCtrl, szBuff, 256);
  613. for(int i = 0; i < nRet; i++)
  614. {
  615. if(szBuff[i] == L'\n')
  616. {
  617. lstrcpynW(pDispInfo->szText, &szBuff[i + 1], sizeof(pDispInfo->szText) / sizeof(pDispInfo->szText[0]));
  618. break;
  619. }
  620. }
  621. #if (_WIN32_IE >= 0x0300)
  622. if(nRet > 0) // string was loaded, save it
  623. pDispInfo->uFlags |= TTF_DI_SETITEM;
  624. #endif //(_WIN32_IE >= 0x0300)
  625. }
  626. return 0;
  627. }
  628. #if (_WIN32_IE >= 0x0500)
  629. bool PrepareChevronMenu(_ChevronMenuInfo& cmi)
  630. {
  631. // get rebar and toolbar
  632. REBARBANDINFO rbbi;
  633. rbbi.cbSize = sizeof(REBARBANDINFO);
  634. rbbi.fMask = RBBIM_CHILD;
  635. BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);
  636. ATLASSERT(bRet);
  637. // assume the band is a toolbar
  638. CWindow wnd = rbbi.hwndChild;
  639. int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);
  640. if(nCount <= 0) // probably not a toolbar
  641. return false;
  642. // check if it's a command bar
  643. CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);
  644. cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);
  645. // build a menu from hidden items
  646. CMenuHandle menu;
  647. bRet = menu.CreatePopupMenu();
  648. ATLASSERT(bRet);
  649. RECT rcClient;
  650. bRet = wnd.GetClientRect(&rcClient);
  651. ATLASSERT(bRet);
  652. for(int i = 0; i < nCount; i++)
  653. {
  654. TBBUTTON tbb;
  655. bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);
  656. ATLASSERT(bRet);
  657. RECT rcButton;
  658. bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);
  659. ATLASSERT(bRet);
  660. bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);
  661. if(rcButton.right > rcClient.right)
  662. {
  663. if(tbb.fsStyle & BTNS_SEP)
  664. {
  665. if(menu.GetMenuItemCount() > 0)
  666. menu.AppendMenu(MF_SEPARATOR);
  667. }
  668. else if(cmi.bCmdBar)
  669. {
  670. TCHAR szBuff[100];
  671. CMenuItemInfo mii;
  672. mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
  673. mii.dwTypeData = szBuff;
  674. mii.cch = sizeof(szBuff) / sizeof(TCHAR);
  675. bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
  676. ATLASSERT(bRet);
  677. // Note: CmdBar currently supports only drop-down items
  678. ATLASSERT(::IsMenu(mii.hSubMenu));
  679. bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
  680. ATLASSERT(bRet);
  681. }
  682. else
  683. {
  684. // get button's text
  685. TCHAR szBuff[100];
  686. LPTSTR lpstrText = szBuff;
  687. if(wnd.SendMessage(TB_GETBUTTONTEXT, tbb.idCommand, (LPARAM)szBuff) == -1)
  688. {
  689. // no text for this button, try a resource string
  690. lpstrText = _T("?");
  691. ::LoadString(_Module.GetResourceInstance(), tbb.idCommand, szBuff, sizeof(szBuff) / sizeof(TCHAR));
  692. for(int n = 0; n < lstrlen(szBuff); n++)
  693. {
  694. if(szBuff[n] == _T('\n'))
  695. {
  696. lpstrText = &szBuff[n + 1];
  697. break;
  698. }
  699. }
  700. }
  701. bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);
  702. ATLASSERT(bRet);
  703. }
  704. }
  705. }
  706. if(menu.GetMenuItemCount() == 0) // no hidden buttons after all
  707. {
  708. menu.DestroyMenu();
  709. ::MessageBeep((UINT)-1);
  710. return false;
  711. }
  712. cmi.hMenu = menu;
  713. return true;
  714. }
  715. void DisplayChevronMenu(_ChevronMenuInfo& cmi)
  716. {
  717. // convert chevron rect to screen coordinates
  718. CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
  719. RECT rc = cmi.lpnm->rc;
  720. wndFrom.ClientToScreen(&rc);
  721. // set up flags and rect
  722. UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);
  723. TPMPARAMS TPMParams;
  724. TPMParams.cbSize = sizeof(TPMPARAMS);
  725. TPMParams.rcExclude = rc;
  726. // check if this window has a command bar
  727. HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);
  728. if(::IsWindow(hWndCmdBar))
  729. {
  730. CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, rc.left, rc.bottom, &TPMParams };
  731. ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);
  732. }
  733. else
  734. {
  735. ::TrackPopupMenuEx(cmi.hMenu, uMenuFlags, rc.left, rc.bottom, m_hWnd, &TPMParams);
  736. }
  737. }
  738. void CleanupChevronMenu(_ChevronMenuInfo& cmi)
  739. {
  740. CMenuHandle menu = cmi.hMenu;
  741. // if menu is from a command bar, detach submenus so they are not destroyed
  742. if(cmi.bCmdBar)
  743. {
  744. for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
  745. menu.RemoveMenu(i, MF_BYPOSITION);
  746. }
  747. // destroy menu
  748. menu.DestroyMenu();
  749. // convert chevron rect to screen coordinates
  750. CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
  751. RECT rc = cmi.lpnm->rc;
  752. wndFrom.ClientToScreen(&rc);
  753. // eat next message if click is on the same button
  754. MSG msg;
  755. if(::PeekMessage(&msg, m_hWnd, NULL, NULL, PM_NOREMOVE))
  756. {
  757. if(msg.message == WM_LBUTTONDOWN && ::PtInRect(&rc, msg.pt))
  758. ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
  759. }
  760. }
  761. #endif //(_WIN32_IE >= 0x0500)
  762. };
  763. template <class T, class TBase /*= CWindow */, class TWinTraits /*= CFrameWinTraits */ >
  764. class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits >
  765. {
  766. public:
  767. HWND Create(HWND hWndParent = NULL, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  768. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  769. HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
  770. {
  771. ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
  772. dwStyle = T::GetWndStyle(dwStyle);
  773. dwExStyle = T::GetWndExStyle(dwExStyle);
  774. if(rect.m_lpRect == NULL)
  775. rect.m_lpRect = &TBase::rcDefault;
  776. return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
  777. }
  778. HWND CreateEx(HWND hWndParent = NULL, _U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  779. {
  780. TCHAR szWindowName[256];
  781. szWindowName[0] = 0;
  782. ::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 256);
  783. HMENU hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  784. T* pT = static_cast<T*>(this);
  785. HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
  786. if(hWnd != NULL)
  787. m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  788. return hWnd;
  789. }
  790. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  791. {
  792. ATLASSERT(!::IsWindow(m_hWndToolBar));
  793. if(nResourceID == 0)
  794. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  795. m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
  796. return (m_hWndToolBar != NULL);
  797. }
  798. // message map and handlers
  799. typedef CFrameWindowImpl< T, TBase, TWinTraits > thisClass;
  800. typedef CFrameWindowImplBase< TBase, TWinTraits > baseClass;
  801. BEGIN_MSG_MAP(thisClass)
  802. MESSAGE_HANDLER(WM_SIZE, OnSize)
  803. #ifndef _ATL_NO_REBAR_SUPPORT
  804. #if (_WIN32_IE >= 0x0400)
  805. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  806. #endif //(_WIN32_IE >= 0x0400)
  807. #if (_WIN32_IE >= 0x0500)
  808. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  809. #endif //(_WIN32_IE >= 0x0500)
  810. #endif //!_ATL_NO_REBAR_SUPPORT
  811. CHAIN_MSG_MAP(baseClass)
  812. END_MSG_MAP()
  813. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  814. {
  815. if(wParam != SIZE_MINIMIZED)
  816. {
  817. T* pT = static_cast<T*>(this);
  818. pT->UpdateLayout();
  819. }
  820. bHandled = FALSE;
  821. return 1;
  822. }
  823. #ifndef _ATL_NO_REBAR_SUPPORT
  824. #if (_WIN32_IE >= 0x0400)
  825. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  826. {
  827. T* pT = static_cast<T*>(this);
  828. pT->UpdateLayout(FALSE);
  829. return 0;
  830. }
  831. #endif //(_WIN32_IE >= 0x0400)
  832. #if (_WIN32_IE >= 0x0500)
  833. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  834. {
  835. T* pT = static_cast<T*>(this);
  836. _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  837. if(!pT->PrepareChevronMenu(cmi))
  838. {
  839. bHandled = FALSE;
  840. return 1;
  841. }
  842. // display a popup menu with hidden items
  843. pT->DisplayChevronMenu(cmi);
  844. // cleanup
  845. pT->CleanupChevronMenu(cmi);
  846. return 0;
  847. }
  848. #endif //(_WIN32_IE >= 0x0500)
  849. #endif //!_ATL_NO_REBAR_SUPPORT
  850. };
  851. /////////////////////////////////////////////////////////////////////////////
  852. // CMDIWindow
  853. class CMDIWindow : public CWindow
  854. {
  855. public:
  856. // Data members
  857. HWND m_hWndMDIClient;
  858. HMENU m_hMenu;
  859. // Constructors
  860. CMDIWindow(HWND hWnd = NULL) : CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) { }
  861. CMDIWindow& operator=(HWND hWnd)
  862. {
  863. m_hWnd = hWnd;
  864. return *this;
  865. }
  866. // Operations
  867. HWND MDIGetActive(BOOL* lpbMaximized = NULL)
  868. {
  869. ATLASSERT(::IsWindow(m_hWndMDIClient));
  870. return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized);
  871. }
  872. void MDIActivate(HWND hWndChildToActivate)
  873. {
  874. ATLASSERT(::IsWindow(m_hWndMDIClient));
  875. ATLASSERT(::IsWindow(hWndChildToActivate));
  876. ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0);
  877. }
  878. void MDINext(HWND hWndChild, BOOL bPrevious = FALSE)
  879. {
  880. ATLASSERT(::IsWindow(m_hWndMDIClient));
  881. ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild));
  882. ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious);
  883. }
  884. void MDIMaximize(HWND hWndChildToMaximize)
  885. {
  886. ATLASSERT(::IsWindow(m_hWndMDIClient));
  887. ATLASSERT(::IsWindow(hWndChildToMaximize));
  888. ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0);
  889. }
  890. void MDIRestore(HWND hWndChildToRestore)
  891. {
  892. ATLASSERT(::IsWindow(m_hWndMDIClient));
  893. ATLASSERT(::IsWindow(hWndChildToRestore));
  894. ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0);
  895. }
  896. void MDIDestroy(HWND hWndChildToDestroy)
  897. {
  898. ATLASSERT(::IsWindow(m_hWndMDIClient));
  899. ATLASSERT(::IsWindow(hWndChildToDestroy));
  900. ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0);
  901. }
  902. BOOL MDICascade(UINT uFlags = 0)
  903. {
  904. ATLASSERT(::IsWindow(m_hWndMDIClient));
  905. return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0);
  906. }
  907. BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL)
  908. {
  909. ATLASSERT(::IsWindow(m_hWndMDIClient));
  910. return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0);
  911. }
  912. void MDIIconArrange()
  913. {
  914. ATLASSERT(::IsWindow(m_hWndMDIClient));
  915. ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
  916. }
  917. HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow)
  918. {
  919. ATLASSERT(::IsWindow(m_hWndMDIClient));
  920. return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow);
  921. }
  922. HMENU MDIRefreshMenu()
  923. {
  924. ATLASSERT(::IsWindow(m_hWndMDIClient));
  925. return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
  926. }
  927. // Additional operations
  928. static HMENU GetStandardWindowMenu(HMENU hMenu)
  929. {
  930. int nCount = ::GetMenuItemCount(hMenu);
  931. if(nCount == -1)
  932. return NULL;
  933. int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
  934. if(nLen == 0)
  935. return NULL;
  936. LPTSTR lpszText = (LPTSTR)_alloca((nLen + 1) * sizeof(TCHAR));
  937. if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
  938. return NULL;
  939. if(lstrcmp(lpszText, _T("&Window")))
  940. return NULL;
  941. return ::GetSubMenu(hMenu, nCount - 2);
  942. }
  943. void SetMDIFrameMenu()
  944. {
  945. HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu);
  946. MDISetMenu(m_hMenu, hWindowMenu);
  947. MDIRefreshMenu();
  948. ::DrawMenuBar(GetMDIFrame());
  949. }
  950. HWND GetMDIFrame() const
  951. {
  952. return ::GetParent(m_hWndMDIClient);
  953. }
  954. };
  955. /////////////////////////////////////////////////////////////////////////////
  956. // CMDIFrameWindowImpl
  957. // MDI child command chaining macro
  958. #define CHAIN_MDI_CHILD_COMMANDS() \
  959. if(uMsg == WM_COMMAND) \
  960. { \
  961. HWND hWndChild = MDIGetActive(); \
  962. if(hWndChild != NULL) \
  963. ::SendMessage(hWndChild, uMsg, wParam, lParam); \
  964. }
  965. template <class T, class TBase /*= CMDIWindow */, class TWinTraits /*= CFrameWinTraits */ >
  966. class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
  967. {
  968. public:
  969. HWND Create(HWND hWndParent = NULL, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  970. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  971. HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
  972. {
  973. m_hMenu = hMenu;
  974. ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
  975. dwStyle = T::GetWndStyle(dwStyle);
  976. dwExStyle = T::GetWndExStyle(dwExStyle);
  977. if(rect.m_lpRect == NULL)
  978. rect.m_lpRect = &TBase::rcDefault;
  979. return CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
  980. }
  981. HWND CreateEx(HWND hWndParent = NULL, _U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  982. {
  983. TCHAR szWindowName[256];
  984. szWindowName[0] = 0;
  985. ::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 256);
  986. HMENU hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  987. T* pT = static_cast<T*>(this);
  988. HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
  989. if(hWnd != NULL)
  990. m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  991. return hWnd;
  992. }
  993. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  994. {
  995. ATLASSERT(!::IsWindow(m_hWndToolBar));
  996. if(nResourceID == 0)
  997. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  998. m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
  999. return (m_hWndToolBar != NULL);
  1000. }
  1001. virtual WNDPROC GetWindowProc()
  1002. {
  1003. return MDIFrameWindowProc;
  1004. }
  1005. static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1006. {
  1007. CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd;
  1008. // set a ptr to this message and save the old value
  1009. #if defined(_ATL_TMP_IMPL1) || defined(_ATL_TMP_IMPL2)
  1010. _ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
  1011. const _ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
  1012. #else
  1013. MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
  1014. const MSG* pOldMsg = pThis->m_pCurrentMsg;
  1015. #endif
  1016. pThis->m_pCurrentMsg = &msg;
  1017. // pass to the message map to process
  1018. LRESULT lRes;
  1019. BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
  1020. // restore saved value for the current message
  1021. ATLASSERT(pThis->m_pCurrentMsg == &msg);
  1022. pThis->m_pCurrentMsg = pOldMsg;
  1023. // do the default processing if message was not handled
  1024. if(!bRet)
  1025. {
  1026. if(uMsg != WM_NCDESTROY)
  1027. lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
  1028. else
  1029. {
  1030. // unsubclass, if needed
  1031. LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
  1032. lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
  1033. if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
  1034. ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
  1035. #ifdef _ATL_TMP_IMPL2
  1036. // mark window as destryed
  1037. pThis->m_dwState |= WINSTATE_DESTROYED;
  1038. #else
  1039. // clear out window handle
  1040. HWND hWnd = pThis->m_hWnd;
  1041. pThis->m_hWnd = NULL;
  1042. // clean up after window is destroyed
  1043. pThis->OnFinalMessage(hWnd);
  1044. #endif
  1045. }
  1046. }
  1047. #ifdef _ATL_TMP_IMPL2
  1048. if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL)
  1049. {
  1050. // clear out window handle
  1051. HWND hWnd = pThis->m_hWnd;
  1052. pThis->m_hWnd = NULL;
  1053. pThis->m_dwState &= ~WINSTATE_DESTROYED;
  1054. // clean up after window is destroyed
  1055. pThis->OnFinalMessage(hWnd);
  1056. }
  1057. #endif
  1058. return lRes;
  1059. }
  1060. // Overriden to call DefWindowProc which uses DefFrameProc
  1061. LRESULT DefWindowProc()
  1062. {
  1063. const MSG* pMsg = m_pCurrentMsg;
  1064. LRESULT lRes = 0;
  1065. if (pMsg != NULL)
  1066. lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
  1067. return lRes;
  1068. }
  1069. LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1070. {
  1071. return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam);
  1072. }
  1073. BOOL PreTranslateMessage(MSG* pMsg)
  1074. {
  1075. if(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg))
  1076. return TRUE;
  1077. return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg);
  1078. }
  1079. HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
  1080. {
  1081. DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;
  1082. DWORD dwExStyle = WS_EX_CLIENTEDGE;
  1083. CLIENTCREATESTRUCT ccs;
  1084. ccs.hWindowMenu = hWindowMenu;
  1085. ccs.idFirstChild = nFirstChildID;
  1086. if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0)
  1087. {
  1088. // parent MDI frame's scroll styles move to the MDICLIENT
  1089. dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL));
  1090. // fast way to turn off the scrollbar bits (without a resize)
  1091. ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED);
  1092. }
  1093. // Create MDICLIENT window
  1094. m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL,
  1095. dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID),
  1096. _Module.GetModuleInstance(), (LPVOID)&ccs);
  1097. if (m_hWndClient == NULL)
  1098. {
  1099. ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n"));
  1100. return NULL;
  1101. }
  1102. // Move it to the top of z-order
  1103. ::BringWindowToTop(m_hWndClient);
  1104. // set as MDI client window
  1105. m_hWndMDIClient = m_hWndClient;
  1106. // update to proper size
  1107. T* pT = static_cast<T*>(this);
  1108. pT->UpdateLayout();
  1109. return m_hWndClient;
  1110. }
  1111. typedef CMDIFrameWindowImpl< T, TBase, TWinTraits > thisClass;
  1112. typedef CFrameWindowImplBase<TBase, TWinTraits > baseClass;
  1113. BEGIN_MSG_MAP(thisClass)
  1114. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1115. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  1116. MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
  1117. #ifndef _ATL_NO_REBAR_SUPPORT
  1118. #if (_WIN32_IE >= 0x0400)
  1119. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1120. #endif //(_WIN32_IE >= 0x0400)
  1121. #if (_WIN32_IE >= 0x0500)
  1122. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1123. #endif //(_WIN32_IE >= 0x0500)
  1124. #endif //!_ATL_NO_REBAR_SUPPORT
  1125. CHAIN_MSG_MAP(baseClass)
  1126. END_MSG_MAP()
  1127. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1128. {
  1129. if(wParam != SIZE_MINIMIZED)
  1130. {
  1131. T* pT = static_cast<T*>(this);
  1132. pT->UpdateLayout();
  1133. }
  1134. // message must be handled, otherwise DefFrameProc would resize the client again
  1135. return 0;
  1136. }
  1137. LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1138. {
  1139. // don't allow CFrameWindowImplBase to handle this one
  1140. return DefWindowProc(uMsg, wParam, lParam);
  1141. }
  1142. LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1143. {
  1144. SetMDIFrameMenu();
  1145. return 0;
  1146. }
  1147. #ifndef _ATL_NO_REBAR_SUPPORT
  1148. #if (_WIN32_IE >= 0x0400)
  1149. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1150. {
  1151. T* pT = static_cast<T*>(this);
  1152. pT->UpdateLayout(FALSE);
  1153. return 0;
  1154. }
  1155. #endif //(_WIN32_IE >= 0x0400)
  1156. #if (_WIN32_IE >= 0x0500)
  1157. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1158. {
  1159. T* pT = static_cast<T*>(this);
  1160. _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1161. if(!pT->PrepareChevronMenu(cmi))
  1162. {
  1163. bHandled = FALSE;
  1164. return 1;
  1165. }
  1166. // display a popup menu with hidden items
  1167. pT->DisplayChevronMenu(cmi);
  1168. // cleanup
  1169. pT->CleanupChevronMenu(cmi);
  1170. return 0;
  1171. }
  1172. #endif //(_WIN32_IE >= 0x0500)
  1173. #endif //!_ATL_NO_REBAR_SUPPORT
  1174. };
  1175. /////////////////////////////////////////////////////////////////////////////
  1176. // CMDIChildWindowImpl
  1177. template <class T, class TBase /*= CMDIWindow */, class TWinTraits /*= CMDIChildWinTraits */ >
  1178. class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
  1179. {
  1180. public:
  1181. HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  1182. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  1183. UINT nMenuID = 0, LPVOID lpCreateParam = NULL)
  1184. {
  1185. ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
  1186. if(nMenuID != 0)
  1187. m_hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(nMenuID));
  1188. dwStyle = T::GetWndStyle(dwStyle);
  1189. dwExStyle = T::GetWndExStyle(dwExStyle);
  1190. dwExStyle |= WS_EX_MDICHILD; // force this one
  1191. m_pfnSuperWindowProc = ::DefMDIChildProc;
  1192. m_hWndMDIClient = hWndParent;
  1193. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1194. if(rect.m_lpRect == NULL)
  1195. rect.m_lpRect = &TBase::rcDefault;
  1196. HWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam);
  1197. if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus()))
  1198. ::SetFocus(hWnd);
  1199. return hWnd;
  1200. }
  1201. HWND CreateEx(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  1202. {
  1203. TCHAR szWindowName[256];
  1204. szWindowName[0] = 0;
  1205. if(lpcstrWindowName == NULL)
  1206. {
  1207. ::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 256);
  1208. lpcstrWindowName = szWindowName;
  1209. }
  1210. T* pT = static_cast<T*>(this);
  1211. HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam);
  1212. if(hWnd != NULL)
  1213. m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1214. return hWnd;
  1215. }
  1216. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1217. {
  1218. ATLASSERT(!::IsWindow(m_hWndToolBar));
  1219. if(nResourceID == 0)
  1220. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1221. m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
  1222. return (m_hWndToolBar != NULL);
  1223. }
  1224. BOOL UpdateClientEdge(LPRECT lpRect = NULL)
  1225. {
  1226. // only adjust for active MDI child window
  1227. HWND hWndChild = MDIGetActive();
  1228. if(hWndChild != NULL && hWndChild != m_hWnd)
  1229. return FALSE;
  1230. // need to adjust the client edge style as max/restore happens
  1231. DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE);
  1232. DWORD dwNewStyle = dwStyle;
  1233. if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0))
  1234. dwNewStyle &= ~(WS_EX_CLIENTEDGE);
  1235. else
  1236. dwNewStyle |= WS_EX_CLIENTEDGE;
  1237. if(dwStyle != dwNewStyle)
  1238. {
  1239. // SetWindowPos will not move invalid bits
  1240. ::RedrawWindow(m_hWndMDIClient, NULL, NULL,
  1241. RDW_INVALIDATE | RDW_ALLCHILDREN);
  1242. // remove/add WS_EX_CLIENTEDGE to MDI client area
  1243. ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
  1244. ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0,
  1245. SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
  1246. SWP_NOZORDER | SWP_NOCOPYBITS);
  1247. // return new client area
  1248. if (lpRect != NULL)
  1249. ::GetClientRect(m_hWndMDIClient, lpRect);
  1250. return TRUE;
  1251. }
  1252. return FALSE;
  1253. }
  1254. typedef CMDIChildWindowImpl< T, TBase, TWinTraits > thisClass;
  1255. typedef CFrameWindowImplBase<TBase, TWinTraits > baseClass;
  1256. BEGIN_MSG_MAP(thisClass)
  1257. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1258. MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging)
  1259. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  1260. MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)
  1261. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  1262. #ifndef _ATL_NO_REBAR_SUPPORT
  1263. #if (_WIN32_IE >= 0x0400)
  1264. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1265. #endif //(_WIN32_IE >= 0x0400)
  1266. #if (_WIN32_IE >= 0x0500)
  1267. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1268. #endif //(_WIN32_IE >= 0x0500)
  1269. #endif //!_ATL_NO_REBAR_SUPPORT
  1270. CHAIN_MSG_MAP(baseClass)
  1271. END_MSG_MAP()
  1272. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1273. {
  1274. DefWindowProc(uMsg, wParam, lParam); // needed for MDI children
  1275. if(wParam != SIZE_MINIMIZED)
  1276. {
  1277. T* pT = static_cast<T*>(this);
  1278. pT->UpdateLayout();
  1279. }
  1280. return 0;
  1281. }
  1282. LRESULT OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1283. {
  1284. // update MDI client edge and adjust MDI child rect
  1285. LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam;
  1286. if(!(lpWndPos->flags & SWP_NOSIZE))
  1287. {
  1288. CWindow wnd(m_hWndMDIClient);
  1289. RECT rectClient;
  1290. if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0))
  1291. {
  1292. ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle());
  1293. lpWndPos->x = rectClient.left;
  1294. lpWndPos->y = rectClient.top;
  1295. lpWndPos->cx = rectClient.right - rectClient.left;
  1296. lpWndPos->cy = rectClient.bottom - rectClient.top;
  1297. }
  1298. }
  1299. bHandled = FALSE;
  1300. return 1;
  1301. }
  1302. LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1303. {
  1304. return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam);
  1305. }
  1306. LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1307. {
  1308. if((HWND)lParam == m_hWnd && m_hMenu != NULL)
  1309. SetMDIFrameMenu();
  1310. else if((HWND)lParam == NULL)
  1311. ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0);
  1312. bHandled = FALSE;
  1313. return 1;
  1314. }
  1315. LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1316. {
  1317. UpdateClientEdge();
  1318. bHandled = FALSE;
  1319. return 1;
  1320. }
  1321. #ifndef _ATL_NO_REBAR_SUPPORT
  1322. #if (_WIN32_IE >= 0x0400)
  1323. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1324. {
  1325. T* pT = static_cast<T*>(this);
  1326. pT->UpdateLayout(FALSE);
  1327. return 0;
  1328. }
  1329. #endif //(_WIN32_IE >= 0x0400)
  1330. #if (_WIN32_IE >= 0x0500)
  1331. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1332. {
  1333. T* pT = static_cast<T*>(this);
  1334. _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1335. if(!pT->PrepareChevronMenu(cmi))
  1336. {
  1337. bHandled = FALSE;
  1338. return 1;
  1339. }
  1340. // display a popup menu with hidden items
  1341. pT->DisplayChevronMenu(cmi);
  1342. // cleanup
  1343. pT->CleanupChevronMenu(cmi);
  1344. return 0;
  1345. }
  1346. #endif //(_WIN32_IE >= 0x0500)
  1347. #endif //!_ATL_NO_REBAR_SUPPORT
  1348. };
  1349. /////////////////////////////////////////////////////////////////////////////
  1350. // COwnerDraw - MI class for owner-draw support
  1351. template <class T>
  1352. class COwnerDraw
  1353. {
  1354. public:
  1355. #if !defined(_ATL_TMP_IMPL1) && !defined(_ATL_TMP_IMPL2)
  1356. BOOL m_bHandledOD;
  1357. BOOL IsMsgHandled() const
  1358. {
  1359. return m_bHandledOD;
  1360. }
  1361. void SetMsgHandled(BOOL bHandled)
  1362. {
  1363. m_bHandledOD = bHandled;
  1364. }
  1365. #endif //!defined(_ATL_TMP_IMPL1) && !defined(_ATL_TMP_IMPL2)
  1366. // Message map and handlers
  1367. BEGIN_MSG_MAP(COwnerDraw< T >)
  1368. MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
  1369. MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
  1370. MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
  1371. MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
  1372. ALT_MSG_MAP(1)
  1373. MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
  1374. MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
  1375. MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
  1376. MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
  1377. END_MSG_MAP()
  1378. LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1379. {
  1380. T* pT = static_cast<T*>(this);
  1381. pT->SetMsgHandled(TRUE);
  1382. pT->DrawItem((LPDRAWITEMSTRUCT)lParam);
  1383. bHandled = pT->IsMsgHandled();
  1384. return (LRESULT)TRUE;
  1385. }
  1386. LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1387. {
  1388. T* pT = static_cast<T*>(this);
  1389. pT->SetMsgHandled(TRUE);
  1390. pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam);
  1391. bHandled = pT->IsMsgHandled();
  1392. return (LRESULT)TRUE;
  1393. }
  1394. LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1395. {
  1396. T* pT = static_cast<T*>(this);
  1397. pT->SetMsgHandled(TRUE);
  1398. bHandled = pT->IsMsgHandled();
  1399. return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam);
  1400. }
  1401. LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1402. {
  1403. T* pT = static_cast<T*>(this);
  1404. pT->SetMsgHandled(TRUE);
  1405. pT->DeleteItem((LPDELETEITEMSTRUCT)lParam);
  1406. bHandled = pT->IsMsgHandled();
  1407. return (LRESULT)TRUE;
  1408. }
  1409. // Overrideables
  1410. void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)
  1411. {
  1412. // must be implemented
  1413. ATLASSERT(FALSE);
  1414. }
  1415. void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  1416. {
  1417. if(lpMeasureItemStruct->CtlType != ODT_MENU)
  1418. {
  1419. // return default height for a system font
  1420. T* pT = static_cast<T*>(this);
  1421. HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID);
  1422. CClientDC dc(hWnd);
  1423. TEXTMETRIC tm;
  1424. dc.GetTextMetrics(&tm);
  1425. lpMeasureItemStruct->itemHeight = tm.tmHeight;
  1426. }
  1427. else
  1428. lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU);
  1429. }
  1430. int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/)
  1431. {
  1432. // all items are equal
  1433. return 0;
  1434. }
  1435. void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
  1436. {
  1437. // default - nothing
  1438. }
  1439. };
  1440. /////////////////////////////////////////////////////////////////////////////
  1441. // Update UI macros
  1442. // these build the Update UI map inside a class definition
  1443. #define BEGIN_UPDATE_UI_MAP(thisClass) \
  1444. static const _AtlUpdateUIMap* GetUpdateUIMap() \
  1445. { \
  1446. static const _AtlUpdateUIMap theMap[] = \
  1447. {
  1448. #define UPDATE_ELEMENT(nID, wType) \
  1449. { nID, wType },
  1450. #define END_UPDATE_UI_MAP() \
  1451. { (WORD)-1, 0 } \
  1452. }; \
  1453. return theMap; \
  1454. }
  1455. ///////////////////////////////////////////////////////////////////////////////
  1456. // CUpdateUI - manages UI elements updating
  1457. class CUpdateUIBase
  1458. {
  1459. public:
  1460. // constants
  1461. enum
  1462. {
  1463. // UI element type
  1464. UPDUI_MENUPOPUP = 0x0001,
  1465. UPDUI_MENUBAR = 0x0002,
  1466. UPDUI_CHILDWINDOW = 0x0004,
  1467. UPDUI_TOOLBAR = 0x0008,
  1468. UPDUI_STATUSBAR = 0x0010,
  1469. // state
  1470. UPDUI_ENABLED = 0x0000,
  1471. UPDUI_DISABLED = 0x0100,
  1472. UPDUI_CHECKED = 0x0200,
  1473. UPDUI_CHECKED2 = 0x0400,
  1474. UPDUI_RADIO = 0x0800,
  1475. UPDUI_DEFAULT = 0x1000,
  1476. UPDUI_TEXT = 0x2000,
  1477. };
  1478. // element data
  1479. struct _AtlUpdateUIElement
  1480. {
  1481. HWND m_hWnd;
  1482. WORD m_wType;
  1483. bool operator==(const _AtlUpdateUIElement& e) const
  1484. { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); }
  1485. };
  1486. // map data
  1487. struct _AtlUpdateUIMap
  1488. {
  1489. WORD m_nID;
  1490. WORD m_wType;
  1491. };
  1492. // instance data
  1493. struct _AtlUpdateUIData
  1494. {
  1495. WORD m_wState;
  1496. void* m_lpData;
  1497. };
  1498. CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data
  1499. const _AtlUpdateUIMap* m_pUIMap; // static UI data
  1500. _AtlUpdateUIData* m_pUIData; // instance UI data
  1501. WORD m_wDirtyType; // global dirty flag
  1502. bool m_bBlockAccelerators;
  1503. // Constructor, destructor
  1504. CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false)
  1505. { }
  1506. ~CUpdateUIBase()
  1507. {
  1508. if(m_pUIMap != NULL && m_pUIData != NULL)
  1509. {
  1510. const _AtlUpdateUIMap* pUIMap = m_pUIMap;
  1511. _AtlUpdateUIData* pUIData = m_pUIData;
  1512. while(pUIMap->m_nID != (WORD)-1)
  1513. {
  1514. if(pUIData->m_wState & UPDUI_TEXT)
  1515. free(pUIData->m_lpData);
  1516. pUIMap++;
  1517. pUIData++;
  1518. }
  1519. delete [] m_pUIData;
  1520. }
  1521. }
  1522. // Check for disabled commands
  1523. bool UIGetBlockAccelerators() const
  1524. {
  1525. return m_bBlockAccelerators;
  1526. }
  1527. bool UISetBlockAccelerators(bool bBlock)
  1528. {
  1529. bool bOld = m_bBlockAccelerators;
  1530. m_bBlockAccelerators = bBlock;
  1531. return bOld;
  1532. }
  1533. // Add elements
  1534. BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu)
  1535. {
  1536. if(hWnd == NULL)
  1537. return FALSE;
  1538. _AtlUpdateUIElement e;
  1539. e.m_hWnd = hWnd;
  1540. e.m_wType = UPDUI_MENUBAR;
  1541. return m_UIElements.Add(e);
  1542. }
  1543. BOOL UIAddToolBar(HWND hWnd) // toolbar
  1544. {
  1545. if(hWnd == NULL)
  1546. return FALSE;
  1547. _AtlUpdateUIElement e;
  1548. e.m_hWnd = hWnd;
  1549. e.m_wType = UPDUI_TOOLBAR;
  1550. return m_UIElements.Add(e);
  1551. }
  1552. BOOL UIAddStatusBar(HWND hWnd) // status bar
  1553. {
  1554. if(hWnd == NULL)
  1555. return FALSE;
  1556. _AtlUpdateUIElement e;
  1557. e.m_hWnd = hWnd;
  1558. e.m_wType = UPDUI_STATUSBAR;
  1559. return m_UIElements.Add(e);
  1560. }
  1561. BOOL UIAddChildWindowContainer(HWND hWnd) // child window
  1562. {
  1563. if(hWnd == NULL)
  1564. return FALSE;
  1565. _AtlUpdateUIElement e;
  1566. e.m_hWnd = hWnd;
  1567. e.m_wType = UPDUI_CHILDWINDOW;
  1568. return m_UIElements.Add(e);
  1569. }
  1570. // Message map for popup menu updates and accelerator blocking
  1571. BEGIN_MSG_MAP(CUpdateUIBase)
  1572. MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
  1573. MESSAGE_HANDLER(WM_COMMAND, OnCommand)
  1574. END_MSG_MAP()
  1575. LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1576. {
  1577. bHandled = FALSE;
  1578. HMENU hMenu = (HMENU)wParam;
  1579. if(hMenu == NULL)
  1580. return 1;
  1581. _AtlUpdateUIData* pUIData = m_pUIData;
  1582. if(pUIData == NULL)
  1583. return 1;
  1584. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1585. while(pMap->m_nID != (WORD)-1)
  1586. {
  1587. if(pMap->m_wType & UPDUI_MENUPOPUP)
  1588. UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
  1589. pMap++;
  1590. pUIData++;
  1591. }
  1592. return 0;
  1593. }
  1594. LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1595. {
  1596. bHandled = FALSE;
  1597. if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only
  1598. {
  1599. int nID = LOWORD(wParam);
  1600. if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED)
  1601. {
  1602. ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID);
  1603. bHandled = TRUE; // eat the command, UI item is disabled
  1604. }
  1605. }
  1606. return 0;
  1607. }
  1608. // methods for setting UI element state
  1609. BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
  1610. {
  1611. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1612. _AtlUpdateUIData* pUIData = m_pUIData;
  1613. if(pUIData == NULL)
  1614. return FALSE;
  1615. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1616. {
  1617. if(nID == (int)pMap->m_nID)
  1618. {
  1619. if(bEnable)
  1620. {
  1621. if(pUIData->m_wState & UPDUI_DISABLED)
  1622. {
  1623. pUIData->m_wState |= pMap->m_wType;
  1624. pUIData->m_wState &= ~UPDUI_DISABLED;
  1625. }
  1626. }
  1627. else
  1628. {
  1629. if(!(pUIData->m_wState & UPDUI_DISABLED))
  1630. {
  1631. pUIData->m_wState |= pMap->m_wType;
  1632. pUIData->m_wState |= UPDUI_DISABLED;
  1633. }
  1634. }
  1635. if(bForceUpdate)
  1636. pUIData->m_wState |= pMap->m_wType;
  1637. if(pUIData->m_wState & pMap->m_wType)
  1638. m_wDirtyType |= pMap->m_wType;
  1639. break; // found
  1640. }
  1641. }
  1642. return TRUE;
  1643. }
  1644. BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE)
  1645. {
  1646. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1647. _AtlUpdateUIData* pUIData = m_pUIData;
  1648. if(pUIData == NULL)
  1649. return FALSE;
  1650. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1651. {
  1652. if(nID == (int)pMap->m_nID)
  1653. {
  1654. switch(nCheck)
  1655. {
  1656. case 0:
  1657. if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2))
  1658. {
  1659. pUIData->m_wState |= pMap->m_wType;
  1660. pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2);
  1661. }
  1662. break;
  1663. case 1:
  1664. if(!(pUIData->m_wState & UPDUI_CHECKED))
  1665. {
  1666. pUIData->m_wState |= pMap->m_wType;
  1667. pUIData->m_wState &= ~UPDUI_CHECKED2;
  1668. pUIData->m_wState |= UPDUI_CHECKED;
  1669. }
  1670. break;
  1671. case 2:
  1672. if(!(pUIData->m_wState & UPDUI_CHECKED2))
  1673. {
  1674. pUIData->m_wState |= pMap->m_wType;
  1675. pUIData->m_wState &= ~UPDUI_CHECKED;
  1676. pUIData->m_wState |= UPDUI_CHECKED2;
  1677. }
  1678. break;
  1679. }
  1680. if(bForceUpdate)
  1681. pUIData->m_wState |= pMap->m_wType;
  1682. if(pUIData->m_wState & pMap->m_wType)
  1683. m_wDirtyType |= pMap->m_wType;
  1684. break; // found
  1685. }
  1686. }
  1687. return TRUE;
  1688. }
  1689. BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE)
  1690. {
  1691. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1692. _AtlUpdateUIData* pUIData = m_pUIData;
  1693. if(pUIData == NULL)
  1694. return FALSE;
  1695. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1696. {
  1697. if(nID == (int)pMap->m_nID)
  1698. {
  1699. if(bRadio)
  1700. {
  1701. if(!(pUIData->m_wState & UPDUI_RADIO))
  1702. {
  1703. pUIData->m_wState |= pMap->m_wType;
  1704. pUIData->m_wState |= UPDUI_RADIO;
  1705. }
  1706. }
  1707. else
  1708. {
  1709. if(pUIData->m_wState & UPDUI_RADIO)
  1710. {
  1711. pUIData->m_wState |= pMap->m_wType;
  1712. pUIData->m_wState &= ~UPDUI_RADIO;
  1713. }
  1714. }
  1715. if(bForceUpdate)
  1716. pUIData->m_wState |= pMap->m_wType;
  1717. if(pUIData->m_wState & pMap->m_wType)
  1718. m_wDirtyType |= pMap->m_wType;
  1719. break; // found
  1720. }
  1721. }
  1722. return TRUE;
  1723. }
  1724. BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE)
  1725. {
  1726. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1727. _AtlUpdateUIData* pUIData = m_pUIData;
  1728. if(pUIData == NULL)
  1729. return FALSE;
  1730. if(lpstrText == NULL)
  1731. lpstrText = _T("");
  1732. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1733. {
  1734. if(nID == (int)pMap->m_nID)
  1735. {
  1736. if(pUIData->m_lpData == NULL || lstrcmp((LPTSTR)pUIData->m_lpData, lpstrText))
  1737. {
  1738. int nStrLen = lstrlen(lpstrText);
  1739. free(pUIData->m_lpData);
  1740. pUIData->m_lpData = NULL;
  1741. ATLTRY(pUIData->m_lpData = malloc((nStrLen + 1) * sizeof(TCHAR)));
  1742. if(pUIData->m_lpData == NULL)
  1743. {
  1744. ATLTRACE2(atlTraceUI, 0, _T("UISetText - malloc failed\n"));
  1745. break;
  1746. }
  1747. lstrcpy((LPTSTR)pUIData->m_lpData, lpstrText);
  1748. pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
  1749. }
  1750. if(bForceUpdate)
  1751. pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
  1752. if(pUIData->m_wState | pMap->m_wType)
  1753. m_wDirtyType |= pMap->m_wType;
  1754. break; // found
  1755. }
  1756. }
  1757. return TRUE;
  1758. }
  1759. // methods for complete state set/get
  1760. BOOL UISetState(int nID, DWORD dwState)
  1761. {
  1762. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1763. _AtlUpdateUIData* pUIData = m_pUIData;
  1764. if(pUIData == NULL)
  1765. return FALSE;
  1766. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1767. {
  1768. if(nID == (int)pMap->m_nID)
  1769. {
  1770. pUIData->m_wState |= dwState | pMap->m_wType;
  1771. m_wDirtyType |= pMap->m_wType;
  1772. break; // found
  1773. }
  1774. }
  1775. return TRUE;
  1776. }
  1777. DWORD UIGetState(int nID)
  1778. {
  1779. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1780. _AtlUpdateUIData* pUIData = m_pUIData;
  1781. if(pUIData == NULL)
  1782. return 0;
  1783. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1784. {
  1785. if(nID == (int)pMap->m_nID)
  1786. return pUIData->m_wState;
  1787. }
  1788. return 0;
  1789. }
  1790. // methods for updating UI
  1791. BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE)
  1792. {
  1793. if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate)
  1794. return TRUE;
  1795. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1796. _AtlUpdateUIData* pUIData = m_pUIData;
  1797. if(pUIData == NULL)
  1798. return FALSE;
  1799. while(pMap->m_nID != (WORD)-1)
  1800. {
  1801. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1802. {
  1803. if(m_UIElements[i].m_wType == UPDUI_MENUBAR)
  1804. {
  1805. HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd);
  1806. if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR))
  1807. UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
  1808. }
  1809. if(bMainMenu)
  1810. ::DrawMenuBar(m_UIElements[i].m_hWnd);
  1811. }
  1812. pMap++;
  1813. pUIData->m_wState &= ~UPDUI_MENUBAR;
  1814. if(pUIData->m_wState & UPDUI_TEXT)
  1815. {
  1816. free(pUIData->m_lpData);
  1817. pUIData->m_lpData = NULL;
  1818. pUIData->m_wState &= ~UPDUI_TEXT;
  1819. }
  1820. pUIData++;
  1821. }
  1822. m_wDirtyType &= ~UPDUI_MENUBAR;
  1823. return TRUE;
  1824. }
  1825. BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE)
  1826. {
  1827. if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate)
  1828. return TRUE;
  1829. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1830. _AtlUpdateUIData* pUIData = m_pUIData;
  1831. if(pUIData == NULL)
  1832. return FALSE;
  1833. while(pMap->m_nID != (WORD)-1)
  1834. {
  1835. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1836. {
  1837. if(m_UIElements[i].m_wType == UPDUI_TOOLBAR)
  1838. {
  1839. if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR))
  1840. UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  1841. }
  1842. }
  1843. pMap++;
  1844. pUIData->m_wState &= ~UPDUI_TOOLBAR;
  1845. pUIData++;
  1846. }
  1847. m_wDirtyType &= ~UPDUI_TOOLBAR;
  1848. return TRUE;
  1849. }
  1850. BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
  1851. {
  1852. if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
  1853. return TRUE;
  1854. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1855. _AtlUpdateUIData* pUIData = m_pUIData;
  1856. if(pUIData == NULL)
  1857. return FALSE;
  1858. while(pMap->m_nID != (WORD)-1)
  1859. {
  1860. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1861. {
  1862. if(m_UIElements[i].m_wType == UPDUI_STATUSBAR)
  1863. {
  1864. if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR))
  1865. UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  1866. }
  1867. }
  1868. pMap++;
  1869. pUIData->m_wState &= ~UPDUI_STATUSBAR;
  1870. if(pUIData->m_wState & UPDUI_TEXT)
  1871. {
  1872. free(pUIData->m_lpData);
  1873. pUIData->m_lpData = NULL;
  1874. pUIData->m_wState &= ~UPDUI_TEXT;
  1875. }
  1876. pUIData++;
  1877. }
  1878. m_wDirtyType &= ~UPDUI_STATUSBAR;
  1879. return TRUE;
  1880. }
  1881. BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
  1882. {
  1883. if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
  1884. return TRUE;
  1885. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1886. _AtlUpdateUIData* pUIData = m_pUIData;
  1887. if(pUIData == NULL)
  1888. return FALSE;
  1889. while(pMap->m_nID != (WORD)-1)
  1890. {
  1891. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1892. {
  1893. if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
  1894. {
  1895. if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
  1896. UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  1897. }
  1898. }
  1899. pMap++;
  1900. pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
  1901. if(pUIData->m_wState & UPDUI_TEXT)
  1902. {
  1903. free(pUIData->m_lpData);
  1904. pUIData->m_lpData = NULL;
  1905. pUIData->m_wState &= ~UPDUI_TEXT;
  1906. }
  1907. pUIData++;
  1908. }
  1909. m_wDirtyType &= ~UPDUI_CHILDWINDOW;
  1910. return TRUE;
  1911. }
  1912. // internal element specific methods
  1913. static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu)
  1914. {
  1915. MENUITEMINFO mii;
  1916. memset(&mii, 0, sizeof(MENUITEMINFO));
  1917. mii.cbSize = sizeof(MENUITEMINFO);
  1918. mii.fMask = MIIM_STATE;
  1919. mii.wID = nID;
  1920. if(pUIData->m_wState & UPDUI_DISABLED)
  1921. mii.fState |= MFS_DISABLED | MFS_GRAYED;
  1922. else
  1923. mii.fState |= MFS_ENABLED;
  1924. if(pUIData->m_wState & UPDUI_CHECKED)
  1925. mii.fState |= MFS_CHECKED;
  1926. else
  1927. mii.fState |= MFS_UNCHECKED;
  1928. if(pUIData->m_wState & UPDUI_DEFAULT)
  1929. mii.fState |= MFS_DEFAULT;
  1930. if(pUIData->m_wState & UPDUI_TEXT)
  1931. {
  1932. mii.fMask |= MIIM_TYPE;
  1933. mii.fType = MFT_STRING;
  1934. mii.dwTypeData = (LPTSTR)pUIData->m_lpData;
  1935. }
  1936. ::SetMenuItemInfo(hMenu, nID, FALSE, &mii);
  1937. }
  1938. static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar)
  1939. {
  1940. // Note: only handles enabled/disabled, checked state, and radio (press)
  1941. ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
  1942. ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE);
  1943. ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE);
  1944. ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE);
  1945. }
  1946. static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar)
  1947. {
  1948. // Note: only handles text
  1949. if(pUIData->m_wState & UPDUI_TEXT)
  1950. ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpData);
  1951. }
  1952. static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd)
  1953. {
  1954. HWND hChild = ::GetDlgItem(hWnd, nID);
  1955. ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
  1956. // for check and radio, assume that window is a button
  1957. int nCheck = BST_UNCHECKED;
  1958. if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO)
  1959. nCheck = BST_CHECKED;
  1960. else if(pUIData->m_wState & UPDUI_CHECKED2)
  1961. nCheck = BST_INDETERMINATE;
  1962. ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L);
  1963. if(pUIData->m_wState & UPDUI_DEFAULT)
  1964. {
  1965. DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L);
  1966. if(HIWORD(dwRet) == DC_HASDEFID)
  1967. {
  1968. HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet));
  1969. // remove BS_DEFPUSHBUTTON
  1970. ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
  1971. }
  1972. ::SendMessage(hWnd, DM_SETDEFID, nID, 0L);
  1973. }
  1974. if(pUIData->m_wState & UPDUI_TEXT)
  1975. ::SetWindowText(hChild, (LPTSTR)pUIData->m_lpData);
  1976. }
  1977. };
  1978. template <class T>
  1979. class CUpdateUI : public CUpdateUIBase
  1980. {
  1981. public:
  1982. CUpdateUI()
  1983. {
  1984. T* pT = static_cast<T*>(this);
  1985. pT;
  1986. const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
  1987. m_pUIMap = pMap;
  1988. ATLASSERT(m_pUIMap != NULL);
  1989. int nCount;
  1990. for(nCount = 1; pMap->m_nID != (WORD)-1; nCount++)
  1991. pMap++;
  1992. // check for duplicates (debug only)
  1993. #ifdef _DEBUG
  1994. for(int i = 0; i < nCount; i++)
  1995. {
  1996. for(int j = 0; j < nCount; j++)
  1997. {
  1998. // shouldn't have duplicates in the update UI map
  1999. if(i != j)
  2000. ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID);
  2001. }
  2002. }
  2003. #endif //_DEBUG
  2004. ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]);
  2005. ATLASSERT(m_pUIData != NULL);
  2006. if(m_pUIData != NULL)
  2007. memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount);
  2008. }
  2009. };
  2010. /////////////////////////////////////////////////////////////////////////////
  2011. // CDialogResize - provides support for resizing dialog controls
  2012. // (works for any window that has child controls)
  2013. // Put CDialogResize in the list of base classes for a dialog (or even plain window),
  2014. // then implement DLGRESIZE map by specifying controls and groups of control
  2015. // and using DLSZ_* values to specify how are they supposed to be resized.
  2016. // dialog resize map macros
  2017. #define BEGIN_DLGRESIZE_MAP(thisClass) \
  2018. static const _AtlDlgResizeMap* GetDlgResizeMap() \
  2019. { \
  2020. static const _AtlDlgResizeMap theMap[] = \
  2021. {
  2022. #define END_DLGRESIZE_MAP() \
  2023. { -1, 0 }, \
  2024. }; \
  2025. return theMap; \
  2026. }
  2027. #define DLGRESIZE_CONTROL(id, flags) \
  2028. { id, flags },
  2029. #define BEGIN_DLGRESIZE_GROUP() \
  2030. { -1, _DLSZ_BEGIN_GROUP },
  2031. #define END_DLGRESIZE_GROUP() \
  2032. { -1, _DLSZ_END_GROUP },
  2033. template <class T>
  2034. class CDialogResize
  2035. {
  2036. public:
  2037. // Data declarations and members
  2038. enum
  2039. {
  2040. DLSZ_SIZE_X = 0x00000001,
  2041. DLSZ_SIZE_Y = 0x00000002,
  2042. DLSZ_MOVE_X = 0x00000004,
  2043. DLSZ_MOVE_Y = 0x00000008,
  2044. DLSZ_REPAINT = 0x00000010,
  2045. // internal use only
  2046. _DLSZ_BEGIN_GROUP = 0x00001000,
  2047. _DLSZ_END_GROUP = 0x00002000,
  2048. _DLSZ_GRIPPER = 0x00004000
  2049. };
  2050. struct _AtlDlgResizeMap
  2051. {
  2052. int m_nCtlID;
  2053. DWORD m_dwResizeFlags;
  2054. };
  2055. struct _AtlDlgResizeData
  2056. {
  2057. int m_nCtlID;
  2058. DWORD m_dwResizeFlags;
  2059. RECT m_rect;
  2060. int GetGroupCount() const
  2061. {
  2062. return (int)LOBYTE(HIWORD(m_dwResizeFlags));
  2063. }
  2064. void SetGroupCount(int nCount)
  2065. {
  2066. ATLASSERT(nCount > 0 && nCount < 256);
  2067. DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0));
  2068. m_dwResizeFlags &= 0xFF00FFFF;
  2069. m_dwResizeFlags |= dwCount;
  2070. }
  2071. bool operator==(const _AtlDlgResizeData& r) const
  2072. { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); }
  2073. };
  2074. CSimpleArray<_AtlDlgResizeData> m_arrData;
  2075. SIZE m_sizeDialog;
  2076. POINT m_ptMinTrackSize;
  2077. bool m_bGripper;
  2078. // Constructor
  2079. CDialogResize() : m_bGripper(false)
  2080. {
  2081. m_sizeDialog.cx = 0;
  2082. m_sizeDialog.cy = 0;
  2083. m_ptMinTrackSize.x = -1;
  2084. m_ptMinTrackSize.y = -1;
  2085. }
  2086. // Operations
  2087. void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_THICKFRAME | WS_CLIPCHILDREN)
  2088. {
  2089. T* pT = static_cast<T*>(this);
  2090. ATLASSERT(::IsWindow(pT->m_hWnd));
  2091. // Force specified styles (default WS_THICKFRAME | WS_CLIPCHILDREN to enable resizing border and reduce flicker)
  2092. if((pT->GetStyle() & dwForceStyle) != dwForceStyle)
  2093. pT->ModifyStyle(0, dwForceStyle);
  2094. // Cleanup in case of multiple initialization
  2095. // block: first check for the gripper control, destroy it if needed
  2096. {
  2097. CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2098. if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0)
  2099. wndGripper.DestroyWindow();
  2100. }
  2101. // clear out everything else
  2102. m_arrData.RemoveAll();
  2103. m_sizeDialog.cx = 0;
  2104. m_sizeDialog.cy = 0;
  2105. m_ptMinTrackSize.x = -1;
  2106. m_ptMinTrackSize.y = -1;
  2107. // Get initial dialog client size
  2108. RECT rectDlg;
  2109. pT->GetClientRect(&rectDlg);
  2110. m_sizeDialog.cx = rectDlg.right;
  2111. m_sizeDialog.cy = rectDlg.bottom;
  2112. // Create gripper if requested
  2113. m_bGripper = false;
  2114. if(bAddGripper)
  2115. {
  2116. // shouldn't exist already
  2117. ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)));
  2118. if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)))
  2119. {
  2120. CWindow wndGripper;
  2121. 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);
  2122. ATLASSERT(wndGripper.IsWindow());
  2123. if(wndGripper.IsWindow())
  2124. {
  2125. m_bGripper = true;
  2126. RECT rectCtl;
  2127. wndGripper.GetWindowRect(&rectCtl);
  2128. pT->ScreenToClient(&rectCtl);
  2129. _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  2130. m_arrData.Add(data);
  2131. }
  2132. }
  2133. }
  2134. // Get min track position if requested
  2135. if(bUseMinTrackSize)
  2136. {
  2137. RECT rect;
  2138. pT->GetWindowRect(&rect);
  2139. m_ptMinTrackSize.x = rect.right - rect.left;
  2140. m_ptMinTrackSize.y = rect.bottom - rect.top;
  2141. }
  2142. // Walk the map and initialize data
  2143. const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap();
  2144. ATLASSERT(pMap != NULL);
  2145. int nGroupStart = -1;
  2146. for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++)
  2147. {
  2148. if(pMap->m_nCtlID == -1)
  2149. {
  2150. switch(pMap->m_dwResizeFlags)
  2151. {
  2152. case _DLSZ_BEGIN_GROUP:
  2153. ATLASSERT(nGroupStart == -1);
  2154. nGroupStart = m_arrData.GetSize();
  2155. break;
  2156. case _DLSZ_END_GROUP:
  2157. {
  2158. ATLASSERT(nGroupStart != -1);
  2159. int nGroupCount = m_arrData.GetSize() - nGroupStart;
  2160. m_arrData[nGroupStart].SetGroupCount(nGroupCount);
  2161. nGroupStart = -1;
  2162. }
  2163. break;
  2164. default:
  2165. ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry"));
  2166. break;
  2167. }
  2168. }
  2169. else
  2170. {
  2171. // this ID conflicts with the default gripper one
  2172. ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE);
  2173. CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID);
  2174. ATLASSERT(ctl.IsWindow());
  2175. RECT rectCtl;
  2176. ctl.GetWindowRect(&rectCtl);
  2177. pT->ScreenToClient(&rectCtl);
  2178. DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0;
  2179. _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  2180. m_arrData.Add(data);
  2181. }
  2182. }
  2183. ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map"));
  2184. }
  2185. void DlgResize_UpdateLayout(int cxWidth, int cyHeight)
  2186. {
  2187. T* pT = static_cast<T*>(this);
  2188. ATLASSERT(::IsWindow(pT->m_hWnd));
  2189. pT->SetRedraw(FALSE);
  2190. RECT rectGroup = { 0, 0, 0, 0 };
  2191. for(int i = 0; i < m_arrData.GetSize(); i++)
  2192. {
  2193. if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group
  2194. {
  2195. int nGroupCount = m_arrData[i].GetGroupCount();
  2196. ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize());
  2197. rectGroup = m_arrData[i].m_rect;
  2198. int j;
  2199. for(j = 1; j < nGroupCount; j++)
  2200. {
  2201. rectGroup.left = min(rectGroup.left, m_arrData[i + j].m_rect.left);
  2202. rectGroup.top = min(rectGroup.top, m_arrData[i + j].m_rect.top);
  2203. rectGroup.right = max(rectGroup.right, m_arrData[i + j].m_rect.right);
  2204. rectGroup.bottom = max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);
  2205. }
  2206. RECT rcThis;
  2207. RECT rcNext;
  2208. for(j = 0; j < nGroupCount; j++)
  2209. {
  2210. int xyStartNext = -1;
  2211. if((j < (nGroupCount - 1)) && ((m_arrData[i + j].m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y)) != 0) && ((m_arrData[i + j + 1].m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y)) != 0))
  2212. {
  2213. CWindow ctlThis = pT->GetDlgItem(m_arrData[i + j].m_nCtlID);
  2214. ctlThis.GetWindowRect(&rcThis);
  2215. pT->ScreenToClient(&rcThis);
  2216. CWindow ctlNext = pT->GetDlgItem(m_arrData[i + j + 1].m_nCtlID);
  2217. ctlNext.GetWindowRect(&rcNext);
  2218. pT->ScreenToClient(&rcNext);
  2219. if((m_arrData[i + j].m_dwResizeFlags & DLSZ_SIZE_X) == DLSZ_SIZE_X && (m_arrData[i + j + 1].m_dwResizeFlags & DLSZ_SIZE_X) == DLSZ_SIZE_X)
  2220. {
  2221. if(rcNext.left >= rcThis.right)
  2222. xyStartNext = m_arrData[i + j + 1].m_rect.left;
  2223. }
  2224. else if((m_arrData[i + j].m_dwResizeFlags & DLSZ_SIZE_Y) == DLSZ_SIZE_Y && (m_arrData[i + j + 1].m_dwResizeFlags & DLSZ_SIZE_Y) == DLSZ_SIZE_Y)
  2225. {
  2226. if(rcNext.top >= rcThis.bottom)
  2227. xyStartNext = m_arrData[i + j + 1].m_rect.top;
  2228. }
  2229. }
  2230. pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, xyStartNext);
  2231. }
  2232. // increment to skip all group controls
  2233. i += nGroupCount - 1;
  2234. }
  2235. else // one control entry
  2236. {
  2237. pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);
  2238. }
  2239. }
  2240. pT->SetRedraw(TRUE);
  2241. pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
  2242. }
  2243. // Message map and handlers
  2244. BEGIN_MSG_MAP(CDialogResize)
  2245. MESSAGE_HANDLER(WM_SIZE, OnSize)
  2246. MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
  2247. END_MSG_MAP()
  2248. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  2249. {
  2250. T* pT = static_cast<T*>(this);
  2251. if(m_bGripper)
  2252. {
  2253. CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2254. if(wParam == SIZE_MAXIMIZED)
  2255. wndGripper.ShowWindow(SW_HIDE);
  2256. else if(wParam == SIZE_RESTORED)
  2257. wndGripper.ShowWindow(SW_SHOW);
  2258. }
  2259. if(wParam != SIZE_MINIMIZED)
  2260. {
  2261. ATLASSERT(::IsWindow(pT->m_hWnd));
  2262. pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  2263. }
  2264. return 0;
  2265. }
  2266. LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  2267. {
  2268. if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
  2269. {
  2270. LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
  2271. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  2272. }
  2273. return 0;
  2274. }
  2275. // Implementation
  2276. bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, int xyStartNext = -1)
  2277. {
  2278. T* pT = static_cast<T*>(this);
  2279. ATLASSERT(::IsWindow(pT->m_hWnd));
  2280. CWindow ctl;
  2281. RECT rectCtl;
  2282. ctl = pT->GetDlgItem(data.m_nCtlID);
  2283. if(!ctl.GetWindowRect(&rectCtl))
  2284. return false;
  2285. if(!pT->ScreenToClient(&rectCtl))
  2286. return false;
  2287. if(bGroup)
  2288. {
  2289. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  2290. {
  2291. rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  2292. if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)
  2293. {
  2294. if(xyStartNext != -1)
  2295. rectCtl.right = rectGroup.left + ::MulDiv(xyStartNext - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left) - (xyStartNext - data.m_rect.right);
  2296. else
  2297. rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  2298. }
  2299. else
  2300. {
  2301. rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);
  2302. }
  2303. }
  2304. if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  2305. {
  2306. rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  2307. if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)
  2308. {
  2309. if(xyStartNext != -1)
  2310. rectCtl.bottom = rectGroup.top + ::MulDiv(xyStartNext - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top) - (xyStartNext - data.m_rect.bottom);
  2311. else
  2312. rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  2313. }
  2314. else
  2315. {
  2316. rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);
  2317. }
  2318. }
  2319. }
  2320. else
  2321. {
  2322. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  2323. {
  2324. rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);
  2325. if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)
  2326. rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);
  2327. }
  2328. if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  2329. {
  2330. rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);
  2331. if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)
  2332. rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);
  2333. }
  2334. }
  2335. if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)
  2336. ctl.Invalidate();
  2337. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT)) != 0)
  2338. ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE);
  2339. return true;
  2340. }
  2341. };
  2342. // command bar support
  2343. #ifndef __ATLCTRLW_H__
  2344. #undef CBRM_GETMENU
  2345. #undef CBRM_TRACKPOPUPMENU
  2346. #undef CBRM_GETCMDBAR
  2347. #undef CBRPOPUPMENU
  2348. #endif //!__ATLCTRLW_H__
  2349. }; //namespace WTL
  2350. #endif // __ATLFRAME_H__