Fixed issue #1336: Have visible the name of the branch in Repository Browser
[TortoiseGit.git] / ext / ResizableLib / ResizableSheet.cpp
blob9c69cd0432201cb0ebfb993c8a4bf845f939ee1b
1 // ResizableSheet.cpp : implementation file
2 //
3 /////////////////////////////////////////////////////////////////////////////
4 //
5 // This file is part of ResizableLib
6 // http://sourceforge.net/projects/resizablelib
7 //
8 // Copyright (C) 2000-2004 by Paolo Messina
9 // http://www.geocities.com/ppescher - mailto:ppescher@hotmail.com
11 // The contents of this file are subject to the Artistic License (the "License").
12 // You may not use this file except in compliance with the License.
13 // You may obtain a copy of the License at:
14 // http://www.opensource.org/licenses/artistic-license.html
16 // If you find this code useful, credits would be nice!
18 /////////////////////////////////////////////////////////////////////////////
20 #include "stdafx.h"
21 #include "ResizableSheet.h"
23 #ifdef _DEBUG
24 #define new DEBUG_NEW
25 #undef THIS_FILE
26 static char THIS_FILE[] = __FILE__;
27 #endif
29 /////////////////////////////////////////////////////////////////////////////
30 // CResizableSheet
32 IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)
34 inline void CResizableSheet::PrivateConstruct()
36 m_bEnableSaveRestore = FALSE;
37 m_bSavePage = FALSE;
38 m_dwGripTempState = 1;
39 m_bLayoutDone = FALSE;
42 inline BOOL CResizableSheet::IsWizard() const
44 return (m_psh.dwFlags & PSH_WIZARD);
47 CResizableSheet::CResizableSheet()
49 PrivateConstruct();
52 CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)
53 : CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
55 PrivateConstruct();
58 CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)
59 : CPropertySheet(pszCaption, pParentWnd, iSelectPage)
61 PrivateConstruct();
64 CResizableSheet::~CResizableSheet()
68 BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
69 //{{AFX_MSG_MAP(CResizableSheet)
70 ON_WM_GETMINMAXINFO()
71 ON_WM_SIZE()
72 ON_WM_DESTROY()
73 ON_WM_ERASEBKGND()
74 ON_WM_NCCREATE()
75 //}}AFX_MSG_MAP
76 ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)
77 END_MESSAGE_MAP()
79 /////////////////////////////////////////////////////////////////////////////
80 // CResizableSheet message handlers
82 BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
84 if (!CPropertySheet::OnNcCreate(lpCreateStruct))
85 return FALSE;
87 // child dialogs don't want resizable border or size grip,
88 // nor they can handle the min/max size constraints
89 BOOL bChild = lpCreateStruct->style & WS_CHILD;
91 // create and init the size-grip
92 if (!CreateSizeGrip(!bChild))
93 return FALSE;
95 MakeResizable(lpCreateStruct);
97 return TRUE;
100 BOOL CResizableSheet::OnInitDialog()
102 BOOL bResult = CPropertySheet::OnInitDialog();
104 // set the initial size as the min track size
105 CRect rc;
106 GetWindowRect(&rc);
107 SetMinTrackSize(rc.Size());
109 // initialize layout
110 PresetLayout();
111 m_bLayoutDone = TRUE;
113 return bResult;
116 void CResizableSheet::OnDestroy()
118 if (m_bEnableSaveRestore)
120 SaveWindowRect(m_sSection, m_bRectOnly);
121 if (m_bSavePage)
122 SavePage(m_sSection);
125 RemoveAllAnchors();
127 CPropertySheet::OnDestroy();
130 // maps an index to a button ID and vice-versa
131 static UINT _propButtons[] =
133 IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
134 ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
136 const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT);
138 // horizontal line in wizard mode
139 #define ID_WIZLINE ID_WIZFINISH+1
141 void CResizableSheet::PresetLayout()
143 // set the initial size as the min track size
144 CRect rc;
145 GetWindowRect(&rc);
146 SetMinTrackSize(rc.Size());
148 if (GetStyle() & WS_CHILD)
150 GetClientRect(&rc);
151 GetTabControl()->MoveWindow(&rc);
154 if (IsWizard()) // wizard mode
156 // hide tab control
157 GetTabControl()->ShowWindow(SW_HIDE);
159 AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);
161 else // tab mode
163 AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);
166 // add a callback for active page (which can change at run-time)
167 m_nCallbackID = AddAnchorCallback();
169 // use *total* parent size to have correct margins
170 CRect rectPage, rectSheet;
171 GetTotalClientRect(&rectSheet);
173 GetActivePage()->GetWindowRect(&rectPage);
174 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);
176 // pre-calculate margins
177 m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();
178 m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();
180 // add all possible buttons, if they exist
181 for (int i = 0; i < _propButtonsCount; i++)
183 if (NULL != GetDlgItem(_propButtons[i]))
184 AddAnchor(_propButtons[i], BOTTOM_RIGHT);
187 // prevent flickering
188 GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
191 BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const
193 if (layout.nCallbackID != m_nCallbackID) // we only added 1 callback
194 return CResizableLayout::ArrangeLayoutCallback(layout);
196 // set layout info for active page
197 layout.hWnd = (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0);
198 if (!::IsWindow(layout.hWnd))
199 return FALSE;
201 // set margins
202 if (IsWizard()) // wizard mode
204 // use pre-calculated margins
205 layout.marginTopLeft = m_sizePageTL;
206 layout.marginBottomRight = m_sizePageBR;
208 else // tab mode
210 CTabCtrl* pTab = GetTabControl();
211 ASSERT(pTab != NULL);
213 // get tab position after resizing and calc page rect
214 CRect rectPage, rectSheet;
215 GetTotalClientRect(&rectSheet);
217 if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))
218 return FALSE; // no page yet
220 // temporarily resize the tab control to calc page size
221 CRect rectSave;
222 pTab->GetWindowRect(rectSave);
223 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);
224 pTab->SetRedraw(FALSE);
225 pTab->MoveWindow(rectPage, FALSE);
226 pTab->AdjustRect(FALSE, &rectPage);
227 pTab->MoveWindow(rectSave, FALSE);
228 pTab->SetRedraw(TRUE);
230 // set margins
231 layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft();
232 layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight();
235 // set anchor types
236 layout.anchorTopLeft = TOP_LEFT;
237 layout.anchorBottomRight = BOTTOM_RIGHT;
239 // use this layout info
240 return TRUE;
243 void CResizableSheet::OnSize(UINT nType, int cx, int cy)
245 CWnd::OnSize(nType, cx, cy);
247 if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
248 return; // arrangement not needed
250 if (nType == SIZE_MAXIMIZED)
251 HideSizeGrip(&m_dwGripTempState);
252 else
253 ShowSizeGrip(&m_dwGripTempState);
255 // update grip and layout
256 UpdateSizeGrip();
257 ArrangeLayout();
260 BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/)
262 // update new wizard page
263 // active page changes after this notification
264 PostMessage(WM_SIZE);
266 return FALSE; // continue routing
269 BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC)
271 ClipChildren(pDC, FALSE);
273 BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC);
275 ClipChildren(pDC, TRUE);
277 return bRet;
280 BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, CSize sizeChild, CSize &sizeExtra)
282 CTabCtrl* pTab = GetTabControl();
283 if (!pTab)
284 return FALSE;
286 // get margins of tabcontrol
287 CRect rectMargins;
288 if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins))
289 return FALSE;
291 // get margin caused by tabcontrol
292 CRect rectTabMargins(0,0,0,0);
294 // get tab position after resizing and calc page rect
295 CRect rectPage, rectSheet;
296 GetTotalClientRect(&rectSheet);
298 if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))
299 return FALSE; // no page yet
301 // temporarily resize the tab control to calc page size
302 CRect rectSave;
303 pTab->GetWindowRect(rectSave);
304 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);
305 pTab->SetRedraw(FALSE);
306 pTab->MoveWindow(rectPage, FALSE);
307 pTab->AdjustRect(TRUE, &rectTabMargins);
308 pTab->MoveWindow(rectSave, FALSE);
309 pTab->SetRedraw(TRUE);
311 // add non-client size
312 ::AdjustWindowRectEx(&rectTabMargins, GetStyle(), !(GetStyle() & WS_CHILD) &&
313 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
315 // compute extra size
316 sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() +
317 rectTabMargins.Size();
318 return TRUE;
321 void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
323 MinMaxInfo(lpMMI);
325 CTabCtrl* pTab = GetTabControl();
326 if (!pTab)
327 return;
329 int nCount = GetPageCount();
330 for (int idx = 0; idx < nCount; ++idx)
332 if (IsWizard()) // wizard mode
334 // use pre-calculated margins
335 CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR));
336 // add non-client size
337 ::AdjustWindowRectEx(&rectExtra, GetStyle(), !(GetStyle() & WS_CHILD) &&
338 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
339 ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size());
341 else // tab mode
343 ChainMinMaxInfoCB(lpMMI, *GetPage(idx));
348 // protected members
350 int CResizableSheet::GetMinWidth()
352 CWnd* pWnd = NULL;
353 CRect rectWnd, rectSheet;
354 GetTotalClientRect(&rectSheet);
356 int max = 0, min = rectSheet.Width();
357 // search for leftmost and rightmost button margins
358 for (int i = 0; i < 7; i++)
360 pWnd = GetDlgItem(_propButtons[i]);
361 // exclude not present or hidden buttons
362 if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))
363 continue;
365 // left position is relative to the right border
366 // of the parent window (negative value)
367 pWnd->GetWindowRect(&rectWnd);
368 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);
369 int left = rectSheet.right - rectWnd.left;
370 int right = rectSheet.right - rectWnd.right;
372 if (left > max)
373 max = left;
374 if (right < min)
375 min = right;
378 // sizing border width
379 int border = GetSystemMetrics(SM_CXSIZEFRAME);
381 // compute total width
382 return max + min + 2*border;
386 // NOTE: this must be called after all the other settings
387 // to have the window and its controls displayed properly
388 void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)
390 m_sSection = pszSection;
391 m_bSavePage = bWithPage;
393 m_bEnableSaveRestore = TRUE;
394 m_bRectOnly = bRectOnly;
396 // restore immediately
397 LoadWindowRect(pszSection, bRectOnly);
399 LoadPage(pszSection);
400 ArrangeLayout(); // needs refresh
404 void CResizableSheet::RefreshLayout()
406 SendMessage(WM_SIZE);
409 LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
411 if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone)
412 return CPropertySheet::WindowProc(message, wParam, lParam);
414 // specifying valid rects needs controls already anchored
415 LRESULT lResult = 0;
416 HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult);
417 lResult = CPropertySheet::WindowProc(message, wParam, lParam);
418 HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult);
419 return lResult;