1 // ResizableSheet.cpp : implementation file
3 /////////////////////////////////////////////////////////////////////////////
5 // This file is part of ResizableLib
6 // http://sourceforge.net/projects/resizablelib
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 /////////////////////////////////////////////////////////////////////////////
21 #include "ResizableSheet.h"
26 static char THIS_FILE
[] = __FILE__
;
29 /////////////////////////////////////////////////////////////////////////////
32 IMPLEMENT_DYNAMIC(CResizableSheet
, CPropertySheet
)
34 inline void CResizableSheet::PrivateConstruct()
36 m_bEnableSaveRestore
= 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()
52 CResizableSheet::CResizableSheet(UINT nIDCaption
, CWnd
*pParentWnd
, UINT iSelectPage
)
53 : CPropertySheet(nIDCaption
, pParentWnd
, iSelectPage
)
58 CResizableSheet::CResizableSheet(LPCTSTR pszCaption
, CWnd
*pParentWnd
, UINT iSelectPage
)
59 : CPropertySheet(pszCaption
, pParentWnd
, iSelectPage
)
64 CResizableSheet::~CResizableSheet()
68 BEGIN_MESSAGE_MAP(CResizableSheet
, CPropertySheet
)
69 //{{AFX_MSG_MAP(CResizableSheet)
76 ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE
, OnPageChanging
)
79 /////////////////////////////////////////////////////////////////////////////
80 // CResizableSheet message handlers
82 BOOL
CResizableSheet::OnNcCreate(LPCREATESTRUCT lpCreateStruct
)
84 if (!CPropertySheet::OnNcCreate(lpCreateStruct
))
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
))
95 MakeResizable(lpCreateStruct
);
100 BOOL
CResizableSheet::OnInitDialog()
102 BOOL bResult
= CPropertySheet::OnInitDialog();
104 // set the initial size as the min track size
107 SetMinTrackSize(rc
.Size());
111 m_bLayoutDone
= TRUE
;
116 void CResizableSheet::OnDestroy()
118 if (m_bEnableSaveRestore
)
120 SaveWindowRect(m_sSection
, m_bRectOnly
);
122 SavePage(m_sSection
);
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
146 SetMinTrackSize(rc
.Size());
148 if (GetStyle() & WS_CHILD
)
151 GetTabControl()->MoveWindow(&rc
);
154 if (IsWizard()) // wizard mode
157 GetTabControl()->ShowWindow(SW_HIDE
);
159 AddAnchor(ID_WIZLINE
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
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
))
202 if (IsWizard()) // wizard mode
204 // use pre-calculated margins
205 layout
.marginTopLeft
= m_sizePageTL
;
206 layout
.marginBottomRight
= m_sizePageBR
;
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
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
);
231 layout
.marginTopLeft
= rectPage
.TopLeft() - rectSheet
.TopLeft();
232 layout
.marginBottomRight
= rectPage
.BottomRight() - rectSheet
.BottomRight();
236 layout
.anchorTopLeft
= TOP_LEFT
;
237 layout
.anchorBottomRight
= BOTTOM_RIGHT
;
239 // use this layout info
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
);
253 ShowSizeGrip(&m_dwGripTempState
);
255 // update grip and layout
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
);
280 BOOL
CResizableSheet::CalcSizeExtra(HWND
/*hWndChild*/, CSize sizeChild
, CSize
&sizeExtra
)
282 CTabCtrl
* pTab
= GetTabControl();
286 // get margins of tabcontrol
288 if (!GetAnchorMargins(pTab
->m_hWnd
, sizeChild
, rectMargins
))
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
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();
321 void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR
* lpMMI
)
325 CTabCtrl
* pTab
= GetTabControl();
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());
343 ChainMinMaxInfoCB(lpMMI
, *GetPage(idx
));
350 int CResizableSheet::GetMinWidth()
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
))
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
;
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
416 HandleNcCalcSize(FALSE
, (LPNCCALCSIZE_PARAMS
)lParam
, lResult
);
417 lResult
= CPropertySheet::WindowProc(message
, wParam
, lParam
);
418 HandleNcCalcSize(TRUE
, (LPNCCALCSIZE_PARAMS
)lParam
, lResult
);