403 lines
9.6 KiB
C++
403 lines
9.6 KiB
C++
|
// ResizableSheet.cpp : implementation file
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Modified 14/09/2000 by David Fleury
|
||
|
// get rid if the "resizable" stuff, just kept the auto arrange of controls
|
||
|
//
|
||
|
// Copyright (C) 2000 by Paolo Messina
|
||
|
// (ppescher@yahoo.com)
|
||
|
//
|
||
|
// Free for non-commercial use.
|
||
|
// You may change the code to your needs,
|
||
|
// provided that credits to the original
|
||
|
// author is given in the modified files.
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "ResizableSheet.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CResizableSheet
|
||
|
|
||
|
IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)
|
||
|
|
||
|
inline void CResizableSheet::Construct()
|
||
|
{
|
||
|
m_bInitDone = FALSE;
|
||
|
|
||
|
m_bEnableSaveRestore = FALSE;
|
||
|
m_bSavePage = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
CResizableSheet::CResizableSheet()
|
||
|
{
|
||
|
Construct();
|
||
|
}
|
||
|
|
||
|
CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd *pParentWnd, UINT iSelectPage)
|
||
|
: CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
|
||
|
{
|
||
|
Construct();
|
||
|
}
|
||
|
|
||
|
CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd, UINT iSelectPage)
|
||
|
: CPropertySheet(pszCaption, pParentWnd, iSelectPage)
|
||
|
{
|
||
|
Construct();
|
||
|
}
|
||
|
|
||
|
CResizableSheet::~CResizableSheet()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
|
||
|
//{{AFX_MSG_MAP(CResizableSheet)
|
||
|
ON_WM_SIZE()
|
||
|
ON_WM_DESTROY()
|
||
|
ON_WM_CREATE()
|
||
|
//}}AFX_MSG_MAP
|
||
|
ON_BN_CLICKED(ID_WIZBACK, OnPageChanged)
|
||
|
ON_BN_CLICKED(ID_WIZNEXT, OnPageChanged)
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CResizableSheet message handlers
|
||
|
|
||
|
int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct)
|
||
|
{
|
||
|
if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
|
||
|
return -1;
|
||
|
|
||
|
/*********************************/
|
||
|
// MODIFIED 14/09/2000 Fleury David, I don't want the user to be able to resize the sheet
|
||
|
// // change window style to be resizable
|
||
|
// ModifyStyle(0,/* WS_THICKFRAME |*/ WS_CLIPCHILDREN);
|
||
|
/*********************************/
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
BOOL CResizableSheet::OnInitDialog()
|
||
|
{
|
||
|
BOOL bResult = CPropertySheet::OnInitDialog();
|
||
|
|
||
|
// prevent flickering
|
||
|
GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
|
||
|
|
||
|
m_bInitDone = TRUE;
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
void CResizableSheet::OnDestroy()
|
||
|
{
|
||
|
CPropertySheet::OnDestroy();
|
||
|
|
||
|
if (m_bEnableSaveRestore)
|
||
|
{
|
||
|
SaveWindowRect();
|
||
|
}
|
||
|
|
||
|
CPropertySheet::OnDestroy();
|
||
|
}
|
||
|
|
||
|
// maps an index to a button ID and vice-versa
|
||
|
static UINT _propButtons[] =
|
||
|
{
|
||
|
IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
|
||
|
ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
|
||
|
};
|
||
|
|
||
|
// horizontal line in wizard mode
|
||
|
#define ID_WIZLINE ID_WIZFINISH+1
|
||
|
|
||
|
void CResizableSheet::PresetLayout()
|
||
|
{
|
||
|
CWnd* pWnd; // points to various children
|
||
|
CRect wndrc, objrc;
|
||
|
GetClientRect(&wndrc);
|
||
|
|
||
|
// tab control or wizard line position
|
||
|
if (m_psh.dwFlags & PSH_WIZARD) // wizard mode
|
||
|
{
|
||
|
// get wizard line's bottom-right corner
|
||
|
pWnd = GetDlgItem(ID_WIZLINE);
|
||
|
|
||
|
// hide tab control
|
||
|
GetTabControl()->ShowWindow(SW_HIDE);
|
||
|
}
|
||
|
else // tabbed mode
|
||
|
{
|
||
|
// get tab control's bottom-right corner
|
||
|
pWnd = GetTabControl();
|
||
|
}
|
||
|
// whatever it is, take the right margin
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
m_szLayoutTabLine.cx = objrc.right - wndrc.right;
|
||
|
m_szLayoutTabLine.cy = objrc.bottom - wndrc.bottom;
|
||
|
|
||
|
// get child dialog's bottom-right corner
|
||
|
pWnd = GetActivePage();
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
m_szLayoutPage.cx = objrc.right - wndrc.right;
|
||
|
m_szLayoutPage.cy = objrc.bottom - wndrc.bottom;
|
||
|
|
||
|
// store buttons position
|
||
|
for (int i = 0; i < 7; i++)
|
||
|
{
|
||
|
pWnd = GetDlgItem(_propButtons[i]);
|
||
|
|
||
|
if (pWnd == NULL)
|
||
|
{
|
||
|
// invalid position, button does not exist
|
||
|
// (just to initialize, any button you may activate
|
||
|
// in the future is present, but hidden)
|
||
|
m_szLayoutButton[i].cx = 0;
|
||
|
m_szLayoutButton[i].cy = 0;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
m_szLayoutButton[i].cx = objrc.left - wndrc.right;
|
||
|
m_szLayoutButton[i].cy = objrc.top - wndrc.bottom;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CResizableSheet::ArrangeLayout()
|
||
|
{
|
||
|
// init some vars
|
||
|
CWnd* pWnd;
|
||
|
CRect wndrc, objrc;
|
||
|
GetClientRect(&wndrc);
|
||
|
|
||
|
// usually no more than
|
||
|
// 4 buttons +
|
||
|
// 1 tab control or wizard line +
|
||
|
// 1 active page
|
||
|
HDWP hdwp = BeginDeferWindowPos(6);
|
||
|
|
||
|
if (m_psh.dwFlags & PSH_WIZARD) // wizard mode
|
||
|
{
|
||
|
// get wizard line's bottom-right corner
|
||
|
pWnd = GetDlgItem(ID_WIZLINE);
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
int oldHeight = objrc.Height();
|
||
|
objrc.right = m_szLayoutTabLine.cx + wndrc.right;
|
||
|
objrc.bottom = m_szLayoutTabLine.cy + wndrc.bottom;
|
||
|
objrc.top = objrc.bottom - oldHeight;
|
||
|
|
||
|
// add the control
|
||
|
DeferWindowPos(hdwp, *pWnd, NULL, objrc.left, objrc.top,
|
||
|
objrc.Width(), objrc.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
}
|
||
|
else // tabbed mode
|
||
|
{
|
||
|
// get tab control's bottom-right corner
|
||
|
pWnd = GetTabControl();
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
objrc.right = m_szLayoutTabLine.cx + wndrc.right;
|
||
|
objrc.bottom = m_szLayoutTabLine.cy + wndrc.bottom;
|
||
|
|
||
|
// add the control, only resize
|
||
|
DeferWindowPos(hdwp, *pWnd, NULL, 0, 0, objrc.Width(),
|
||
|
objrc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
}
|
||
|
|
||
|
// get child dialog's bottom-right corner
|
||
|
pWnd = GetActivePage();
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
objrc.right = m_szLayoutPage.cx + wndrc.right;
|
||
|
objrc.bottom = m_szLayoutPage.cy + wndrc.bottom;
|
||
|
|
||
|
// add the control, only resize
|
||
|
DeferWindowPos(hdwp, *pWnd, NULL, 0, 0, objrc.Width(),
|
||
|
objrc.Height(), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
|
||
|
// arrange buttons position
|
||
|
for (int i = 0; i < 7; i++)
|
||
|
{
|
||
|
pWnd = GetDlgItem(_propButtons[i]);
|
||
|
|
||
|
if (pWnd == NULL)
|
||
|
continue; // ignores deleted buttons
|
||
|
|
||
|
// this should never happen, because all the buttons you
|
||
|
// may activate already exist at time PresetLayout is called
|
||
|
ASSERT(m_szLayoutButton[i].cx != 0 || m_szLayoutButton[i].cy != 0);
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
objrc.left = m_szLayoutButton[i].cx + wndrc.right;
|
||
|
objrc.top = m_szLayoutButton[i].cy + wndrc.bottom;
|
||
|
|
||
|
// add the control, only move
|
||
|
DeferWindowPos(hdwp, *pWnd, NULL, objrc.left, objrc.top,
|
||
|
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
}
|
||
|
|
||
|
// go re-arrange child windows
|
||
|
EndDeferWindowPos(hdwp);
|
||
|
}
|
||
|
|
||
|
void CResizableSheet::OnSize(UINT nType, int cx, int cy)
|
||
|
{
|
||
|
CWnd::OnSize(nType, cx, cy);
|
||
|
|
||
|
if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
|
||
|
return; // arrangement not needed
|
||
|
|
||
|
if (m_bInitDone)
|
||
|
ArrangeLayout();
|
||
|
}
|
||
|
|
||
|
// only gets called in wizard mode
|
||
|
// (when back or next button pressed)
|
||
|
void CResizableSheet::OnPageChanged()
|
||
|
{
|
||
|
// call default handler to allow page change
|
||
|
Default();
|
||
|
|
||
|
// update new wizard page
|
||
|
ArrangeLayout();
|
||
|
}
|
||
|
|
||
|
|
||
|
// protected members
|
||
|
|
||
|
|
||
|
// NOTE: this must be called after all the other settings
|
||
|
// to have the dialog and its controls displayed properly
|
||
|
void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, LPCTSTR pszEntry, BOOL bWithPage)
|
||
|
{
|
||
|
m_sSection = pszSection;
|
||
|
m_sEntry = pszEntry;
|
||
|
m_bSavePage = bWithPage;
|
||
|
|
||
|
m_bEnableSaveRestore = TRUE;
|
||
|
|
||
|
LoadWindowRect();
|
||
|
}
|
||
|
|
||
|
// private memebers
|
||
|
|
||
|
// used to save/restore window's size and position
|
||
|
// either in the registry or a private .INI file
|
||
|
// depending on your application settings
|
||
|
|
||
|
#define PROFILE_FMT _T("%d,%d,%d,%d,%d,%d [%d]")
|
||
|
|
||
|
void CResizableSheet::SaveWindowRect()
|
||
|
{
|
||
|
CString data;
|
||
|
WINDOWPLACEMENT wp;
|
||
|
|
||
|
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
|
||
|
wp.length = sizeof(WINDOWPLACEMENT);
|
||
|
GetWindowPlacement(&wp);
|
||
|
|
||
|
RECT& rc = wp.rcNormalPosition; // alias
|
||
|
|
||
|
// also saves active page index, zero (the first) if problems
|
||
|
// cannot use GetActivePage, because it always fails
|
||
|
CTabCtrl *pTab = GetTabControl();
|
||
|
int page = 0;
|
||
|
|
||
|
if (pTab != NULL)
|
||
|
page = pTab->GetCurSel();
|
||
|
if (page < 0)
|
||
|
page = 0;
|
||
|
|
||
|
// always save page
|
||
|
data.Format(PROFILE_FMT, rc.left, rc.top,
|
||
|
rc.right, rc.bottom, wp.showCmd, wp.flags, page);
|
||
|
|
||
|
AfxGetApp()->WriteProfileString(m_sSection, m_sEntry, data);
|
||
|
}
|
||
|
|
||
|
void CResizableSheet::LoadWindowRect()
|
||
|
{
|
||
|
CString data;
|
||
|
WINDOWPLACEMENT wp;
|
||
|
int page;
|
||
|
|
||
|
data = AfxGetApp()->GetProfileString(m_sSection, m_sEntry);
|
||
|
|
||
|
if (data.IsEmpty()) // never saved before
|
||
|
return;
|
||
|
|
||
|
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
|
||
|
wp.length = sizeof(WINDOWPLACEMENT);
|
||
|
|
||
|
RECT& rc = wp.rcNormalPosition; // alias
|
||
|
|
||
|
if (_stscanf_s(data, PROFILE_FMT, &rc.left, &rc.top,
|
||
|
&rc.right, &rc.bottom, &wp.showCmd, &wp.flags, &page) == 7)
|
||
|
{
|
||
|
SetWindowPlacement(&wp);
|
||
|
if (m_bSavePage)
|
||
|
{
|
||
|
SetActivePage(page);
|
||
|
ArrangeLayout(); // needs refresh
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int CResizableSheet::GetMinWidth()
|
||
|
{/*
|
||
|
int min = 0;
|
||
|
|
||
|
// search for leftmost button
|
||
|
for (int i = 0; i < 7; i++)
|
||
|
{
|
||
|
// left position is relative to the right border
|
||
|
// of the parent window (negative value)
|
||
|
if (m_szLayoutButton[i].cx < min)
|
||
|
min = m_szLayoutButton[i].cx;
|
||
|
}
|
||
|
|
||
|
// sizing border width
|
||
|
int border = GetSystemMetrics(SM_CXSIZEFRAME);
|
||
|
|
||
|
// get tab control or wizard line left position
|
||
|
CWnd* pWnd;
|
||
|
CRect objrc;
|
||
|
|
||
|
if (m_psh.dwFlags & PSH_WIZARD)
|
||
|
pWnd = GetDlgItem(ID_WIZLINE);
|
||
|
else
|
||
|
pWnd = GetTabControl();
|
||
|
|
||
|
pWnd->GetWindowRect(&objrc);
|
||
|
ScreenToClient(&objrc);
|
||
|
|
||
|
// add the left margin and window's border
|
||
|
return -min + objrc.left + border*2;
|
||
|
*/
|
||
|
return 1;
|
||
|
}
|