ResizableSheet.cpp 7.6 KB

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