diff options
Diffstat (limited to 'win32/common/atlprsht.h')
-rw-r--r-- | win32/common/atlprsht.h | 915 |
1 files changed, 915 insertions, 0 deletions
diff --git a/win32/common/atlprsht.h b/win32/common/atlprsht.h new file mode 100644 index 0000000..e5181ea --- /dev/null +++ b/win32/common/atlprsht.h @@ -0,0 +1,915 @@ +/* + * AUTHOR + * N. Nielsen + * + * LICENSE + * This software is in the public domain. + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties + * of merchantability, fitness for a particular purpose, and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages, or other liability, whether in an action of + * contract, tort, or otherwise, arising from, out of, or in connection + * with the software or the use or other dealings in the software. + * + * SUPPORT + * Send bug reports to: <nielsen@memberwebs.com> + */ + +// PropertyPage.h: interface for the CPropertyPage class. +// Implements Property Pages and Sheets for ATL +// By Stef 06/10/99 +// +// This class uses an MFC type Interface (CPropertySheet, CPropertyPage) +// the only difference being that many of the virtual notify functions +// are left for you to define in your derived classes using your message map +// +// Notes for CPropertySheet: +// 1. If you define a WM_INITDIALOG handler in your derived class make +// sure to either call the base handler (OnInitDialog) or set +// bHandled to false. +// +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_PROPERTYPAGE_H__1508DAF4_7AD1_11D3_BF96_0020182B97FC__INCLUDED_) +#define AFX_PROPERTYPAGE_H__1508DAF4_7AD1_11D3_BF96_0020182B97FC__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +#include <atlwin.h> +#include <atlwinhk.h> +#include <commctrl.h> + + +// Property Sheet control id's (determined with Spy++) +#define ID_APPLY_NOW 0x3021 +#define ID_WIZBACK 0x3023 +#define ID_WIZNEXT 0x3024 +#define ID_WIZFINISH 0x3025 + +#define AFX_IDC_TAB_CONTROL 0x3020 + +// determine number of elements in an array (not bytes) +#define _countof(array) (sizeof(array)/sizeof(array[0])) + +template <class TBase> class CPropertySheetT; +template <class TBase> class CPropertyPageT; + +const int _PropSheetIDs[] = + { ID_WIZNEXT, ID_WIZFINISH, ID_WIZBACK, IDCANCEL }; +const int _PropSheetButtons[] = + { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; + +//////////////////////////////////////////////////////////////////////// +// Implements one page of a Property Sheet +template <class TBase = CWindow> +class CPropertyPageT : public CDialogImplBaseT< TBase > +{ +// Construction +public: + CPropertyPageT(UINT IDD) : m_szCaption(NULL) + { Construct(IDD, _T("")); } + + // Caption from Resource + CPropertyPageT(UINT IDD, UINT nIDCaption) : m_szCaption(NULL) + { Construct(IDD, nIDCaption); } + + CPropertyPageT(UINT IDD, LPCTSTR szCaption) : m_szCaption(NULL) + { Construct(IDD, szCaption); } + + void Construct(UINT IDD, LPCTSTR szCaption) + { CommonConstruct(IDD, szCaption); } + + void Construct(UINT IDD, UINT nIDCaption) + { + ATLASSERT(nIDCaption != 0); + USES_CONVERSION; + CComBSTR bsCaption; + bsCaption.LoadString(nIDCaption); + CommonConstruct(IDD, OLE2T(bsCaption)); + } + + // All Construction ends up here + void CommonConstruct(UINT IDD, LPCTSTR szCaption); + + ~CPropertyPageT() + { if(m_szCaption) delete[] m_szCaption; } + +// Operations + void CancelToClose(); + void SetModified(bool bChanged); + void SetHelp(bool bHelp); + LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam); + bool IsButtonEnabled(int iButton); + void EndDialog(int nID); + +// Status + CPropertySheetT<TBase>* GetParentSheet(); + +// Implementaition +protected: + CPropertySheetT<TBase>* m_pSheet; // Pointer to Sheet + static UINT CALLBACK PropPageCallback(HWND hwnd, UINT uMsg, + LPPROPSHEETPAGE ppsp); + +// Data +public: + PROPSHEETPAGE m_psp; // API Structure + LPTSTR m_szCaption; // Caption + + friend class CPropertySheetT<TBase>; +}; + +// Common Construction +template <class TBase> +void CPropertyPageT<TBase>::CommonConstruct(UINT IDD, LPCTSTR szCaption) +{ + // Clear + memset(&m_psp, 0, sizeof(m_psp)); + + m_psp.dwSize = sizeof(m_psp); + m_psp.hInstance = _Module.m_hInstResource; + m_psp.pszTemplate = MAKEINTRESOURCE(IDD); + // Set to DialogProc + m_psp.pfnDlgProc = (DLGPROC)StartDialogProc; + // Use to hook up to ATL WndProc + m_psp.pfnCallback = PropPageCallback; + m_psp.dwFlags = PSP_USETITLE | PSP_USECALLBACK; + // Passed to PropPageCallback + m_psp.lParam = (LPARAM)this; + + // Allocate String + if(m_szCaption && _tcslen(m_szCaption) < _tcslen(szCaption)) + { + delete[] m_szCaption; + m_szCaption = NULL; + } + + if(!m_szCaption) + m_szCaption = new TCHAR[_tcslen(szCaption) + 1]; + + _tcscpy(m_szCaption, szCaption); + m_psp.pszTitle = m_szCaption; + + // Set by CPropertySheetT::AddPage + m_pSheet = NULL; + +} + +// Callback used during actual creation of page +template <class TBase> +UINT CALLBACK CPropertyPageT<TBase>::PropPageCallback(HWND hwnd, UINT uMsg, + LPPROPSHEETPAGE ppsp) +{ + switch (uMsg) + { + case PSPCB_CREATE: + { + // Get ready for hooking up to an ATL WndProc + CPropertyPageT<TBase>* pPage = + (CPropertyPageT<TBase>*)ppsp->lParam; + _Module.AddCreateWndData(&(pPage->m_thunk.cd), pPage); + + return TRUE; + } + case PSPCB_RELEASE: + break; + } + + return 0; +} + +// Thin Wrapper +template <class TBase> +void CPropertyPageT<TBase>::CancelToClose() +{ + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + + ::SendMessage(GetParent(), PSM_CANCELTOCLOSE, NULL, NULL); +} + +// Thin Wrapper +template <class TBase> +void CPropertyPageT<TBase>::SetModified(bool bChanged) +{ + ATLASSERT(m_hWnd != NULL); + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + + if (bChanged) + ::SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, NULL); + else + ::SendMessage(GetParent(), PSM_UNCHANGED, (WPARAM)m_hWnd, NULL); +} + +// Thin Wrapper +template <class TBase> +LRESULT CPropertyPageT<TBase>::QuerySiblings(WPARAM wParam, LPARAM lParam) +{ + ATLASSERT(::IsWindow(m_hWnd)); + ATLASSERT(GetParent() != NULL); + + return ::SendMessage(GetParent(), PSM_QUERYSIBLINGS, wParam, lParam); +} + +template <class TBase> +void CPropertyPageT<TBase>::SetHelp(bool bHelp) +{ + if(bHelp) + m_psp.dwFlags |= PSP_HASHELP; + else + m_psp.dwFlags &= ~(PSP_HASHELP); +} + +// Thin wrapper +template <class TBase> +bool CPropertyPageT<TBase>::IsButtonEnabled(int iButton) +{ + HWND hWnd = ::GetDlgItem(::GetParent(m_hWnd), iButton); + if (hWnd == NULL) + return false; + return ::IsWindowEnabled(hWnd) ? true : false; +} + +// Routes EndDialog calls to the Sheet +template <class TBase> +void CPropertyPageT<TBase>::EndDialog(int nID) +{ + // Normally you shouldn't call EndDialog from a page. But in case it does + // happen during error situations, call CPropertySheetT::EndDialog instead. + CPropertySheetT<TBase>* pParent = GetParentSheet(); + if (pParent != NULL) + pParent->EndDialog(nID); +} + +// Return Sheet Pointer (which is initialized in CPropertySheetT::AddPage) +template <class TBase> +CPropertySheetT<TBase>* CPropertyPageT<TBase>::GetParentSheet() + { ATLASSERT(m_pSheet != NULL); return m_pSheet; } + + + + + +//////////////////////////////////////////////////////////////////////// +// Implements and hooks into Actual Property Sheet Window +template <class TBase = CWindow> +class CPropertySheetT : public CWindowImplBaseT< TBase > +{ +// Construction +public: + CPropertySheetT() : m_szCaption(NULL) + { CommonConstruct(_T(""), 0); } + + // Caption from Resource + CPropertySheetT(UINT nIDCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) + : m_szCaption(NULL) + { Construct(nIDCaption, hwndParent, iSelectPage); } + + CPropertySheetT(LPCTSTR pszCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) + : m_szCaption(NULL) + { Construct(pszCaption, hwndParent, iSelectPage); } + + // Caption from Resource + void Construct(UINT nIDCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) + { + ATLASSERT(nIDCaption != 0); + USES_CONVERSION; + CComBSTR bsCaption; + bsCaption.LoadString(nIDCaption); + CommonConstruct(OLE2T(bsCaption), hwndParent, iSelectPage); + } + + void Construct(LPCTSTR pszCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) + { CommonConstruct(pszCaption, hwndParent, iSelectPage); } + + // All actual initialization takes place here + void CommonConstruct(LPCTSTR sCaption, HWND hwndParent = NULL, UINT iSelectPage = 0); + + virtual ~CPropertySheetT() + { if(m_szCaption) delete[] m_szCaption; } + +// Creation +public: + // for modeless creation + // the default style, expressed by passing -1 as dwStyle, is actually: + // WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | WS_VISIBLE + bool Create(HWND hwndParent = NULL, DWORD dwStyle = (DWORD)-1, DWORD dwExStyle = 0); + int DoModal(HWND hwndParent = NULL, DWORD dwStyle = (DWORD)-1, DWORD dwExStyle = 0); + +// Operations +public: + void AddPage(CPropertyPageT<TBase>* pPage); + void RemovePage(CPropertyPageT<TBase>* pPage); + void RemovePage(int nPage); + void EndDialog(int nEndID); // used to terminate a modal dialog + bool PressButton(int nButton); + +// Status and Settings +public: + int GetPageCount() const; + int GetActiveIndex() const; + CPropertyPageT<TBase>* GetActivePage() const; + CPropertyPageT<TBase>* GetPage(int nPage) const; + int GetPageIndex(CPropertyPageT<TBase>* pPage); + HWND GetTabControl() const; + void SetWizardMode(); + void SetHelp(bool bHelp); + void SetFinishText(LPCTSTR lpszText); + void SetWizardButtons(DWORD dwFlags); + void EnableStackedTabs(BOOL bStacked); + bool IsWizard() const; + bool SetActivePage(int nPage); + bool SetActivePage(CPropertyPageT<TBase>* pPage); + void SetTitle(LPCTSTR lpszText, UINT nStyle = 0); + +// Message Map +protected: +typedef CPropertySheetT<TBase> sheetClass; +BEGIN_MSG_MAP(sheetClass) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) + MESSAGE_HANDLER(WM_CLOSE, OnClose) + COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnEndCode) + COMMAND_HANDLER(IDOK, BN_CLICKED, OnEndCode) + COMMAND_HANDLER(ID_WIZFINISH, BN_CLICKED, OnEndCode) +END_MSG_MAP() + +// Message Handlers + LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnEndCode(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); + + +// Implementation +protected: + void BuildPropPageArray(); // Finalizes the Array of Pages + + // Used during creation to set styles + static int CALLBACK PropSheetCallback(HWND, UINT nMsg, LPARAM lParam); + + // For hooking into creation and subclassing the window + DECLARE_HOOK_AND_SUBCLASS(sheetClass); + + // Style cache (used in PropSheetCallback) + DWORD m_dwCurStyle; + DWORD m_dwCurExStyle; + +// Data +protected: + CSimpleArray< CPropertyPageT<TBase>* > m_pages; // array of CPropertyPageT pointers + LPTSTR m_szCaption; // caption of the pseudo-dialog + bool m_bStacked; // EnableStackedTabs sets this + bool m_bModeless; // TRUE when Create called instead of DoModal + int m_nDlgRet; // Result from EndDialog + +public: + PROPSHEETHEADER m_psh; +}; + +// All Initialization here +template <class TBase> +void CPropertySheetT<TBase>::CommonConstruct(LPCTSTR szCaption, + HWND hwndParent /*= NULL*/, + UINT iSelectPage /*= 0*/) +{ + // Clear + memset(&m_psh, 0, sizeof(m_psh)); + + m_psh.dwSize = sizeof(m_psh); + m_psh.dwFlags = PSH_PROPSHEETPAGE; + m_psh.nStartPage = iSelectPage; + + // Allocate String + if(m_szCaption && _tcslen(m_szCaption) < _tcslen(szCaption)) + { + delete[] m_szCaption; + m_szCaption = NULL; + } + + if(!m_szCaption) + m_szCaption = new TCHAR[_tcslen(szCaption) + 1]; + + _tcscpy(m_szCaption, szCaption); + m_psh.pszCaption = m_szCaption; + + m_bStacked = true; // Tab Control + m_bModeless = false; + m_dwCurStyle = 0; + m_dwCurExStyle = 0; + m_nDlgRet = 0; + + // m_psh.hwndParent set in DoModal/create +} + +// Callback used to set styles of Property Sheet +template <class TBase> +int CALLBACK CPropertySheetT<TBase>::PropSheetCallback(HWND hwnd, UINT nMsg, + LPARAM lParam) +{ + switch (nMsg) + { + case PSCB_PRECREATE: + { + // Extract Thunk Create (whatever) data + CPropertySheetT<TBase>* pThis = (CPropertySheetT<TBase>*)_Module.ExtractCreateWndData(); + // We need it later in the proces so add it back again + _Module.AddCreateWndData(&(pThis->m_thunk.cd), pThis); + + LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam; + if (lpTemplate->style != pThis->m_dwCurStyle || + lpTemplate->dwExtendedStyle != pThis->m_dwCurExStyle) + { + + // Mark the dialog template as read-write. + DWORD dwOldProtect; + VirtualProtect(lpTemplate, sizeof(DLGTEMPLATE), PAGE_READWRITE, + &dwOldProtect); + + // Ensure DS_SETFONT is set correctly. + lpTemplate->style = lpTemplate->style & DS_SETFONT ? + pThis->m_dwCurStyle | DS_SETFONT : + pThis->m_dwCurStyle & ~DS_SETFONT; + + lpTemplate->dwExtendedStyle = pThis->m_dwCurExStyle; + } + return TRUE; + } + case PSCB_INITIALIZED: + return TRUE; + + } + + return 0; +} + +// Creates a Modeless Property Sheet +template <class TBase> +bool CPropertySheetT<TBase>::Create(HWND hwndParent /*= NULL*/, DWORD dwStyle /*= (DWORD)-1*/, + DWORD dwExStyle /*= 0*/) +{ + // Calculate the default window style. + if (dwStyle == (DWORD)-1) + { + dwStyle = DS_MODALFRAME | DS_3DLOOK | DS_SETFONT | WS_POPUP | + WS_VISIBLE | WS_CAPTION; + + // Wizards don't have WS_SYSMENU by default + if (!IsWizard()) + dwStyle |= WS_SYSMENU; + } + + // Cache the styles (for use in PropSheetCallback) + m_dwCurStyle = dwStyle; + m_dwCurExStyle = dwExStyle; + + ATLASSERT(m_hWnd == NULL); + + // finish building PROPSHEETHEADER structure + BuildPropPageArray(); + + // Some more settings + m_bModeless = true; + m_psh.dwFlags |= (PSH_MODELESS | PSH_USECALLBACK); + m_psh.pfnCallback = PropSheetCallback; + m_psh.hwndParent = hwndParent; + + // Add Create Thunk whatever Data + _Module.AddCreateWndData(&m_thunk.cd, this); + // Hook into creation so we can subclass before any messages come in + HOOK_AND_SUBCLASS_NEXT(); + + // Do it! + HWND hWnd = (HWND)::PropertySheet((PROPSHEETHEADER*)&m_psh); + + // Modeless so we return right away +#ifdef _DEBUG + DWORD dwError = ::GetLastError(); +#endif + + if (hWnd == NULL || hWnd == (HWND)-1) + { +#ifdef _DEBUG + ATLTRACE("PropertySheet() failed: GetLastError returned %d\n", dwError); +#endif + return false; + } + + m_hWnd = hWnd; + + return true; +} + +// Create a Modal Dialog +template <class TBase> +int CPropertySheetT<TBase>::DoModal(HWND hwndParent /*= NULL*/, DWORD dwStyle /*= (DWORD)-1*/, + DWORD dwExStyle /*= 0*/) +{ + ATLASSERT(m_hWnd == NULL); + + // Calculate the default window style. + if (dwStyle == (DWORD)-1) + { + dwStyle = DS_MODALFRAME | DS_3DLOOK | DS_SETFONT | WS_POPUP | + WS_VISIBLE | WS_CAPTION; + + // Wizards don't have WS_SYSMENU by default + if (!IsWizard()) + dwStyle |= WS_SYSMENU; + } + + // Cache the styles (for use in PropSheetCallback) + m_dwCurStyle = dwStyle; + m_dwCurExStyle = dwExStyle; + + // finish building PROPSHEETHEADER structure + BuildPropPageArray(); + + // Set options + m_bModeless = false; + m_nDlgRet = -1; + m_psh.dwFlags |= (PSH_USECALLBACK); + m_psh.pfnCallback = PropSheetCallback; + m_psh.hwndParent = hwndParent; + + // Add Create Thunk whatever Data + _Module.AddCreateWndData(&m_thunk.cd, this); + // Hook into creation so we can subclass before any messages come in + HOOK_AND_SUBCLASS_NEXT(); + + // Do it. Doesn't come back until after the fact + int nRet = ::PropertySheet((PROPSHEETHEADER*)&m_psh); + + if(nRet == -1) + return nRet; + + return m_nDlgRet; +} + +// Finalize the Array +template <class TBase> +void CPropertySheetT<TBase>::BuildPropPageArray() +{ + // delete existing prop page array + delete[] (PROPSHEETPAGE*)m_psh.ppsp; + m_psh.ppsp = NULL; + + // build new prop page array + PROPSHEETPAGE* ppsp = new PROPSHEETPAGE[m_pages.GetSize()]; + m_psh.ppsp = (PROPSHEETPAGE*)ppsp; + BOOL bWizard = (m_psh.dwFlags & (PSH_WIZARD)); + for (int i = 0; i < m_pages.GetSize(); i++) + { + CPropertyPageT<TBase>* pPage = GetPage(i); + memcpy(&ppsp[i], &pPage->m_psp, sizeof(pPage->m_psp)); +// pPage->PreProcessPageTemplate((PROPSHEETPAGE&)ppsp[i], bWizard); + } + m_psh.nPages = m_pages.GetSize(); +} + +// Adds a Page (either before or after we're on the screen) +template <class TBase> +void CPropertySheetT<TBase>::AddPage(CPropertyPageT<TBase>* pPage) +{ + ATLASSERT(pPage != NULL); + + // Add page to internal list + m_pages.Add(pPage); + pPage->m_pSheet = this; + + // Add page externally + if (m_hWnd != NULL) + { + // build new prop page array + PROPSHEETPAGE* ppsp = new PROPSHEETPAGE[m_pages.GetSize()]; + memcpy(ppsp, m_psh.ppsp, sizeof(PROPSHEETPAGE) * (m_pages.GetSize() - 1)); + delete[] (PROPSHEETPAGE*)m_psh.ppsp; + m_psh.ppsp = ppsp; + ppsp += m_pages.GetSize() - 1; + + // copy processed PROPSHEETPAGE struct to end + memcpy(ppsp, &(pPage->m_psp), sizeof(pPage->m_psp)); +// pPage->PreProcessPageTemplate((PROPSHEETPAGE&)*ppsp, IsWizard()); + HPROPSHEETPAGE hPSP = CreatePropertySheetPage((PROPSHEETPAGE*)ppsp); + ATLASSERT(hPSP != NULL); + + // Tray and add it + if (!SendMessage(PSM_ADDPAGE, 0, (LPARAM)hPSP)) + { + DestroyPropertySheetPage(hPSP); + ATLASSERT(false); + } + } +} + +// Removes a Page (either before or after we're on the screen) +template <class TBase> +void CPropertySheetT<TBase>::RemovePage(CPropertyPageT<TBase>* pPage) +{ + ATLASSERT(pPage != NULL); + + // Get Index + int nPage = GetPageIndex(pPage); + pPage->m_pSheet = NULL; + ATLASSERT(nPage >= 0); + + RemovePage(nPage); +} + +// Removes a Page (either before or after we're on the screen) +template <class TBase> +void CPropertySheetT<TBase>::RemovePage(int nPage) +{ + // remove the page externally + if (m_hWnd != NULL) + SendMessage(PSM_REMOVEPAGE, nPage); + + // remove the page from internal list + m_pages.RemoveAt(nPage); +} + +// Closes the Property Sheet +template <class TBase> +void CPropertySheetT<TBase>::EndDialog(int nEndID) +{ + m_nDlgRet = nEndID; + + if (m_bModeless) + DestroyWindow(); + else + PostMessage(PSM_PRESSBUTTON, PSBTN_CANCEL); +} + +// Need to handle WM_CLOSE for Modeless Property Sheets +template <class TBase> +LRESULT CPropertySheetT<TBase>::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + if (m_bModeless) + DestroyWindow(); + else + bHandled = false; + + return 0; +} + +// Need to handle SC_CLOSE for Modeless Property Sheets +template <class TBase> +LRESULT CPropertySheetT<TBase>::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + switch (wParam & 0xFFF0) + { + case SC_CLOSE: + if (m_bModeless) + { + SendMessage(WM_CLOSE); + return 0; + } + } + bHandled = false; + return 0; +} + +// Returns number of Pages +template <class TBase> +int CPropertySheetT<TBase>::GetPageCount() const +{ + if (m_hWnd == NULL) + return m_pages.GetSize(); + + return TabCtrl_GetItemCount(GetTabControl()); +} + +// Returns Current Page +template <class TBase> +int CPropertySheetT<TBase>::GetActiveIndex() const +{ + if (m_hWnd == NULL) + return m_psh.nStartPage; + + return TabCtrl_GetCurSel(GetTabControl()); +} + +// Moves to Page +template <class TBase> +bool CPropertySheetT<TBase>::SetActivePage(int nPage) +{ + if (m_hWnd == NULL) + { + m_psh.nStartPage = nPage; + return true; + } + return (bool)SendMessage(PSM_SETCURSEL, nPage); +} + +// Moves to Page +template <class TBase> +bool CPropertySheetT<TBase>::SetActivePage(CPropertyPageT<TBase>* pPage) +{ + ATLASSERT(pPage != NULL); + + int nPage = GetPageIndex(pPage); + ATLASSERT(pPage >= 0); + + return SetActivePage(nPage); +} + +// Gets number of Page +template <class TBase> +int CPropertySheetT<TBase>::GetPageIndex(CPropertyPageT<TBase>* pPage) +{ + ATLASSERT(pPage != NULL); + for (int i = 0; i < GetPageCount(); i++) + { + if (GetPage(i) == pPage) + return i; + } + return -1; // pPage not found +} + +// Get a Page from Array +template <class TBase> +CPropertyPageT<TBase>* CPropertySheetT<TBase>::GetPage(int nPage) const + { return m_pages[nPage]; } + +// Initdialog: Complete creation and setup for modeless etc... +template <class TBase> +LRESULT CPropertySheetT<TBase>::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + // Change tab style if scrolling tabs desired (stacked tabs are default) + if (!m_bStacked) + ((CWindow)GetTabControl()).ModifyStyle(TCS_MULTILINE, TCS_SINGLELINE, 0); + + // For Property Sheets + if (!IsWizard()) + { + // Resize the tab control so the layout is less restrictive + HWND hWndTab = ::GetDlgItem(m_hWnd, AFX_IDC_TAB_CONTROL); + ATLASSERT(hWndTab != NULL); + RECT rcOld; + ::GetWindowRect(hWndTab, &rcOld); + ScreenToClient(&rcOld); + RECT rcNew = {0, 0, 0, 32}; + ::MapDialogRect(m_hWnd, &rcNew); + if (rcNew.bottom < rcNew.bottom) + { + // Move tab control + int cyDiff = (rcOld.bottom - rcOld.top) - rcNew.bottom; + ::SetWindowPos(hWndTab, NULL, 0, 0, rcOld.right - rcOld.left, rcNew.bottom, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + + // Move buttons by similar amount + for (int i = 0; i < _countof(_PropSheetButtons); i++) + { + HWND hWndBtn = ::GetDlgItem(m_hWnd, _PropSheetButtons[i]); + if (hWndBtn != NULL) + { + ::GetWindowRect(hWndBtn, &rcOld); + ScreenToClient(&rcOld); + ::SetWindowPos(hWndBtn, NULL, + rcOld.left, rcOld.top - cyDiff, + 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + // Resize property sheet itself similarly + GetWindowRect(&rcOld); + SetWindowPos(NULL, 0, 0, rcOld.right - rcOld.left, (rcOld.bottom - rcOld.top) - cyDiff, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } + } + + // For Modeless Sheets + if (m_bModeless && !IsWizard()) + { + // Layout property sheet so button area is not accounted for + RECT rcWnd; + GetWindowRect(&rcWnd); + RECT rcBtn; + HWND hWndBtn = ::GetDlgItem(m_hWnd, IDOK); + ATLASSERT(hWndBtn != NULL); + ::GetWindowRect(hWndBtn, &rcBtn); + SetWindowPos(NULL, 0, 0, + rcWnd.right - rcWnd.left, + (rcBtn.top - rcWnd.top) + ::GetSystemMetrics(SM_CYBORDER), + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + + // Remove standard buttons for modeless dialogs + for (int i = 0; i < _countof(_PropSheetButtons); i++) + { + hWndBtn = ::GetDlgItem(m_hWnd, _PropSheetButtons[i]); + if (hWndBtn != NULL) + { + ::ShowWindow(hWndBtn, SW_HIDE); + ::EnableWindow(hWndBtn, FALSE); + } + } + } + + // Center the property sheet relative to the parent window + if (!(GetStyle() & WS_CHILD)) + CenterWindow(); + + // API implementation probably needs this message + bHandled = FALSE; + return 1; +} + +// Gets the return code for DoModal +template <class TBase> +LRESULT CPropertySheetT<TBase>::OnEndCode(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) +{ + // API implementation probably needs this message + bHandled = FALSE; + m_nDlgRet = wID; + return 0; +} + + +// Are we a wizard? +template <class TBase> +bool CPropertySheetT<TBase>::IsWizard() const + { return ((m_psh.dwFlags & PSH_WIZARD) != 0); } + +// Return HWND of Tab Control +template <class TBase> +HWND CPropertySheetT<TBase>::GetTabControl() const + { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0); } + +// Press Button on Property Sheet +template <class TBase> +bool CPropertySheetT<TBase>::PressButton(int nButton) + { ATLASSERT(::IsWindow(m_hWnd)); return ::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0) ? true : false; } + +// Get the Active Page +template <class TBase> +CPropertyPageT<TBase>* CPropertySheetT<TBase>::GetActivePage() const + { return GetPage(GetActiveIndex()); } + +// Change the Title +template <class TBase> +void CPropertySheetT<TBase>::SetTitle(LPCTSTR lpszText, UINT nStyle) +{ + ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid + + // Set Internal State + if(m_szCaption && _tcslen(m_szCaption) < _tcslen(lpszText)) + { + delete[] m_szCaption; + m_szCaption = NULL; + } + + if(!m_szCaption) + m_szCaption = new TCHAR[_tcslen(lpszText) + 1]; + + _tcscpy(m_szCaption, lpszText); + m_psh.pszCaption = m_szCaption; + + // Set the options + m_psh.dwFlags &= ~PSH_PROPTITLE; + m_psh.dwFlags |= nStyle; + + if (m_hWnd != NULL) + { + // set external state + SendMessage(PSM_SETTITLE, nStyle, (LPARAM)lpszText); + } +} + +// Make us a Wizard +template <class TBase> +void CPropertySheetT<TBase>::SetWizardMode() + { m_psh.dwFlags |= PSH_WIZARD; } + +template <class TBase> +void CPropertySheetT<TBase>::SetHelp(bool bHelp) +{ + if(bHelp) + m_psh.dwFlags |= PSH_HASHELP; + else + m_psh.dwFlags &= ~(PSH_HASHELP); +} + +// Set Text of Finish Button +template <class TBase> +void CPropertySheetT<TBase>::SetFinishText(LPCTSTR lpszText) + { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText); } + +// Choose which buttons to have in Wizard +template <class TBase> +void CPropertySheetT<TBase>::SetWizardButtons(DWORD dwFlags) + { ATLASSERT(::IsWindow(m_hWnd)); ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags); } + +// Stacked Tabs +template <class TBase> +void CPropertySheetT<TBase>::EnableStackedTabs(BOOL bStacked) + { m_bStacked = bStacked; } + +typedef CPropertySheetT<CWindow> CPropertySheet; +typedef CPropertyPageT<CWindow> CPropertyPage; + +#endif // !defined(AFX_PROPERTYPAGE_H__1508DAF4_7AD1_11D3_BF96_0020182B97FC__INCLUDED_) |