ResizableSheet.cpp

00001 // ResizableSheet.cpp : implementation file
00002 //
00004 //
00005 // Copyright (C) 2000-2002 by Paolo Messina
00006 // (http://www.geocities.com/ppescher - [email protected])
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 }

Generated on Tue Dec 13 14:47:57 2005 for guliverkli by  doxygen 1.4.5