DialogResize.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /****************************************************************/
  2. /* */
  3. /* DialogResize.cpp */
  4. /* */
  5. /* Implementation of the CDialogResize class. */
  6. /* Provides support for resizing dialog controls. */
  7. /* */
  8. /* Based on the WTL class CDialogResize from Microsoft */
  9. /* Modified for use with MFC by LYFZ van der Meer */
  10. /* */
  11. /* Copyright LYFZ Software Solutions 2002 */
  12. /* http://www.LYFZvandermeer.nl */
  13. /* */
  14. /* Last updated: 10 july 2002 */
  15. /* */
  16. /****************************************************************/
  17. #include "stdafx.h"
  18. #include "DialogResize.h"
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. CDialogResize::CDialogResize()
  25. {
  26. CommonConstruct();
  27. }
  28. CDialogResize::CDialogResize(UINT uResource, CWnd* pParent)
  29. : CDialog(uResource, pParent)
  30. {
  31. CommonConstruct();
  32. }
  33. CDialogResize::CDialogResize(LPCTSTR pszResource, CWnd* pParent)
  34. : CDialog(pszResource, pParent)
  35. {
  36. CommonConstruct();
  37. }
  38. void CDialogResize::CommonConstruct()
  39. {
  40. //{{AFX_DATA_INIT(CDialogResize)
  41. // NOTE: the ClassWizard will add member initialization here
  42. //}}AFX_DATA_INIT
  43. m_bGripper = FALSE;
  44. m_sizeDialog.cx = 0;
  45. m_sizeDialog.cy = 0;
  46. m_ptMinTrackSize.x = -1;
  47. m_ptMinTrackSize.y = -1;
  48. }
  49. void CDialogResize::DoDataExchange(CDataExchange* pDX)
  50. {
  51. CDialog::DoDataExchange(pDX);
  52. //{{AFX_DATA_MAP(CDialogResize)
  53. // NOTE: the ClassWizard will add DDX and DDV calls here
  54. //}}AFX_DATA_MAP
  55. }
  56. BEGIN_MESSAGE_MAP(CDialogResize, CDialog)
  57. //{{AFX_MSG_MAP(CDialogResize)
  58. ON_WM_SIZE()
  59. ON_WM_GETMINMAXINFO()
  60. //}}AFX_MSG_MAP
  61. END_MESSAGE_MAP()
  62. BEGIN_DLGRESIZE_MAP(CDialogResize)
  63. END_DLGRESIZE_MAP()
  64. // Operations
  65. void CDialogResize::InitResizing(BOOL bAddGripper, BOOL bUseMinTrackSize, DWORD dwForceStyle)
  66. {
  67. // Force specified styles (default WS_THICKFRAME | WS_CLIPCHILDREN to enable resizing border and reduce flicker)
  68. if((GetStyle() & dwForceStyle) != dwForceStyle)
  69. ModifyStyle(0, dwForceStyle);
  70. // Cleanup in case of multiple initialization
  71. // block: first check for the gripper control, destroy it if needed
  72. {
  73. CWnd *wndGripper = GetDlgItem(AFX_IDW_STATUS_BAR);
  74. if (wndGripper != NULL)
  75. {
  76. }
  77. }
  78. // clear out everything else
  79. m_arrData.RemoveAll();
  80. m_sizeDialog.cx = 0;
  81. m_sizeDialog.cy = 0;
  82. m_ptMinTrackSize.x = -1;
  83. m_ptMinTrackSize.y = -1;
  84. // Get initial dialog client size
  85. RECT rectDlg;
  86. GetClientRect(&rectDlg);
  87. m_sizeDialog.cx = rectDlg.right;
  88. m_sizeDialog.cy = rectDlg.bottom;
  89. // Create gripper if requested
  90. m_bGripper = false;
  91. if(bAddGripper)
  92. {
  93. // shouldn't exist already
  94. ASSERT(!::IsWindow(::GetDlgItem(m_hWnd, AFX_IDW_STATUS_BAR)));
  95. if(!::IsWindow(::GetDlgItem(m_hWnd, AFX_IDW_STATUS_BAR)))
  96. {
  97. m_wndGripper.Create(_T("SCROLLBAR"), "", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, rectDlg, this, AFX_IDW_STATUS_BAR);
  98. if(IsWindow(m_wndGripper.m_hWnd))
  99. {
  100. m_bGripper = true;
  101. RECT rectCtl;
  102. m_wndGripper.GetWindowRect(&rectCtl);
  103. ScreenToClient(&rectCtl);
  104. AfxResizeData data = {AFX_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  105. m_arrData.Add(data);
  106. }
  107. }
  108. }
  109. // Get min track position if requested
  110. if(bUseMinTrackSize)
  111. {
  112. RECT rect;
  113. GetWindowRect(&rect);
  114. m_ptMinTrackSize.x = rect.right - rect.left;
  115. m_ptMinTrackSize.y = rect.bottom - rect.top;
  116. }
  117. // Walk the map and initialize data
  118. const AfxResizeMap* pMap = GetDlgResizeMap();
  119. ASSERT(pMap != NULL);
  120. int nGroupStart = -1;
  121. for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++)
  122. {
  123. if(pMap->m_nCtlID == -1)
  124. {
  125. switch(pMap->m_dwResizeFlags)
  126. {
  127. case _DLSZ_BEGIN_GROUP:
  128. ASSERT(nGroupStart == -1);
  129. nGroupStart = m_arrData.GetSize();
  130. break;
  131. case _DLSZ_END_GROUP:
  132. {
  133. ASSERT(nGroupStart != -1);
  134. int nGroupCount = m_arrData.GetSize() - nGroupStart;
  135. m_arrData[nGroupStart].SetGroupCount(nGroupCount);
  136. nGroupStart = -1;
  137. }
  138. break;
  139. default:
  140. ASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry"));
  141. break;
  142. }
  143. }
  144. else
  145. {
  146. // this ID conflicts with the default gripper one
  147. ASSERT(m_bGripper ? (pMap->m_nCtlID != AFX_IDW_STATUS_BAR) : TRUE);
  148. CWnd *ctl = GetDlgItem(pMap->m_nCtlID);
  149. if (ctl)
  150. {
  151. RECT rectCtl;
  152. ctl->GetWindowRect(&rectCtl);
  153. ScreenToClient(&rectCtl);
  154. DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0;
  155. AfxResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  156. m_arrData.Add(data);
  157. }
  158. }
  159. }
  160. ASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map"));
  161. }
  162. void CDialogResize::UpdateLayout(int cxWidth, int cyHeight)
  163. {
  164. ASSERT(::IsWindow(m_hWnd));
  165. // SetRedraw(FALSE);
  166. RECT rectGroup = { 0, 0, 0, 0 };
  167. for(int i = 0; i < m_arrData.GetSize(); i++)
  168. {
  169. if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group
  170. {
  171. int nGroupCount = m_arrData[i].GetGroupCount();
  172. ASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize());
  173. rectGroup = m_arrData[i].m_rect;
  174. int j;
  175. for(j = 1; j < nGroupCount; j++)
  176. {
  177. rectGroup.left = min(rectGroup.left, m_arrData[i + j].m_rect.left);
  178. rectGroup.top = min(rectGroup.top, m_arrData[i + j].m_rect.top);
  179. rectGroup.right = max(rectGroup.right, m_arrData[i + j].m_rect.right);
  180. rectGroup.bottom = max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);
  181. }
  182. RECT rcThis;
  183. RECT rcNext;
  184. for(j = 0; j < nGroupCount; j++)
  185. {
  186. int xyStartNext = -1;
  187. 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))
  188. {
  189. CWnd *ctlThis = GetDlgItem(m_arrData[i + j].m_nCtlID);
  190. ctlThis->GetWindowRect(&rcThis);
  191. ScreenToClient(&rcThis);
  192. CWnd *ctlNext = GetDlgItem(m_arrData[i + j + 1].m_nCtlID);
  193. ctlNext->GetWindowRect(&rcNext);
  194. ScreenToClient(&rcNext);
  195. 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)
  196. {
  197. if(rcNext.left >= rcThis.right)
  198. xyStartNext = m_arrData[i + j + 1].m_rect.left;
  199. }
  200. else
  201. 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)
  202. {
  203. if(rcNext.top >= rcThis.bottom)
  204. xyStartNext = m_arrData[i + j + 1].m_rect.top;
  205. }
  206. }
  207. PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, xyStartNext);
  208. }
  209. // increment to skip all group controls
  210. i += nGroupCount - 1;
  211. }
  212. else // one control entry
  213. {
  214. PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);
  215. }
  216. }
  217. // SetRedraw(TRUE);
  218. Invalidate();
  219. RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
  220. }
  221. void CDialogResize::OnSize(UINT nType, int cx, int cy)
  222. {
  223. CDialog::OnSize(nType, cx, cy);
  224. if(m_bGripper)
  225. {
  226. if(nType == SIZE_MAXIMIZED)
  227. m_wndGripper.ShowWindow(SW_HIDE);
  228. else
  229. if(nType == SIZE_RESTORED)
  230. m_wndGripper.ShowWindow(SW_SHOW);
  231. }
  232. if(nType != SIZE_MINIMIZED)
  233. {
  234. ASSERT(::IsWindow(m_hWnd));
  235. UpdateLayout(cx, cy);
  236. }
  237. }
  238. void CDialogResize::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
  239. {
  240. if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
  241. {
  242. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  243. }
  244. CDialog::OnGetMinMaxInfo(lpMMI);
  245. }
  246. // Implementation
  247. BOOL CDialogResize::PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, AfxResizeData& data, bool bGroup, int xyStartNext)
  248. {
  249. ASSERT(::IsWindow(m_hWnd));
  250. CWnd *ctl;
  251. CRect rectCtl;
  252. ctl = GetDlgItem(data.m_nCtlID);
  253. ctl->GetWindowRect(rectCtl);
  254. ScreenToClient(rectCtl);
  255. if(bGroup)
  256. {
  257. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  258. {
  259. rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  260. if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)
  261. {
  262. if(xyStartNext != -1)
  263. 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);
  264. else
  265. rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  266. }
  267. else
  268. {
  269. rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);
  270. }
  271. }
  272. if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  273. {
  274. rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  275. if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)
  276. {
  277. if(xyStartNext != -1)
  278. 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);
  279. else
  280. rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  281. }
  282. else
  283. {
  284. rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);
  285. }
  286. }
  287. }
  288. else
  289. {
  290. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  291. {
  292. rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);
  293. if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)
  294. rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);
  295. }
  296. if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  297. {
  298. rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);
  299. if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)
  300. rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);
  301. }
  302. }
  303. if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)
  304. ctl->Invalidate();
  305. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT)) != 0)
  306. ctl->SetWindowPos(NULL, rectCtl.left, rectCtl.top, rectCtl.right - rectCtl.left, rectCtl.bottom - rectCtl.top, SWP_NOZORDER | SWP_NOACTIVATE);
  307. return TRUE;
  308. }