ResizableSheetEx.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // ResizableSheetEx.cpp : implementation file
  2. //
  3. /////////////////////////////////////////////////////////////////////////////
  4. //
  5. // Copyright (C) 2000-2001 by Paolo Messina
  6. // (http://www.geocities.com/ppescher - ppescher@yahoo.com)
  7. //
  8. // The contents of this file are subject to the Artistic License (the "License").
  9. // You may not use this file except in compliance with the License.
  10. // You may obtain a copy of the License at:
  11. // http://www.opensource.org/licenses/artistic-license.html
  12. //
  13. // If you find this code useful, credits would be nice!
  14. //
  15. /////////////////////////////////////////////////////////////////////////////
  16. #include "stdafx.h"
  17. #include "ResizableSheetEx.h"
  18. #ifdef _DEBUG
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CResizableSheetEx
  25. IMPLEMENT_DYNAMIC(CResizableSheetEx, CPropertySheetEx)
  26. inline void CResizableSheetEx::Construct()
  27. {
  28. m_bInitDone = FALSE;
  29. m_bEnableSaveRestore = FALSE;
  30. m_bSavePage = FALSE;
  31. }
  32. CResizableSheetEx::CResizableSheetEx()
  33. {
  34. Construct();
  35. }
  36. CResizableSheetEx::CResizableSheetEx(UINT nIDCaption, CWnd* pParentWnd,
  37. UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,
  38. HBITMAP hbmHeader)
  39. : CPropertySheetEx(nIDCaption, pParentWnd, iSelectPage,
  40. hbmWatermark, hpalWatermark, hbmHeader)
  41. {
  42. Construct();
  43. }
  44. CResizableSheetEx::CResizableSheetEx(LPCTSTR pszCaption, CWnd* pParentWnd,
  45. UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,
  46. HBITMAP hbmHeader)
  47. : CPropertySheetEx(pszCaption, pParentWnd, iSelectPage,
  48. hbmWatermark, hpalWatermark, hbmHeader)
  49. {
  50. Construct();
  51. }
  52. CResizableSheetEx::~CResizableSheetEx()
  53. {
  54. }
  55. BEGIN_MESSAGE_MAP(CResizableSheetEx, CPropertySheetEx)
  56. //{{AFX_MSG_MAP(CResizableSheetEx)
  57. ON_WM_GETMINMAXINFO()
  58. ON_WM_SIZE()
  59. ON_WM_DESTROY()
  60. ON_WM_CREATE()
  61. ON_WM_ERASEBKGND()
  62. //}}AFX_MSG_MAP
  63. ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)
  64. END_MESSAGE_MAP()
  65. /////////////////////////////////////////////////////////////////////////////
  66. // CResizableSheetEx message handlers
  67. int CResizableSheetEx::OnCreate(LPCREATESTRUCT lpCreateStruct)
  68. {
  69. if (CPropertySheetEx::OnCreate(lpCreateStruct) == -1)
  70. return -1;
  71. // keep client area
  72. CRect rect;
  73. GetClientRect(&rect);
  74. // set resizable style
  75. ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
  76. // adjust size to reflect new style
  77. ::AdjustWindowRectEx(&rect, GetStyle(),
  78. ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
  79. SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED|
  80. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION);
  81. if (!InitGrip())
  82. return -1;
  83. return 0;
  84. }
  85. BOOL CResizableSheetEx::OnInitDialog()
  86. {
  87. BOOL bResult = CPropertySheetEx::OnInitDialog();
  88. // set the initial size as the min track size
  89. CRect rc;
  90. GetWindowRect(&rc);
  91. SetMinTrackSize(rc.Size());
  92. // init
  93. UpdateGripPos();
  94. PresetLayout();
  95. // prevent flickering
  96. GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
  97. m_bInitDone = TRUE;
  98. ArrangeLayout();
  99. return bResult;
  100. }
  101. void CResizableSheetEx::OnDestroy()
  102. {
  103. if (m_bEnableSaveRestore)
  104. {
  105. SaveWindowRect(m_sSection, m_bRectOnly);
  106. SavePage();
  107. }
  108. RemoveAllAnchors();
  109. CPropertySheetEx::OnDestroy();
  110. }
  111. // maps an index to a button ID and vice-versa
  112. static UINT _propButtons[] =
  113. {
  114. IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
  115. ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
  116. };
  117. // horizontal line in wizard mode
  118. #define ID_WIZLINE ID_WIZFINISH+1
  119. #define ID_WIZLINEHDR ID_WIZFINISH+2
  120. void CResizableSheetEx::PresetLayout()
  121. {
  122. if (IsWizard() || IsWizard97()) // wizard mode
  123. {
  124. // hide tab control
  125. GetTabControl()->ShowWindow(SW_HIDE);
  126. AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);
  127. if (IsWizard97()) // add header line for wizard97 dialogs
  128. AddAnchor(ID_WIZLINEHDR, TOP_LEFT, TOP_RIGHT);
  129. }
  130. else // tab mode
  131. {
  132. AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);
  133. }
  134. // add a callback for active page (which can change at run-time)
  135. AddAnchorCallback(1);
  136. // use *total* parent size to have correct margins
  137. CRect rectPage, rectSheet;
  138. GetTotalClientRect(&rectSheet);
  139. GetActivePage()->GetWindowRect(&rectPage);
  140. ScreenToClient(&rectPage);
  141. // pre-calculate margins
  142. m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();
  143. m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();
  144. // add all possible buttons, if they exist
  145. for (int i = 0; i < 7; i++)
  146. {
  147. if (NULL != GetDlgItem(_propButtons[i]))
  148. AddAnchor(_propButtons[i], BOTTOM_RIGHT);
  149. }
  150. }
  151. BOOL CResizableSheetEx::ArrangeLayoutCallback(LayoutInfo &layout)
  152. {
  153. if (layout.nCallbackID != 1) // we only added 1 callback
  154. return CResizableLayout::ArrangeLayoutCallback(layout);
  155. // set layout info for active page
  156. layout.hWnd = GetActivePage()->GetSafeHwnd();
  157. // set margins
  158. if (IsWizard()) // wizard mode
  159. {
  160. // use pre-calculated margins
  161. layout.sizeMarginTL = m_sizePageTL;
  162. layout.sizeMarginBR = m_sizePageBR;
  163. }
  164. else if (IsWizard97()) // wizard 97
  165. {
  166. // use pre-calculated margins
  167. layout.sizeMarginTL = m_sizePageTL;
  168. layout.sizeMarginBR = m_sizePageBR;
  169. if (!(GetActivePage()->m_psp.dwFlags & PSP_HIDEHEADER))
  170. {
  171. // add header vertical offset
  172. CRect rectLine;
  173. GetDlgItem(ID_WIZLINEHDR)->GetWindowRect(&rectLine);
  174. ScreenToClient(&rectLine);
  175. layout.sizeMarginTL.cy = rectLine.bottom;
  176. }
  177. }
  178. else // tab mode
  179. {
  180. CRect rectPage, rectSheet;
  181. GetTotalClientRect(&rectSheet);
  182. CTabCtrl* pTab = GetTabControl();
  183. pTab->GetWindowRect(&rectPage);
  184. pTab->AdjustRect(FALSE, &rectPage);
  185. ScreenToClient(&rectPage);
  186. // use tab control
  187. layout.sizeMarginTL = rectPage.TopLeft() - rectSheet.TopLeft();
  188. layout.sizeMarginBR = rectPage.BottomRight() - rectSheet.BottomRight();
  189. }
  190. // set anchor types
  191. layout.sizeTypeTL = TOP_LEFT;
  192. layout.sizeTypeBR = BOTTOM_RIGHT;
  193. // use this layout info
  194. return TRUE;
  195. }
  196. void CResizableSheetEx::OnSize(UINT nType, int cx, int cy)
  197. {
  198. CWnd::OnSize(nType, cx, cy);
  199. if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
  200. return; // arrangement not needed
  201. if (m_bInitDone)
  202. {
  203. // update size-grip
  204. UpdateGripPos();
  205. ArrangeLayout();
  206. }
  207. }
  208. BOOL CResizableSheetEx::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/)
  209. {
  210. // update new wizard page
  211. // active page changes after this notification
  212. PostMessage(WM_SIZE);
  213. return FALSE; // continue routing
  214. }
  215. BOOL CResizableSheetEx::OnEraseBkgnd(CDC* pDC)
  216. {
  217. ClipChildren(pDC);
  218. return CPropertySheetEx::OnEraseBkgnd(pDC);
  219. }
  220. void CResizableSheetEx::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
  221. {
  222. if (!m_bInitDone)
  223. return;
  224. MinMaxInfo(lpMMI);
  225. }
  226. // protected members
  227. int CResizableSheetEx::GetMinWidth()
  228. {
  229. CWnd* pWnd = NULL;
  230. CRect rectWnd, rectSheet;
  231. GetTotalClientRect(&rectSheet);
  232. int max = 0, min = rectSheet.Width();
  233. // search for leftmost and rightmost button margins
  234. for (int i = 0; i < 7; i++)
  235. {
  236. pWnd = GetDlgItem(_propButtons[i]);
  237. // exclude not present or hidden buttons
  238. if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))
  239. continue;
  240. // left position is relative to the right border
  241. // of the parent window (negative value)
  242. pWnd->GetWindowRect(&rectWnd);
  243. ScreenToClient(&rectWnd);
  244. int left = rectSheet.right - rectWnd.left;
  245. int right = rectSheet.right - rectWnd.right;
  246. if (left > max)
  247. max = left;
  248. if (right < min)
  249. min = right;
  250. }
  251. // sizing border width
  252. int border = GetSystemMetrics(SM_CXSIZEFRAME);
  253. // compute total width
  254. return max + min + 2*border;
  255. }
  256. // NOTE: this must be called after all the other settings
  257. // to have the window and its controls displayed properly
  258. void CResizableSheetEx::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)
  259. {
  260. m_sSection = pszSection;
  261. m_bSavePage = bWithPage;
  262. m_bEnableSaveRestore = TRUE;
  263. m_bRectOnly = bRectOnly;
  264. // restore immediately
  265. LoadWindowRect(pszSection, bRectOnly);
  266. LoadPage();
  267. }
  268. // private memebers
  269. // used to save/restore active page
  270. // either in the registry or a private .INI file
  271. // depending on your application settings
  272. #define ACTIVEPAGE _T("ActivePage")
  273. void CResizableSheetEx::SavePage()
  274. {
  275. if (!m_bSavePage)
  276. return;
  277. // saves active page index, zero (the first) if problems
  278. // cannot use GetActivePage, because it always fails
  279. CTabCtrl *pTab = GetTabControl();
  280. int page = 0;
  281. if (pTab != NULL)
  282. page = pTab->GetCurSel();
  283. if (page < 0)
  284. page = 0;
  285. AfxGetApp()->WriteProfileInt(m_sSection, ACTIVEPAGE, page);
  286. }
  287. void CResizableSheetEx::LoadPage()
  288. {
  289. // restore active page, zero (the first) if not found
  290. int page = AfxGetApp()->GetProfileInt(m_sSection, ACTIVEPAGE, 0);
  291. if (m_bSavePage)
  292. {
  293. SetActivePage(page);
  294. ArrangeLayout(); // needs refresh
  295. }
  296. }