1 // ResizableSheet.cpp : implementation file
3 /////////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2000-2002 by Paolo Messina
6 // (http://www.geocities.com/ppescher - ppescher@yahoo.com)
8 // The contents of this file are subject to the Artistic License (the "License").
9 // You may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at:
11 // http://www.opensource.org/licenses/artistic-license.html
13 // If you find this code useful, credits would be nice!
15 /////////////////////////////////////////////////////////////////////////////
18 #include "ResizableSheet.h"
23 static char THIS_FILE
[] = __FILE__
;
26 /////////////////////////////////////////////////////////////////////////////
29 IMPLEMENT_DYNAMIC(CResizableSheet
, CPropertySheet
)
31 inline void CResizableSheet::PrivateConstruct()
33 m_bEnableSaveRestore
= FALSE
;
35 m_dwGripTempState
= 1;
39 CResizableSheet::CResizableSheet()
44 CResizableSheet::CResizableSheet(UINT nIDCaption
, CWnd
*pParentWnd
, UINT iSelectPage
)
45 : CPropertySheet(nIDCaption
, pParentWnd
, iSelectPage
)
50 CResizableSheet::CResizableSheet(LPCTSTR pszCaption
, CWnd
*pParentWnd
, UINT iSelectPage
)
51 : CPropertySheet(pszCaption
, pParentWnd
, iSelectPage
)
56 CResizableSheet::~CResizableSheet()
60 BEGIN_MESSAGE_MAP(CResizableSheet
, CPropertySheet
)
61 //{{AFX_MSG_MAP(CResizableSheet)
68 ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE
, OnPageChanging
)
71 /////////////////////////////////////////////////////////////////////////////
72 // CResizableSheet message handlers
74 int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct
)
76 if (CPropertySheet::OnCreate(lpCreateStruct
) == -1)
82 // set resizable style
83 ModifyStyle(DS_MODALFRAME
, WS_POPUP
| WS_THICKFRAME
);
84 // adjust size to reflect new style
85 ::AdjustWindowRectEx(&rect
, GetStyle(),
86 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
87 SetWindowPos(NULL
, 0, 0, rect
.Width(), rect
.Height(), SWP_FRAMECHANGED
|
88 SWP_NOMOVE
|SWP_NOZORDER
|SWP_NOACTIVATE
|SWP_NOREPOSITION
);
90 // create and init the size-grip
91 if (!CreateSizeGrip())
97 BOOL
CResizableSheet::OnInitDialog()
99 BOOL bResult
= CPropertySheet::OnInitDialog();
101 // set the initial size as the min track size
104 SetMinTrackSize(rc
.Size());
109 // prevent flickering
110 GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS
);
115 void CResizableSheet::OnDestroy()
117 if (m_bEnableSaveRestore
)
119 SaveWindowRect(m_sSection
, m_bRectOnly
);
125 CPropertySheet::OnDestroy();
128 // maps an index to a button ID and vice-versa
129 static UINT _propButtons
[] =
131 IDOK
, IDCANCEL
, ID_APPLY_NOW
, IDHELP
,
132 ID_WIZBACK
, ID_WIZNEXT
, ID_WIZFINISH
134 const int _propButtonsCount
= sizeof(_propButtons
)/sizeof(UINT
);
136 // horizontal line in wizard mode
137 #define ID_WIZLINE ID_WIZFINISH+1
139 void CResizableSheet::PresetLayout()
141 if (IsWizard()) // wizard mode
144 GetTabControl()->ShowWindow(SW_HIDE
);
146 AddAnchor(ID_WIZLINE
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
150 AddAnchor(AFX_IDC_TAB_CONTROL
, TOP_LEFT
, BOTTOM_RIGHT
);
153 // add a callback for active page (which can change at run-time)
154 AddAnchorCallback(1);
156 // use *total* parent size to have correct margins
157 CRect rectPage
, rectSheet
;
158 GetTotalClientRect(&rectSheet
);
160 GetActivePage()->GetWindowRect(&rectPage
);
161 ::MapWindowPoints(NULL
, m_hWnd
, (LPPOINT
)&rectPage
, 2);
163 // pre-calculate margins
164 m_sizePageTL
= rectPage
.TopLeft() - rectSheet
.TopLeft();
165 m_sizePageBR
= rectPage
.BottomRight() - rectSheet
.BottomRight();
167 // add all possible buttons, if they exist
168 for (int i
= 0; i
< _propButtonsCount
; i
++)
170 if (NULL
!= GetDlgItem(_propButtons
[i
]))
171 AddAnchor(_propButtons
[i
], BOTTOM_RIGHT
);
175 BOOL
CResizableSheet::ArrangeLayoutCallback(LayoutInfo
&layout
)
177 if (layout
.nCallbackID
!= 1) // we only added 1 callback
178 return CResizableLayout::ArrangeLayoutCallback(layout
);
180 // set layout info for active page
181 layout
.hWnd
= (HWND
)::SendMessage(m_hWnd
, PSM_GETCURRENTPAGEHWND
, 0, 0);
182 if (!::IsWindow(layout
.hWnd
))
186 if (IsWizard()) // wizard mode
188 // use pre-calculated margins
189 layout
.sizeMarginTL
= m_sizePageTL
;
190 layout
.sizeMarginBR
= m_sizePageBR
;
194 CTabCtrl
* pTab
= GetTabControl();
195 ASSERT(pTab
!= NULL
);
197 // get tab position after resizing and calc page rect
198 CRect rectPage
, rectSheet
;
199 GetTotalClientRect(&rectSheet
);
201 VERIFY(GetAnchorPosition(pTab
->m_hWnd
, rectSheet
, rectPage
));
202 pTab
->AdjustRect(FALSE
, &rectPage
);
205 layout
.sizeMarginTL
= rectPage
.TopLeft() - rectSheet
.TopLeft();
206 layout
.sizeMarginBR
= rectPage
.BottomRight() - rectSheet
.BottomRight();
210 layout
.sizeTypeTL
= TOP_LEFT
;
211 layout
.sizeTypeBR
= BOTTOM_RIGHT
;
213 // use this layout info
217 void CResizableSheet::OnSize(UINT nType
, int cx
, int cy
)
219 CWnd::OnSize(nType
, cx
, cy
);
221 if (nType
== SIZE_MAXHIDE
|| nType
== SIZE_MAXSHOW
)
222 return; // arrangement not needed
224 if (nType
== SIZE_MAXIMIZED
)
225 HideSizeGrip(&m_dwGripTempState
);
227 ShowSizeGrip(&m_dwGripTempState
);
229 // update grip and layout
234 BOOL
CResizableSheet::OnPageChanging(NMHDR
* /*pNotifyStruct*/, LRESULT
* /*pResult*/)
236 // update new wizard page
237 // active page changes after this notification
238 PostMessage(WM_SIZE
);
240 return FALSE
; // continue routing
243 BOOL
CResizableSheet::OnEraseBkgnd(CDC
* pDC
)
245 // Windows XP doesn't like clipping regions ...try this!
246 EraseBackground(pDC
);
249 /* ClipChildren(pDC); // old-method (for safety)
251 return CPropertySheet::OnEraseBkgnd(pDC);
255 void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR
* lpMMI
)
262 int CResizableSheet::GetMinWidth()
265 CRect rectWnd
, rectSheet
;
266 GetTotalClientRect(&rectSheet
);
268 int max
= 0, min
= rectSheet
.Width();
269 // search for leftmost and rightmost button margins
270 for (int i
= 0; i
< 7; i
++)
272 pWnd
= GetDlgItem(_propButtons
[i
]);
273 // exclude not present or hidden buttons
274 if (pWnd
== NULL
|| !(pWnd
->GetStyle() & WS_VISIBLE
))
277 // left position is relative to the right border
278 // of the parent window (negative value)
279 pWnd
->GetWindowRect(&rectWnd
);
280 ::MapWindowPoints(NULL
, m_hWnd
, (LPPOINT
)&rectWnd
, 2);
281 int left
= rectSheet
.right
- rectWnd
.left
;
282 int right
= rectSheet
.right
- rectWnd
.right
;
290 // sizing border width
291 int border
= GetSystemMetrics(SM_CXSIZEFRAME
);
293 // compute total width
294 return max
+ min
+ 2*border
;
298 // NOTE: this must be called after all the other settings
299 // to have the window and its controls displayed properly
300 void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection
, BOOL bRectOnly
, BOOL bWithPage
)
302 m_sSection
= pszSection
;
303 m_bSavePage
= bWithPage
;
305 m_bEnableSaveRestore
= TRUE
;
306 m_bRectOnly
= bRectOnly
;
308 // restore immediately
309 LoadWindowRect(pszSection
, bRectOnly
);
315 // used to save/restore active page
316 // either in the registry or a private .INI file
317 // depending on your application settings
319 #define ACTIVEPAGE _T("ActivePage")
321 void CResizableSheet::SavePage()
326 // saves active page index, zero (the first) if problems
327 // cannot use GetActivePage, because it always fails
329 CTabCtrl
*pTab
= GetTabControl();
333 page
= pTab
->GetCurSel();
337 AfxGetApp()->WriteProfileInt(m_sSection
, ACTIVEPAGE
, page
);
340 void CResizableSheet::LoadPage()
342 // restore active page, zero (the first) if not found
343 int page
= AfxGetApp()->GetProfileInt(m_sSection
, ACTIVEPAGE
, 0);
348 ArrangeLayout(); // needs refresh
352 void CResizableSheet::RefreshLayout()
354 SendMessage(WM_SIZE
);