ResizableSheet.cpp
上传用户:hjw22cn
上传日期:2007-01-11
资源大小:192k
文件大小:12k
源码类别:

Tab控件

开发平台:

Visual C++

  1. // ResizableSheet.cpp : implementation file
  2. //
  3. /////////////////////////////////////////////////////////////////////////////
  4. //
  5. // Copyright (C) 2000 by Paolo Messina
  6. // (ppescher@yahoo.com)
  7. //
  8. // Free for non-commercial use.
  9. // You may change the code to your needs,
  10. // provided that credits to the original 
  11. // author is given in the modified files.
  12. //  
  13. /////////////////////////////////////////////////////////////////////////////
  14. #include "stdafx.h"
  15. #include "ResizableSheet.h"
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CResizableSheet
  23. IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)
  24. inline void CResizableSheet::Construct()
  25. {
  26. m_bInitDone = FALSE;
  27. m_bUseMinTrack = TRUE;
  28. m_bUseMaxTrack = FALSE;
  29. m_bUseMaxRect = FALSE;
  30. m_bShowGrip = TRUE;
  31. m_bEnableSaveRestore = FALSE;
  32. m_bSavePage = FALSE;
  33. m_szGripSize.cx = GetSystemMetrics(SM_CXVSCROLL);
  34. m_szGripSize.cy = GetSystemMetrics(SM_CYHSCROLL);
  35. }
  36. CResizableSheet::CResizableSheet()
  37. {
  38. Construct();
  39. }
  40. CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)
  41.  : CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
  42. {
  43. Construct();
  44. }
  45. CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)
  46.  : CPropertySheet(pszCaption, pParentWnd, iSelectPage)
  47. {
  48. Construct();
  49. }
  50. CResizableSheet::~CResizableSheet()
  51. {
  52. }
  53. BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
  54. //{{AFX_MSG_MAP(CResizableSheet)
  55. ON_WM_PAINT()
  56. ON_WM_NCHITTEST()
  57. ON_WM_GETMINMAXINFO()
  58. ON_WM_SIZE()
  59. ON_WM_DESTROY()
  60. ON_WM_CREATE()
  61. //}}AFX_MSG_MAP
  62. ON_BN_CLICKED(ID_WIZBACK, OnPageChanged)
  63. ON_BN_CLICKED(ID_WIZNEXT, OnPageChanged)
  64. END_MESSAGE_MAP()
  65. /////////////////////////////////////////////////////////////////////////////
  66. // CResizableSheet message handlers
  67. int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  68. {
  69. if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
  70. return -1;
  71. // change window style to be resizable
  72. ModifyStyle(0, WS_THICKFRAME | WS_CLIPCHILDREN);
  73. return 0;
  74. }
  75. BOOL CResizableSheet::OnInitDialog() 
  76. {
  77. BOOL bResult = CPropertySheet::OnInitDialog();
  78. CRect rc;
  79. GetWindowRect(&rc);
  80. // set the initial size as the min track size
  81. m_ptMinTrackSize.x = rc.Width();
  82. m_ptMinTrackSize.y = rc.Height();
  83. UpdateGripPos();
  84. PresetLayout();
  85. // prevent flickering
  86. GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
  87. m_bInitDone = TRUE;
  88. return bResult;
  89. }
  90. void CResizableSheet::OnDestroy() 
  91. {
  92. CPropertySheet::OnDestroy();
  93. if (m_bEnableSaveRestore)
  94. SaveWindowRect();
  95. }
  96. // maps an index to a button ID and vice-versa
  97. static UINT _propButtons[] =
  98. {
  99. IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
  100. ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
  101. };
  102. // horizontal line in wizard mode
  103. #define ID_WIZLINE ID_WIZFINISH+1
  104. void CResizableSheet::PresetLayout()
  105. {
  106. CWnd* pWnd; // points to various children
  107. CRect wndrc, objrc;
  108. GetClientRect(&wndrc);
  109. // tab control or wizard line position
  110. if (m_psh.dwFlags & PSH_WIZARD) // wizard mode
  111. {
  112. // get wizard line's bottom-right corner
  113. pWnd = GetDlgItem(ID_WIZLINE);
  114. // hide tab control
  115. GetTabControl()->ShowWindow(SW_HIDE);
  116. }
  117. else // tabbed mode
  118. {
  119. // get tab control's bottom-right corner
  120. pWnd = GetTabControl();
  121. }
  122. // whatever it is, take the right margin
  123. pWnd->GetWindowRect(&objrc);
  124. ScreenToClient(&objrc);
  125. m_szLayoutTabLine.cx = objrc.right - wndrc.right;
  126. m_szLayoutTabLine.cy = objrc.bottom - wndrc.bottom;
  127. // get child dialog's bottom-right corner
  128. pWnd = GetActivePage();
  129. pWnd->GetWindowRect(&objrc);
  130. ScreenToClient(&objrc);
  131. m_szLayoutPage.cx = objrc.right - wndrc.right;
  132. m_szLayoutPage.cy = objrc.bottom - wndrc.bottom;
  133. // store buttons position
  134. for (int i = 0; i < 7; i++)
  135. {
  136. pWnd = GetDlgItem(_propButtons[i]);
  137. if (pWnd == NULL)
  138. {
  139. // invalid position, button does not exist
  140. // (just to initialize, any button you may activate
  141. // in the future is present, but hidden)
  142. m_szLayoutButton[i].cx = 0;
  143. m_szLayoutButton[i].cy = 0;
  144. continue;
  145. }
  146. pWnd->GetWindowRect(&objrc);
  147. ScreenToClient(&objrc);
  148. m_szLayoutButton[i].cx = objrc.left - wndrc.right;
  149. m_szLayoutButton[i].cy = objrc.top - wndrc.bottom;
  150. }
  151. }
  152. void CResizableSheet::ArrangeLayout()
  153. {
  154. // init some vars
  155. CWnd* pWnd;
  156. CRect wndrc, objrc;
  157. GetClientRect(&wndrc);
  158. // usually no more than
  159. // 4 buttons +
  160. // 1 tab control or wizard line +
  161. // 1 active page
  162. HDWP hdwp = BeginDeferWindowPos(6);
  163. if (m_psh.dwFlags & PSH_WIZARD) // wizard mode
  164. {
  165. // get wizard line's bottom-right corner
  166. pWnd = GetDlgItem(ID_WIZLINE);
  167. pWnd->GetWindowRect(&objrc);
  168. ScreenToClient(&objrc);
  169. int oldHeight = objrc.Height();
  170. objrc.right = m_szLayoutTabLine.cx + wndrc.right;
  171. objrc.bottom = m_szLayoutTabLine.cy + wndrc.bottom;
  172. objrc.top = objrc.bottom - oldHeight;
  173. // add the control
  174. DeferWindowPos(hdwp, *pWnd, NULL, objrc.left, objrc.top,
  175. objrc.Width(), objrc.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
  176. }
  177. else // tabbed mode
  178. {
  179. // get tab control's bottom-right corner
  180. pWnd = GetTabControl();
  181. pWnd->GetWindowRect(&objrc);
  182. ScreenToClient(&objrc);
  183. objrc.right = m_szLayoutTabLine.cx + wndrc.right;
  184. objrc.bottom = m_szLayoutTabLine.cy + wndrc.bottom;
  185. // add the control, only resize
  186. DeferWindowPos(hdwp, *pWnd, NULL, 0, 0, objrc.Width(),
  187. objrc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  188. }
  189. // get child dialog's bottom-right corner
  190. pWnd = GetActivePage();
  191. pWnd->GetWindowRect(&objrc);
  192. ScreenToClient(&objrc);
  193. objrc.right = m_szLayoutPage.cx + wndrc.right;
  194. objrc.bottom = m_szLayoutPage.cy + wndrc.bottom;
  195. // add the control, only resize
  196. DeferWindowPos(hdwp, *pWnd, NULL, 0, 0, objrc.Width(),
  197. objrc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  198. // arrange buttons position
  199. for (int i = 0; i < 7; i++)
  200. {
  201. pWnd = GetDlgItem(_propButtons[i]);
  202. if (pWnd == NULL)
  203. continue; // ignores deleted buttons
  204. // this should never happen, because all the buttons you
  205. // may activate already exist at time PresetLayout is called
  206. ASSERT(m_szLayoutButton[i].cx != 0 || m_szLayoutButton[i].cy != 0);
  207. pWnd->GetWindowRect(&objrc);
  208. ScreenToClient(&objrc);
  209. objrc.left = m_szLayoutButton[i].cx + wndrc.right;
  210. objrc.top = m_szLayoutButton[i].cy + wndrc.bottom;
  211. // add the control, only move
  212. DeferWindowPos(hdwp, *pWnd, NULL, objrc.left, objrc.top,
  213. 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  214. }
  215. // update size-grip
  216. InvalidateRect(&m_rcGripRect);
  217. UpdateGripPos();
  218. InvalidateRect(&m_rcGripRect);
  219. // go re-arrange child windows
  220. EndDeferWindowPos(hdwp);
  221. }
  222. void CResizableSheet::OnSize(UINT nType, int cx, int cy) 
  223. {
  224. CWnd::OnSize(nType, cx, cy);
  225. if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
  226. return; // arrangement not needed
  227. if (m_bInitDone)
  228. ArrangeLayout();
  229. }
  230. // only gets called in wizard mode
  231. // (when back or next button pressed)
  232. void CResizableSheet::OnPageChanged()
  233. {
  234. // call default handler to allow page change
  235. Default();
  236. // update new wizard page
  237. ArrangeLayout();
  238. }
  239. void CResizableSheet::OnPaint() 
  240. {
  241. CPaintDC dc(this);
  242. if (m_bShowGrip && !IsZoomed())
  243. {
  244. // draw size-grip
  245. dc.DrawFrameControl(&m_rcGripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
  246. }
  247. }
  248. UINT CResizableSheet::OnNcHitTest(CPoint point) 
  249. {
  250. CPoint pt = point;
  251. ScreenToClient(&pt);
  252. if (m_bShowGrip && m_rcGripRect.PtInRect(pt))
  253. return HTBOTTOMRIGHT;
  254. return CPropertySheet::OnNcHitTest(point);
  255. }
  256. void CResizableSheet::UpdateGripPos()
  257. {
  258. // size-grip goes bottom right in the client area
  259. GetClientRect(&m_rcGripRect);
  260. m_rcGripRect.left = m_rcGripRect.right - m_szGripSize.cx;
  261. m_rcGripRect.top = m_rcGripRect.bottom - m_szGripSize.cy;
  262. }
  263. void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) 
  264. {
  265. if (!m_bInitDone)
  266. return;
  267. if (m_bUseMinTrack)
  268. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  269. if (m_bUseMaxTrack)
  270. lpMMI->ptMaxTrackSize = m_ptMaxTrackSize;
  271. if (m_bUseMaxRect)
  272. {
  273. lpMMI->ptMaxPosition = m_ptMaxPos;
  274. lpMMI->ptMaxSize = m_ptMaxSize;
  275. }
  276. }
  277. // protected members
  278. void CResizableSheet::SetMaximizedRect(const CRect& rc)
  279. {
  280. m_bUseMaxRect = TRUE;
  281. m_ptMaxPos = rc.TopLeft();
  282. CSize sz = rc.Size();
  283. m_ptMaxSize.x = sz.cx;
  284. m_ptMaxSize.y = sz.cy;
  285. }
  286. void CResizableSheet::ResetMaximizedRect()
  287. {
  288. m_bUseMaxRect = FALSE;
  289. }
  290. void CResizableSheet::ShowSizeGrip(BOOL bShow)
  291. {
  292. if (m_bShowGrip != bShow)
  293. {
  294. m_bShowGrip = bShow;
  295. InvalidateRect(&m_rcGripRect);
  296. }
  297. }
  298. void CResizableSheet::SetMinTrackSize(const CSize& size)
  299. {
  300. m_bUseMinTrack = TRUE;
  301. m_ptMinTrackSize.x = size.cx;
  302. m_ptMinTrackSize.y = size.cy;
  303. }
  304. void CResizableSheet::ResetMinTrackSize()
  305. {
  306. m_bUseMinTrack = FALSE;
  307. }
  308. void CResizableSheet::SetMaxTrackSize(const CSize& size)
  309. {
  310. m_bUseMaxTrack = TRUE;
  311. m_ptMaxTrackSize.x = size.cx;
  312. m_ptMaxTrackSize.y = size.cy;
  313. }
  314. void CResizableSheet::ResetMaxTrackSize()
  315. {
  316. m_bUseMaxTrack = FALSE;
  317. }
  318. // NOTE: this must be called after all the other settings
  319. //       to have the dialog and its controls displayed properly
  320. void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, LPCTSTR pszEntry, BOOL bWithPage)
  321. {
  322. m_sSection = pszSection;
  323. m_sEntry = pszEntry;
  324. m_bSavePage = bWithPage;
  325. m_bEnableSaveRestore = TRUE;
  326. LoadWindowRect();
  327. }
  328. // private memebers
  329. // used to save/restore window's size and position
  330. // either in the registry or a private .INI file
  331. // depending on your application settings
  332. #define PROFILE_FMT  _T("%d,%d,%d,%d,%d,%d [%d]")
  333. void CResizableSheet::SaveWindowRect()
  334. {
  335. CString data;
  336. WINDOWPLACEMENT wp;
  337. ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
  338. wp.length = sizeof(WINDOWPLACEMENT);
  339. GetWindowPlacement(&wp);
  340. RECT& rc = wp.rcNormalPosition; // alias
  341. // also saves active page index, zero (the first) if problems
  342. // cannot use GetActivePage, because it always fails
  343. CTabCtrl *pTab = GetTabControl();
  344. int page = 0;
  345. if (pTab != NULL) 
  346. page = pTab->GetCurSel();
  347. if (page < 0)
  348. page = 0;
  349. // always save page
  350. data.Format(PROFILE_FMT, rc.left, rc.top,
  351. rc.right, rc.bottom, wp.showCmd, wp.flags, page);
  352. AfxGetApp()->WriteProfileString(m_sSection, m_sEntry, data);
  353. }
  354. void CResizableSheet::LoadWindowRect()
  355. {
  356. CString data;
  357. WINDOWPLACEMENT wp;
  358. int page;
  359. data = AfxGetApp()->GetProfileString(m_sSection, m_sEntry);
  360. if (data.IsEmpty()) // never saved before
  361. return;
  362. ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
  363. wp.length = sizeof(WINDOWPLACEMENT);
  364. RECT& rc = wp.rcNormalPosition; // alias
  365. if (_stscanf(data, PROFILE_FMT, &rc.left, &rc.top,
  366. &rc.right, &rc.bottom, &wp.showCmd, &wp.flags, &page) == 7)
  367. {
  368. SetWindowPlacement(&wp);
  369. if (m_bSavePage)
  370. {
  371. SetActivePage(page);
  372. ArrangeLayout(); // needs refresh
  373. }
  374. }
  375. }
  376. int CResizableSheet::GetMinWidth()
  377. {
  378. int min = 0;
  379. // search for leftmost button
  380. for (int i = 0; i < 7; i++)
  381. {
  382. // left position is relative to the right border
  383. // of the parent window (negative value)
  384. if (m_szLayoutButton[i].cx < min)
  385. min = m_szLayoutButton[i].cx;
  386. }
  387. // sizing border width
  388. int border = GetSystemMetrics(SM_CXSIZEFRAME);
  389. // get tab control or wizard line left position
  390. CWnd* pWnd;
  391. CRect objrc;
  392. if (m_psh.dwFlags & PSH_WIZARD)
  393. pWnd = GetDlgItem(ID_WIZLINE);
  394. else
  395. pWnd = GetTabControl();
  396. pWnd->GetWindowRect(&objrc);
  397. ScreenToClient(&objrc);
  398. // add the left margin and window's border
  399. return -min + objrc.left + border*2;
  400. }