473 lines
15 KiB
C++
473 lines
15 KiB
C++
#ifndef __VWINDOW_HPP
|
|
#define __VWINDOW_HPP
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
#include "vApplication.hpp"
|
|
#endif
|
|
|
|
#include "vRTTI.hpp"
|
|
#include <commctrl.h>
|
|
|
|
class VWindow;
|
|
|
|
typedef struct tagVWCL_ENUM_PARAM
|
|
{
|
|
UINT nMessageOrID;
|
|
LPVOID lpInData; // Normally input pointer
|
|
LPVOID lpOutData; // Normally output pointer
|
|
|
|
} VWCL_ENUM_PARAM;
|
|
|
|
// <VDOC<CLASS=VWindow><BASE=VRTTI><DESC=Base window object encapsulation><FAMILY=VWCL Core><AUTHOR=Todd Osborne (todd.osborne@poboxes.com)>VDOC>
|
|
class VWindow : public VRTTI
|
|
{
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
friend class VApplication;
|
|
#endif
|
|
|
|
public:
|
|
VWindow(UINT nRTTI = VWCL_RTTI_WINDOW)
|
|
: VRTTI(nRTTI)
|
|
{
|
|
m_hWindow = NULL;
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
m_lpfnOldWndProc = NULL;
|
|
#endif
|
|
}
|
|
|
|
virtual ~VWindow()
|
|
{
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
DestroyWindow();
|
|
#endif
|
|
}
|
|
|
|
// Returns HWND
|
|
operator HWND ()
|
|
{ return GetSafeWindow(); }
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Attach an existing Windows window to a VWindow object, subclassing it routing messages through the object
|
|
BOOL Attach(HWND hWnd);
|
|
#else
|
|
// Simply assign hWnd to this object, but do not subclass it
|
|
HWND Attach(HWND hWnd)
|
|
{ assert(hWnd && ::IsWindow(hWnd)); m_hWindow = hWnd; return m_hWindow; }
|
|
#endif
|
|
|
|
// Center a window on screen
|
|
void CenterWindow()
|
|
{
|
|
assert(GetSafeWindow());
|
|
|
|
// Center a window on screen
|
|
RECT r;
|
|
GetWindowRect(&r);
|
|
SetWindowPos( m_hWindow,
|
|
HWND_TOP,
|
|
((GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2),
|
|
((GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2),
|
|
0,
|
|
0,
|
|
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
}
|
|
|
|
void CheckDlgButton(int nID, UINT nCheck = BST_CHECKED)
|
|
{ assert(GetSafeWindow()); ::CheckDlgButton(m_hWindow, nID, nCheck); }
|
|
|
|
BOOL ClientToScreen(LPPOINT lpPoint)
|
|
{ assert(GetSafeWindow() && lpPoint); return ::ClientToScreen(m_hWindow, lpPoint); }
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Lowest common denominator of window creation functions
|
|
BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, LPRECT lpRect, HWND hWndParent, UINT nIDorMenu, BOOL bDontCallPostCreateWindow = FALSE);
|
|
#endif
|
|
|
|
virtual BOOL DestroyWindow()
|
|
{ if ( GetSafeWindow() ) return ::DestroyWindow(m_hWindow); return FALSE; }
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Detach an existing Windows window with an associated VWindow object, removing any subclassing, and restore to previous state
|
|
void Detach();
|
|
#else
|
|
// Simply remove the window handle from object
|
|
void Detach()
|
|
{ m_hWindow = NULL; }
|
|
#endif
|
|
|
|
BOOL EnableWindow(BOOL bEnable = TRUE)
|
|
{ assert(GetSafeWindow()); return ::EnableWindow(m_hWindow, bEnable); }
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Enter a message loop
|
|
WPARAM EnterMessageLoop(HACCEL hAccel)
|
|
{
|
|
MSG msg;
|
|
|
|
// Enter message loop
|
|
while ( GetMessage(&msg, NULL, 0, 0) != 0 )
|
|
{
|
|
if ( hAccel == NULL || hAccel && TranslateAccelerator(m_hWindow, hAccel, &msg) == 0 )
|
|
HandleMessage(&msg);
|
|
}
|
|
|
|
return msg.wParam;
|
|
}
|
|
#endif
|
|
|
|
// Find a child window when the class is known
|
|
HWND FindChildWindowByClass(LPCTSTR lpszClass)
|
|
{
|
|
assert(lpszClass && lstrlen(lpszClass));
|
|
|
|
// Iterate child windows
|
|
VWCL_ENUM_PARAM EnumParam = {ENUM_FIND_CHILD_BY_CLASS, (LPVOID)lpszClass, NULL};
|
|
EnumChildWindows(m_hWindow, (WNDENUMPROC)EnumChildWndProc, (LPARAM)&EnumParam);
|
|
|
|
// EnumParam.lpOutData will be non-NULL if a handle was found
|
|
if ( EnumParam.lpOutData )
|
|
return (HWND)EnumParam.lpOutData;
|
|
return NULL;
|
|
}
|
|
|
|
HWND GetDlgItem(int nID)
|
|
{ assert(GetSafeWindow()); return ::GetDlgItem(m_hWindow, nID); }
|
|
|
|
UINT GetDlgItemInt(int nID, LPBOOL lpTranslated = NULL, BOOL bSigned = FALSE)
|
|
{ assert(GetSafeWindow()); return ::GetDlgItemInt(m_hWindow, nID, lpTranslated, bSigned); }
|
|
|
|
int GetDlgItemText(int nID, LPTSTR lpszBuffer, int nSizeOfBuffer)
|
|
{ assert(GetSafeWindow()); return ::GetDlgItemText(m_hWindow, nID, lpszBuffer, nSizeOfBuffer); }
|
|
|
|
HFONT GetFont()
|
|
{ assert(GetSafeWindow()); return (HFONT)::SendMessage(m_hWindow, WM_GETFONT, 0, 0); }
|
|
|
|
HMENU GetMenu()
|
|
{ assert(GetSafeWindow()); return ::GetMenu(m_hWindow); }
|
|
|
|
HWND GetParent()
|
|
{ assert(GetSafeWindow()); return ::GetParent(m_hWindow); }
|
|
|
|
HWND GetSafeWindow()
|
|
{ return (IsWindow()) ? m_hWindow : NULL; }
|
|
|
|
LONG GetStyle()
|
|
{ return GetWindowLong(GWL_STYLE); }
|
|
|
|
LONG GetWindowLong(int nIndex)
|
|
{ assert(GetSafeWindow()); return ::GetWindowLong(m_hWindow, nIndex); }
|
|
|
|
#ifdef WIN32
|
|
BOOL GetClientRect(LPRECT lpRect)
|
|
{ assert(lpRect && GetSafeWindow()); return ::GetClientRect(m_hWindow, lpRect); }
|
|
|
|
BOOL GetWindowRect(LPRECT lpRect)
|
|
{ assert(lpRect && GetSafeWindow()); return ::GetWindowRect(m_hWindow, lpRect); }
|
|
#else
|
|
void GetClientRect(LPRECT lpRect)
|
|
{ assert(lpRect && GetSafeWindow()); ::GetClientRect(m_hWindow, lpRect); }
|
|
|
|
void GetWindowRect(LPRECT lpRect)
|
|
{ assert(lpRect && GetSafeWindow()); ::GetWindowRect(m_hWindow, lpRect); }
|
|
#endif
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Called from a VWindow class that implements a message loop
|
|
virtual void HandleMessage(LPMSG lpMsg)
|
|
{
|
|
assert(lpMsg);
|
|
|
|
// Called from a VWindow derived class that implements a message loop
|
|
if ( !PreTranslateMessage(lpMsg) )
|
|
{
|
|
TranslateMessage(lpMsg);
|
|
DispatchMessage(lpMsg);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void InvalidateRect(LPRECT lpRect = NULL, BOOL bErase = TRUE)
|
|
{ assert(GetSafeWindow()); ::InvalidateRect(m_hWindow, lpRect, bErase); }
|
|
|
|
// Return TRUE if the object is a VDialog type (That is, a VDialogXXX class, not all VDialog derivitives)
|
|
BOOL IsVDialogType()
|
|
{
|
|
switch ( RTTI() )
|
|
{
|
|
// Top level window is a dialog
|
|
case VWindow::VWCL_RTTI_DIALOG:
|
|
case VWindow::VWCL_RTTI_MAIN_DIALOG:
|
|
case VWindow::VWCL_RTTI_SPLIT_MAIN_DIALOG:
|
|
case VWindow::VWCL_RTTI_SPLIT_DIALOG:
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
UINT IsDlgButtonChecked(int nID)
|
|
{ assert(GetSafeWindow()); return ::IsDlgButtonChecked(m_hWindow, nID); }
|
|
|
|
BOOL IsIconic()
|
|
{ assert(GetSafeWindow()); return ::IsIconic(m_hWindow); }
|
|
|
|
BOOL IsWindow()
|
|
{ return (m_hWindow) ? ::IsWindow(m_hWindow) : FALSE; }
|
|
|
|
BOOL IsWindowEnabled()
|
|
{ assert(GetSafeWindow()); return ::IsWindowEnabled(m_hWindow); }
|
|
|
|
BOOL IsWindowVisible()
|
|
{ assert(GetSafeWindow()); return ::IsWindowVisible(m_hWindow); }
|
|
|
|
int MessageBox(LPCTSTR lpcszText, LPCTSTR lpcszCaption, UINT nType = MB_OK)
|
|
{ int nResult; HWND hWndFocus = GetFocus(); nResult = ::MessageBox(m_hWindow, lpcszText, lpcszCaption, nType); if ( hWndFocus ) ::SetFocus(hWndFocus); return nResult; }
|
|
|
|
int MessageBox(LPCTSTR lpcszText, UINT nType = MB_OK)
|
|
{ return MessageBox(lpcszText, VGetAppTitle(), nType); }
|
|
|
|
// If VString.hpp is included, implement these functions
|
|
#ifdef __VSTRING_HPP
|
|
int MessageBox(UINT nStringID, UINT nType = MB_OK, HINSTANCE hResource = NULL)
|
|
{ return MessageBox(VString(nStringID, hResource), nType); }
|
|
|
|
int MessageBox(UINT nStringID, LPCTSTR lpcszCaption, UINT nType = MB_OK, HINSTANCE hResource = NULL)
|
|
{ return MessageBox(VString(nStringID, hResource), lpcszCaption, nType); }
|
|
|
|
int MessageBox(UINT nStringID, UINT nCaptionID, UINT nType, HINSTANCE hResource = NULL)
|
|
{ return MessageBox(VString(nStringID, hResource), VString(nCaptionID, hResource), nType); }
|
|
#endif
|
|
|
|
BOOL MoveWindow(int x, int y, int cx, int cy, BOOL bRedraw = TRUE)
|
|
{ assert(GetSafeWindow()); return ::MoveWindow(m_hWindow, x, y, cx, cy, bRedraw); }
|
|
|
|
BOOL MoveWindow(LPRECT lpRect, BOOL bRedraw = TRUE)
|
|
{ assert(lpRect); assert(GetSafeWindow()); return ::MoveWindow(m_hWindow, lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, bRedraw); }
|
|
|
|
BOOL PostMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
|
|
{ assert(GetSafeWindow()); return ::PostMessage(m_hWindow, nMessage, wParam, lParam); }
|
|
|
|
// Override to allow user to call IsDialogMessage() or perform other
|
|
// processing before message is dispatched. Return TRUE if message was processed
|
|
virtual BOOL PreTranslateMessage(LPMSG lpMsg)
|
|
{ return FALSE; }
|
|
|
|
BOOL ReleaseCapture()
|
|
{ assert(GetSafeWindow()); return ::ReleaseCapture(); }
|
|
|
|
BOOL ScreenToClient(LPPOINT lpPoint)
|
|
{ assert(GetSafeWindow() && lpPoint); return ::ScreenToClient(m_hWindow, lpPoint); }
|
|
|
|
LRESULT SendDlgItemMessage(UINT nID, UINT nMessage, WPARAM wParam, LPARAM lParam)
|
|
{ assert(GetSafeWindow()); return ::SendDlgItemMessage(m_hWindow, nID, nMessage, wParam, lParam); }
|
|
|
|
LRESULT SendMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
|
|
{ assert(GetSafeWindow()); return ::SendMessage(m_hWindow, nMessage, wParam, lParam); }
|
|
|
|
HWND SetCapture()
|
|
{ assert(GetSafeWindow()); return ::SetCapture(m_hWindow); }
|
|
|
|
BOOL SetDlgItemInt(int nID, UINT nValue, BOOL bSigned = FALSE)
|
|
{ assert(GetSafeWindow()); return ::SetDlgItemInt(m_hWindow, nID, nValue, bSigned); }
|
|
|
|
#ifdef WIN32
|
|
BOOL SetDlgItemText(int nID, LPCTSTR lpszText)
|
|
{ assert(GetSafeWindow()); return ::SetDlgItemText(m_hWindow, nID, lpszText); }
|
|
#else
|
|
void SetDlgItemText(int nID, LPCTSTR lpszText)
|
|
{ assert(GetSafeWindow()); ::SetDlgItemText(m_hWindow, nID, lpszText); }
|
|
#endif
|
|
|
|
HWND SetFocus()
|
|
{ assert(GetSafeWindow()); return ::SetFocus(m_hWindow); }
|
|
|
|
BOOL SetMenu(HMENU hMenu)
|
|
{ assert(GetSafeWindow()); return ::SetMenu(m_hWindow, hMenu); }
|
|
|
|
LONG SetStyle(DWORD dwStyle)
|
|
{ return SetWindowLong(GWL_STYLE, dwStyle); }
|
|
|
|
LONG SetWindowLong(int nIndex, LONG nNewLong)
|
|
{ assert(GetSafeWindow()); return ::SetWindowLong(m_hWindow, nIndex, nNewLong); }
|
|
|
|
#if defined(_WIN64)
|
|
LONG_PTR SetWindowLongPtr(int nIndex, LONG_PTR nNewLongPtr)
|
|
{ assert(GetSafeWindow()); return ::SetWindowLongPtr(m_hWindow, nIndex, nNewLongPtr); }
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
BOOL SetWindowText(LPCTSTR lpszText)
|
|
{ assert(GetSafeWindow()); return ::SetWindowText(m_hWindow, lpszText); }
|
|
#else
|
|
void SetWindowText(LPCTSTR lpszText)
|
|
{ assert(GetSafeWindow()); ::SetWindowText(m_hWindow, lpszText); }
|
|
#endif
|
|
|
|
BOOL ShowWindow(int nCmdShow = SW_SHOWNORMAL)
|
|
{ assert(GetSafeWindow()); return ::ShowWindow(m_hWindow, nCmdShow); }
|
|
|
|
#ifdef WIN32
|
|
BOOL UpdateWindow()
|
|
{ assert(GetSafeWindow()); return ::UpdateWindow(m_hWindow); }
|
|
#else
|
|
void UpdateWindow()
|
|
{ assert(GetSafeWindow()); ::UpdateWindow(m_hWindow); }
|
|
#endif
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Window procedure
|
|
virtual LRESULT WindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam);
|
|
#endif
|
|
|
|
// Fast Runtime Type Information supported on ALL compilers
|
|
// Implemented int VRTTI base class for VWindow and derived classes
|
|
enum { VWCL_RTTI_UNKNOWN,
|
|
VWCL_RTTI_BUTTON,
|
|
VWCL_RTTI_CHECKBOX,
|
|
VWCL_RTTI_COMBOBOX,
|
|
VWCL_RTTI_DIALOG,
|
|
VWCL_RTTI_EDIT,
|
|
VWCL_RTTI_GROUPBOX,
|
|
VWCL_RTTI_LISTBOX,
|
|
VWCL_RTTI_LISTVIEW_CTRL,
|
|
VWCL_RTTI_MAIN_DIALOG,
|
|
VWCL_RTTI_MAIN_WINDOW,
|
|
VWCL_RTTI_PAGE_SETUP_DIALOG,
|
|
VWCL_RTTI_PRINT_DIALOG,
|
|
VWCL_RTTI_PRINT_SETUP_DIALOG,
|
|
VWCL_RTTI_RADIO_BUTTON,
|
|
VWCL_RTTI_SCROLLBAR,
|
|
VWCL_RTTI_SPLASH_WINDOW,
|
|
VWCL_RTTI_SPLIT_MAIN_DIALOG,
|
|
VWCL_RTTI_SPLIT_MAIN_WINDOW,
|
|
VWCL_RTTI_SPLIT_WINDOW,
|
|
VWCL_RTTI_SS_TREE_CTRL,
|
|
VWCL_RTTI_STATIC,
|
|
VWCL_RTTI_STATUSBAR_CTRL,
|
|
VWCL_RTTI_TAB_CTRL,
|
|
VWCL_RTTI_TAB_CTRL_WINDOW,
|
|
VWCL_RTTI_TOOLBAR_CTRL,
|
|
VWCL_RTTI_TREE_CTRL,
|
|
VWCL_RTTI_WINDOW,
|
|
VWCL_RTTI_SPLIT_DIALOG,
|
|
VWCL_RTTI_SHELL_TAB_WINDOW,
|
|
VWCL_RTTI_MINI_WINDOW,
|
|
VWCL_RTTI_DIRECTORY_TREE_CTRL,
|
|
VWCL_RTTI_XTREE_CTRL,
|
|
VWCL_RTTI_XEDIT,
|
|
VWCL_RTTI_SS_INDEXED_TREE_CTRL,
|
|
VWCL_RTTI_PROPERTY_SHEET,
|
|
VWCL_RTTI_PROPERTY_PAGE,
|
|
VWCL_RTTI_PROGRESS_CTRL,
|
|
};
|
|
|
|
// Handle this object encapsulates
|
|
HWND m_hWindow;
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// For subclased windows, the old Window Procedure
|
|
WNDPROC m_lpfnOldWndProc;
|
|
#endif
|
|
|
|
// Enumeration is VWLC_ENUM_PARAM::nMessageOrID in EnumChildWndProc() call
|
|
enum { ENUM_FIND_CHILD_BY_CLASS = WM_USER + 4096,
|
|
};
|
|
|
|
protected:
|
|
// Enumerate child windows (for various reasons). LPARAM is a pointer to a VWLC_ENUM_PARAM struct
|
|
static BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam)
|
|
{
|
|
VWCL_ENUM_PARAM* pEnumParam = (VWCL_ENUM_PARAM*)lParam;
|
|
assert(pEnumParam);
|
|
|
|
// Determine what we need to do
|
|
switch ( pEnumParam->nMessageOrID )
|
|
{
|
|
case WM_DESTROY:
|
|
::DestroyWindow(hWnd);
|
|
break;
|
|
|
|
case ENUM_FIND_CHILD_BY_CLASS:
|
|
{
|
|
// pEnumParam->lpInData is a string
|
|
LPCTSTR lpszFind = (LPCTSTR)pEnumParam->lpInData;
|
|
assert(lpszFind && lstrlen(lpszFind));
|
|
|
|
// Get the class of this window
|
|
TCHAR szClass[50];
|
|
::GetClassName(hWnd, szClass, sizeof(szClass)/sizeof(TCHAR));
|
|
|
|
// Did we find a hit?
|
|
if ( lstrcmpi(szClass, lpszFind) == 0 )
|
|
{
|
|
// Set the hWnd into the pEnumParam->lpOutData field and quit
|
|
pEnumParam->lpOutData = hWnd;
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifndef VWCL_WRAP_WINDOWS_ONLY
|
|
// Handler for WM_CLOSE. Default implementation calls DestroyWindow()
|
|
virtual void OnClose()
|
|
{ DestroyWindow(); }
|
|
|
|
// Handler for WM_COMMAND. Return 0 if message was handled
|
|
virtual int OnCommand(WORD wNotifyCode, WORD wID, HWND hWndControl)
|
|
{ return 1; }
|
|
|
|
// Handler for WM_CREATE. Return 0 if message was handled, -1 to stop window creation
|
|
virtual int OnCreate(LPCREATESTRUCT lpCreateStruct)
|
|
{ return 1; }
|
|
|
|
// Handler for WM_DESTROY. Return 0 if message was handled
|
|
virtual int OnDestroy()
|
|
{ return 1; }
|
|
|
|
// Handler for WM_PAINT. Return 0 if message was handled
|
|
virtual int OnPaint()
|
|
{ return 1; }
|
|
|
|
// Handler for WM_SIZE. Return 0 if message was handled
|
|
virtual int OnSize(WPARAM wFlags, int cx, int cy)
|
|
{ return 1; }
|
|
|
|
// Handler for WM_NOTIFY. Return 0 if message was handled
|
|
virtual LRESULT OnNotify(int nIDControl, LPNMHDR lpNMHDR)
|
|
{ return 1; }
|
|
|
|
// Support for reflected WM_NOTIFY messages. Derived class must
|
|
// return 0 is message was handled, -1 if handled and parent should
|
|
// NOT be notified, or 1 if message was not handled and parent should
|
|
// be notified. If -1 if returned, derived classes must also set
|
|
// the lCommonControlResult to the return value expected by the common control
|
|
virtual int OnReflectedNotify(LPNMHDR lpNMHDR, LPARAM& lCommonControlResult)
|
|
{ return 1; }
|
|
|
|
// Called after Attach() returns successfully
|
|
virtual void PostAttachWindow()
|
|
{;}
|
|
|
|
// Called after Create() returns successfully. Returning FALSE from
|
|
// this override will cause the window to be destroyed
|
|
virtual BOOL PostCreateWindow()
|
|
{ return TRUE;}
|
|
|
|
// Called after WM_DESTROY completes. Safe to do a delete this on VWindow object
|
|
virtual void PostNcDestroy()
|
|
{;}
|
|
|
|
// Custom virtual functions for common overrides and default returns
|
|
virtual BOOL PreCreateWindow(LPCREATESTRUCT lpCreateStruct)
|
|
{ return TRUE; }
|
|
#endif
|
|
};
|
|
|
|
#endif // __VWINDOW_HPP
|