summaryrefslogtreecommitdiff
path: root/win32/common/atlprsht.h
diff options
context:
space:
mode:
authorStef Walter <stef@thewalter.net>2003-09-20 07:12:49 +0000
committerStef Walter <stef@thewalter.net>2003-09-20 07:12:49 +0000
commitb49d8ebefe9b10c53a6a09ad564e22111b7b25c6 (patch)
tree1d5dd4abc38170a7bc106dabbc59b915017222f0 /win32/common/atlprsht.h
parent1cda9ebbd62916c7c2136722597a86c583e1ecf6 (diff)
Initial Import
Diffstat (limited to 'win32/common/atlprsht.h')
-rw-r--r--win32/common/atlprsht.h915
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_)