- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# ResizableSheet.cpp

    00001 // ResizableSheet.cpp : implementation file
    00002 //
    00004 //
    00005 // Copyright (C) 2000-2002 by Paolo Messina
    00006 // (http://www.geocities.com/ppescher - ppescher@yahoo.com)
    00007 //
    00008 // The contents of this file are subject to the Artistic License (the "License").
    00009 // You may not use this file except in compliance with the License.
    00010 // You may obtain a copy of the License at:
    00011 // http://www.opensource.org/licenses/artistic-license.html
    00012 //
    00013 // If you find this code useful, credits would be nice!
    00014 //
    00016
    00017 #include "stdafx.h"
    00018 #include "ResizableSheet.h"
    00019
    00020 #ifdef _DEBUG
    00021 #define new DEBUG_NEW
    00022 #undef THIS_FILE
    00023 static char THIS_FILE[] = __FILE__;
    00024 #endif
    00025
    00027 // CResizableSheet
    00028
    00029 IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)
    00030
    00031 inline void CResizableSheet::PrivateConstruct()
    00032 {
    00033         m_bEnableSaveRestore = FALSE;
    00034         m_bSavePage = FALSE;
    00035         m_dwGripTempState = 1;
    00036 }
    00037
    00038
    00039 CResizableSheet::CResizableSheet()
    00040 {
    00041         PrivateConstruct();
    00042 }
    00043
    00044 CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)
    00045          : CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
    00046 {
    00047         PrivateConstruct();
    00048 }
    00049
    00050 CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)
    00051          : CPropertySheet(pszCaption, pParentWnd, iSelectPage)
    00052 {
    00053         PrivateConstruct();
    00054 }
    00055
    00056 CResizableSheet::~CResizableSheet()
    00057 {
    00058 }
    00059
    00060 BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
    00061         //{{AFX_MSG_MAP(CResizableSheet)
    00062         ON_WM_GETMINMAXINFO()
    00063         ON_WM_SIZE()
    00064         ON_WM_DESTROY()
    00065         ON_WM_CREATE()
    00066         ON_WM_ERASEBKGND()
    00067         //}}AFX_MSG_MAP
    00068         ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)
    00069 END_MESSAGE_MAP()
    00070
    00072 // CResizableSheet message handlers
    00073
    00074 int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct)
    00075 {
    00076         if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
    00077                 return -1;
    00078
    00079         // keep client area
    00080         CRect rect;
    00081         GetClientRect(&rect);
    00082         // set resizable style
    00083         ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
    00084         // adjust size to reflect new style
    00085         ::AdjustWindowRectEx(&rect, GetStyle(),
    00086                 ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
    00087         SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED|
    00088                 SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION);
    00089
    00090         // create and init the size-grip
    00091         if (!CreateSizeGrip())
    00092                 return -1;
    00093
    00094         return 0;
    00095 }
    00096
    00097 BOOL CResizableSheet::OnInitDialog()
    00098 {
    00099         BOOL bResult = CPropertySheet::OnInitDialog();
    00100
    00101         // set the initial size as the min track size
    00102         CRect rc;
    00103         GetWindowRect(&rc);
    00104         SetMinTrackSize(rc.Size());
    00105
    00106         // initialize layout
    00107         PresetLayout();
    00108
    00109         // prevent flickering
    00110         GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
    00111
    00112         return bResult;
    00113 }
    00114
    00115 void CResizableSheet::OnDestroy()
    00116 {
    00117         if (m_bEnableSaveRestore)
    00118         {
    00119                 SaveWindowRect(m_sSection, m_bRectOnly);
    00120                 SavePage();
    00121         }
    00122
    00123         RemoveAllAnchors();
    00124
    00125         CPropertySheet::OnDestroy();
    00126 }
    00127
    00128 // maps an index to a button ID and vice-versa
    00129 static UINT _propButtons[] =
    00130 {
    00131         IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
    00132         ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
    00133 };
    00134 const int _propButtonsCount = sizeof(_propButtons)/sizeof(UINT);
    00135
    00136 // horizontal line in wizard mode
    00137 #define ID_WIZLINE      ID_WIZFINISH+1
    00138
    00139 void CResizableSheet::PresetLayout()
    00140 {
    00141         if (IsWizard()) // wizard mode
    00142         {
    00143                 // hide tab control
    00144                 GetTabControl()->ShowWindow(SW_HIDE);
    00145
    00146                 AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);
    00147         }
    00148         else    // tab mode
    00149         {
    00150                 AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);
    00151         }
    00152
    00153         // add a callback for active page (which can change at run-time)
    00154         AddAnchorCallback(1);
    00155
    00156         // use *total* parent size to have correct margins
    00157         CRect rectPage, rectSheet;
    00158         GetTotalClientRect(&rectSheet);
    00159
    00160         GetActivePage()->GetWindowRect(&rectPage);
    00161         ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);
    00162
    00163         // pre-calculate margins
    00164         m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();
    00165         m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();
    00166
    00167         // add all possible buttons, if they exist
    00168         for (int i = 0; i < _propButtonsCount; i++)
    00169         {
    00170                 if (NULL != GetDlgItem(_propButtons[i]))
    00171                         AddAnchor(_propButtons[i], BOTTOM_RIGHT);
    00172         }
    00173 }
    00174
    00175 BOOL CResizableSheet::ArrangeLayoutCallback(LayoutInfo &layout)
    00176 {
    00177         if (layout.nCallbackID != 1)    // we only added 1 callback
    00178                 return CResizableLayout::ArrangeLayoutCallback(layout);
    00179
    00180         // set layout info for active page
    00181         layout.hWnd = (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0);
    00182         if (!::IsWindow(layout.hWnd))
    00183                 return FALSE;
    00184
    00185         // set margins
    00186         if (IsWizard()) // wizard mode
    00187         {
    00188                 // use pre-calculated margins
    00189                 layout.sizeMarginTL = m_sizePageTL;
    00190                 layout.sizeMarginBR = m_sizePageBR;
    00191         }
    00192         else    // tab mode
    00193         {
    00194                 CTabCtrl* pTab = GetTabControl();
    00195                 ASSERT(pTab != NULL);
    00196
    00197                 // get tab position after resizing and calc page rect
    00198                 CRect rectPage, rectSheet;
    00199                 GetTotalClientRect(&rectSheet);
    00200
    00201                 VERIFY(GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage));
    00202                 pTab->AdjustRect(FALSE, &rectPage);
    00203
    00204                 // set margins
    00205                 layout.sizeMarginTL = rectPage.TopLeft() - rectSheet.TopLeft();
    00206                 layout.sizeMarginBR = rectPage.BottomRight() - rectSheet.BottomRight();
    00207         }
    00208
    00209         // set anchor types
    00210         layout.sizeTypeTL = TOP_LEFT;
    00211         layout.sizeTypeBR = BOTTOM_RIGHT;
    00212
    00213         // use this layout info
    00214         return TRUE;
    00215 }
    00216
    00217 void CResizableSheet::OnSize(UINT nType, int cx, int cy)
    00218 {
    00219         CWnd::OnSize(nType, cx, cy);
    00220
    00221         if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
    00222                 return;         // arrangement not needed
    00223
    00224         if (nType == SIZE_MAXIMIZED)
    00225                 HideSizeGrip(&m_dwGripTempState);
    00226         else
    00227                 ShowSizeGrip(&m_dwGripTempState);
    00228
    00229         // update grip and layout
    00230         UpdateSizeGrip();
    00231         ArrangeLayout();
    00232 }
    00233
    00234 BOOL CResizableSheet::OnPageChanging(NMHDR* /*pNotifyStruct*/, LRESULT* /*pResult*/)
    00235 {
    00236         // update new wizard page
    00237         // active page changes after this notification
    00238         PostMessage(WM_SIZE);
    00239
    00240         return FALSE;   // continue routing
    00241 }
    00242
    00243 BOOL CResizableSheet::OnEraseBkgnd(CDC* pDC)
    00244 {
    00245         // Windows XP doesn't like clipping regions ...try this!
    00246         EraseBackground(pDC);
    00247         return TRUE;
    00248
    00249 /*      ClipChildren(pDC);      // old-method (for safety)
    00250
    00251         return CPropertySheet::OnEraseBkgnd(pDC);
    00252 */
    00253 }
    00254
    00255 void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
    00256 {
    00257         MinMaxInfo(lpMMI);
    00258 }
    00259
    00260 // protected members
    00261
    00262 int CResizableSheet::GetMinWidth()
    00263 {
    00264         CWnd* pWnd = NULL;
    00265         CRect rectWnd, rectSheet;
    00266         GetTotalClientRect(&rectSheet);
    00267
    00268         int max = 0, min = rectSheet.Width();
    00269         // search for leftmost and rightmost button margins
    00270         for (int i = 0; i < 7; i++)
    00271         {
    00272                 pWnd = GetDlgItem(_propButtons[i]);
    00273                 // exclude not present or hidden buttons
    00274                 if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))
    00275                         continue;
    00276
    00277                 // left position is relative to the right border
    00278                 // of the parent window (negative value)
    00279                 pWnd->GetWindowRect(&rectWnd);
    00280                 ::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);
    00281                 int left = rectSheet.right - rectWnd.left;
    00282                 int right = rectSheet.right - rectWnd.right;
    00283
    00284                 if (left > max)
    00285                         max = left;
    00286                 if (right < min)
    00287                         min = right;
    00288         }
    00289
    00290         // sizing border width
    00291         int border = GetSystemMetrics(SM_CXSIZEFRAME);
    00292
    00293         // compute total width
    00294         return max + min + 2*border;
    00295 }
    00296
    00297
    00298 // NOTE: this must be called after all the other settings
    00299 //       to have the window and its controls displayed properly
    00300 void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)
    00301 {
    00302         m_sSection = pszSection;
    00303         m_bSavePage = bWithPage;
    00304
    00305         m_bEnableSaveRestore = TRUE;
    00306         m_bRectOnly = bRectOnly;
    00307
    00308         // restore immediately
    00309         LoadWindowRect(pszSection, bRectOnly);
    00310         LoadPage();
    00311 }
    00312
    00313 // private memebers
    00314
    00315 // used to save/restore active page
    00316 // either in the registry or a private .INI file
    00317 // depending on your application settings
    00318
    00319 #define ACTIVEPAGE      _T("ActivePage")
    00320
    00321 void CResizableSheet::SavePage()
    00322 {
    00323         if (!m_bSavePage)
    00324                 return;
    00325
    00326         // saves active page index, zero (the first) if problems
    00327         // cannot use GetActivePage, because it always fails
    00328
    00329         CTabCtrl *pTab = GetTabControl();
    00330         int page = 0;
    00331
    00332         if (pTab != NULL)
    00333                 page = pTab->GetCurSel();
    00334         if (page < 0)
    00335                 page = 0;
    00336
    00337         AfxGetApp()->WriteProfileInt(m_sSection, ACTIVEPAGE, page);
    00338 }
    00339
    00340 void CResizableSheet::LoadPage()
    00341 {
    00342         // restore active page, zero (the first) if not found
    00343         int page = AfxGetApp()->GetProfileInt(m_sSection, ACTIVEPAGE, 0);
    00344
    00345         if (m_bSavePage)
    00346         {
    00347                 SetActivePage(page);
    00348                 ArrangeLayout();        // needs refresh
    00349         }
    00350 }
    00351
    00352 void CResizableSheet::RefreshLayout()
    00353 {
    00354         SendMessage(WM_SIZE);
    00355 }