OSDN Git Service

Add Show Whole Project Button at commitDialog
[tortoisegit/TortoiseGitJp.git] / ext / ResizableLib / ResizableSheet.cpp
1 // ResizableSheet.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 "ResizableSheet.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 // CResizableSheet\r
31 \r
32 IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)\r
33 \r
34 inline void CResizableSheet::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 CResizableSheet::IsWizard() const\r
43 {\r
44         return (m_psh.dwFlags & PSH_WIZARD);\r
45 }\r
46 \r
47 CResizableSheet::CResizableSheet()\r
48 {\r
49         PrivateConstruct();\r
50 }\r
51 \r
52 CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)\r
53          : CPropertySheet(nIDCaption, pParentWnd, iSelectPage)\r
54 {\r
55         PrivateConstruct();\r
56 }\r
57 \r
58 CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)\r
59          : CPropertySheet(pszCaption, pParentWnd, iSelectPage)\r
60 {\r
61         PrivateConstruct();\r
62 }\r
63 \r
64 CResizableSheet::~CResizableSheet()\r
65 {\r
66 }\r
67 \r
68 BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)\r
69         //{{AFX_MSG_MAP(CResizableSheet)\r
70         ON_WM_GETMINMAXINFO()\r
71         ON_WM_SIZE()\r
72         ON_WM_DESTROY()\r
73         ON_WM_ERASEBKGND()\r
74         ON_WM_NCCREATE()\r
75         //}}AFX_MSG_MAP\r
76         ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)\r
77 END_MESSAGE_MAP()\r
78 \r
79 /////////////////////////////////////////////////////////////////////////////\r
80 // CResizableSheet message handlers\r
81 \r
82 BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct) \r
83 {\r
84         if (!CPropertySheet::OnNcCreate(lpCreateStruct))\r
85                 return FALSE;\r
86 \r
87         // child dialogs don't want resizable border or size grip,\r
88         // nor they can handle the min/max size constraints\r
89         BOOL bChild = lpCreateStruct->style & WS_CHILD;\r
90 \r
91         // create and init the size-grip\r
92         if (!CreateSizeGrip(!bChild))\r
93                 return FALSE;\r
94 \r
95         MakeResizable(lpCreateStruct);\r
96         \r
97         return TRUE;\r
98 }\r
99 \r
100 BOOL CResizableSheet::OnInitDialog() \r
101 {\r
102         BOOL bResult = CPropertySheet::OnInitDialog();\r
103 \r
104         // set the initial size as the min track size\r
105         CRect rc;\r
106         GetWindowRect(&rc);\r
107         SetMinTrackSize(rc.Size());\r
108 \r
109         // initialize layout\r
110         PresetLayout();\r
111         m_bLayoutDone = TRUE;\r
112 \r
113         return bResult;\r
114 }\r
115 \r
116 void CResizableSheet::OnDestroy() \r
117 {\r
118         if (m_bEnableSaveRestore)\r
119         {\r
120                 SaveWindowRect(m_sSection, m_bRectOnly);\r
121                 if (m_bSavePage)\r
122                         SavePage(m_sSection);\r
123         }\r
124 \r
125         RemoveAllAnchors();\r
126 \r
127         CPropertySheet::OnDestroy();\r
128 }\r
129 \r
130 // maps an index to a button ID and vice-versa\r
131 static UINT _propButtons[] =\r
132 {\r
133         IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,\r
134         ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH\r
135 };\r
136 const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT);\r
137 \r
138 // horizontal line in wizard mode\r
139 #define ID_WIZLINE      ID_WIZFINISH+1\r
140 \r
141 void CResizableSheet::PresetLayout()\r
142 {\r
143         // set the initial size as the min track size\r
144         CRect rc;\r
145         GetWindowRect(&rc);\r
146         SetMinTrackSize(rc.Size());\r
147 \r
148         if (GetStyle() & WS_CHILD)\r
149         {\r
150                 GetClientRect(&rc);\r
151                 GetTabControl()->MoveWindow(&rc);\r
152         }\r
153 \r
154         if (IsWizard()) // wizard mode\r
155         {\r
156                 // hide tab control\r
157                 GetTabControl()->ShowWindow(SW_HIDE);\r
158 \r
159                 AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);\r
160         }\r
161         else    // tab mode\r
162         {\r
163                 AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);\r
164         }\r
165 \r
166         // add a callback for active page (which can change at run-time)\r
167         m_nCallbackID = AddAnchorCallback();\r
168 \r
169         // use *total* parent size to have correct margins\r
170         CRect rectPage, rectSheet;\r
171         GetTotalClientRect(&rectSheet);\r
172 \r
173         GetActivePage()->GetWindowRect(&rectPage);\r
174         ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);\r
175 \r
176         // pre-calculate margins\r
177         m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();\r
178         m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();\r
179 \r
180         // add all possible buttons, if they exist\r
181         for (int i = 0; i < _propButtonsCount; i++)\r
182         {\r
183                 if (NULL != GetDlgItem(_propButtons[i]))\r
184                         AddAnchor(_propButtons[i], BOTTOM_RIGHT);\r
185         }\r
186 \r
187         // prevent flickering\r
188         GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);\r
189 }\r
190 \r
191 BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const\r
192 {\r
193         if (layout.nCallbackID != m_nCallbackID)        // we only added 1 callback\r
194                 return CResizableLayout::ArrangeLayoutCallback(layout);\r
195 \r
196         // set layout info for active page\r
197         layout.hWnd = (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0);\r
198         if (!::IsWindow(layout.hWnd))\r
199                 return FALSE;\r
200 \r
201         // set margins\r
202         if (IsWizard()) // wizard mode\r
203         {\r
204                 // use pre-calculated margins\r
205                 layout.marginTopLeft = m_sizePageTL;\r
206                 layout.marginBottomRight = m_sizePageBR;\r
207         }\r
208         else    // tab mode\r
209         {\r
210                 CTabCtrl* pTab = GetTabControl();\r
211                 ASSERT(pTab != NULL);\r
212 \r
213                 // get tab position after resizing and calc page rect\r
214                 CRect rectPage, rectSheet;\r
215                 GetTotalClientRect(&rectSheet);\r
216 \r
217                 if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))\r
218                         return FALSE; // no page yet\r
219 \r
220                 // temporarily resize the tab control to calc page size\r
221                 CRect rectSave;\r
222                 pTab->GetWindowRect(rectSave);\r
223                 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);\r
224                 pTab->SetRedraw(FALSE);\r
225                 pTab->MoveWindow(rectPage, FALSE);\r
226                 pTab->AdjustRect(FALSE, &rectPage);\r
227                 pTab->MoveWindow(rectSave, FALSE);\r
228                 pTab->SetRedraw(TRUE);\r
229 \r
230                 // set margins\r
231                 layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft();\r
232                 layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight();\r
233         }\r
234 \r
235         // set anchor types\r
236         layout.anchorTopLeft = TOP_LEFT;\r
237         layout.anchorBottomRight = BOTTOM_RIGHT;\r
238 \r
239         // use this layout info\r
240         return TRUE;\r
241 }\r
242 \r
243 void CResizableSheet::OnSize(UINT nType, int cx, int cy) \r
244 {\r
245         CWnd::OnSize(nType, cx, cy);\r
246         \r
247         if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)\r
248                 return;         // arrangement not needed\r
249 \r
250         if (nType == SIZE_MAXIMIZED)\r
251                 HideSizeGrip(&m_dwGripTempState);\r
252         else\r
253                 ShowSizeGrip(&m_dwGripTempState);\r
254 \r
255         // update grip and layout\r
256         UpdateSizeGrip();\r
257         ArrangeLayout();\r
258 }\r
259 \r
260 BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/)\r
261 {\r
262         // update new wizard page\r
263         // active page changes after this notification\r
264         PostMessage(WM_SIZE);\r
265 \r
266         return FALSE;   // continue routing\r
267 }\r
268 \r
269 BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC) \r
270 {\r
271         ClipChildren(pDC, FALSE);\r
272 \r
273         BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC);\r
274 \r
275         ClipChildren(pDC, TRUE);\r
276 \r
277         return bRet;\r
278 }\r
279 \r
280 BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, CSize sizeChild, CSize &sizeExtra)\r
281 {\r
282         CTabCtrl* pTab = GetTabControl();\r
283         if (!pTab)\r
284                 return FALSE;\r
285 \r
286         // get margins of tabcontrol\r
287         CRect rectMargins;\r
288         if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins))\r
289                 return FALSE;\r
290 \r
291         // get margin caused by tabcontrol\r
292         CRect rectTabMargins(0,0,0,0);\r
293 \r
294         // get tab position after resizing and calc page rect\r
295         CRect rectPage, rectSheet;\r
296         GetTotalClientRect(&rectSheet);\r
297 \r
298         if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))\r
299                 return FALSE; // no page yet\r
300 \r
301         // temporarily resize the tab control to calc page size\r
302         CRect rectSave;\r
303         pTab->GetWindowRect(rectSave);\r
304         ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);\r
305         pTab->SetRedraw(FALSE);\r
306         pTab->MoveWindow(rectPage, FALSE);\r
307         pTab->AdjustRect(TRUE, &rectTabMargins);\r
308         pTab->MoveWindow(rectSave, FALSE);\r
309         pTab->SetRedraw(TRUE);\r
310 \r
311         // add non-client size\r
312         ::AdjustWindowRectEx(&rectTabMargins, GetStyle(), !(GetStyle() & WS_CHILD) &&\r
313                 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());\r
314 \r
315         // compute extra size\r
316         sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() +\r
317                 rectTabMargins.Size();\r
318         return TRUE;\r
319 }\r
320 \r
321 void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) \r
322 {\r
323         MinMaxInfo(lpMMI);\r
324 \r
325         CTabCtrl* pTab = GetTabControl();\r
326         if (!pTab)\r
327                 return;\r
328 \r
329         int nCount = GetPageCount();\r
330         for (int idx = 0; idx < nCount; ++idx)\r
331         {\r
332                 if (IsWizard()) // wizard mode\r
333                 {\r
334                         // use pre-calculated margins\r
335                         CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR));\r
336                         // add non-client size\r
337                         ::AdjustWindowRectEx(&rectExtra, GetStyle(), !(GetStyle() & WS_CHILD) &&\r
338                                 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());\r
339                         ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size());\r
340                 }\r
341                 else    // tab mode\r
342                 {\r
343                         ChainMinMaxInfoCB(lpMMI, *GetPage(idx));\r
344                 }\r
345         }\r
346 }\r
347 \r
348 // protected members\r
349 \r
350 int CResizableSheet::GetMinWidth()\r
351 {\r
352         CWnd* pWnd = NULL;\r
353         CRect rectWnd, rectSheet;\r
354         GetTotalClientRect(&rectSheet);\r
355 \r
356         int max = 0, min = rectSheet.Width();\r
357         // search for leftmost and rightmost button margins\r
358         for (int i = 0; i < 7; i++)\r
359         {\r
360                 pWnd = GetDlgItem(_propButtons[i]);\r
361                 // exclude not present or hidden buttons\r
362                 if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))\r
363                         continue;\r
364 \r
365                 // left position is relative to the right border\r
366                 // of the parent window (negative value)\r
367                 pWnd->GetWindowRect(&rectWnd);\r
368                 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);\r
369                 int left = rectSheet.right - rectWnd.left;\r
370                 int right = rectSheet.right - rectWnd.right;\r
371 \r
372                 if (left > max)\r
373                         max = left;\r
374                 if (right < min)\r
375                         min = right;\r
376         }\r
377 \r
378         // sizing border width\r
379         int border = GetSystemMetrics(SM_CXSIZEFRAME);\r
380         \r
381         // compute total width\r
382         return max + min + 2*border;\r
383 }\r
384 \r
385 \r
386 // NOTE: this must be called after all the other settings\r
387 //       to have the window and its controls displayed properly\r
388 void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)\r
389 {\r
390         m_sSection = pszSection;\r
391         m_bSavePage = bWithPage;\r
392 \r
393         m_bEnableSaveRestore = TRUE;\r
394         m_bRectOnly = bRectOnly;\r
395 \r
396         // restore immediately\r
397         LoadWindowRect(pszSection, bRectOnly);\r
398         {\r
399                 LoadPage(pszSection);\r
400                 ArrangeLayout();        // needs refresh\r
401         }\r
402 }\r
403 \r
404 void CResizableSheet::RefreshLayout()\r
405 {\r
406         SendMessage(WM_SIZE);\r
407 }\r
408 \r
409 LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) \r
410 {\r
411         if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone)\r
412                 return CPropertySheet::WindowProc(message, wParam, lParam);\r
413 \r
414         // specifying valid rects needs controls already anchored\r
415         LRESULT lResult = 0;\r
416         HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult);\r
417         lResult = CPropertySheet::WindowProc(message, wParam, lParam);\r
418         HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult);\r
419         return lResult;\r
420 }\r