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

Tab控件

开发平台:

Visual C++

  1. // ResizableDialog.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 "ResizableDialog.h"
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CResizableDialog
  23. inline void CResizableDialog::Construct()
  24. {
  25. m_bInitDone = FALSE;
  26. m_bUseMinTrack = TRUE;
  27. m_bUseMaxTrack = FALSE;
  28. m_bUseMaxRect = FALSE;
  29. m_bShowGrip = TRUE;
  30. m_bEnableSaveRestore = FALSE;
  31. m_szGripSize.cx = GetSystemMetrics(SM_CXVSCROLL);
  32. m_szGripSize.cy = GetSystemMetrics(SM_CYHSCROLL);
  33. }
  34. CResizableDialog::CResizableDialog()
  35. {
  36. Construct();
  37. }
  38. CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd)
  39. : CDialog(nIDTemplate, pParentWnd)
  40. {
  41. Construct();
  42. }
  43. CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
  44. : CDialog(lpszTemplateName, pParentWnd)
  45. {
  46. Construct();
  47. }
  48. CResizableDialog::~CResizableDialog()
  49. {
  50. // free memory used by the layout
  51. Layout *pl;
  52. POSITION pos = m_plLayoutList.GetHeadPosition();
  53. while (pos != NULL)
  54. {
  55. pl = (Layout*)m_plLayoutList.GetNext(pos);
  56. delete pl;
  57. }
  58. }
  59. BEGIN_MESSAGE_MAP(CResizableDialog, CDialog)
  60. //{{AFX_MSG_MAP(CResizableDialog)
  61. ON_WM_NCHITTEST()
  62. ON_WM_GETMINMAXINFO()
  63. ON_WM_SIZE()
  64. ON_WM_DESTROY()
  65. ON_WM_PAINT()
  66. //}}AFX_MSG_MAP
  67. END_MESSAGE_MAP()
  68. /////////////////////////////////////////////////////////////////////////////
  69. // CResizableDialog message handlers
  70. BOOL CResizableDialog::OnInitDialog() 
  71. {
  72. CDialog::OnInitDialog();
  73. UpdateGripPos();
  74. // gets the template size as the min track size
  75. CRect rc;
  76. GetWindowRect(&rc);
  77. m_ptMinTrackSize.x = rc.Width();
  78. m_ptMinTrackSize.y = rc.Height();
  79. m_bInitDone = TRUE;
  80. return TRUE;  // return TRUE unless you set the focus to a control
  81.               // EXCEPTION: OCX Property Pages should return FALSE
  82. }
  83. void CResizableDialog::OnDestroy() 
  84. {
  85. CDialog::OnDestroy();
  86. if (m_bEnableSaveRestore)
  87. SaveWindowRect();
  88. }
  89. void CResizableDialog::OnPaint() 
  90. {
  91. CPaintDC dc(this); // device context for painting
  92. if (m_bShowGrip && !IsZoomed())
  93. {
  94. // draw size-grip
  95. dc.DrawFrameControl(&m_rcGripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
  96. }
  97. }
  98. void CResizableDialog::OnSize(UINT nType, int cx, int cy) 
  99. {
  100. CWnd::OnSize(nType, cx, cy);
  101. if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
  102. return; // arrangement not needed
  103. if (m_bInitDone)
  104. ArrangeLayout();
  105. }
  106. UINT CResizableDialog::OnNcHitTest(CPoint point) 
  107. {
  108. CPoint pt = point;
  109. ScreenToClient(&pt);
  110. // if in size grip and in client area
  111. if (m_bShowGrip && m_rcGripRect.PtInRect(pt) &&
  112. pt.x >= 0 && pt.y >= 0)
  113. return HTBOTTOMRIGHT;
  114. return CDialog::OnNcHitTest(point);
  115. }
  116. void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) 
  117. {
  118. if (!m_bInitDone)
  119. return;
  120. if (m_bUseMinTrack)
  121. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  122. if (m_bUseMaxTrack)
  123. lpMMI->ptMaxTrackSize = m_ptMaxTrackSize;
  124. if (m_bUseMaxRect)
  125. {
  126. lpMMI->ptMaxPosition = m_ptMaxPos;
  127. lpMMI->ptMaxSize = m_ptMaxSize;
  128. }
  129. }
  130. // layout functions
  131. void CResizableDialog::AddAnchor(HWND wnd, CSize tl_type, CSize br_type)
  132. {
  133. ASSERT(wnd != NULL && ::IsWindow(wnd));
  134. ASSERT(::IsChild(*this, wnd));
  135. ASSERT(tl_type != NOANCHOR);
  136. // get control's window class
  137. CString st;
  138. GetClassName(wnd, st.GetBufferSetLength(MAX_PATH), MAX_PATH);
  139. st.ReleaseBuffer();
  140. st.MakeUpper();
  141. // add the style 'clipsiblings' to a GroupBox
  142. // to avoid unnecessary repainting of controls inside
  143. if (st == "BUTTON")
  144. {
  145. DWORD style = GetWindowLong(wnd, GWL_STYLE);
  146. if (style & BS_GROUPBOX)
  147. SetWindowLong(wnd, GWL_STYLE, style | WS_CLIPSIBLINGS);
  148. }
  149. // wnd classes that don't redraw client area correctly
  150. // when the hor scroll pos changes due to a resizing
  151. BOOL hscroll = FALSE;
  152. if (st == "LISTBOX")
  153. hscroll = TRUE;
  154. // wnd classes that need refresh when resized
  155. BOOL refresh = FALSE;
  156. if (st == "STATIC")
  157. {
  158. DWORD style = GetWindowLong(wnd, GWL_STYLE);
  159. switch (style & SS_TYPEMASK)
  160. {
  161. case SS_LEFT:
  162. case SS_CENTER:
  163. case SS_RIGHT:
  164. // word-wrapped text needs refresh
  165. refresh = TRUE;
  166. }
  167. // centered images or text need refresh
  168. if (style & SS_CENTERIMAGE)
  169. refresh = TRUE;
  170. // simple text never needs refresh
  171. if (style & SS_TYPEMASK == SS_SIMPLE)
  172. refresh = FALSE;
  173. }
  174. // get dialog's and control's rect
  175. CRect wndrc, objrc;
  176. GetClientRect(&wndrc);
  177. ::GetWindowRect(wnd, &objrc);
  178. ScreenToClient(&objrc);
  179. CSize tl_margin, br_margin;
  180. if (br_type == NOANCHOR)
  181. br_type = tl_type;
  182. // calculate margin for the top-left corner
  183. tl_margin.cx = objrc.left - wndrc.Width() * tl_type.cx / 100;
  184. tl_margin.cy = objrc.top - wndrc.Height() * tl_type.cy / 100;
  185. // calculate margin for the bottom-right corner
  186. br_margin.cx = objrc.right - wndrc.Width() * br_type.cx / 100;
  187. br_margin.cy = objrc.bottom - wndrc.Height() * br_type.cy / 100;
  188. // add to the list
  189. m_plLayoutList.AddTail(new Layout(wnd, tl_type, tl_margin,
  190. br_type, br_margin, hscroll, refresh));
  191. }
  192. void CResizableDialog::ArrangeLayout()
  193. {
  194. // init some vars
  195. CRect wndrc;
  196. GetClientRect(&wndrc);
  197. Layout *pl;
  198. POSITION pos = m_plLayoutList.GetHeadPosition();
  199. HDWP hdwp = BeginDeferWindowPos(m_plLayoutList.GetCount());
  200. while (pos != NULL)
  201. {
  202. pl = (Layout*)m_plLayoutList.GetNext(pos);
  203. CRect objrc, newrc;
  204. CWnd* wnd = CWnd::FromHandle(pl->hwnd); // temporary solution
  205. wnd->GetWindowRect(&objrc);
  206. ScreenToClient(&objrc);
  207. // calculate new top-left corner
  208. newrc.left = pl->tl_margin.cx + wndrc.Width() * pl->tl_type.cx / 100;
  209. newrc.top = pl->tl_margin.cy + wndrc.Height() * pl->tl_type.cy / 100;
  210. // calculate new bottom-right corner
  211. newrc.right = pl->br_margin.cx + wndrc.Width() * pl->br_type.cx / 100;
  212. newrc.bottom = pl->br_margin.cy + wndrc.Height() * pl->br_type.cy / 100;
  213. if (!newrc.EqualRect(&objrc))
  214. {
  215. BOOL add = TRUE;
  216. if (pl->adj_hscroll)
  217. {
  218. // needs repainting, due to horiz scrolling
  219. int diff = newrc.Width() - objrc.Width();
  220. int max = wnd->GetScrollLimit(SB_HORZ);
  221. if (max > 0 && wnd->GetScrollPos(SB_HORZ) > max - diff)
  222. {
  223. wnd->MoveWindow(&newrc);
  224. wnd->Invalidate();
  225. wnd->UpdateWindow();
  226. add = FALSE;
  227. }
  228. }
  229. if (pl->need_refresh)
  230. {
  231. wnd->MoveWindow(&newrc);
  232. wnd->Invalidate();
  233. wnd->UpdateWindow();
  234. add = FALSE;
  235. }
  236. if (add)
  237. DeferWindowPos(hdwp, pl->hwnd, NULL, newrc.left, newrc.top,
  238. newrc.Width(), newrc.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
  239. }
  240. }
  241. // update size-grip
  242. InvalidateRect(&m_rcGripRect);
  243. UpdateGripPos();
  244. InvalidateRect(&m_rcGripRect);
  245. // go re-arrange child windows
  246. EndDeferWindowPos(hdwp);
  247. }
  248. void CResizableDialog::UpdateGripPos()
  249. {
  250. // size-grip goes bottom right in the client area
  251. GetClientRect(&m_rcGripRect);
  252. m_rcGripRect.left = m_rcGripRect.right - m_szGripSize.cx;
  253. m_rcGripRect.top = m_rcGripRect.bottom - m_szGripSize.cy;
  254. }
  255. // protected members
  256. void CResizableDialog::ShowSizeGrip(BOOL bShow)
  257. {
  258. if (m_bShowGrip != bShow)
  259. {
  260. m_bShowGrip = bShow;
  261. InvalidateRect(&m_rcGripRect);
  262. }
  263. }
  264. void CResizableDialog::SetMaximizedRect(const CRect& rc)
  265. {
  266. m_bUseMaxRect = TRUE;
  267. m_ptMaxPos = rc.TopLeft();
  268. m_ptMaxSize.x = rc.Width();
  269. m_ptMaxSize.y = rc.Height();
  270. }
  271. void CResizableDialog::ResetMaximizedRect()
  272. {
  273. m_bUseMaxRect = FALSE;
  274. }
  275. void CResizableDialog::SetMinTrackSize(const CSize& size)
  276. {
  277. m_bUseMinTrack = TRUE;
  278. m_ptMinTrackSize.x = size.cx;
  279. m_ptMinTrackSize.y = size.cy;
  280. }
  281. void CResizableDialog::ResetMinTrackSize()
  282. {
  283. m_bUseMinTrack = FALSE;
  284. }
  285. void CResizableDialog::SetMaxTrackSize(const CSize& size)
  286. {
  287. m_bUseMaxTrack = TRUE;
  288. m_ptMaxTrackSize.x = size.cx;
  289. m_ptMaxTrackSize.y = size.cy;
  290. }
  291. void CResizableDialog::ResetMaxTrackSize()
  292. {
  293. m_bUseMaxTrack = FALSE;
  294. }
  295. // NOTE: this must be called after all the other settings
  296. //       to have the dialog and its controls displayed properly
  297. void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, LPCTSTR pszEntry)
  298. {
  299. m_sSection = pszSection;
  300. m_sEntry = pszEntry;
  301. m_bEnableSaveRestore = TRUE;
  302. LoadWindowRect();
  303. }
  304. // used to save/restore window's size and position
  305. // either in the registry or a private .INI file
  306. // depending on your application settings
  307. #define PROFILE_FMT  _T("%d,%d,%d,%d,%d,%d")
  308. void CResizableDialog::SaveWindowRect()
  309. {
  310. CString data;
  311. WINDOWPLACEMENT wp;
  312. ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
  313. wp.length = sizeof(WINDOWPLACEMENT);
  314. GetWindowPlacement(&wp);
  315. RECT& rc = wp.rcNormalPosition; // alias
  316. data.Format(PROFILE_FMT, rc.left, rc.top,
  317. rc.right, rc.bottom, wp.showCmd, wp.flags);
  318. AfxGetApp()->WriteProfileString(m_sSection, m_sEntry, data);
  319. }
  320. void CResizableDialog::LoadWindowRect()
  321. {
  322. CString data;
  323. WINDOWPLACEMENT wp;
  324. data = AfxGetApp()->GetProfileString(m_sSection, m_sEntry);
  325. if (data.IsEmpty()) // never saved before
  326. return;
  327. ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
  328. wp.length = sizeof(WINDOWPLACEMENT);
  329. GetWindowPlacement(&wp);
  330. RECT& rc = wp.rcNormalPosition; // alias
  331. if (_stscanf(data, PROFILE_FMT, &rc.left, &rc.top,
  332. &rc.right, &rc.bottom, &wp.showCmd, &wp.flags) == 6)
  333. {
  334. SetWindowPlacement(&wp);
  335. }
  336. }