961 lines
26 KiB
C
961 lines
26 KiB
C
|
// Win32++ Version 7.2
|
||
|
// Released: 5th AUgust 2011
|
||
|
//
|
||
|
// David Nash
|
||
|
// email: dnash@bigpond.net.au
|
||
|
// url: https://sourceforge.net/projects/win32-framework
|
||
|
//
|
||
|
//
|
||
|
// Copyright (c) 2005-2011 David Nash
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to
|
||
|
// any person obtaining a copy of this software and
|
||
|
// associated documentation files (the "Software"),
|
||
|
// to deal in the Software without restriction, including
|
||
|
// without limitation the rights to use, copy, modify,
|
||
|
// merge, publish, distribute, sublicense, and/or sell
|
||
|
// copies of the Software, and to permit persons to whom
|
||
|
// the Software is furnished to do so, subject to the
|
||
|
// following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice
|
||
|
// shall be included in all copies or substantial portions
|
||
|
// of the Software.
|
||
|
//
|
||
|
// 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 AUTHORS OR COPYRIGHT HOLDERS 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.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////
|
||
|
// propertysheet.h
|
||
|
// Declaration of the following classes:
|
||
|
// CPropertyPage and CPropertySheet
|
||
|
|
||
|
// These classes add support for property sheets to Win32++. A property sheet
|
||
|
// will have one or more property pages. These pages are much like dialogs
|
||
|
// which are presented within a tabbed dialog or within a wizard. The data
|
||
|
// on a property page can be validated before the next page is presented.
|
||
|
// Property sheets have three modes of use: Modal, Modeless, and Wizard.
|
||
|
//
|
||
|
// Refer to the PropertySheet demo program for an example of how propert sheets
|
||
|
// can be used.
|
||
|
|
||
|
|
||
|
#ifndef _WIN32XX_PROPERTYSHEET_H_
|
||
|
#define _WIN32XX_PROPERTYSHEET_H_
|
||
|
|
||
|
#include "dialog.h"
|
||
|
|
||
|
#define ID_APPLY_NOW 0x3021
|
||
|
#define ID_WIZBACK 0x3023
|
||
|
#define ID_WIZNEXT 0x3024
|
||
|
#define ID_WIZFINISH 0x3025
|
||
|
#define ID_HELP 0xE146
|
||
|
|
||
|
#ifndef PROPSHEETHEADER_V1_SIZE
|
||
|
#define PROPSHEETHEADER_V1_SIZE 40
|
||
|
#endif
|
||
|
|
||
|
namespace Win32xx
|
||
|
{
|
||
|
class CPropertyPage;
|
||
|
typedef Shared_Ptr<CPropertyPage> PropertyPagePtr;
|
||
|
|
||
|
class CPropertyPage : public CWnd
|
||
|
{
|
||
|
public:
|
||
|
CPropertyPage (UINT nIDTemplate, LPCTSTR szTitle = NULL);
|
||
|
virtual ~CPropertyPage() {}
|
||
|
|
||
|
virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
virtual INT_PTR DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
virtual int OnApply();
|
||
|
virtual void OnCancel();
|
||
|
virtual void OnHelp();
|
||
|
virtual BOOL OnInitDialog();
|
||
|
virtual BOOL OnKillActive();
|
||
|
virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);
|
||
|
virtual int OnOK();
|
||
|
virtual BOOL OnQueryCancel();
|
||
|
virtual BOOL OnQuerySiblings(WPARAM wParam, LPARAM lParam);
|
||
|
virtual int OnSetActive();
|
||
|
virtual int OnWizardBack();
|
||
|
virtual INT_PTR OnWizardFinish();
|
||
|
virtual int OnWizardNext();
|
||
|
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||
|
|
||
|
static UINT CALLBACK StaticPropSheetPageProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp);
|
||
|
static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
void CancelToClose() const;
|
||
|
PROPSHEETPAGE GetPSP() const {return m_PSP;}
|
||
|
BOOL IsButtonEnabled(int iButton) const;
|
||
|
LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) const;
|
||
|
void SetModified(BOOL bChanged) const;
|
||
|
void SetTitle(LPCTSTR szTitle);
|
||
|
void SetWizardButtons(DWORD dwFlags) const;
|
||
|
|
||
|
protected:
|
||
|
PROPSHEETPAGE m_PSP;
|
||
|
|
||
|
private:
|
||
|
CPropertyPage(const CPropertyPage&); // Disable copy construction
|
||
|
CPropertyPage& operator = (const CPropertyPage&); // Disable assignment operator
|
||
|
|
||
|
tString m_Title;
|
||
|
};
|
||
|
|
||
|
class CPropertySheet : public CWnd
|
||
|
{
|
||
|
public:
|
||
|
CPropertySheet(UINT nIDCaption, CWnd* pParent = NULL);
|
||
|
CPropertySheet(LPCTSTR pszCaption = NULL, CWnd* pParent = NULL);
|
||
|
virtual ~CPropertySheet() {}
|
||
|
|
||
|
// Operations
|
||
|
virtual CPropertyPage* AddPage(CPropertyPage* pPage);
|
||
|
virtual HWND Create(CWnd* pParent = 0);
|
||
|
virtual INT_PTR CreatePropertySheet(LPCPROPSHEETHEADER ppsph);
|
||
|
virtual void DestroyButton(int iButton);
|
||
|
virtual void Destroy();
|
||
|
virtual int DoModal();
|
||
|
virtual void RemovePage(CPropertyPage* pPage);
|
||
|
|
||
|
// State functions
|
||
|
BOOL IsModeless() const;
|
||
|
BOOL IsWizard() const;
|
||
|
|
||
|
//Attributes
|
||
|
CPropertyPage* GetActivePage() const;
|
||
|
int GetPageCount() const;
|
||
|
int GetPageIndex(CPropertyPage* pPage) const;
|
||
|
HWND GetTabControl() const;
|
||
|
virtual BOOL SetActivePage(int nPage);
|
||
|
virtual BOOL SetActivePage(CPropertyPage* pPage);
|
||
|
virtual void SetIcon(UINT idIcon);
|
||
|
virtual void SetTitle(LPCTSTR szTitle);
|
||
|
virtual void SetWizardMode(BOOL bWizard);
|
||
|
|
||
|
protected:
|
||
|
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
||
|
virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
private:
|
||
|
CPropertySheet(const CPropertySheet&); // Disable copy construction
|
||
|
CPropertySheet& operator = (const CPropertySheet&); // Disable assignment operator
|
||
|
void BuildPageArray();
|
||
|
static void CALLBACK Callback(HWND hwnd, UINT uMsg, LPARAM lParam);
|
||
|
|
||
|
tString m_Title;
|
||
|
std::vector<PropertyPagePtr> m_vPages; // vector of CPropertyPage
|
||
|
std::vector<PROPSHEETPAGE> m_vPSP; // vector of PROPSHEETPAGE
|
||
|
BOOL m_bInitialUpdate;
|
||
|
PROPSHEETHEADER m_PSH;
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||
|
|
||
|
namespace Win32xx
|
||
|
{
|
||
|
|
||
|
//////////////////////////////////////////
|
||
|
// Definitions for the CPropertyPage class
|
||
|
//
|
||
|
inline CPropertyPage::CPropertyPage(UINT nIDTemplate, LPCTSTR szTitle /* = NULL*/)
|
||
|
{
|
||
|
ZeroMemory(&m_PSP, sizeof(PROPSHEETPAGE));
|
||
|
SetTitle(szTitle);
|
||
|
|
||
|
m_PSP.dwSize = sizeof(PROPSHEETPAGE);
|
||
|
m_PSP.dwFlags |= PSP_USECALLBACK;
|
||
|
m_PSP.hInstance = GetApp()->GetResourceHandle();
|
||
|
m_PSP.pszTemplate = MAKEINTRESOURCE(nIDTemplate);
|
||
|
m_PSP.pszTitle = m_Title.c_str();
|
||
|
m_PSP.pfnDlgProc = (DLGPROC)CPropertyPage::StaticDialogProc;
|
||
|
m_PSP.lParam = (LPARAM)this;
|
||
|
m_PSP.pfnCallback = CPropertyPage::StaticPropSheetPageProc;
|
||
|
}
|
||
|
|
||
|
inline void CPropertyPage::CancelToClose() const
|
||
|
// Disables the Cancel button and changes the text of the OK button to "Close."
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
SendMessage(PSM_CANCELTOCLOSE, 0L, 0L);
|
||
|
}
|
||
|
|
||
|
|
||
|
inline INT_PTR CPropertyPage::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
// Override this function in your class derrived from CPropertyPage if you wish to handle messages
|
||
|
// A typical function might look like this:
|
||
|
|
||
|
// switch (uMsg)
|
||
|
// {
|
||
|
// case MESSAGE1: // Some Win32 API message
|
||
|
// OnMessage1(); // A user defined function
|
||
|
// break; // Also do default processing
|
||
|
// case MESSAGE2:
|
||
|
// OnMessage2();
|
||
|
// return x; // Don't do default processing, but instead return
|
||
|
// // a value recommended by the Win32 API documentation
|
||
|
// }
|
||
|
|
||
|
// Always pass unhandled messages on to DialogProcDefault
|
||
|
return DialogProcDefault(uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
inline INT_PTR CPropertyPage::DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
// All DialogProc functions should pass unhandled messages to this function
|
||
|
{
|
||
|
LRESULT lr = 0L;
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case UWM_CLEANUPTEMPS:
|
||
|
{
|
||
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||
|
pTLSData->vTmpWnds.clear();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_INITDIALOG:
|
||
|
return OnInitDialog();
|
||
|
|
||
|
case PSM_QUERYSIBLINGS:
|
||
|
return (BOOL)OnQuerySiblings(wParam, lParam);
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
{
|
||
|
// Refelect this message if it's from a control
|
||
|
CWnd* pWnd = GetApp()->GetCWndFromMap((HWND)lParam);
|
||
|
if (pWnd != NULL)
|
||
|
lr = pWnd->OnCommand(wParam, lParam);
|
||
|
|
||
|
// Handle user commands
|
||
|
if (!lr)
|
||
|
lr = OnCommand(wParam, lParam);
|
||
|
|
||
|
if (lr) return 0L;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_NOTIFY:
|
||
|
{
|
||
|
// Do Notification reflection if it came from a CWnd object
|
||
|
HWND hwndFrom = ((LPNMHDR)lParam)->hwndFrom;
|
||
|
CWnd* pWndFrom = GetApp()->GetCWndFromMap(hwndFrom);
|
||
|
|
||
|
if (pWndFrom != NULL)
|
||
|
lr = pWndFrom->OnNotifyReflect(wParam, lParam);
|
||
|
else
|
||
|
{
|
||
|
// Some controls (eg ListView) have child windows.
|
||
|
// Reflect those notifications too.
|
||
|
CWnd* pWndFromParent = GetApp()->GetCWndFromMap(::GetParent(hwndFrom));
|
||
|
if (pWndFromParent != NULL)
|
||
|
lr = pWndFromParent->OnNotifyReflect(wParam, lParam);
|
||
|
}
|
||
|
|
||
|
// Handle user notifications
|
||
|
if (!lr) lr = OnNotify(wParam, lParam);
|
||
|
|
||
|
// Set the return code for notifications
|
||
|
if (IsWindow())
|
||
|
SetWindowLongPtr(DWLP_MSGRESULT, (LONG_PTR)lr);
|
||
|
|
||
|
return (BOOL)lr;
|
||
|
}
|
||
|
|
||
|
case WM_PAINT:
|
||
|
{
|
||
|
if (::GetUpdateRect(m_hWnd, NULL, FALSE))
|
||
|
{
|
||
|
CPaintDC dc(this);
|
||
|
OnDraw(&dc);
|
||
|
}
|
||
|
else
|
||
|
// RedrawWindow can require repainting without an update rect
|
||
|
{
|
||
|
CClientDC dc(this);
|
||
|
OnDraw(&dc);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case WM_ERASEBKGND:
|
||
|
{
|
||
|
CDC dc((HDC)wParam);
|
||
|
BOOL bResult = OnEraseBkgnd(&dc);
|
||
|
dc.Detach();
|
||
|
if (bResult) return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// A set of messages to be reflected back to the control that generated them
|
||
|
case WM_CTLCOLORBTN:
|
||
|
case WM_CTLCOLOREDIT:
|
||
|
case WM_CTLCOLORDLG:
|
||
|
case WM_CTLCOLORLISTBOX:
|
||
|
case WM_CTLCOLORSCROLLBAR:
|
||
|
case WM_CTLCOLORSTATIC:
|
||
|
case WM_DRAWITEM:
|
||
|
case WM_MEASUREITEM:
|
||
|
case WM_DELETEITEM:
|
||
|
case WM_COMPAREITEM:
|
||
|
case WM_CHARTOITEM:
|
||
|
case WM_VKEYTOITEM:
|
||
|
case WM_HSCROLL:
|
||
|
case WM_VSCROLL:
|
||
|
case WM_PARENTNOTIFY:
|
||
|
return MessageReflect(m_hWnd, uMsg, wParam, lParam);
|
||
|
|
||
|
} // switch(uMsg)
|
||
|
return FALSE;
|
||
|
|
||
|
} // INT_PTR CALLBACK CPropertyPage::DialogProc(...)
|
||
|
|
||
|
inline BOOL CPropertyPage::IsButtonEnabled(int iButton) const
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
return GetParent()->GetDlgItem(iButton)->IsWindowEnabled();
|
||
|
}
|
||
|
|
||
|
inline int CPropertyPage::OnApply()
|
||
|
{
|
||
|
// This function is called for each page when the Apply button is pressed
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
// The possible return values are:
|
||
|
// PSNRET_NOERROR. The changes made to this page are valid and have been applied
|
||
|
// PSNRET_INVALID. The property sheet will not be destroyed, and focus will be returned to this page.
|
||
|
// PSNRET_INVALID_NOCHANGEPAGE. The property sheet will not be destroyed, and focus will be returned;
|
||
|
|
||
|
return PSNRET_NOERROR;
|
||
|
}
|
||
|
|
||
|
inline void CPropertyPage::OnCancel()
|
||
|
{
|
||
|
// This function is called for each page when the Cancel button is pressed
|
||
|
// Override this function in your derived class if required.
|
||
|
}
|
||
|
|
||
|
inline void CPropertyPage::OnHelp()
|
||
|
{
|
||
|
// This function is called in response to the PSN_HELP notification.
|
||
|
SendMessage(m_hWnd, WM_COMMAND, ID_HELP, 0L);
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertyPage::OnQueryCancel()
|
||
|
{
|
||
|
// Called when the cancel button is pressed, and before the cancel has taken place
|
||
|
// Returns TRUE to prevent the cancel operation, or FALSE to allow it.
|
||
|
|
||
|
return FALSE; // Allow cancel to proceed
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertyPage::OnQuerySiblings(WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
UNREFERENCED_PARAMETER(wParam);
|
||
|
UNREFERENCED_PARAMETER(lParam);
|
||
|
|
||
|
// Responds to a query request from the Property Sheet.
|
||
|
// The values for wParam and lParam are the ones set by
|
||
|
// the CPropertySheet::QuerySiblings call
|
||
|
|
||
|
// return FALSE to allow other siblings to be queried, or
|
||
|
// return TRUE to stop query at this page.
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertyPage::OnInitDialog()
|
||
|
{
|
||
|
// Called when the property page is created
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
return TRUE; // Pass Keyboard control to handle in WPARAM
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertyPage::OnKillActive()
|
||
|
{
|
||
|
// This is called in response to a PSN_KILLACTIVE notification, which
|
||
|
// is sent whenever the OK or Apply button is pressed.
|
||
|
// It provides an opportunity to validate the page contents before it's closed.
|
||
|
// Return TRUE to prevent the page from losing the activation, or FALSE to allow it.
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
inline int CPropertyPage::OnOK()
|
||
|
{
|
||
|
// Called for each page when the OK button is pressed
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
// The possible return values are:
|
||
|
// PSNRET_NOERROR. The changes made to this page are valid and have been applied
|
||
|
// PSNRET_INVALID. The property sheet will not be destroyed, and focus will be returned to this page.
|
||
|
// PSNRET_INVALID_NOCHANGEPAGE. The property sheet will not be destroyed, and focus will be returned;
|
||
|
|
||
|
return PSNRET_NOERROR;
|
||
|
}
|
||
|
|
||
|
inline LRESULT CPropertyPage::OnNotify(WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
UNREFERENCED_PARAMETER(wParam);
|
||
|
|
||
|
LPPSHNOTIFY pNotify = (LPPSHNOTIFY)lParam;
|
||
|
switch(pNotify->hdr.code)
|
||
|
{
|
||
|
case PSN_SETACTIVE:
|
||
|
return OnSetActive();
|
||
|
case PSN_KILLACTIVE:
|
||
|
return OnKillActive();
|
||
|
case PSN_APPLY:
|
||
|
if (pNotify->lParam)
|
||
|
return OnOK();
|
||
|
else
|
||
|
return OnApply();
|
||
|
case PSN_RESET:
|
||
|
OnCancel();
|
||
|
return FALSE;
|
||
|
case PSN_QUERYCANCEL:
|
||
|
return OnQueryCancel();
|
||
|
case PSN_WIZNEXT:
|
||
|
return OnWizardNext();
|
||
|
case PSN_WIZBACK:
|
||
|
return OnWizardBack();
|
||
|
case PSN_WIZFINISH:
|
||
|
return OnWizardFinish();
|
||
|
case PSN_HELP:
|
||
|
OnHelp();
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
inline int CPropertyPage::OnSetActive()
|
||
|
{
|
||
|
// Called when a page becomes active
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
// Returns zero to accept the activation, or -1 to activate the next or the previous page (depending
|
||
|
// on whether the user clicked the Next or Back button). To set the activation to a particular page,
|
||
|
// return the resource identifier of the page.
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
inline int CPropertyPage::OnWizardBack()
|
||
|
{
|
||
|
// This function is called when the Back button is pressed on a wizard page
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
// Returns 0 to allow the wizard to go to the previous page. Returns -1 to prevent the wizard
|
||
|
// from changing pages. To display a particular page, return its dialog resource identifier.
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
inline INT_PTR CPropertyPage::OnWizardFinish()
|
||
|
{
|
||
|
// This function is called when the Finish button is pressed on a wizard page
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
// Return Value:
|
||
|
// Return non-zero to prevent the wizard from finishing.
|
||
|
// Version 5.80. and later. Return a window handle to prevent the wizard from finishing. The wizard will set the focus to that window. The window must be owned by the wizard page.
|
||
|
// Return 0 to allow the wizard to finish.
|
||
|
|
||
|
return 0; // Allow wizard to finish
|
||
|
}
|
||
|
|
||
|
inline int CPropertyPage::OnWizardNext()
|
||
|
{
|
||
|
// This function is called when the Next button is pressed on a wizard page
|
||
|
// Override this function in your derived class if required.
|
||
|
|
||
|
// Return 0 to allow the wizard to go to the next page. Return -1 to prevent the wizard from
|
||
|
// changing pages. To display a particular page, return its dialog resource identifier.
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertyPage::PreTranslateMessage(MSG* pMsg)
|
||
|
{
|
||
|
// allow the tab control to translate keyboard input
|
||
|
if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
|
||
|
(pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))
|
||
|
{
|
||
|
CWnd* pWndParent = GetParent();
|
||
|
if (pWndParent->SendMessage(PSM_ISDIALOGMESSAGE, 0L, (LPARAM)pMsg))
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// allow the dialog to translate keyboard input
|
||
|
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
|
||
|
{
|
||
|
if (IsDialogMessage(pMsg))
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return CWnd::PreTranslateMessage(pMsg);
|
||
|
}
|
||
|
|
||
|
inline LRESULT CPropertyPage::QuerySiblings(WPARAM wParam, LPARAM lParam) const
|
||
|
{
|
||
|
// Sent to a property sheet, which then forwards the message to each of its pages.
|
||
|
// Set wParam and lParam to values you want passed to the property pages.
|
||
|
// Returns the nonzero value from a page in the property sheet, or zero if no page returns a nonzero value.
|
||
|
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
return GetParent()->SendMessage(PSM_QUERYSIBLINGS, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
inline void CPropertyPage::SetModified(BOOL bChanged) const
|
||
|
{
|
||
|
// The property sheet will enable the Apply button if bChanged is TRUE.
|
||
|
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
|
||
|
if (bChanged)
|
||
|
GetParent()->SendMessage(PSM_CHANGED, (WPARAM)m_hWnd, 0L);
|
||
|
else
|
||
|
GetParent()->SendMessage(PSM_UNCHANGED, (WPARAM)m_hWnd, 0L);
|
||
|
}
|
||
|
|
||
|
inline void CPropertyPage::SetTitle(LPCTSTR szTitle)
|
||
|
{
|
||
|
if (szTitle)
|
||
|
{
|
||
|
m_Title = szTitle;
|
||
|
m_PSP.dwFlags |= PSP_USETITLE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_Title.erase();
|
||
|
m_PSP.dwFlags &= ~PSP_USETITLE;
|
||
|
}
|
||
|
|
||
|
m_PSP.pszTitle = m_Title.c_str();
|
||
|
}
|
||
|
|
||
|
inline void CPropertyPage::SetWizardButtons(DWORD dwFlags) const
|
||
|
{
|
||
|
// dwFlags: A value that specifies which wizard buttons are enabled. You can combine one or more of the following flags.
|
||
|
// PSWIZB_BACK Enable the Back button. If this flag is not set, the Back button is displayed as disabled.
|
||
|
// PSWIZB_DISABLEDFINISH Display a disabled Finish button.
|
||
|
// PSWIZB_FINISH Display an enabled Finish button.
|
||
|
// PSWIZB_NEXT Enable the Next button. If this flag is not set, the Next button is displayed as disabled.
|
||
|
|
||
|
assert (::IsWindow(m_hWnd));
|
||
|
PropSheet_SetWizButtons(::GetParent(m_hWnd), dwFlags);
|
||
|
}
|
||
|
|
||
|
inline UINT CALLBACK CPropertyPage::StaticPropSheetPageProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
|
||
|
{
|
||
|
assert( GetApp() );
|
||
|
UNREFERENCED_PARAMETER(hwnd);
|
||
|
|
||
|
// Note: the hwnd is always NULL
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case PSPCB_CREATE:
|
||
|
{
|
||
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||
|
assert(pTLSData);
|
||
|
|
||
|
// Store the CPropertyPage pointer in Thread Local Storage
|
||
|
pTLSData->pCWnd = (CWnd*)ppsp->lParam;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
inline INT_PTR CALLBACK CPropertyPage::StaticDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
assert( GetApp() );
|
||
|
|
||
|
// Find matching CWnd pointer for this HWND
|
||
|
CPropertyPage* pPage = (CPropertyPage*)GetApp()->GetCWndFromMap(hwndDlg);
|
||
|
if (0 == pPage)
|
||
|
{
|
||
|
// matching CWnd pointer not found, so add it to HWNDMap now
|
||
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||
|
pPage = (CPropertyPage*)pTLSData->pCWnd;
|
||
|
|
||
|
// Set the hWnd members and call DialogProc for this message
|
||
|
pPage->m_hWnd = hwndDlg;
|
||
|
pPage->AddToMap();
|
||
|
}
|
||
|
|
||
|
return pPage->DialogProc(uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////
|
||
|
// Definitions for the CPropertySheet class
|
||
|
//
|
||
|
inline CPropertySheet::CPropertySheet(UINT nIDCaption, CWnd* pParent /* = NULL*/)
|
||
|
{
|
||
|
ZeroMemory(&m_PSH, sizeof (PROPSHEETHEADER));
|
||
|
SetTitle(LoadString(nIDCaption));
|
||
|
m_bInitialUpdate = FALSE;
|
||
|
|
||
|
#ifdef _WIN32_WCE
|
||
|
m_PSH.dwSize = sizeof(PROPSHEETHEADER);
|
||
|
#else
|
||
|
if (GetComCtlVersion() >= 471)
|
||
|
m_PSH.dwSize = sizeof(PROPSHEETHEADER);
|
||
|
else
|
||
|
m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;
|
||
|
#endif
|
||
|
|
||
|
m_PSH.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
|
||
|
m_PSH.hwndParent = pParent? pParent->GetHwnd() : 0;
|
||
|
m_PSH.hInstance = GetApp()->GetInstanceHandle();
|
||
|
m_PSH.pfnCallback = (PFNPROPSHEETCALLBACK)CPropertySheet::Callback;
|
||
|
}
|
||
|
|
||
|
inline CPropertySheet::CPropertySheet(LPCTSTR pszCaption /*= NULL*/, CWnd* pParent /* = NULL*/)
|
||
|
{
|
||
|
ZeroMemory(&m_PSH, sizeof (PROPSHEETHEADER));
|
||
|
SetTitle(pszCaption);
|
||
|
m_bInitialUpdate = FALSE;
|
||
|
|
||
|
#ifdef _WIN32_WCE
|
||
|
m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;
|
||
|
#else
|
||
|
if (GetComCtlVersion() >= 471)
|
||
|
m_PSH.dwSize = sizeof(PROPSHEETHEADER);
|
||
|
else
|
||
|
m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;
|
||
|
#endif
|
||
|
|
||
|
m_PSH.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
|
||
|
m_PSH.hwndParent = pParent? pParent->GetHwnd() : 0;;
|
||
|
m_PSH.hInstance = GetApp()->GetInstanceHandle();
|
||
|
m_PSH.pfnCallback = (PFNPROPSHEETCALLBACK)CPropertySheet::Callback;
|
||
|
}
|
||
|
|
||
|
inline CPropertyPage* CPropertySheet::AddPage(CPropertyPage* pPage)
|
||
|
// Adds a Property Page to the Property Sheet
|
||
|
{
|
||
|
assert(NULL != pPage);
|
||
|
|
||
|
m_vPages.push_back(PropertyPagePtr(pPage));
|
||
|
|
||
|
if (m_hWnd)
|
||
|
{
|
||
|
// property sheet already exists, so add page to it
|
||
|
PROPSHEETPAGE psp = pPage->GetPSP();
|
||
|
HPROPSHEETPAGE hpsp = ::CreatePropertySheetPage(&psp);
|
||
|
PropSheet_AddPage(m_hWnd, hpsp);
|
||
|
}
|
||
|
|
||
|
m_PSH.nPages = (int)m_vPages.size();
|
||
|
|
||
|
return pPage;
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::BuildPageArray()
|
||
|
// Builds the PROPSHEETPAGE array
|
||
|
{
|
||
|
m_vPSP.clear();
|
||
|
std::vector<PropertyPagePtr>::iterator iter;
|
||
|
for (iter = m_vPages.begin(); iter < m_vPages.end(); ++iter)
|
||
|
m_vPSP.push_back((*iter)->GetPSP());
|
||
|
|
||
|
PROPSHEETPAGE* pPSPArray = &m_vPSP.front(); // Array of PROPSHEETPAGE
|
||
|
m_PSH.ppsp = pPSPArray;
|
||
|
}
|
||
|
|
||
|
inline void CALLBACK CPropertySheet::Callback(HWND hwnd, UINT uMsg, LPARAM lParam)
|
||
|
{
|
||
|
assert( GetApp() );
|
||
|
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
//called before the dialog is created, hwnd = NULL, lParam points to dialog resource
|
||
|
case PSCB_PRECREATE:
|
||
|
{
|
||
|
LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;
|
||
|
|
||
|
if(!(lpTemplate->style & WS_SYSMENU))
|
||
|
{
|
||
|
lpTemplate->style |= WS_SYSMENU;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
//called after the dialog is created
|
||
|
case PSCB_INITIALIZED:
|
||
|
{
|
||
|
// Retrieve pointer to CWnd object from Thread Local Storage
|
||
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
||
|
assert(pTLSData);
|
||
|
|
||
|
CPropertySheet* w = (CPropertySheet*)pTLSData->pCWnd;
|
||
|
assert(w);
|
||
|
|
||
|
w->Attach(hwnd);
|
||
|
w->OnCreate();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
inline HWND CPropertySheet::Create(CWnd* pParent /*= 0*/)
|
||
|
// Creates a modeless Property Sheet
|
||
|
{
|
||
|
assert( GetApp() );
|
||
|
|
||
|
if (pParent)
|
||
|
{
|
||
|
m_PSH.hwndParent = pParent->GetHwnd();
|
||
|
}
|
||
|
|
||
|
BuildPageArray();
|
||
|
PROPSHEETPAGE* pPSPArray = &m_vPSP.front();
|
||
|
m_PSH.ppsp = pPSPArray;
|
||
|
|
||
|
// Create a modeless Property Sheet
|
||
|
m_PSH.dwFlags &= ~PSH_WIZARD;
|
||
|
m_PSH.dwFlags |= PSH_MODELESS;
|
||
|
HWND hWnd = (HWND)CreatePropertySheet(&m_PSH);
|
||
|
|
||
|
return hWnd;
|
||
|
}
|
||
|
|
||
|
inline INT_PTR CPropertySheet::CreatePropertySheet(LPCPROPSHEETHEADER ppsph)
|
||
|
{
|
||
|
assert( GetApp() );
|
||
|
|
||
|
INT_PTR ipResult = 0;
|
||
|
|
||
|
// Only one window per CWnd instance allowed
|
||
|
assert(!::IsWindow(m_hWnd));
|
||
|
|
||
|
// Ensure this thread has the TLS index set
|
||
|
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
||
|
|
||
|
// Store the 'this' pointer in Thread Local Storage
|
||
|
pTLSData->pCWnd = this;
|
||
|
|
||
|
// Create the property sheet
|
||
|
ipResult = PropertySheet(ppsph);
|
||
|
|
||
|
return ipResult;
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::DestroyButton(int IDButton)
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
|
||
|
HWND hwndButton = ::GetDlgItem(m_hWnd, IDButton);
|
||
|
if (hwndButton != NULL)
|
||
|
{
|
||
|
// Hide and disable the button
|
||
|
::ShowWindow(hwndButton, SW_HIDE);
|
||
|
::EnableWindow(hwndButton, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::Destroy()
|
||
|
{
|
||
|
CWnd::Destroy();
|
||
|
m_vPages.clear();
|
||
|
}
|
||
|
|
||
|
inline int CPropertySheet::DoModal()
|
||
|
{
|
||
|
assert( GetApp() );
|
||
|
|
||
|
BuildPageArray();
|
||
|
PROPSHEETPAGE* pPSPArray = &m_vPSP.front();
|
||
|
m_PSH.ppsp = pPSPArray;
|
||
|
|
||
|
// Create the Property Sheet
|
||
|
int nResult = (int)CreatePropertySheet(&m_PSH);
|
||
|
|
||
|
m_vPages.clear();
|
||
|
|
||
|
return nResult;
|
||
|
}
|
||
|
|
||
|
inline CPropertyPage* CPropertySheet::GetActivePage() const
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
|
||
|
CPropertyPage* pPage = NULL;
|
||
|
if (m_hWnd != NULL)
|
||
|
{
|
||
|
HWND hPage = (HWND)SendMessage(PSM_GETCURRENTPAGEHWND, 0L, 0L);
|
||
|
pPage = (CPropertyPage*)FromHandle(hPage);
|
||
|
}
|
||
|
|
||
|
return pPage;
|
||
|
}
|
||
|
|
||
|
inline int CPropertySheet::GetPageCount() const
|
||
|
// Returns the number of Property Pages in this Property Sheet
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
return (int)m_vPages.size();
|
||
|
}
|
||
|
|
||
|
inline int CPropertySheet::GetPageIndex(CPropertyPage* pPage) const
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
|
||
|
for (int i = 0; i < GetPageCount(); i++)
|
||
|
{
|
||
|
if (m_vPages[i].get() == pPage)
|
||
|
return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
inline HWND CPropertySheet::GetTabControl() const
|
||
|
// Returns the handle to the Property Sheet's tab control
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
return (HWND)SendMessage(PSM_GETTABCONTROL, 0L, 0L);
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertySheet::IsModeless() const
|
||
|
{
|
||
|
return (m_PSH.dwFlags & PSH_MODELESS);
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertySheet::IsWizard() const
|
||
|
{
|
||
|
return (m_PSH.dwFlags & PSH_WIZARD);
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::RemovePage(CPropertyPage* pPage)
|
||
|
// Removes a Property Page from the Property Sheet
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
|
||
|
int nPage = GetPageIndex(pPage);
|
||
|
if (m_hWnd != NULL)
|
||
|
SendMessage(m_hWnd, PSM_REMOVEPAGE, nPage, 0L);
|
||
|
|
||
|
m_vPages.erase(m_vPages.begin() + nPage, m_vPages.begin() + nPage+1);
|
||
|
m_PSH.nPages = (int)m_vPages.size();
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertySheet::PreTranslateMessage(MSG* pMsg)
|
||
|
{
|
||
|
// allow sheet to translate Ctrl+Tab, Shift+Ctrl+Tab, Ctrl+PageUp, and Ctrl+PageDown
|
||
|
if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
|
||
|
(pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))
|
||
|
{
|
||
|
if (SendMessage(PSM_ISDIALOGMESSAGE, 0L, (LPARAM)pMsg))
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// allow the dialog to translate keyboard input
|
||
|
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
|
||
|
{
|
||
|
return GetActivePage()->PreTranslateMessage(pMsg);
|
||
|
}
|
||
|
|
||
|
return CWnd::PreTranslateMessage(pMsg);
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertySheet::SetActivePage(int nPage)
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
return (BOOL)SendMessage(m_hWnd, PSM_SETCURSEL, nPage, 0L);
|
||
|
}
|
||
|
|
||
|
inline BOOL CPropertySheet::SetActivePage(CPropertyPage* pPage)
|
||
|
{
|
||
|
assert(::IsWindow(m_hWnd));
|
||
|
int nPage = GetPageIndex(pPage);
|
||
|
if ((nPage >= 0))
|
||
|
return SetActivePage(nPage);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::SetIcon(UINT idIcon)
|
||
|
{
|
||
|
m_PSH.pszIcon = MAKEINTRESOURCE(idIcon);
|
||
|
m_PSH.dwFlags |= PSH_USEICONID;
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::SetTitle(LPCTSTR szTitle)
|
||
|
{
|
||
|
if (szTitle)
|
||
|
m_Title = szTitle;
|
||
|
else
|
||
|
m_Title.erase();
|
||
|
|
||
|
m_PSH.pszCaption = m_Title.c_str();
|
||
|
}
|
||
|
|
||
|
inline void CPropertySheet::SetWizardMode(BOOL bWizard)
|
||
|
{
|
||
|
if (bWizard)
|
||
|
m_PSH.dwFlags |= PSH_WIZARD;
|
||
|
else
|
||
|
m_PSH.dwFlags &= ~PSH_WIZARD;
|
||
|
}
|
||
|
|
||
|
inline LRESULT CPropertySheet::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
|
||
|
case WM_WINDOWPOSCHANGED:
|
||
|
{
|
||
|
LPWINDOWPOS lpWinPos = (LPWINDOWPOS)lParam;
|
||
|
if (lpWinPos->flags & SWP_SHOWWINDOW)
|
||
|
{
|
||
|
if (!m_bInitialUpdate)
|
||
|
// The first window positioning with the window visible
|
||
|
OnInitialUpdate();
|
||
|
m_bInitialUpdate = TRUE;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
m_bInitialUpdate = FALSE;
|
||
|
break;
|
||
|
|
||
|
case WM_SYSCOMMAND:
|
||
|
if ((SC_CLOSE == wParam) && (m_PSH.dwFlags & PSH_MODELESS))
|
||
|
{
|
||
|
Destroy();
|
||
|
return 0L;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// pass unhandled messages on for default processing
|
||
|
return CWnd::WndProcDefault(uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // _WIN32XX_PROPERTYSHEET_H_
|