OSDN Git Service

Show Column at Log List
[tortoisegit/TortoiseGitJp.git] / ext / ResizableLib / ResizableSheetEx.cpp
1 // ResizableSheetEx.cpp : implementation file\r
2 //\r
3 /////////////////////////////////////////////////////////////////////////////\r
4 //\r
5 // This file is part of ResizableLib\r
6 // http://sourceforge.net/projects/resizablelib\r
7 //\r
8 // Copyright (C) 2000-2004 by Paolo Messina\r
9 // http://www.geocities.com/ppescher - mailto:ppescher@hotmail.com\r
10 //\r
11 // The contents of this file are subject to the Artistic License (the "License").\r
12 // You may not use this file except in compliance with the License. \r
13 // You may obtain a copy of the License at:\r
14 // http://www.opensource.org/licenses/artistic-license.html\r
15 //\r
16 // If you find this code useful, credits would be nice!\r
17 //\r
18 /////////////////////////////////////////////////////////////////////////////\r
19 \r
20 #include "stdafx.h"\r
21 #include "ResizableSheetEx.h"\r
22 \r
23 #ifdef _DEBUG\r
24 #define new DEBUG_NEW\r
25 #undef THIS_FILE\r
26 static char THIS_FILE[] = __FILE__;\r
27 #endif\r
28 \r
29 /////////////////////////////////////////////////////////////////////////////\r
30 // CResizableSheetEx\r
31 \r
32 IMPLEMENT_DYNAMIC(CResizableSheetEx, CPropertySheetEx)\r
33 \r
34 inline void CResizableSheetEx::PrivateConstruct()\r
35 {\r
36         m_bEnableSaveRestore = FALSE;\r
37         m_bSavePage = FALSE;\r
38         m_dwGripTempState = 1;\r
39         m_bLayoutDone = FALSE;\r
40 }\r
41 \r
42 inline BOOL CResizableSheetEx::IsWizard() const\r
43 {\r
44         return (m_psh.dwFlags & PSH_WIZARD);\r
45 }\r
46 \r
47 inline BOOL CResizableSheetEx::IsWizard97() const\r
48 {\r
49         return (m_psh.dwFlags & (PSH_IE4WIZARD97 | PSH_IE5WIZARD97));\r
50 }\r
51 \r
52 CResizableSheetEx::CResizableSheetEx()\r
53 {\r
54         PrivateConstruct();\r
55 }\r
56 \r
57 CResizableSheetEx::CResizableSheetEx(UINT nIDCaption, CWnd* pParentWnd,\r
58         UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,\r
59         HBITMAP hbmHeader)\r
60 : CPropertySheetEx(nIDCaption, pParentWnd, iSelectPage,\r
61                                   hbmWatermark, hpalWatermark, hbmHeader)\r
62 {\r
63         PrivateConstruct();\r
64 }\r
65 \r
66 CResizableSheetEx::CResizableSheetEx(LPCTSTR pszCaption, CWnd* pParentWnd,\r
67         UINT iSelectPage, HBITMAP hbmWatermark, HPALETTE hpalWatermark,\r
68         HBITMAP hbmHeader)\r
69 : CPropertySheetEx(pszCaption, pParentWnd, iSelectPage,\r
70                                           hbmWatermark, hpalWatermark, hbmHeader)\r
71 {\r
72         PrivateConstruct();\r
73 }\r
74 \r
75 \r
76 CResizableSheetEx::~CResizableSheetEx()\r
77 {\r
78 }\r
79 \r
80 BEGIN_MESSAGE_MAP(CResizableSheetEx, CPropertySheetEx)\r
81         //{{AFX_MSG_MAP(CResizableSheetEx)\r
82         ON_WM_GETMINMAXINFO()\r
83         ON_WM_SIZE()\r
84         ON_WM_DESTROY()\r
85         ON_WM_ERASEBKGND()\r
86         ON_WM_NCCREATE()\r
87         //}}AFX_MSG_MAP\r
88         ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)\r
89         ON_REGISTERED_MESSAGE(WMU_RESIZESUPPORT, OnResizeSupport)\r
90 END_MESSAGE_MAP()\r
91 \r
92 /////////////////////////////////////////////////////////////////////////////\r
93 // CResizableSheetEx message handlers\r
94 \r
95 BOOL CResizableSheetEx::OnNcCreate(LPCREATESTRUCT lpCreateStruct) \r
96 {\r
97         if (!CPropertySheetEx::OnNcCreate(lpCreateStruct))\r
98                 return FALSE;\r
99 \r
100         // child dialogs don't want resizable border or size grip,\r
101         // nor they can handle the min/max size constraints\r
102         BOOL bChild = lpCreateStruct->style & WS_CHILD;\r
103 \r
104         // create and init the size-grip\r
105         if (!CreateSizeGrip(!bChild))\r
106                 return FALSE;\r
107 \r
108         MakeResizable(lpCreateStruct);\r
109         \r
110         return TRUE;\r
111 }\r
112 \r
113 BOOL CResizableSheetEx::OnInitDialog() \r
114 {\r
115         BOOL bResult = CPropertySheetEx::OnInitDialog();\r
116         \r
117         // set the initial size as the min track size\r
118         CRect rc;\r
119         GetWindowRect(&rc);\r
120         SetMinTrackSize(rc.Size());\r
121 \r
122         // initialize layout\r
123         PresetLayout();\r
124         m_bLayoutDone = TRUE;\r
125 \r
126         return bResult;\r
127 }\r
128 \r
129 LRESULT CResizableSheetEx::OnResizeSupport(WPARAM wParam, LPARAM lParam)\r
130 {\r
131         switch (wParam)\r
132         {\r
133         case RSZSUP_SHEETPAGEEXHACK:\r
134                 {\r
135                         // a window object must be still associated to the page handle\r
136                         // but MFC subclassing has been turned off to allow the system\r
137                         // to subclass it first, so we can catch all the messages\r
138                         CWnd* pWnd = CWnd::FromHandlePermanent((HWND)lParam);\r
139                         if (pWnd == NULL)\r
140                                 return 0;\r
141 \r
142                         // suclass the window again and refresh page and sheet\r
143                         pWnd->SubclassWindow(pWnd->Detach());\r
144                         RefreshLayout();\r
145                         pWnd->SendMessage(WM_SIZE);\r
146                         Invalidate();\r
147                         UnlockWindowUpdate();\r
148 \r
149                         if (pWnd->IsWindowVisible())\r
150                         {\r
151                                 // send lost PSN_SETACTIVE notification message\r
152                                 CPropertyPage* pPage = DYNAMIC_DOWNCAST(CPropertyPage, pWnd);\r
153                                 if (pPage != NULL)\r
154                                         SetActivePage(pPage);\r
155                         }\r
156                 }\r
157                 break;\r
158 \r
159         default:\r
160                 return FALSE;\r
161         }\r
162         return TRUE;\r
163 }\r
164 \r
165 void CResizableSheetEx::OnDestroy() \r
166 {\r
167         if (m_bEnableSaveRestore)\r
168         {\r
169                 SaveWindowRect(m_sSection, m_bRectOnly);\r
170                 if (m_bSavePage)\r
171                         SavePage(m_sSection);\r
172         }\r
173 \r
174         RemoveAllAnchors();\r
175 \r
176         CPropertySheetEx::OnDestroy();\r
177 }\r
178 \r
179 // maps an index to a button ID and vice-versa\r
180 static UINT _propButtons[] =\r
181 {\r
182         IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,\r
183         ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH\r
184 };\r
185 const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT);\r
186 \r
187 // horizontal line in wizard mode\r
188 #define ID_WIZLINE              ID_WIZFINISH+1\r
189 #define ID_WIZLINEHDR   ID_WIZFINISH+2\r
190 \r
191 void CResizableSheetEx::PresetLayout()\r
192 {\r
193         if (IsWizard() || IsWizard97()) // wizard mode\r
194         {\r
195                 // hide tab control\r
196                 GetTabControl()->ShowWindow(SW_HIDE);\r
197 \r
198                 AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);\r
199 \r
200                 if (IsWizard97())       // add header line for wizard97 dialogs\r
201                         AddAnchor(ID_WIZLINEHDR, TOP_LEFT, TOP_RIGHT);\r
202         }\r
203         else    // tab mode\r
204         {\r
205                 AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);\r
206         }\r
207 \r
208         // add a callback for active page (which can change at run-time)\r
209         m_nCallbackID = AddAnchorCallback();\r
210 \r
211         // use *total* parent size to have correct margins\r
212         CRect rectPage, rectSheet;\r
213         GetTotalClientRect(&rectSheet);\r
214 \r
215         GetActivePage()->GetWindowRect(&rectPage);\r
216         ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);\r
217 \r
218         // pre-calculate margins\r
219         m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();\r
220         m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();\r
221 \r
222         // add all possible buttons, if they exist\r
223         for (int i = 0; i < _propButtonsCount; i++)\r
224         {\r
225                 if (NULL != GetDlgItem(_propButtons[i]))\r
226                         AddAnchor(_propButtons[i], BOTTOM_RIGHT);\r
227         }\r
228 }\r
229 \r
230 BOOL CResizableSheetEx::ArrangeLayoutCallback(LAYOUTINFO &layout) const\r
231 {\r
232         if (layout.nCallbackID != m_nCallbackID)        // we only added 1 callback\r
233                 return CResizableLayout::ArrangeLayoutCallback(layout);\r
234 \r
235         // set layout info for active page\r
236         layout.hWnd = (HWND)::SendMessage(GetSafeHwnd(), PSM_GETCURRENTPAGEHWND, 0, 0);\r
237         if (!::IsWindow(layout.hWnd))\r
238                 return FALSE;\r
239 \r
240         // set margins\r
241         if (IsWizard()) // wizard mode\r
242         {\r
243                 // use pre-calculated margins\r
244                 layout.marginTopLeft = m_sizePageTL;\r
245                 layout.marginBottomRight = m_sizePageBR;\r
246         }\r
247         else if (IsWizard97())  // wizard 97\r
248         {\r
249                 // use pre-calculated margins\r
250                 layout.marginTopLeft = m_sizePageTL;\r
251                 layout.marginBottomRight = m_sizePageBR;\r
252 \r
253                 if (!(GetActivePage()->m_psp.dwFlags & PSP_HIDEHEADER))\r
254                 {\r
255                         // add header vertical offset\r
256                         CRect rectLine, rectSheet;\r
257                         GetTotalClientRect(&rectSheet);\r
258                         GetAnchorPosition(ID_WIZLINEHDR, rectSheet, rectLine);\r
259 \r
260                         layout.marginTopLeft.cy = rectLine.bottom;\r
261                 }\r
262         }\r
263         else    // tab mode\r
264         {\r
265                 CTabCtrl* pTab = GetTabControl();\r
266                 ASSERT(pTab != NULL);\r
267 \r
268                 // get tab position after resizing and calc page rect\r
269                 CRect rectPage, rectSheet;\r
270                 GetTotalClientRect(&rectSheet);\r
271 \r
272                 if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))\r
273                         return FALSE; // no page yet\r
274 \r
275                 // temporarily resize the tab control to calc page size\r
276                 CRect rectSave;\r
277                 pTab->GetWindowRect(rectSave);\r
278                 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);\r
279                 pTab->SetRedraw(FALSE);\r
280                 pTab->MoveWindow(rectPage, FALSE);\r
281                 pTab->AdjustRect(FALSE, &rectPage);\r
282                 pTab->MoveWindow(rectSave, FALSE);\r
283                 pTab->SetRedraw(TRUE);\r
284 \r
285                 // set margins\r
286                 layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft();\r
287                 layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight();\r
288         }\r
289 \r
290         // set anchor types\r
291         layout.anchorTopLeft = TOP_LEFT;\r
292         layout.anchorBottomRight = BOTTOM_RIGHT;\r
293 \r
294         // use this layout info\r
295         return TRUE;\r
296 }\r
297 \r
298 void CResizableSheetEx::OnSize(UINT nType, int cx, int cy) \r
299 {\r
300         CWnd::OnSize(nType, cx, cy);\r
301         \r
302         if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)\r
303                 return;         // arrangement not needed\r
304 \r
305         if (nType == SIZE_MAXIMIZED)\r
306                 HideSizeGrip(&m_dwGripTempState);\r
307         else\r
308                 ShowSizeGrip(&m_dwGripTempState);\r
309 \r
310         // update grip and layout\r
311         UpdateSizeGrip();\r
312         ArrangeLayout();\r
313 \r
314         if (IsWizard97())\r
315         {\r
316                 // refresh header area\r
317                 CRect rect;\r
318                 GetHeaderRect(rect);\r
319                 InvalidateRect(rect, FALSE);\r
320         }\r
321 }\r
322 \r
323 BOOL CResizableSheetEx::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/)\r
324 {\r
325         // update new wizard page\r
326         // active page changes after this notification\r
327         PostMessage(WM_SIZE);\r
328 \r
329         return FALSE;   // continue routing\r
330 }\r
331 \r
332 BOOL CResizableSheetEx::OnEraseBkgnd(CDC* pDC) \r
333 {\r
334         if (ClipChildren(pDC, FALSE))\r
335         {\r
336                 // when clipping, remove header from clipping area\r
337                 if (IsWizard97())\r
338                 {\r
339                         // clip header area out\r
340                         CRect rect;\r
341                         GetHeaderRect(rect);\r
342                         pDC->ExcludeClipRect(rect);\r
343                 }\r
344         }\r
345 \r
346         BOOL bRet = CPropertySheetEx::OnEraseBkgnd(pDC);\r
347 \r
348         ClipChildren(pDC, TRUE);\r
349 \r
350         return bRet;\r
351 }\r
352 \r
353 BOOL CResizableSheetEx::CalcSizeExtra(HWND /*hWndChild*/, CSize sizeChild, CSize &sizeExtra)\r
354 {\r
355         CTabCtrl* pTab = GetTabControl();\r
356         if (!pTab)\r
357                 return FALSE;\r
358 \r
359         // get margins of tabcontrol\r
360         CRect rectMargins;\r
361         if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins))\r
362                 return FALSE;\r
363 \r
364         // get margin caused by tabcontrol\r
365         CRect rectTabMargins(0,0,0,0);\r
366 \r
367         // get tab position after resizing and calc page rect\r
368         CRect rectPage, rectSheet;\r
369         GetTotalClientRect(&rectSheet);\r
370 \r
371         if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))\r
372                 return FALSE; // no page yet\r
373 \r
374         // temporarily resize the tab control to calc page size\r
375         CRect rectSave;\r
376         pTab->GetWindowRect(rectSave);\r
377         ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);\r
378         pTab->SetRedraw(FALSE);\r
379         pTab->MoveWindow(rectPage, FALSE);\r
380         pTab->AdjustRect(TRUE, &rectTabMargins);\r
381         pTab->MoveWindow(rectSave, FALSE);\r
382         pTab->SetRedraw(TRUE);\r
383 \r
384         // add non-client size\r
385         ::AdjustWindowRectEx(&rectTabMargins, GetStyle(), !(GetStyle() & WS_CHILD) &&\r
386                 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());\r
387 \r
388         // compute extra size\r
389         sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() +\r
390                 rectTabMargins.Size();\r
391         return TRUE;\r
392 }\r
393 \r
394 void CResizableSheetEx::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) \r
395 {\r
396         MinMaxInfo(lpMMI);\r
397 \r
398         CTabCtrl* pTab = GetTabControl();\r
399         if (!pTab)\r
400                 return;\r
401 \r
402         int nCount = GetPageCount();\r
403         for (int idx = 0; idx < nCount; ++idx)\r
404         {\r
405                 if (IsWizard()) // wizard mode\r
406                 {\r
407                         // use pre-calculated margins\r
408                         CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR));\r
409                         // add non-client size\r
410                         ::AdjustWindowRectEx(&rectExtra, GetStyle(), !(GetStyle() & WS_CHILD) &&\r
411                                 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());\r
412                         ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size());\r
413                 }\r
414                 else if (IsWizard97())  // wizard 97\r
415                 {\r
416                         // use pre-calculated margins\r
417                         CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR));\r
418 \r
419                         if (!(GetPage(idx)->m_psp.dwFlags & PSP_HIDEHEADER))\r
420                         {\r
421                                 // add header vertical offset\r
422                                 CRect rectLine, rectSheet;\r
423                                 GetTotalClientRect(&rectSheet);\r
424                                 GetAnchorPosition(ID_WIZLINEHDR, rectSheet, rectLine);\r
425 \r
426                                 rectExtra.top = -rectLine.bottom;\r
427                         }\r
428                         // add non-client size\r
429                         ::AdjustWindowRectEx(&rectExtra, GetStyle(), !(GetStyle() & WS_CHILD) &&\r
430                                 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());\r
431                         ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size());\r
432                 }\r
433                 else    // tab mode\r
434                 {\r
435                         ChainMinMaxInfoCB(lpMMI, *GetPage(idx));\r
436                 }\r
437         }\r
438 }\r
439 \r
440 // protected members\r
441 \r
442 void CResizableSheetEx::GetHeaderRect(LPRECT lpRect)\r
443 {\r
444         CWnd* pWizLineHdr = GetDlgItem(ID_WIZLINEHDR);\r
445         if (pWizLineHdr != NULL && pWizLineHdr->IsWindowVisible())\r
446         {\r
447                 pWizLineHdr->GetWindowRect(lpRect);\r
448                 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)lpRect, 2);\r
449                 LONG bottom = lpRect->top;\r
450                 GetClientRect(lpRect);\r
451                 lpRect->bottom = bottom;\r
452         }\r
453         else\r
454                 ::SetRectEmpty(lpRect);\r
455 }\r
456 \r
457 int CResizableSheetEx::GetMinWidth()\r
458 {\r
459         CWnd* pWnd = NULL;\r
460         CRect rectWnd, rectSheet;\r
461         GetTotalClientRect(&rectSheet);\r
462 \r
463         int max = 0, min = rectSheet.Width();\r
464         // search for leftmost and rightmost button margins\r
465         for (int i = 0; i < 7; i++)\r
466         {\r
467                 pWnd = GetDlgItem(_propButtons[i]);\r
468                 // exclude not present or hidden buttons\r
469                 if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))\r
470                         continue;\r
471 \r
472                 // left position is relative to the right border\r
473                 // of the parent window (negative value)\r
474                 pWnd->GetWindowRect(&rectWnd);\r
475                 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);\r
476                 int left = rectSheet.right - rectWnd.left;\r
477                 int right = rectSheet.right - rectWnd.right;\r
478                 \r
479                 if (left > max)\r
480                         max = left;\r
481                 if (right < min)\r
482                         min = right;\r
483         }\r
484 \r
485         // sizing border width\r
486         int border = GetSystemMetrics(SM_CXSIZEFRAME);\r
487         \r
488         // compute total width\r
489         return max + min + 2*border;\r
490 }\r
491 \r
492 // NOTE: this must be called after all the other settings\r
493 //       to have the window and its controls displayed properly\r
494 void CResizableSheetEx::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)\r
495 {\r
496         m_sSection = pszSection;\r
497         m_bSavePage = bWithPage;\r
498 \r
499         m_bEnableSaveRestore = TRUE;\r
500         m_bRectOnly = bRectOnly;\r
501 \r
502         // restore immediately\r
503         LoadWindowRect(pszSection, bRectOnly);\r
504         if (bWithPage)\r
505         {\r
506                 LoadPage(pszSection);\r
507                 ArrangeLayout();        // needs refresh\r
508         }\r
509 }\r
510 \r
511 void CResizableSheetEx::RefreshLayout()\r
512 {\r
513         SendMessage(WM_SIZE);\r
514 }\r
515 \r
516 LRESULT CResizableSheetEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) \r
517 {\r
518         if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone)\r
519                 return CPropertySheetEx::WindowProc(message, wParam, lParam);\r
520 \r
521         // specifying valid rects needs controls already anchored\r
522         LRESULT lResult = 0;\r
523         HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult);\r
524         lResult = CPropertySheetEx::WindowProc(message, wParam, lParam);\r
525         HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult);\r
526         return lResult;\r
527 }\r