Fix missing reset of index
[TortoiseGit.git] / ext / ResizableLib / ResizableSheet.cpp
blob4c2d28550c6eddd29e982646792f8f845df87c19
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;
40 m_bRectOnly = FALSE;
41 m_nCallbackID = 0;
44 inline BOOL CResizableSheet::IsWizard() const
46 return (m_psh.dwFlags & PSH_WIZARD);
49 CResizableSheet::CResizableSheet()
51 PrivateConstruct();
54 CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)
55 : CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
57 PrivateConstruct();
60 CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)
61 : CPropertySheet(pszCaption, pParentWnd, iSelectPage)
63 PrivateConstruct();
66 CResizableSheet::~CResizableSheet()
70 BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
71 //{{AFX_MSG_MAP(CResizableSheet)
72 ON_WM_GETMINMAXINFO()
73 ON_WM_SIZE()
74 ON_WM_DESTROY()
75 ON_WM_ERASEBKGND()
76 ON_WM_NCCREATE()
77 //}}AFX_MSG_MAP
78 ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)
79 END_MESSAGE_MAP()
81 /////////////////////////////////////////////////////////////////////////////
82 // CResizableSheet message handlers
84 BOOL CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
86 if (!CPropertySheet::OnNcCreate(lpCreateStruct))
87 return FALSE;
89 // child dialogs don't want resizable border or size grip,
90 // nor they can handle the min/max size constraints
91 BOOL bChild = lpCreateStruct->style & WS_CHILD;
93 // create and init the size-grip
94 if (!CreateSizeGrip(!bChild))
95 return FALSE;
97 MakeResizable(lpCreateStruct);
99 return TRUE;
102 BOOL CResizableSheet::OnInitDialog()
104 BOOL bResult = CPropertySheet::OnInitDialog();
106 // set the initial size as the min track size
107 CRect rc;
108 GetWindowRect(&rc);
109 SetMinTrackSize(rc.Size());
111 // initialize layout
112 PresetLayout();
113 m_bLayoutDone = TRUE;
115 return bResult;
118 void CResizableSheet::OnDestroy()
120 if (m_bEnableSaveRestore)
122 SaveWindowRect(m_sSection, m_bRectOnly);
123 if (m_bSavePage)
124 SavePage(m_sSection);
127 RemoveAllAnchors();
129 CPropertySheet::OnDestroy();
132 // maps an index to a button ID and vice-versa
133 static UINT _propButtons[] =
135 IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
136 ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
138 const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT);
140 // horizontal line in wizard mode
141 #define ID_WIZLINE ID_WIZFINISH+1
143 void CResizableSheet::PresetLayout()
145 // set the initial size as the min track size
146 CRect rc;
147 GetWindowRect(&rc);
148 SetMinTrackSize(rc.Size());
150 if (GetStyle() & WS_CHILD)
152 GetClientRect(&rc);
153 GetTabControl()->MoveWindow(&rc);
156 if (IsWizard()) // wizard mode
158 // hide tab control
159 GetTabControl()->ShowWindow(SW_HIDE);
161 AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);
163 else // tab mode
165 AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);
168 // add a callback for active page (which can change at run-time)
169 m_nCallbackID = AddAnchorCallback();
171 // use *total* parent size to have correct margins
172 CRect rectPage, rectSheet;
173 GetTotalClientRect(&rectSheet);
175 GetActivePage()->GetWindowRect(&rectPage);
176 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);
178 // pre-calculate margins
179 m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();
180 m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();
182 // add all possible buttons, if they exist
183 for (int i = 0; i < _propButtonsCount; i++)
185 if (NULL != GetDlgItem(_propButtons[i]))
186 AddAnchor(_propButtons[i], BOTTOM_RIGHT);
189 // prevent flickering
190 GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
193 BOOL CResizableSheet::ArrangeLayoutCallback(LAYOUTINFO &layout) const
195 if (layout.nCallbackID != m_nCallbackID) // we only added 1 callback
196 return CResizableLayout::ArrangeLayoutCallback(layout);
198 // set layout info for active page
199 layout.hWnd = (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0);
200 if (!::IsWindow(layout.hWnd))
201 return FALSE;
203 // set margins
204 if (IsWizard()) // wizard mode
206 // use pre-calculated margins
207 layout.marginTopLeft = m_sizePageTL;
208 layout.marginBottomRight = m_sizePageBR;
210 else // tab mode
212 CTabCtrl* pTab = GetTabControl();
213 ASSERT(pTab != NULL);
215 // get tab position after resizing and calc page rect
216 CRect rectPage, rectSheet;
217 GetTotalClientRect(&rectSheet);
219 if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))
220 return FALSE; // no page yet
222 // temporarily resize the tab control to calc page size
223 CRect rectSave;
224 pTab->GetWindowRect(rectSave);
225 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);
226 pTab->SetRedraw(FALSE);
227 pTab->MoveWindow(rectPage, FALSE);
228 pTab->AdjustRect(FALSE, &rectPage);
229 pTab->MoveWindow(rectSave, FALSE);
230 pTab->SetRedraw(TRUE);
232 // set margins
233 layout.marginTopLeft = rectPage.TopLeft() - rectSheet.TopLeft();
234 layout.marginBottomRight = rectPage.BottomRight() - rectSheet.BottomRight();
237 // set anchor types
238 layout.anchorTopLeft = TOP_LEFT;
239 layout.anchorBottomRight = BOTTOM_RIGHT;
241 // use this layout info
242 return TRUE;
245 void CResizableSheet::OnSize(UINT nType, int cx, int cy)
247 CWnd::OnSize(nType, cx, cy);
249 if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
250 return; // arrangement not needed
252 if (nType == SIZE_MAXIMIZED)
253 HideSizeGrip(&m_dwGripTempState);
254 else
255 ShowSizeGrip(&m_dwGripTempState);
257 // update grip and layout
258 UpdateSizeGrip();
259 ArrangeLayout();
262 BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/)
264 // update new wizard page
265 // active page changes after this notification
266 PostMessage(WM_SIZE);
268 return FALSE; // continue routing
271 BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC)
273 ClipChildren(pDC, FALSE);
275 BOOL bRet = CPropertySheet::OnEraseBkgnd(pDC);
277 ClipChildren(pDC, TRUE);
279 return bRet;
282 BOOL CResizableSheet::CalcSizeExtra(HWND /*hWndChild*/, CSize sizeChild, CSize &sizeExtra)
284 CTabCtrl* pTab = GetTabControl();
285 if (!pTab)
286 return FALSE;
288 // get margins of tabcontrol
289 CRect rectMargins;
290 if (!GetAnchorMargins(pTab->m_hWnd, sizeChild, rectMargins))
291 return FALSE;
293 // get margin caused by tabcontrol
294 CRect rectTabMargins(0,0,0,0);
296 // get tab position after resizing and calc page rect
297 CRect rectPage, rectSheet;
298 GetTotalClientRect(&rectSheet);
300 if (!GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage))
301 return FALSE; // no page yet
303 // temporarily resize the tab control to calc page size
304 CRect rectSave;
305 pTab->GetWindowRect(rectSave);
306 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectSave, 2);
307 pTab->SetRedraw(FALSE);
308 pTab->MoveWindow(rectPage, FALSE);
309 pTab->AdjustRect(TRUE, &rectTabMargins);
310 pTab->MoveWindow(rectSave, FALSE);
311 pTab->SetRedraw(TRUE);
313 // add non-client size
314 ::AdjustWindowRectEx(&rectTabMargins, GetStyle(), !(GetStyle() & WS_CHILD) &&
315 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
317 // compute extra size
318 sizeExtra = rectMargins.TopLeft() + rectMargins.BottomRight() +
319 rectTabMargins.Size();
320 return TRUE;
323 void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
325 MinMaxInfo(lpMMI);
327 CTabCtrl* pTab = GetTabControl();
328 if (!pTab)
329 return;
331 int nCount = GetPageCount();
332 for (int idx = 0; idx < nCount; ++idx)
334 if (IsWizard()) // wizard mode
336 // use pre-calculated margins
337 CRect rectExtra(-CPoint(m_sizePageTL), -CPoint(m_sizePageBR));
338 // add non-client size
339 ::AdjustWindowRectEx(&rectExtra, GetStyle(), !(GetStyle() & WS_CHILD) &&
340 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
341 ChainMinMaxInfo(lpMMI, *GetPage(idx), rectExtra.Size());
343 else // tab mode
345 ChainMinMaxInfoCB(lpMMI, *GetPage(idx));
350 // protected members
352 int CResizableSheet::GetMinWidth()
354 CWnd* pWnd = NULL;
355 CRect rectWnd, rectSheet;
356 GetTotalClientRect(&rectSheet);
358 int max = 0, min = rectSheet.Width();
359 // search for leftmost and rightmost button margins
360 for (int i = 0; i < 7; i++)
362 pWnd = GetDlgItem(_propButtons[i]);
363 // exclude not present or hidden buttons
364 if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))
365 continue;
367 // left position is relative to the right border
368 // of the parent window (negative value)
369 pWnd->GetWindowRect(&rectWnd);
370 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);
371 int left = rectSheet.right - rectWnd.left;
372 int right = rectSheet.right - rectWnd.right;
374 if (left > max)
375 max = left;
376 if (right < min)
377 min = right;
380 // sizing border width
381 int border = GetSystemMetrics(SM_CXSIZEFRAME);
383 // compute total width
384 return max + min + 2*border;
388 // NOTE: this must be called after all the other settings
389 // to have the window and its controls displayed properly
390 void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage, BOOL bHorzResize, BOOL bVertResize)
392 m_sSection = pszSection;
393 m_bSavePage = bWithPage;
395 m_bEnableSaveRestore = TRUE;
396 m_bRectOnly = bRectOnly;
398 // restore immediately
399 LoadWindowRect(pszSection, bRectOnly, bHorzResize, bVertResize);
401 LoadPage(pszSection);
402 ArrangeLayout(); // needs refresh
406 void CResizableSheet::RefreshLayout()
408 SendMessage(WM_SIZE);
411 LRESULT CResizableSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
413 if (message != WM_NCCALCSIZE || wParam == 0 || !m_bLayoutDone)
414 return CPropertySheet::WindowProc(message, wParam, lParam);
416 // specifying valid rects needs controls already anchored
417 LRESULT lResult = 0;
418 HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult);
419 lResult = CPropertySheet::WindowProc(message, wParam, lParam);
420 HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult);
421 return lResult;