6aa9bd0f77
Now with some actual consensus on what the updater will do!
877 lines
24 KiB
C++
877 lines
24 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.
|
|
//
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
// dialog.h
|
|
// Declaration of the CDialog class
|
|
|
|
// CDialog adds support for dialogs to Win32++. Dialogs are specialised
|
|
// windows which are a parent window for common controls. Common controls
|
|
// are special window types such as buttons, edit controls, tree views,
|
|
// list views, static text etc.
|
|
|
|
// The layout of a dialog is typically defined in a resource script file
|
|
// (often Resource.rc). While this script file can be constructed manually,
|
|
// it is often created using a resource editor. If your compiler doesn't
|
|
// include a resource editor, you might find ResEdit useful. It is a free
|
|
// resource editor available for download at:
|
|
// http://www.resedit.net/
|
|
|
|
// CDialog supports modal and modeless dialogs. It also supports the creation
|
|
// of dialogs defined in a resource script file, as well as those defined in
|
|
// a dialog template.
|
|
|
|
// Use the Dialog generic program as the starting point for your own dialog
|
|
// applications.
|
|
// The DlgSubclass sample demonstrates how to use subclassing to customise
|
|
// the behaviour of common controls in a dialog.
|
|
|
|
|
|
#ifndef _WIN32XX_DIALOG_H_
|
|
#define _WIN32XX_DIALOG_H_
|
|
|
|
#include "wincore.h"
|
|
|
|
#ifndef SWP_NOCOPYBITS
|
|
#define SWP_NOCOPYBITS 0x0100
|
|
#endif
|
|
|
|
namespace Win32xx
|
|
{
|
|
|
|
class CDialog : public CWnd
|
|
{
|
|
public:
|
|
CDialog(UINT nResID, CWnd* pParent = NULL);
|
|
CDialog(LPCTSTR lpszResName, CWnd* pParent = NULL);
|
|
CDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent = NULL);
|
|
virtual ~CDialog();
|
|
|
|
// You probably won't need to override these functions
|
|
virtual void AttachItem(int nID, CWnd& Wnd);
|
|
virtual HWND Create(CWnd* pParent = NULL);
|
|
virtual INT_PTR DoModal();
|
|
virtual HWND DoModeless();
|
|
virtual void SetDlgParent(CWnd* pParent);
|
|
BOOL IsModal() const { return m_IsModal; }
|
|
BOOL IsIndirect() const { return (NULL != m_lpTemplate); }
|
|
|
|
protected:
|
|
// These are the functions you might wish to override
|
|
virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
virtual INT_PTR DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
virtual void EndDialog(INT_PTR nResult);
|
|
virtual void OnCancel();
|
|
virtual BOOL OnInitDialog();
|
|
virtual void OnOK();
|
|
virtual BOOL PreTranslateMessage(MSG* pMsg);
|
|
|
|
// Can't override these functions
|
|
static INT_PTR CALLBACK StaticDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
#ifndef _WIN32_WCE
|
|
static LRESULT CALLBACK StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam);
|
|
#endif
|
|
|
|
private:
|
|
CDialog(const CDialog&); // Disable copy construction
|
|
CDialog& operator = (const CDialog&); // Disable assignment operator
|
|
|
|
BOOL m_IsModal; // a flag for modal dialogs
|
|
LPCTSTR m_lpszResName; // the resource name for the dialog
|
|
LPCDLGTEMPLATE m_lpTemplate; // the dialog template for indirect dialogs
|
|
HWND m_hParent; // handle to the dialogs's parent window
|
|
};
|
|
|
|
|
|
#ifndef _WIN32_WCE
|
|
|
|
//////////////////////////////////////
|
|
// Declaration of the CResizer class
|
|
//
|
|
// The CResizer class can be used to rearrange a dialog's child
|
|
// windows when the dialog is resized.
|
|
|
|
// To use CResizer, follow the following steps:
|
|
// 1) Use Initialize to specify the dialog's CWnd, and min and max size.
|
|
// 3) Use AddChild for each child window
|
|
// 4) Call HandleMessage from within DialogProc.
|
|
//
|
|
|
|
// Resize Dialog Styles
|
|
#define RD_STRETCH_WIDTH 0x0001 // The item has a variable width
|
|
#define RD_STRETCH_HEIGHT 0x0002 // The item has a variable height
|
|
|
|
// Resize Dialog alignments
|
|
enum Alignment { topleft, topright, bottomleft, bottomright };
|
|
|
|
class CResizer
|
|
{
|
|
public:
|
|
CResizer() : m_pParent(0), m_xScrollPos(0), m_yScrollPos(0) {}
|
|
virtual ~CResizer() {}
|
|
|
|
virtual void AddChild(CWnd* pWnd, Alignment corner, DWORD dwStyle);
|
|
virtual void AddChild(HWND hWnd, Alignment corner, DWORD dwStyle);
|
|
virtual void HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
virtual void Initialize(CWnd* pParent, RECT rcMin, RECT rcMax = CRect(0,0,0,0));
|
|
virtual void OnHScroll(WPARAM wParam, LPARAM lParam);
|
|
virtual void OnVScroll(WPARAM wParam, LPARAM lParam);
|
|
virtual void RecalcLayout();
|
|
CRect GetMinRect() const { return m_rcMin; }
|
|
CRect GetMaxRect() const { return m_rcMax; }
|
|
|
|
struct ResizeData
|
|
{
|
|
CRect rcInit;
|
|
CRect rcOld;
|
|
Alignment corner;
|
|
BOOL bFixedWidth;
|
|
BOOL bFixedHeight;
|
|
HWND hWnd;
|
|
};
|
|
|
|
private:
|
|
CWnd* m_pParent;
|
|
std::vector<ResizeData> m_vResizeData;
|
|
|
|
CRect m_rcInit;
|
|
CRect m_rcMin;
|
|
CRect m_rcMax;
|
|
|
|
int m_xScrollPos;
|
|
int m_yScrollPos;
|
|
};
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
namespace Win32xx
|
|
{
|
|
////////////////////////////////////
|
|
// Definitions for the CDialog class
|
|
//
|
|
inline CDialog::CDialog(LPCTSTR lpszResName, CWnd* pParent/* = NULL*/)
|
|
: m_IsModal(TRUE), m_lpszResName(lpszResName), m_lpTemplate(NULL)
|
|
{
|
|
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
|
::InitCommonControls();
|
|
}
|
|
|
|
inline CDialog::CDialog(UINT nResID, CWnd* pParent/* = NULL*/)
|
|
: m_IsModal(TRUE), m_lpszResName(MAKEINTRESOURCE (nResID)), m_lpTemplate(NULL)
|
|
{
|
|
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
|
::InitCommonControls();
|
|
}
|
|
|
|
//For indirect dialogs - created from a dialog box template in memory.
|
|
inline CDialog::CDialog(LPCDLGTEMPLATE lpTemplate, CWnd* pParent/* = NULL*/)
|
|
: m_IsModal(TRUE), m_lpszResName(NULL), m_lpTemplate(lpTemplate)
|
|
{
|
|
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
|
::InitCommonControls();
|
|
}
|
|
|
|
inline CDialog::~CDialog()
|
|
{
|
|
if (m_hWnd != NULL)
|
|
{
|
|
if (IsModal())
|
|
::EndDialog(m_hWnd, 0);
|
|
else
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
inline void CDialog::AttachItem(int nID, CWnd& Wnd)
|
|
// Attach a dialog item to a CWnd
|
|
{
|
|
Wnd.AttachDlgItem(nID, this);
|
|
}
|
|
|
|
inline HWND CDialog::Create(CWnd* pParent /* = NULL */)
|
|
{
|
|
// Allow a dialog to be used as a child window
|
|
|
|
assert(GetApp());
|
|
SetDlgParent(pParent);
|
|
return DoModeless();
|
|
}
|
|
|
|
inline INT_PTR CDialog::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Override this function in your class derrived from CDialog if you wish to handle messages
|
|
// A typical function might look like this:
|
|
|
|
// switch (uMsg)
|
|
// {
|
|
// case MESSAGE1: // Some Windows 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 Windows API documentation
|
|
// }
|
|
|
|
// Always pass unhandled messages on to DialogProcDefault
|
|
return DialogProcDefault(uMsg, wParam, lParam);
|
|
}
|
|
|
|
inline INT_PTR CDialog::DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
// All DialogProc functions should pass unhandled messages to this function
|
|
{
|
|
LRESULT lr = 0;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case UWM_CLEANUPTEMPS:
|
|
{
|
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
|
pTLSData->vTmpWnds.clear();
|
|
}
|
|
break;
|
|
case WM_INITDIALOG:
|
|
{
|
|
// Center the dialog
|
|
CenterWindow();
|
|
}
|
|
return OnInitDialog();
|
|
case WM_COMMAND:
|
|
switch (LOWORD (wParam))
|
|
{
|
|
case IDOK:
|
|
OnOK();
|
|
return TRUE;
|
|
case IDCANCEL:
|
|
OnCancel();
|
|
return TRUE;
|
|
default:
|
|
{
|
|
// 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; // Some commands require default processing
|
|
}
|
|
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 CDialog::DialogProc(...)
|
|
|
|
inline INT_PTR CDialog::DoModal()
|
|
{
|
|
// Create a modal dialog
|
|
// A modal dialog box must be closed by the user before the application continues
|
|
|
|
assert( GetApp() ); // Test if Win32++ has been started
|
|
assert(!::IsWindow(m_hWnd)); // Only one window per CWnd instance allowed
|
|
|
|
INT_PTR nResult = 0;
|
|
|
|
try
|
|
{
|
|
m_IsModal=TRUE;
|
|
|
|
// Ensure this thread has the TLS index set
|
|
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
|
|
|
#ifndef _WIN32_WCE
|
|
BOOL IsHookedHere = FALSE;
|
|
if (NULL == pTLSData->hHook )
|
|
{
|
|
pTLSData->hHook = ::SetWindowsHookEx(WH_MSGFILTER, (HOOKPROC)StaticMsgHook, NULL, ::GetCurrentThreadId());
|
|
IsHookedHere = TRUE;
|
|
}
|
|
#endif
|
|
|
|
HINSTANCE hInstance = GetApp()->GetInstanceHandle();
|
|
pTLSData->pCWnd = this;
|
|
|
|
// Create a modal dialog
|
|
if (IsIndirect())
|
|
nResult = ::DialogBoxIndirect(hInstance, m_lpTemplate, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
|
else
|
|
{
|
|
if (::FindResource(GetApp()->GetResourceHandle(), m_lpszResName, RT_DIALOG))
|
|
hInstance = GetApp()->GetResourceHandle();
|
|
nResult = ::DialogBox(hInstance, m_lpszResName, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
|
}
|
|
|
|
// Tidy up
|
|
m_hWnd = NULL;
|
|
pTLSData->pCWnd = NULL;
|
|
GetApp()->CleanupTemps();
|
|
|
|
#ifndef _WIN32_WCE
|
|
if (IsHookedHere)
|
|
{
|
|
::UnhookWindowsHookEx(pTLSData->hHook);
|
|
pTLSData->hHook = NULL;
|
|
}
|
|
#endif
|
|
|
|
if (nResult == -1)
|
|
throw CWinException(_T("Failed to create modal dialog box"));
|
|
|
|
}
|
|
|
|
catch (const CWinException &e)
|
|
{
|
|
TRACE(_T("\n*** Failed to create dialog ***\n"));
|
|
e.what(); // Display the last error message.
|
|
|
|
// eat the exception (don't rethrow)
|
|
}
|
|
|
|
return nResult;
|
|
}
|
|
|
|
inline HWND CDialog::DoModeless()
|
|
{
|
|
assert( GetApp() ); // Test if Win32++ has been started
|
|
assert(!::IsWindow(m_hWnd)); // Only one window per CWnd instance allowed
|
|
|
|
try
|
|
{
|
|
m_IsModal=FALSE;
|
|
|
|
// Ensure this thread has the TLS index set
|
|
TLSData* pTLSData = GetApp()->SetTlsIndex();
|
|
|
|
// Store the CWnd pointer in Thread Local Storage
|
|
pTLSData->pCWnd = this;
|
|
|
|
HINSTANCE hInstance = GetApp()->GetInstanceHandle();
|
|
|
|
// Create a modeless dialog
|
|
if (IsIndirect())
|
|
m_hWnd = ::CreateDialogIndirect(hInstance, m_lpTemplate, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
|
else
|
|
{
|
|
if (::FindResource(GetApp()->GetResourceHandle(), m_lpszResName, RT_DIALOG))
|
|
hInstance = GetApp()->GetResourceHandle();
|
|
|
|
m_hWnd = ::CreateDialog(hInstance, m_lpszResName, m_hParent, (DLGPROC)CDialog::StaticDialogProc);
|
|
}
|
|
|
|
// Tidy up
|
|
pTLSData->pCWnd = NULL;
|
|
|
|
// Now handle dialog creation failure
|
|
if (!m_hWnd)
|
|
throw CWinException(_T("Failed to create dialog"));
|
|
}
|
|
|
|
catch (const CWinException &e)
|
|
{
|
|
TRACE(_T("\n*** Failed to create dialog ***\n"));
|
|
e.what(); // Display the last error message.
|
|
|
|
// eat the exception (don't rethrow)
|
|
}
|
|
|
|
return m_hWnd;
|
|
}
|
|
|
|
inline void CDialog::EndDialog(INT_PTR nResult)
|
|
{
|
|
assert(::IsWindow(m_hWnd));
|
|
|
|
if (IsModal())
|
|
::EndDialog(m_hWnd, nResult);
|
|
else
|
|
Destroy();
|
|
|
|
m_hWnd = NULL;
|
|
}
|
|
|
|
inline void CDialog::OnCancel()
|
|
{
|
|
// Override to customize OnCancel behaviour
|
|
EndDialog(IDCANCEL);
|
|
}
|
|
|
|
inline BOOL CDialog::OnInitDialog()
|
|
{
|
|
// Called when the dialog is initialized
|
|
// Override it in your derived class to automatically perform tasks
|
|
// The return value is used by WM_INITDIALOG
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
inline void CDialog::OnOK()
|
|
{
|
|
// Override to customize OnOK behaviour
|
|
EndDialog(IDOK);
|
|
}
|
|
|
|
inline BOOL CDialog::PreTranslateMessage(MSG* pMsg)
|
|
{
|
|
// allow the dialog to translate keyboard input
|
|
if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
|
|
{
|
|
// Process dialog keystrokes for modeless dialogs
|
|
if (!IsModal())
|
|
{
|
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
|
if (NULL == pTLSData->hHook)
|
|
{
|
|
if (IsDialogMessage(pMsg))
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// A modal message loop is running so we can't do IsDialogMessage.
|
|
// Avoid having modal dialogs create other windows, because those
|
|
// windows will then use the modal dialog's special message loop.
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline void CDialog::SetDlgParent(CWnd* pParent)
|
|
// Allows the parent of the dialog to be set before the dialog is created
|
|
{
|
|
m_hParent = pParent? pParent->GetHwnd() : NULL;
|
|
}
|
|
|
|
inline INT_PTR CALLBACK CDialog::StaticDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Find the CWnd pointer mapped to this HWND
|
|
CDialog* w = (CDialog*)GetApp()->GetCWndFromMap(hWnd);
|
|
if (0 == w)
|
|
{
|
|
// The HWND wasn't in the map, so add it now
|
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
|
assert(pTLSData);
|
|
|
|
// Retrieve pointer to CWnd object from Thread Local Storage TLS
|
|
w = (CDialog*)pTLSData->pCWnd;
|
|
assert(w);
|
|
pTLSData->pCWnd = NULL;
|
|
|
|
// Store the Window pointer into the HWND map
|
|
w->m_hWnd = hWnd;
|
|
w->AddToMap();
|
|
}
|
|
|
|
return w->DialogProc(uMsg, wParam, lParam);
|
|
|
|
} // INT_PTR CALLBACK CDialog::StaticDialogProc(...)
|
|
|
|
#ifndef _WIN32_WCE
|
|
inline LRESULT CALLBACK CDialog::StaticMsgHook(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Used by Modal Dialogs to PreTranslate Messages
|
|
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());
|
|
|
|
if (nCode == MSGF_DIALOGBOX)
|
|
{
|
|
MSG* lpMsg = (MSG*) lParam;
|
|
|
|
// only pre-translate keyboard events
|
|
if ((lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST))
|
|
{
|
|
for (HWND hWnd = lpMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
|
|
{
|
|
CDialog* pDialog = (CDialog*)GetApp()->GetCWndFromMap(hWnd);
|
|
if (pDialog && (lstrcmp(pDialog->GetClassName(), _T("#32770")) == 0)) // only for dialogs
|
|
{
|
|
pDialog->PreTranslateMessage(lpMsg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ::CallNextHookEx(pTLSData->hHook, nCode, wParam, lParam);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _WIN32_WCE
|
|
|
|
/////////////////////////////////////
|
|
// Definitions for the CResizer class
|
|
//
|
|
|
|
void inline CResizer::AddChild(CWnd* pWnd, Alignment corner, DWORD dwStyle)
|
|
// Adds a child window (usually a dialog control) to the set of windows managed by
|
|
// the Resizer.
|
|
//
|
|
// The alignment corner should be set to the closest corner of the dialog. Allowed
|
|
// values are topleft, topright, bottomleft, and bottomright.
|
|
// Set bFixedWidth to TRUE if the width should be fixed instead of variable.
|
|
// Set bFixedHeight to TRUE if the height should be fixed instead of variable.
|
|
{
|
|
ResizeData rd;
|
|
rd.corner = corner;
|
|
rd.bFixedWidth = !(dwStyle & RD_STRETCH_WIDTH);
|
|
rd.bFixedHeight = !(dwStyle & RD_STRETCH_HEIGHT);
|
|
CRect rcInit = pWnd->GetWindowRect();
|
|
m_pParent->ScreenToClient(rcInit);
|
|
rd.rcInit = rcInit;
|
|
rd.hWnd = pWnd->GetHwnd();
|
|
|
|
m_vResizeData.insert(m_vResizeData.begin(), rd);
|
|
}
|
|
|
|
void inline CResizer::AddChild(HWND hWnd, Alignment corner, DWORD dwStyle)
|
|
// Adds a child window (usually a dialog control) to the set of windows managed by
|
|
// the Resizer.
|
|
{
|
|
AddChild(FromHandle(hWnd), corner, dwStyle);
|
|
}
|
|
|
|
inline void CResizer::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_SIZE:
|
|
RecalcLayout();
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
if (0 == lParam)
|
|
OnHScroll(wParam, lParam);
|
|
break;
|
|
|
|
case WM_VSCROLL:
|
|
if (0 == lParam)
|
|
OnVScroll(wParam, lParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void inline CResizer::Initialize(CWnd* pParent, RECT rcMin, RECT rcMax)
|
|
// Sets up the Resizer by specifying the parent window (usually a dialog),
|
|
// and the minimum and maximum allowed rectangle sizes.
|
|
{
|
|
assert (NULL != pParent);
|
|
|
|
m_pParent = pParent;
|
|
m_rcInit = pParent->GetClientRect();
|
|
m_rcMin = rcMin;
|
|
m_rcMax = rcMax;
|
|
|
|
// Add scroll bar support to the parent window
|
|
DWORD dwStyle = (DWORD)m_pParent->GetClassLongPtr(GCL_STYLE);
|
|
dwStyle |= WS_HSCROLL | WS_VSCROLL;
|
|
m_pParent->SetClassLongPtr(GCL_STYLE, dwStyle);
|
|
}
|
|
|
|
void inline CResizer::OnHScroll(WPARAM wParam, LPARAM /*lParam*/)
|
|
{
|
|
int xNewPos;
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case SB_PAGEUP: // User clicked the scroll bar shaft left of the scroll box.
|
|
xNewPos = m_xScrollPos - 50;
|
|
break;
|
|
|
|
case SB_PAGEDOWN: // User clicked the scroll bar shaft right of the scroll box.
|
|
xNewPos = m_xScrollPos + 50;
|
|
break;
|
|
|
|
case SB_LINEUP: // User clicked the left arrow.
|
|
xNewPos = m_xScrollPos - 5;
|
|
break;
|
|
|
|
case SB_LINEDOWN: // User clicked the right arrow.
|
|
xNewPos = m_xScrollPos + 5;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION: // User dragged the scroll box.
|
|
xNewPos = HIWORD(wParam);
|
|
break;
|
|
|
|
case SB_THUMBTRACK: // User dragging the scroll box.
|
|
xNewPos = HIWORD(wParam);
|
|
break;
|
|
|
|
default:
|
|
xNewPos = m_xScrollPos;
|
|
}
|
|
|
|
// Scroll the window.
|
|
xNewPos = MAX(0, xNewPos);
|
|
xNewPos = MIN( xNewPos, GetMinRect().Width() - m_pParent->GetClientRect().Width() );
|
|
int xDelta = xNewPos - m_xScrollPos;
|
|
m_xScrollPos = xNewPos;
|
|
m_pParent->ScrollWindow(-xDelta, 0, NULL, NULL);
|
|
|
|
// Reset the scroll bar.
|
|
SCROLLINFO si = {0};
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
si.nPos = m_xScrollPos;
|
|
m_pParent->SetScrollInfo(SB_HORZ, si, TRUE);
|
|
}
|
|
|
|
void inline CResizer::OnVScroll(WPARAM wParam, LPARAM /*lParam*/)
|
|
{
|
|
int yNewPos;
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case SB_PAGEUP: // User clicked the scroll bar shaft above the scroll box.
|
|
yNewPos = m_yScrollPos - 50;
|
|
break;
|
|
|
|
case SB_PAGEDOWN: // User clicked the scroll bar shaft below the scroll box.
|
|
yNewPos = m_yScrollPos + 50;
|
|
break;
|
|
|
|
case SB_LINEUP: // User clicked the top arrow.
|
|
yNewPos = m_yScrollPos - 5;
|
|
break;
|
|
|
|
case SB_LINEDOWN: // User clicked the bottom arrow.
|
|
yNewPos = m_yScrollPos + 5;
|
|
break;
|
|
|
|
case SB_THUMBPOSITION: // User dragged the scroll box.
|
|
yNewPos = HIWORD(wParam);
|
|
break;
|
|
|
|
case SB_THUMBTRACK: // User dragging the scroll box.
|
|
yNewPos = HIWORD(wParam);
|
|
break;
|
|
|
|
default:
|
|
yNewPos = m_yScrollPos;
|
|
}
|
|
|
|
// Scroll the window.
|
|
yNewPos = MAX(0, yNewPos);
|
|
yNewPos = MIN( yNewPos, GetMinRect().Height() - m_pParent->GetClientRect().Height() );
|
|
int yDelta = yNewPos - m_yScrollPos;
|
|
m_yScrollPos = yNewPos;
|
|
m_pParent->ScrollWindow(0, -yDelta, NULL, NULL);
|
|
|
|
// Reset the scroll bar.
|
|
SCROLLINFO si = {0};
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
si.nPos = m_yScrollPos;
|
|
m_pParent->SetScrollInfo(SB_VERT, si, TRUE);
|
|
}
|
|
|
|
void inline CResizer::RecalcLayout()
|
|
// Repositions the child windows. Call this function when handling
|
|
// the WM_SIZE message in the parent window.
|
|
{
|
|
assert (m_rcInit.Width() > 0 && m_rcInit.Height() > 0);
|
|
assert (NULL != m_pParent);
|
|
|
|
CRect rcCurrent = m_pParent->GetClientRect();
|
|
|
|
// Adjust the scrolling if required
|
|
m_xScrollPos = MIN(m_xScrollPos, MAX(0, m_rcMin.Width() - rcCurrent.Width() ) );
|
|
m_yScrollPos = MIN(m_yScrollPos, MAX(0, m_rcMin.Height() - rcCurrent.Height()) );
|
|
SCROLLINFO si = {0};
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
|
si.nMax = m_rcMin.Width();
|
|
si.nPage = rcCurrent.Width();
|
|
si.nPos = m_xScrollPos;
|
|
m_pParent->SetScrollInfo(SB_HORZ, si, TRUE);
|
|
si.nMax = m_rcMin.Height();
|
|
si.nPage = rcCurrent.Height();
|
|
si.nPos = m_yScrollPos;
|
|
m_pParent->SetScrollInfo(SB_VERT, si, TRUE);
|
|
|
|
rcCurrent.right = MAX( rcCurrent.Width(), m_rcMin.Width() );
|
|
rcCurrent.bottom = MAX( rcCurrent.Height(), m_rcMin.Height() );
|
|
if (!m_rcMax.IsRectEmpty())
|
|
{
|
|
rcCurrent.right = MIN( rcCurrent.Width(), m_rcMax.Width() );
|
|
rcCurrent.bottom = MIN( rcCurrent.Height(), m_rcMax.Height() );
|
|
}
|
|
|
|
// Declare an iterator to step through the vector
|
|
std::vector<ResizeData>::iterator iter;
|
|
|
|
for (iter = m_vResizeData.begin(); iter < m_vResizeData.end(); ++iter)
|
|
{
|
|
int left = 0;
|
|
int top = 0;
|
|
int width = 0;
|
|
int height = 0;
|
|
|
|
// Calculate the new size and position of the child window
|
|
switch( (*iter).corner )
|
|
{
|
|
case topleft:
|
|
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
|
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
|
left = (*iter).rcInit.left;
|
|
top = (*iter).rcInit.top;
|
|
break;
|
|
case topright:
|
|
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
|
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
|
left = (*iter).rcInit.right - width - m_rcInit.Width() + rcCurrent.Width();
|
|
top = (*iter).rcInit.top;
|
|
break;
|
|
case bottomleft:
|
|
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
|
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
|
left = (*iter).rcInit.left;
|
|
top = (*iter).rcInit.bottom - height - m_rcInit.Height() + rcCurrent.Height();
|
|
break;
|
|
case bottomright:
|
|
width = (*iter).bFixedWidth? (*iter).rcInit.Width() : (*iter).rcInit.Width() - m_rcInit.Width() + rcCurrent.Width();
|
|
height = (*iter).bFixedHeight? (*iter).rcInit.Height() : (*iter).rcInit.Height() - m_rcInit.Height() + rcCurrent.Height();
|
|
left = (*iter).rcInit.right - width - m_rcInit.Width() + rcCurrent.Width();
|
|
top = (*iter).rcInit.bottom - height - m_rcInit.Height() + rcCurrent.Height();
|
|
break;
|
|
}
|
|
|
|
// Position the child window.
|
|
CRect rc(left - m_xScrollPos, top - m_yScrollPos, left + width - m_xScrollPos, top + height - m_yScrollPos);
|
|
if ( rc != (*iter).rcOld)
|
|
{
|
|
CWnd* pWnd = FromHandle((*iter).hWnd);
|
|
CWnd *pWndPrev = pWnd->GetWindow(GW_HWNDPREV); // Trick to maintain the original tab order.
|
|
HWND hWnd = pWndPrev ? pWndPrev->GetHwnd():NULL;
|
|
pWnd->SetWindowPos(hWnd, rc, SWP_NOCOPYBITS);
|
|
(*iter).rcOld = rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // #ifndef _WIN32_WCE
|
|
|
|
} // namespace Win32xx
|
|
|
|
|
|
|
|
#endif // _WIN32XX_DIALOG_H_
|
|
|