#include
"
stdafx.h
"
#include " ResizableDialog.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////
// CResizableDialog
inline void CResizableDialog::PrivateConstruct()
{
m_bEnableSaveRestore = FALSE;
m_dwGripTempState = 1;
}
CResizableDialog::CResizableDialog()
{
PrivateConstruct();
}
CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd * pParentWnd)
: CCmdUIDialog(nIDTemplate, pParentWnd)
{
PrivateConstruct();
}
CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd * pParentWnd)
: CCmdUIDialog(lpszTemplateName, pParentWnd)
{
PrivateConstruct();
}
CResizableDialog:: ~ CResizableDialog()
{
}
BEGIN_MESSAGE_MAP(CResizableDialog, CCmdUIDialog)
// {{AFX_MSG_MAP(CResizableDialog)
ON_WM_GETMINMAXINFO()
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
// }}AFX_MSG_MAP
END_MESSAGE_MAP()
/////
// CResizableDialog message handlers
int CResizableDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (__super::OnCreate(lpCreateStruct) == -1)
return -1;
// child dialogs don't want resizable border or size grip,
// nor they can handle the min/max size constraints
BOOL bChild = GetStyle() & WS_CHILD;
if (!bChild)
{
// keep client area
CRect rect;
GetClientRect(&rect);
// set resizable style
ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
// adjust size to reflect new style
::AdjustWindowRectEx(&rect, GetStyle(),
::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED|
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION);
// set the initial size as the min track size
SetMinTrackSize(rect.Size());
}
// create and init the size-grip
if (!CreateSizeGrip(!bChild))
return -1;
return 0;
}
void CResizableDialog::OnDestroy()
{
if (m_bEnableSaveRestore)
SaveWindowRect(m_sSection, m_bRectOnly);
// remove child windows
RemoveAllAnchors();
__super::OnDestroy();
}
void CResizableDialog::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
return; // arrangement not needed
if (nType == SIZE_MAXIMIZED)
HideSizeGrip(&m_dwGripTempState);
else
ShowSizeGrip(&m_dwGripTempState);
// update grip and layout
UpdateSizeGrip();
ArrangeLayout();
}
void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR * lpMMI)
{
MinMaxInfo(lpMMI);
}
// NOTE: this must be called after setting the layout
// to have the dialog and its controls displayed properly
void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly)
{
m_sSection = pszSection;
m_bEnableSaveRestore = TRUE;
m_bRectOnly = bRectOnly;
// restore immediately
LoadWindowRect(pszSection, bRectOnly);
}
BOOL CResizableDialog::OnEraseBkgnd(CDC * pDC)
{
// Windows XP doesn't like clipping regions ...try this!
EraseBackground(pDC);
return TRUE;
/* ClipChildren(pDC); // old-method (for safety)
return CDialog::OnEraseBkgnd(pDC);
*/
}
#include " ResizableDialog.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////
// CResizableDialog
inline void CResizableDialog::PrivateConstruct()
{
m_bEnableSaveRestore = FALSE;
m_dwGripTempState = 1;
}
CResizableDialog::CResizableDialog()
{
PrivateConstruct();
}
CResizableDialog::CResizableDialog(UINT nIDTemplate, CWnd * pParentWnd)
: CCmdUIDialog(nIDTemplate, pParentWnd)
{
PrivateConstruct();
}
CResizableDialog::CResizableDialog(LPCTSTR lpszTemplateName, CWnd * pParentWnd)
: CCmdUIDialog(lpszTemplateName, pParentWnd)
{
PrivateConstruct();
}
CResizableDialog:: ~ CResizableDialog()
{
}
BEGIN_MESSAGE_MAP(CResizableDialog, CCmdUIDialog)
// {{AFX_MSG_MAP(CResizableDialog)
ON_WM_GETMINMAXINFO()
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
// }}AFX_MSG_MAP
END_MESSAGE_MAP()
/////
// CResizableDialog message handlers
int CResizableDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (__super::OnCreate(lpCreateStruct) == -1)
return -1;
// child dialogs don't want resizable border or size grip,
// nor they can handle the min/max size constraints
BOOL bChild = GetStyle() & WS_CHILD;
if (!bChild)
{
// keep client area
CRect rect;
GetClientRect(&rect);
// set resizable style
ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
// adjust size to reflect new style
::AdjustWindowRectEx(&rect, GetStyle(),
::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED|
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION);
// set the initial size as the min track size
SetMinTrackSize(rect.Size());
}
// create and init the size-grip
if (!CreateSizeGrip(!bChild))
return -1;
return 0;
}
void CResizableDialog::OnDestroy()
{
if (m_bEnableSaveRestore)
SaveWindowRect(m_sSection, m_bRectOnly);
// remove child windows
RemoveAllAnchors();
__super::OnDestroy();
}
void CResizableDialog::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
return; // arrangement not needed
if (nType == SIZE_MAXIMIZED)
HideSizeGrip(&m_dwGripTempState);
else
ShowSizeGrip(&m_dwGripTempState);
// update grip and layout
UpdateSizeGrip();
ArrangeLayout();
}
void CResizableDialog::OnGetMinMaxInfo(MINMAXINFO FAR * lpMMI)
{
MinMaxInfo(lpMMI);
}
// NOTE: this must be called after setting the layout
// to have the dialog and its controls displayed properly
void CResizableDialog::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly)
{
m_sSection = pszSection;
m_bEnableSaveRestore = TRUE;
m_bRectOnly = bRectOnly;
// restore immediately
LoadWindowRect(pszSection, bRectOnly);
}
BOOL CResizableDialog::OnEraseBkgnd(CDC * pDC)
{
// Windows XP doesn't like clipping regions ...try this!
EraseBackground(pDC);
return TRUE;
/* ClipChildren(pDC); // old-method (for safety)
return CDialog::OnEraseBkgnd(pDC);
*/
}
#if
!defined(AFX_RESIZABLEGRIP_H__INCLUDED_)
#define AFX_RESIZABLEGRIP_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CResizableGrip
{
private:
class CSizeGrip : public CScrollBar
{
public:
CSizeGrip()
{
m_bTransparent = FALSE;
m_bTriangular = FALSE;
m_size.cx = 0;
m_size.cy = 0;
}
void SetTriangularShape(BOOL bEnable);
void SetTransparency(BOOL bActivate);
BOOL IsRTL(); // right-to-left layout support
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
SIZE m_size; // holds grip size
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL m_bTriangular; // triangular shape active
BOOL m_bTransparent; // transparency active
// memory DCs and bitmaps for transparent grip
CDC m_dcGrip, m_dcMask;
CBitmap m_bmGrip, m_bmMask;
};
CSizeGrip m_wndGrip; // grip control
int m_nShowCount; // support for hiding the grip
protected:
// create a size grip, with options
BOOL CreateSizeGrip(BOOL bVisible = TRUE,
BOOL bTriangular = TRUE, BOOL bTransparent = FALSE);
BOOL IsSizeGripVisible(); // TRUE if grip is set to be visible
void SetSizeGripVisibility(BOOL bVisible); // set default visibility
void UpdateSizeGrip(); // update the grip's visibility and position
void ShowSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp show the size grip
void HideSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp hide the size grip
BOOL SetSizeGripBkMode(int nBkMode); // like CDC::SetBkMode
void SetSizeGripShape(BOOL bTriangular);
virtual CWnd* GetResizableWnd() = 0;
public:
CResizableGrip();
virtual ~CResizableGrip();
} ;
#endif // !defined(AFX_RESIZABLEGRIP_H__INCLUDED_)
#define AFX_RESIZABLEGRIP_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CResizableGrip
{
private:
class CSizeGrip : public CScrollBar
{
public:
CSizeGrip()
{
m_bTransparent = FALSE;
m_bTriangular = FALSE;
m_size.cx = 0;
m_size.cy = 0;
}
void SetTriangularShape(BOOL bEnable);
void SetTransparency(BOOL bActivate);
BOOL IsRTL(); // right-to-left layout support
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
SIZE m_size; // holds grip size
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL m_bTriangular; // triangular shape active
BOOL m_bTransparent; // transparency active
// memory DCs and bitmaps for transparent grip
CDC m_dcGrip, m_dcMask;
CBitmap m_bmGrip, m_bmMask;
};
CSizeGrip m_wndGrip; // grip control
int m_nShowCount; // support for hiding the grip
protected:
// create a size grip, with options
BOOL CreateSizeGrip(BOOL bVisible = TRUE,
BOOL bTriangular = TRUE, BOOL bTransparent = FALSE);
BOOL IsSizeGripVisible(); // TRUE if grip is set to be visible
void SetSizeGripVisibility(BOOL bVisible); // set default visibility
void UpdateSizeGrip(); // update the grip's visibility and position
void ShowSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp show the size grip
void HideSizeGrip(DWORD* pStatus, DWORD dwMask = 1); // temp hide the size grip
BOOL SetSizeGripBkMode(int nBkMode); // like CDC::SetBkMode
void SetSizeGripShape(BOOL bTriangular);
virtual CWnd* GetResizableWnd() = 0;
public:
CResizableGrip();
virtual ~CResizableGrip();
} ;
#endif // !defined(AFX_RESIZABLEGRIP_H__INCLUDED_)
#include
"
stdafx.h
"
#include " ResizableGrip.h "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CResizableGrip::CResizableGrip()
{
m_nShowCount = 0;
}
CResizableGrip:: ~ CResizableGrip()
{
}
void CResizableGrip::UpdateSizeGrip()
{
ASSERT(::IsWindow(m_wndGrip.m_hWnd));
// size-grip goes bottom right in the client area
// (any right-to-left adjustment should go here)
RECT rect;
GetResizableWnd()->GetClientRect(&rect);
rect.left = rect.right - m_wndGrip.m_size.cx;
rect.top = rect.bottom - m_wndGrip.m_size.cy;
// must stay below other children
m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION
| (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
}
// pbStatus points to a variable, maintained by the caller, that
// holds its visibility status. Initialize the variable with 1
// to allow to temporarily hide the grip, 0 to allow to
// temporarily show the grip (with respect to the dwMask bit).
// NB: visibility is effective only after an update
void CResizableGrip::ShowSizeGrip(DWORD * pStatus, DWORD dwMask /*= 1*/ )
{
ASSERT(pStatus != NULL);
if (!(*pStatus & dwMask))
{
m_nShowCount++;
(*pStatus) |= dwMask;
}
}
void CResizableGrip::HideSizeGrip(DWORD * pStatus, DWORD dwMask /*= 1*/ )
{
ASSERT(pStatus != NULL);
if (*pStatus & dwMask)
{
m_nShowCount--;
(*pStatus) &= ~dwMask;
}
}
BOOL CResizableGrip::IsSizeGripVisible()
{
// NB: visibility is effective only after an update
return (m_nShowCount > 0);
}
void CResizableGrip::SetSizeGripVisibility(BOOL bVisible)
{
if (bVisible)
m_nShowCount = 1;
else
m_nShowCount = 0;
}
BOOL CResizableGrip::SetSizeGripBkMode( int nBkMode)
{
if (::IsWindow(m_wndGrip.m_hWnd))
{
if (nBkMode == OPAQUE)
m_wndGrip.SetTransparency(FALSE);
else if (nBkMode == TRANSPARENT)
m_wndGrip.SetTransparency(TRUE);
else
return FALSE;
return TRUE;
}
return FALSE;
}
void CResizableGrip::SetSizeGripShape(BOOL bTriangular)
{
m_wndGrip.SetTriangularShape(bTriangular);
}
BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/ ,
BOOL bTriangular /*= TRUE*/ , BOOL bTransparent /*= FALSE*/ )
{
// create grip
CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy);
BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS
| SBS_SIZEGRIP, rect, GetResizableWnd(), 0);
if (bRet)
{
// set options
m_wndGrip.SetTriangularShape(bTriangular);
m_wndGrip.SetTransparency(bTransparent);
SetSizeGripVisibility(bVisible);
// update position
UpdateSizeGrip();
}
return bRet;
}
/////
// CSizeGrip implementation
BOOL CResizableGrip::CSizeGrip::IsRTL()
{
return GetExStyle() & 0x00400000L/*WS_EX_LAYOUTRTL*/;
}
BOOL CResizableGrip::CSizeGrip::PreCreateWindow(CREATESTRUCT & cs)
{
// set window size
m_size.cx = GetSystemMetrics(SM_CXVSCROLL);
m_size.cy = GetSystemMetrics(SM_CYHSCROLL);
cs.cx = m_size.cx;
cs.cy = m_size.cy;
return CScrollBar::PreCreateWindow(cs);
}
LRESULT CResizableGrip::CSizeGrip::WindowProc(UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_GETDLGCODE:
// fix to prevent the control to gain focus, using arrow keys
// (standard grip returns DLGC_WANTARROWS, like any standard scrollbar)
return DLGC_STATIC;
case WM_NCHITTEST:
// choose proper cursor shape
if (IsRTL())
return HTBOTTOMLEFT;
else
return HTBOTTOMRIGHT;
break;
case WM_SETTINGCHANGE:
{
// update grip's size
CSize sizeOld = m_size;
m_size.cx = GetSystemMetrics(SM_CXVSCROLL);
m_size.cy = GetSystemMetrics(SM_CYHSCROLL);
// resize transparency bitmaps
if (m_bTransparent)
{
CClientDC dc(this);
// destroy bitmaps
m_bmGrip.DeleteObject();
m_bmMask.DeleteObject();
// re-create bitmaps
m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy);
m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL);
}
// re-calc shape
if (m_bTriangular)
SetTriangularShape(m_bTriangular);
// reposition the grip
CRect rect;
GetWindowRect(rect);
rect.InflateRect(m_size.cx - sizeOld.cx, m_size.cy - sizeOld.cy, 0, 0);
::MapWindowPoints(NULL, GetParent()->GetSafeHwnd(), (LPPOINT)&rect, 2);
MoveWindow(rect, TRUE);
}
break;
case WM_DESTROY:
// perform clean up
if (m_bTransparent)
SetTransparency(FALSE);
break;
case WM_PAINT:
if (m_bTransparent)
{
CPaintDC dc(this);
// select bitmaps
CBitmap *pOldGrip, *pOldMask;
pOldGrip = m_dcGrip.SelectObject(&m_bmGrip);
pOldMask = m_dcMask.SelectObject(&m_bmMask);
// obtain original grip bitmap, make the mask and prepare masked bitmap
CScrollBar::WindowProc(WM_PAINT, (WPARAM)m_dcGrip.GetSafeHdc(), lParam);
m_dcGrip.SetBkColor(m_dcGrip.GetPixel(0, 0));
m_dcMask.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCCOPY);
m_dcGrip.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, 0x00220326);
// draw transparently
dc.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, SRCAND);
dc.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCPAINT);
// unselect bitmaps
m_dcGrip.SelectObject(pOldGrip);
m_dcMask.SelectObject(pOldMask);
return 0;
}
break;
}
return CScrollBar::WindowProc(message, wParam, lParam);
}
void CResizableGrip::CSizeGrip::SetTransparency(BOOL bActivate)
{
// creates or deletes DCs and Bitmaps used for
// implementing a transparent size grip
if (bActivate && !m_bTransparent)
{
m_bTransparent = TRUE;
CClientDC dc(this);
// create memory DCs and bitmaps
m_dcGrip.CreateCompatibleDC(&dc);
m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy);
m_dcMask.CreateCompatibleDC(&dc);
m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL);
}
else if (!bActivate && m_bTransparent)
{
m_bTransparent = FALSE;
// destroy memory DCs and bitmaps
m_dcGrip.DeleteDC();
m_bmGrip.DeleteObject();
m_dcMask.DeleteDC();
m_bmMask.DeleteObject();
}
}
void CResizableGrip::CSizeGrip::SetTriangularShape(BOOL bEnable)
{
m_bTriangular = bEnable;
if (bEnable)
{
// set a triangular window region
CRect rect;
GetWindowRect(rect);
rect.OffsetRect(-rect.TopLeft());
POINT arrPoints[] =
{
{ rect.left, rect.bottom },
{ rect.right, rect.bottom },
{ rect.right, rect.top }
};
CRgn rgnGrip;
rgnGrip.CreatePolygonRgn(arrPoints, 3, WINDING);
SetWindowRgn((HRGN)rgnGrip.Detach(), IsWindowVisible());
}
else
{
SetWindowRgn((HRGN)NULL, IsWindowVisible());
}
}
#include " ResizableGrip.h "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CResizableGrip::CResizableGrip()
{
m_nShowCount = 0;
}
CResizableGrip:: ~ CResizableGrip()
{
}
void CResizableGrip::UpdateSizeGrip()
{
ASSERT(::IsWindow(m_wndGrip.m_hWnd));
// size-grip goes bottom right in the client area
// (any right-to-left adjustment should go here)
RECT rect;
GetResizableWnd()->GetClientRect(&rect);
rect.left = rect.right - m_wndGrip.m_size.cx;
rect.top = rect.bottom - m_wndGrip.m_size.cy;
// must stay below other children
m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION
| (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
}
// pbStatus points to a variable, maintained by the caller, that
// holds its visibility status. Initialize the variable with 1
// to allow to temporarily hide the grip, 0 to allow to
// temporarily show the grip (with respect to the dwMask bit).
// NB: visibility is effective only after an update
void CResizableGrip::ShowSizeGrip(DWORD * pStatus, DWORD dwMask /*= 1*/ )
{
ASSERT(pStatus != NULL);
if (!(*pStatus & dwMask))
{
m_nShowCount++;
(*pStatus) |= dwMask;
}
}
void CResizableGrip::HideSizeGrip(DWORD * pStatus, DWORD dwMask /*= 1*/ )
{
ASSERT(pStatus != NULL);
if (*pStatus & dwMask)
{
m_nShowCount--;
(*pStatus) &= ~dwMask;
}
}
BOOL CResizableGrip::IsSizeGripVisible()
{
// NB: visibility is effective only after an update
return (m_nShowCount > 0);
}
void CResizableGrip::SetSizeGripVisibility(BOOL bVisible)
{
if (bVisible)
m_nShowCount = 1;
else
m_nShowCount = 0;
}
BOOL CResizableGrip::SetSizeGripBkMode( int nBkMode)
{
if (::IsWindow(m_wndGrip.m_hWnd))
{
if (nBkMode == OPAQUE)
m_wndGrip.SetTransparency(FALSE);
else if (nBkMode == TRANSPARENT)
m_wndGrip.SetTransparency(TRUE);
else
return FALSE;
return TRUE;
}
return FALSE;
}
void CResizableGrip::SetSizeGripShape(BOOL bTriangular)
{
m_wndGrip.SetTriangularShape(bTriangular);
}
BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/ ,
BOOL bTriangular /*= TRUE*/ , BOOL bTransparent /*= FALSE*/ )
{
// create grip
CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy);
BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS
| SBS_SIZEGRIP, rect, GetResizableWnd(), 0);
if (bRet)
{
// set options
m_wndGrip.SetTriangularShape(bTriangular);
m_wndGrip.SetTransparency(bTransparent);
SetSizeGripVisibility(bVisible);
// update position
UpdateSizeGrip();
}
return bRet;
}
/////
// CSizeGrip implementation
BOOL CResizableGrip::CSizeGrip::IsRTL()
{
return GetExStyle() & 0x00400000L/*WS_EX_LAYOUTRTL*/;
}
BOOL CResizableGrip::CSizeGrip::PreCreateWindow(CREATESTRUCT & cs)
{
// set window size
m_size.cx = GetSystemMetrics(SM_CXVSCROLL);
m_size.cy = GetSystemMetrics(SM_CYHSCROLL);
cs.cx = m_size.cx;
cs.cy = m_size.cy;
return CScrollBar::PreCreateWindow(cs);
}
LRESULT CResizableGrip::CSizeGrip::WindowProc(UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_GETDLGCODE:
// fix to prevent the control to gain focus, using arrow keys
// (standard grip returns DLGC_WANTARROWS, like any standard scrollbar)
return DLGC_STATIC;
case WM_NCHITTEST:
// choose proper cursor shape
if (IsRTL())
return HTBOTTOMLEFT;
else
return HTBOTTOMRIGHT;
break;
case WM_SETTINGCHANGE:
{
// update grip's size
CSize sizeOld = m_size;
m_size.cx = GetSystemMetrics(SM_CXVSCROLL);
m_size.cy = GetSystemMetrics(SM_CYHSCROLL);
// resize transparency bitmaps
if (m_bTransparent)
{
CClientDC dc(this);
// destroy bitmaps
m_bmGrip.DeleteObject();
m_bmMask.DeleteObject();
// re-create bitmaps
m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy);
m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL);
}
// re-calc shape
if (m_bTriangular)
SetTriangularShape(m_bTriangular);
// reposition the grip
CRect rect;
GetWindowRect(rect);
rect.InflateRect(m_size.cx - sizeOld.cx, m_size.cy - sizeOld.cy, 0, 0);
::MapWindowPoints(NULL, GetParent()->GetSafeHwnd(), (LPPOINT)&rect, 2);
MoveWindow(rect, TRUE);
}
break;
case WM_DESTROY:
// perform clean up
if (m_bTransparent)
SetTransparency(FALSE);
break;
case WM_PAINT:
if (m_bTransparent)
{
CPaintDC dc(this);
// select bitmaps
CBitmap *pOldGrip, *pOldMask;
pOldGrip = m_dcGrip.SelectObject(&m_bmGrip);
pOldMask = m_dcMask.SelectObject(&m_bmMask);
// obtain original grip bitmap, make the mask and prepare masked bitmap
CScrollBar::WindowProc(WM_PAINT, (WPARAM)m_dcGrip.GetSafeHdc(), lParam);
m_dcGrip.SetBkColor(m_dcGrip.GetPixel(0, 0));
m_dcMask.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCCOPY);
m_dcGrip.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, 0x00220326);
// draw transparently
dc.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcMask, 0, 0, SRCAND);
dc.BitBlt(0, 0, m_size.cx, m_size.cy, &m_dcGrip, 0, 0, SRCPAINT);
// unselect bitmaps
m_dcGrip.SelectObject(pOldGrip);
m_dcMask.SelectObject(pOldMask);
return 0;
}
break;
}
return CScrollBar::WindowProc(message, wParam, lParam);
}
void CResizableGrip::CSizeGrip::SetTransparency(BOOL bActivate)
{
// creates or deletes DCs and Bitmaps used for
// implementing a transparent size grip
if (bActivate && !m_bTransparent)
{
m_bTransparent = TRUE;
CClientDC dc(this);
// create memory DCs and bitmaps
m_dcGrip.CreateCompatibleDC(&dc);
m_bmGrip.CreateCompatibleBitmap(&dc, m_size.cx, m_size.cy);
m_dcMask.CreateCompatibleDC(&dc);
m_bmMask.CreateBitmap(m_size.cx, m_size.cy, 1, 1, NULL);
}
else if (!bActivate && m_bTransparent)
{
m_bTransparent = FALSE;
// destroy memory DCs and bitmaps
m_dcGrip.DeleteDC();
m_bmGrip.DeleteObject();
m_dcMask.DeleteDC();
m_bmMask.DeleteObject();
}
}
void CResizableGrip::CSizeGrip::SetTriangularShape(BOOL bEnable)
{
m_bTriangular = bEnable;
if (bEnable)
{
// set a triangular window region
CRect rect;
GetWindowRect(rect);
rect.OffsetRect(-rect.TopLeft());
POINT arrPoints[] =
{
{ rect.left, rect.bottom },
{ rect.right, rect.bottom },
{ rect.right, rect.top }
};
CRgn rgnGrip;
rgnGrip.CreatePolygonRgn(arrPoints, 3, WINDING);
SetWindowRgn((HRGN)rgnGrip.Detach(), IsWindowVisible());
}
else
{
SetWindowRgn((HRGN)NULL, IsWindowVisible());
}
}
#if
!defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)
#define AFX_RESIZABLELAYOUT_H__INCLUDED_
#include < afxtempl.h >
#include " ResizableMsgSupport.h "
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// useful compatibility constants (the only one required is NOANCHOR)
const CSize NOANCHOR( - 1 , - 1 ),
TOP_LEFT( 0 , 0 ), TOP_CENTER( 50 , 0 ), TOP_RIGHT( 100 , 0 ),
MIDDLE_LEFT( 0 , 50 ), MIDDLE_CENTER( 50 , 50 ), MIDDLE_RIGHT( 100 , 50 ),
BOTTOM_LEFT( 0 , 100 ), BOTTOM_CENTER( 50 , 100 ), BOTTOM_RIGHT( 100 , 100 );
class CResizableLayout
{
protected:
class LayoutInfo
{
public:
HWND hWnd;
UINT nCallbackID;
CString sWndClass;
// upper-left corner
SIZE sizeTypeTL;
SIZE sizeMarginTL;
// bottom-right corner
SIZE sizeTypeBR;
SIZE sizeMarginBR;
// custom window support
BOOL bMsgSupport;
RESIZEPROPERTIES properties;
public:
LayoutInfo() : hWnd(NULL), nCallbackID(0), bMsgSupport(FALSE)
{
sizeTypeTL.cx = 0;
sizeTypeTL.cy = 0;
sizeMarginTL.cx = 0;
sizeMarginTL.cy = 0;
sizeTypeBR.cx = 0;
sizeTypeBR.cy = 0;
sizeMarginBR.cx = 0;
sizeMarginBR.cy = 0;
memset(&properties, 0, sizeof properties);
}
LayoutInfo(HWND hwnd, SIZE tl_t, SIZE tl_m,
SIZE br_t, SIZE br_m, CString classname)
: hWnd(hwnd), nCallbackID(0),
sWndClass(classname), bMsgSupport(FALSE),
sizeTypeTL(tl_t), sizeMarginTL(tl_m),
sizeTypeBR(br_t), sizeMarginBR(br_m)
{
memset(&properties, 0, sizeof properties);
}
};
private:
// list of repositionable controls
CMap<HWND, HWND, POSITION, POSITION> m_mapLayout;
CList<LayoutInfo, LayoutInfo&> m_listLayout;
CList<LayoutInfo, LayoutInfo&> m_listLayoutCB;
void ClipChildWindow(const CResizableLayout::LayoutInfo &layout, CRgn* pRegion);
void CalcNewChildPosition(const CResizableLayout::LayoutInfo &layout,
const CRect &rectParent, CRect &rectChild, UINT& uFlags);
protected:
// override to initialize resize properties (clipping, refresh)
virtual void InitResizeProperties(CResizableLayout::LayoutInfo& layout);
// override to specify clipping for unsupported windows
virtual BOOL LikesClipping(const CResizableLayout::LayoutInfo &layout);
// override to specify refresh for unsupported windows
virtual BOOL NeedsRefresh(const CResizableLayout::LayoutInfo &layout,
const CRect &rectOld, const CRect &rectNew);
// paint the background on the given DC (for XP theme's compatibility)
void EraseBackground(CDC* pDC);
// clip out child windows from the given DC (support old code)
void ClipChildren(CDC* pDC);
// get the clipping region (without clipped child windows)
void GetClippingRegion(CRgn* pRegion);
// override for scrollable or expanding parent windows
virtual void GetTotalClientRect(LPRECT lpRect);
// add anchors to a control, given its HWND
void AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR = NOANCHOR);
// add anchors to a control, given its ID
void AddAnchor(UINT nID, CSize sizeTypeTL, CSize sizeTypeBR = NOANCHOR)
{
AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
sizeTypeTL, sizeTypeBR);
}
// add a callback (control ID or HWND is unknown or may change)
void AddAnchorCallback(UINT nCallbackID);
// get rect of an anchored window, given the parent's client area
BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent,
CRect &rectChild, UINT* lpFlags = NULL)
{
POSITION pos;
if (!m_mapLayout.Lookup(hWnd, pos))
return FALSE;
UINT uTmpFlags;
CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild,
(lpFlags != NULL) ? (*lpFlags) : uTmpFlags);
return TRUE;
}
// get rect of an anchored window, given the parent's client area
BOOL GetAnchorPosition(UINT nID, const CRect &rectParent,
CRect &rectChild, UINT* lpFlags = NULL)
{
return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
rectParent, rectChild, lpFlags);
}
// remove an anchored control from the layout, given its HWND
BOOL RemoveAnchor(HWND hWnd)
{
POSITION pos;
if (!m_mapLayout.Lookup(hWnd, pos))
return FALSE;
m_listLayout.RemoveAt(pos);
return m_mapLayout.RemoveKey(hWnd);
}
// remove an anchored control from the layout, given its HWND
BOOL RemoveAnchor(UINT nID)
{
return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID));
}
// reset layout content
void RemoveAllAnchors()
{
m_mapLayout.RemoveAll();
m_listLayout.RemoveAll();
m_listLayoutCB.RemoveAll();
}
// adjust children's layout, when parent's size changes
void ArrangeLayout();
// override to provide dynamic control's layout info
virtual BOOL ArrangeLayoutCallback(CResizableLayout::LayoutInfo& layout);
// override to provide the parent window
virtual CWnd* GetResizableWnd() = 0;
public:
CResizableLayout() { }
virtual ~CResizableLayout()
{
// just for safety
RemoveAllAnchors();
}
} ;
#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)
#define AFX_RESIZABLELAYOUT_H__INCLUDED_
#include < afxtempl.h >
#include " ResizableMsgSupport.h "
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// useful compatibility constants (the only one required is NOANCHOR)
const CSize NOANCHOR( - 1 , - 1 ),
TOP_LEFT( 0 , 0 ), TOP_CENTER( 50 , 0 ), TOP_RIGHT( 100 , 0 ),
MIDDLE_LEFT( 0 , 50 ), MIDDLE_CENTER( 50 , 50 ), MIDDLE_RIGHT( 100 , 50 ),
BOTTOM_LEFT( 0 , 100 ), BOTTOM_CENTER( 50 , 100 ), BOTTOM_RIGHT( 100 , 100 );
class CResizableLayout
{
protected:
class LayoutInfo
{
public:
HWND hWnd;
UINT nCallbackID;
CString sWndClass;
// upper-left corner
SIZE sizeTypeTL;
SIZE sizeMarginTL;
// bottom-right corner
SIZE sizeTypeBR;
SIZE sizeMarginBR;
// custom window support
BOOL bMsgSupport;
RESIZEPROPERTIES properties;
public:
LayoutInfo() : hWnd(NULL), nCallbackID(0), bMsgSupport(FALSE)
{
sizeTypeTL.cx = 0;
sizeTypeTL.cy = 0;
sizeMarginTL.cx = 0;
sizeMarginTL.cy = 0;
sizeTypeBR.cx = 0;
sizeTypeBR.cy = 0;
sizeMarginBR.cx = 0;
sizeMarginBR.cy = 0;
memset(&properties, 0, sizeof properties);
}
LayoutInfo(HWND hwnd, SIZE tl_t, SIZE tl_m,
SIZE br_t, SIZE br_m, CString classname)
: hWnd(hwnd), nCallbackID(0),
sWndClass(classname), bMsgSupport(FALSE),
sizeTypeTL(tl_t), sizeMarginTL(tl_m),
sizeTypeBR(br_t), sizeMarginBR(br_m)
{
memset(&properties, 0, sizeof properties);
}
};
private:
// list of repositionable controls
CMap<HWND, HWND, POSITION, POSITION> m_mapLayout;
CList<LayoutInfo, LayoutInfo&> m_listLayout;
CList<LayoutInfo, LayoutInfo&> m_listLayoutCB;
void ClipChildWindow(const CResizableLayout::LayoutInfo &layout, CRgn* pRegion);
void CalcNewChildPosition(const CResizableLayout::LayoutInfo &layout,
const CRect &rectParent, CRect &rectChild, UINT& uFlags);
protected:
// override to initialize resize properties (clipping, refresh)
virtual void InitResizeProperties(CResizableLayout::LayoutInfo& layout);
// override to specify clipping for unsupported windows
virtual BOOL LikesClipping(const CResizableLayout::LayoutInfo &layout);
// override to specify refresh for unsupported windows
virtual BOOL NeedsRefresh(const CResizableLayout::LayoutInfo &layout,
const CRect &rectOld, const CRect &rectNew);
// paint the background on the given DC (for XP theme's compatibility)
void EraseBackground(CDC* pDC);
// clip out child windows from the given DC (support old code)
void ClipChildren(CDC* pDC);
// get the clipping region (without clipped child windows)
void GetClippingRegion(CRgn* pRegion);
// override for scrollable or expanding parent windows
virtual void GetTotalClientRect(LPRECT lpRect);
// add anchors to a control, given its HWND
void AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR = NOANCHOR);
// add anchors to a control, given its ID
void AddAnchor(UINT nID, CSize sizeTypeTL, CSize sizeTypeBR = NOANCHOR)
{
AddAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
sizeTypeTL, sizeTypeBR);
}
// add a callback (control ID or HWND is unknown or may change)
void AddAnchorCallback(UINT nCallbackID);
// get rect of an anchored window, given the parent's client area
BOOL GetAnchorPosition(HWND hWnd, const CRect &rectParent,
CRect &rectChild, UINT* lpFlags = NULL)
{
POSITION pos;
if (!m_mapLayout.Lookup(hWnd, pos))
return FALSE;
UINT uTmpFlags;
CalcNewChildPosition(m_listLayout.GetAt(pos), rectParent, rectChild,
(lpFlags != NULL) ? (*lpFlags) : uTmpFlags);
return TRUE;
}
// get rect of an anchored window, given the parent's client area
BOOL GetAnchorPosition(UINT nID, const CRect &rectParent,
CRect &rectChild, UINT* lpFlags = NULL)
{
return GetAnchorPosition(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID),
rectParent, rectChild, lpFlags);
}
// remove an anchored control from the layout, given its HWND
BOOL RemoveAnchor(HWND hWnd)
{
POSITION pos;
if (!m_mapLayout.Lookup(hWnd, pos))
return FALSE;
m_listLayout.RemoveAt(pos);
return m_mapLayout.RemoveKey(hWnd);
}
// remove an anchored control from the layout, given its HWND
BOOL RemoveAnchor(UINT nID)
{
return RemoveAnchor(::GetDlgItem(GetResizableWnd()->GetSafeHwnd(), nID));
}
// reset layout content
void RemoveAllAnchors()
{
m_mapLayout.RemoveAll();
m_listLayout.RemoveAll();
m_listLayoutCB.RemoveAll();
}
// adjust children's layout, when parent's size changes
void ArrangeLayout();
// override to provide dynamic control's layout info
virtual BOOL ArrangeLayoutCallback(CResizableLayout::LayoutInfo& layout);
// override to provide the parent window
virtual CWnd* GetResizableWnd() = 0;
public:
CResizableLayout() { }
virtual ~CResizableLayout()
{
// just for safety
RemoveAllAnchors();
}
} ;
#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)
#include
"
stdafx.h
"
#include " commctrl.h "
#include " ResizableLayout.h "
#include " ResizableMsgSupport.inl "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
// In August 2002 Platform SDK, some guy at MS thought it was time to
// add the missing symbol BS_TYPEMASK, but forgot its original meaning
// and so now he's telling us not to use that symbol because its
// value is likely to change in the future SDK releases, including all
// the BS_* style bits in the mask, not just the button's type as the
// symbol's name suggests. So now we're forced to use another symbol!
#define _BS_TYPEMASK 0x0000000FL
void CResizableLayout::AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR)
{
CWnd* pParent = GetResizableWnd();
// child window must be valid
ASSERT(::IsWindow(hWnd));
// must be child of parent window
// ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd));
// top-left anchor must be valid
ASSERT(sizeTypeTL != NOANCHOR);
// get control's window class
CString sClassName;
GetClassName(hWnd, sClassName.GetBufferSetLength(MAX_PATH), MAX_PATH);
sClassName.ReleaseBuffer();
// get parent window's rect
CRect rectParent;
GetTotalClientRect(&rectParent);
// and child control's rect
CRect rectChild;
::GetWindowRect(hWnd, &rectChild);
::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
// adjust position, if client area has been scrolled
rectChild.OffsetRect(-rectParent.TopLeft());
// go calculate margins
CSize sizeMarginTL, sizeMarginBR;
if (sizeTypeBR == NOANCHOR)
sizeTypeBR = sizeTypeTL;
// calculate margin for the top-left corner
sizeMarginTL.cx = rectChild.left - rectParent.Width() * sizeTypeTL.cx / 100;
sizeMarginTL.cy = rectChild.top - rectParent.Height() * sizeTypeTL.cy / 100;
// calculate margin for the bottom-right corner
sizeMarginBR.cx = rectChild.right - rectParent.Width() * sizeTypeBR.cx / 100;
sizeMarginBR.cy = rectChild.bottom - rectParent.Height() * sizeTypeBR.cy / 100;
// prepare the structure
LayoutInfo layout(hWnd, sizeTypeTL, sizeMarginTL,
sizeTypeBR, sizeMarginBR, sClassName);
// initialize resize properties (overridable)
InitResizeProperties(layout);
// must not be already there!
// (this is probably due to a duplicate call to AddAnchor)
POSITION pos;
ASSERT(!m_mapLayout.Lookup(hWnd, pos));
// add to the list and the map
pos = m_listLayout.AddTail(layout);
m_mapLayout.SetAt(hWnd, pos);
}
void CResizableLayout::AddAnchorCallback(UINT nCallbackID)
{
// one callback control cannot rely upon another callback control's
// size and/or position (they're updated all together at the end)
// it can however use a non-callback control, which is updated before
// add to the list
LayoutInfo layout;
layout.nCallbackID = nCallbackID;
m_listLayoutCB.AddTail(layout);
}
BOOL CResizableLayout::ArrangeLayoutCallback(CResizableLayout::LayoutInfo & /*layout*/ )
{
ASSERT(FALSE);
// must be overridden, if callback is used
return FALSE; // no output data
}
void CResizableLayout::ArrangeLayout()
{
// common vars
UINT uFlags;
LayoutInfo layout;
CRect rectParent, rectChild;
GetTotalClientRect(&rectParent); // get parent window's rect
int count = m_listLayout.GetCount();
int countCB = m_listLayoutCB.GetCount();
// reposition child windows
HDWP hdwp = ::BeginDeferWindowPos(count + countCB);
POSITION pos = m_listLayout.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayout.GetNext(pos);
// calculate new child's position, size and flags for SetWindowPos
CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
// only if size or position changed
if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
}
}
// for callback items you may use GetAnchorPosition to know the
// new position and size of a non-callback item after resizing
pos = m_listLayoutCB.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayoutCB.GetNext(pos);
// request layout data
if (!ArrangeLayoutCallback(layout))
continue;
// calculate new child's position, size and flags for SetWindowPos
CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
// only if size or position changed
if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
}
}
// finally move all the windows at once
::EndDeferWindowPos(hdwp);
}
void CResizableLayout::ClipChildWindow( const CResizableLayout::LayoutInfo & layout,
CRgn * pRegion)
{
// obtain window position
CRect rect;
::GetWindowRect(layout.hWnd, &rect);
::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2);
// use window region if any
CRgn rgn;
rgn.CreateRectRgn(0,0,0,0);
switch (::GetWindowRgn(layout.hWnd, rgn))
{
case COMPLEXREGION:
case SIMPLEREGION:
rgn.OffsetRgn(rect.TopLeft());
break;
default:
rgn.SetRectRgn(&rect);
}
// get the clipping property
BOOL bClipping = layout.properties.bAskClipping ?
LikesClipping(layout) : layout.properties.bCachedLikesClipping;
// modify region accordingly
if (bClipping)
pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF);
else
pRegion->CombineRgn(pRegion, &rgn, RGN_OR);
}
void CResizableLayout::GetClippingRegion(CRgn * pRegion)
{
CWnd* pWnd = GetResizableWnd();
// System's default clipping area is screen's size,
// not enough for max track size, for example:
// if screen is 1024 x 768 and resizing border is 4 pixels,
// maximized size is 1024+4*2=1032 x 768+4*2=776,
// but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!)
// So, if you resize the window to maximum size, the last 4 pixels
// are clipped out by the default clipping region, that gets created
// as soon as you call clipping functions (my guess).
// reset clipping region to the whole client area
CRect rect;
pWnd->GetClientRect(&rect);
pRegion->CreateRectRgnIndirect(&rect);
// clip only anchored controls
LayoutInfo layout;
POSITION pos = m_listLayout.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayout.GetNext(pos);
if (::IsWindowVisible(layout.hWnd))
ClipChildWindow(layout, pRegion);
}
pos = m_listLayoutCB.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayoutCB.GetNext(pos);
// request data
if (!ArrangeLayoutCallback(layout))
continue;
if (::IsWindowVisible(layout.hWnd))
ClipChildWindow(layout, pRegion);
}
// fix for RTL layouts (1 pixel of horz offset)
if (pWnd->GetExStyle() & 0x00400000L/*WS_EX_LAYOUTRTL*/)
pRegion->OffsetRgn(-1,0);
}
void CResizableLayout::EraseBackground(CDC * pDC)
{
HWND hWnd = GetResizableWnd()->GetSafeHwnd();
// retrieve the background brush
HBRUSH hBrush = NULL;
// is this a dialog box?
// (using class atom is quickier than using the class name)
ATOM atomWndClass = (ATOM)::GetClassLong(hWnd, GCW_ATOM);
if (atomWndClass == (ATOM)0x8002)
{
// send a message to the dialog box
hBrush = (HBRUSH)::SendMessage(hWnd, WM_CTLCOLORDLG,
(WPARAM)pDC->GetSafeHdc(), (LPARAM)hWnd);
}
else
{
// take the background brush from the window's class
hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCL_HBRBACKGROUND);
}
// fill the clipped background
CRgn rgn;
GetClippingRegion(&rgn);
::FillRgn(pDC->GetSafeHdc(), rgn, hBrush);
}
// support legacy code (will disappear in future versions)
void CResizableLayout::ClipChildren(CDC * pDC)
{
CRgn rgn;
GetClippingRegion(&rgn);
// the clipping region is in device units
rgn.OffsetRgn(-pDC->GetWindowOrg());
pDC->SelectClipRgn(&rgn);
}
void CResizableLayout::GetTotalClientRect(LPRECT lpRect)
{
GetResizableWnd()->GetClientRect(lpRect);
}
BOOL CResizableLayout::NeedsRefresh( const CResizableLayout::LayoutInfo & layout,
const CRect & rectOld, const CRect & rectNew)
{
if (layout.bMsgSupport)
{
REFRESHPROPERTY refresh;
refresh.rcOld = rectOld;
refresh.rcNew = rectNew;
if (Send_NeedsRefresh(layout.hWnd, &refresh))
return refresh.bNeedsRefresh;
}
int nDiffWidth = (rectNew.Width() - rectOld.Width());
int nDiffHeight = (rectNew.Height() - rectOld.Height());
// is the same size?
if (nDiffWidth == 0 && nDiffHeight == 0)
return FALSE;
// optimistic, no need to refresh
BOOL bRefresh = FALSE;
// window classes that need refresh when resized
if (layout.sWndClass == WC_STATIC)
{
DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);
switch (style & SS_TYPEMASK)
{
case SS_LEFT:
case SS_CENTER:
case SS_RIGHT:
// word-wrapped text
bRefresh = bRefresh || (nDiffWidth != 0);
// vertically centered text
if (style & SS_CENTERIMAGE)
bRefresh = bRefresh || (nDiffHeight != 0);
break;
case SS_LEFTNOWORDWRAP:
// text with ellipsis
if (style & SS_ELLIPSISMASK)
bRefresh = bRefresh || (nDiffWidth != 0);
// vertically centered text
if (style & SS_CENTERIMAGE)
bRefresh = bRefresh || (nDiffHeight != 0);
break;
case SS_ENHMETAFILE:
case SS_BITMAP:
case SS_ICON:
// images
case SS_BLACKFRAME:
case SS_GRAYFRAME:
case SS_WHITEFRAME:
case SS_ETCHEDFRAME:
// and frames
bRefresh = TRUE;
break;
}
}
// window classes that don't redraw client area correctly
// when the hor scroll pos changes due to a resizing
BOOL bHScroll = FALSE;
if (layout.sWndClass == WC_LISTBOX)
bHScroll = TRUE;
// fix for horizontally scrollable windows
if (bHScroll && (nDiffWidth > 0))
{
// get max scroll position
SCROLLINFO info;
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info))
{
// subtract the page size
info.nMax -= __max(info.nPage-1,0);
}
// resizing will cause the text to scroll on the right
// because the scrollbar is going beyond the right limit
if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax))
{
// needs repainting, due to horiz scrolling
bRefresh = TRUE;
}
}
return bRefresh;
}
BOOL CResizableLayout::LikesClipping( const CResizableLayout::LayoutInfo & layout)
{
if (layout.bMsgSupport)
{
CLIPPINGPROPERTY clipping;
if (Send_LikesClipping(layout.hWnd, &clipping))
return clipping.bLikesClipping;
}
DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);
// skip windows that wants background repainted
if (layout.sWndClass == TOOLBARCLASSNAME && (style & TBSTYLE_TRANSPARENT))
return FALSE;
else if (layout.sWndClass == WC_BUTTON)
{
CRect rect;
switch (style & _BS_TYPEMASK)
{
case BS_GROUPBOX:
return FALSE;
case BS_OWNERDRAW:
// ownerdraw buttons must return correct hittest code
// to notify their transparency to the system and this library
::GetWindowRect(layout.hWnd, &rect);
if ( HTTRANSPARENT == ::SendMessage(layout.hWnd,
WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) )
return FALSE;
break;
}
return TRUE;
}
else if (layout.sWndClass == WC_STATIC)
{
switch (style & SS_TYPEMASK)
{
case SS_LEFT:
case SS_CENTER:
case SS_RIGHT:
case SS_SIMPLE:
case SS_LEFTNOWORDWRAP:
// text
case SS_BLACKRECT:
case SS_GRAYRECT:
case SS_WHITERECT:
// filled rects
case SS_ETCHEDHORZ:
case SS_ETCHEDVERT:
// etched lines
case SS_BITMAP:
// bitmaps
return TRUE;
break;
case SS_ICON:
case SS_ENHMETAFILE:
if (style & SS_CENTERIMAGE)
return FALSE;
return TRUE;
break;
default:
return FALSE;
}
}
// assume the others like clipping
return TRUE;
}
void CResizableLayout::CalcNewChildPosition( const CResizableLayout::LayoutInfo & layout,
const CRect & rectParent, CRect & rectChild, UINT & uFlags)
{
CWnd* pParent = GetResizableWnd();
::GetWindowRect(layout.hWnd, &rectChild);
::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
CRect rectNew;
// calculate new top-left corner
rectNew.left = layout.sizeMarginTL.cx + rectParent.Width() * layout.sizeTypeTL.cx / 100;
rectNew.top = layout.sizeMarginTL.cy + rectParent.Height() * layout.sizeTypeTL.cy / 100;
// calculate new bottom-right corner
rectNew.right = layout.sizeMarginBR.cx + rectParent.Width() * layout.sizeTypeBR.cx / 100;
rectNew.bottom = layout.sizeMarginBR.cy + rectParent.Height() * layout.sizeTypeBR.cy / 100;
// adjust position, if client area has been scrolled
rectNew.OffsetRect(rectParent.TopLeft());
// get the refresh property
BOOL bRefresh = layout.properties.bAskRefresh ?
NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh;
// set flags
uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION;
if (bRefresh)
uFlags |= SWP_NOCOPYBITS;
if (rectNew.TopLeft() == rectChild.TopLeft())
uFlags |= SWP_NOMOVE;
if (rectNew.Size() == rectChild.Size())
uFlags |= SWP_NOSIZE;
// update rect
rectChild = rectNew;
}
void CResizableLayout::InitResizeProperties(CResizableLayout::LayoutInfo & layout)
{
// check if custom window supports this library
// (properties must be correctly set by the window)
layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties);
// default properties
if (!layout.bMsgSupport)
{
// clipping property is assumed as static
layout.properties.bAskClipping = FALSE;
layout.properties.bCachedLikesClipping = LikesClipping(layout);
// refresh property is assumed as dynamic
layout.properties.bAskRefresh = TRUE;
}
}
#include " commctrl.h "
#include " ResizableLayout.h "
#include " ResizableMsgSupport.inl "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
// In August 2002 Platform SDK, some guy at MS thought it was time to
// add the missing symbol BS_TYPEMASK, but forgot its original meaning
// and so now he's telling us not to use that symbol because its
// value is likely to change in the future SDK releases, including all
// the BS_* style bits in the mask, not just the button's type as the
// symbol's name suggests. So now we're forced to use another symbol!
#define _BS_TYPEMASK 0x0000000FL
void CResizableLayout::AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR)
{
CWnd* pParent = GetResizableWnd();
// child window must be valid
ASSERT(::IsWindow(hWnd));
// must be child of parent window
// ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd));
// top-left anchor must be valid
ASSERT(sizeTypeTL != NOANCHOR);
// get control's window class
CString sClassName;
GetClassName(hWnd, sClassName.GetBufferSetLength(MAX_PATH), MAX_PATH);
sClassName.ReleaseBuffer();
// get parent window's rect
CRect rectParent;
GetTotalClientRect(&rectParent);
// and child control's rect
CRect rectChild;
::GetWindowRect(hWnd, &rectChild);
::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
// adjust position, if client area has been scrolled
rectChild.OffsetRect(-rectParent.TopLeft());
// go calculate margins
CSize sizeMarginTL, sizeMarginBR;
if (sizeTypeBR == NOANCHOR)
sizeTypeBR = sizeTypeTL;
// calculate margin for the top-left corner
sizeMarginTL.cx = rectChild.left - rectParent.Width() * sizeTypeTL.cx / 100;
sizeMarginTL.cy = rectChild.top - rectParent.Height() * sizeTypeTL.cy / 100;
// calculate margin for the bottom-right corner
sizeMarginBR.cx = rectChild.right - rectParent.Width() * sizeTypeBR.cx / 100;
sizeMarginBR.cy = rectChild.bottom - rectParent.Height() * sizeTypeBR.cy / 100;
// prepare the structure
LayoutInfo layout(hWnd, sizeTypeTL, sizeMarginTL,
sizeTypeBR, sizeMarginBR, sClassName);
// initialize resize properties (overridable)
InitResizeProperties(layout);
// must not be already there!
// (this is probably due to a duplicate call to AddAnchor)
POSITION pos;
ASSERT(!m_mapLayout.Lookup(hWnd, pos));
// add to the list and the map
pos = m_listLayout.AddTail(layout);
m_mapLayout.SetAt(hWnd, pos);
}
void CResizableLayout::AddAnchorCallback(UINT nCallbackID)
{
// one callback control cannot rely upon another callback control's
// size and/or position (they're updated all together at the end)
// it can however use a non-callback control, which is updated before
// add to the list
LayoutInfo layout;
layout.nCallbackID = nCallbackID;
m_listLayoutCB.AddTail(layout);
}
BOOL CResizableLayout::ArrangeLayoutCallback(CResizableLayout::LayoutInfo & /*layout*/ )
{
ASSERT(FALSE);
// must be overridden, if callback is used
return FALSE; // no output data
}
void CResizableLayout::ArrangeLayout()
{
// common vars
UINT uFlags;
LayoutInfo layout;
CRect rectParent, rectChild;
GetTotalClientRect(&rectParent); // get parent window's rect
int count = m_listLayout.GetCount();
int countCB = m_listLayoutCB.GetCount();
// reposition child windows
HDWP hdwp = ::BeginDeferWindowPos(count + countCB);
POSITION pos = m_listLayout.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayout.GetNext(pos);
// calculate new child's position, size and flags for SetWindowPos
CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
// only if size or position changed
if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
}
}
// for callback items you may use GetAnchorPosition to know the
// new position and size of a non-callback item after resizing
pos = m_listLayoutCB.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayoutCB.GetNext(pos);
// request layout data
if (!ArrangeLayoutCallback(layout))
continue;
// calculate new child's position, size and flags for SetWindowPos
CalcNewChildPosition(layout, rectParent, rectChild, uFlags);
// only if size or position changed
if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
{
hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left,
rectChild.top, rectChild.Width(), rectChild.Height(), uFlags);
}
}
// finally move all the windows at once
::EndDeferWindowPos(hdwp);
}
void CResizableLayout::ClipChildWindow( const CResizableLayout::LayoutInfo & layout,
CRgn * pRegion)
{
// obtain window position
CRect rect;
::GetWindowRect(layout.hWnd, &rect);
::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2);
// use window region if any
CRgn rgn;
rgn.CreateRectRgn(0,0,0,0);
switch (::GetWindowRgn(layout.hWnd, rgn))
{
case COMPLEXREGION:
case SIMPLEREGION:
rgn.OffsetRgn(rect.TopLeft());
break;
default:
rgn.SetRectRgn(&rect);
}
// get the clipping property
BOOL bClipping = layout.properties.bAskClipping ?
LikesClipping(layout) : layout.properties.bCachedLikesClipping;
// modify region accordingly
if (bClipping)
pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF);
else
pRegion->CombineRgn(pRegion, &rgn, RGN_OR);
}
void CResizableLayout::GetClippingRegion(CRgn * pRegion)
{
CWnd* pWnd = GetResizableWnd();
// System's default clipping area is screen's size,
// not enough for max track size, for example:
// if screen is 1024 x 768 and resizing border is 4 pixels,
// maximized size is 1024+4*2=1032 x 768+4*2=776,
// but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!)
// So, if you resize the window to maximum size, the last 4 pixels
// are clipped out by the default clipping region, that gets created
// as soon as you call clipping functions (my guess).
// reset clipping region to the whole client area
CRect rect;
pWnd->GetClientRect(&rect);
pRegion->CreateRectRgnIndirect(&rect);
// clip only anchored controls
LayoutInfo layout;
POSITION pos = m_listLayout.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayout.GetNext(pos);
if (::IsWindowVisible(layout.hWnd))
ClipChildWindow(layout, pRegion);
}
pos = m_listLayoutCB.GetHeadPosition();
while (pos != NULL)
{
// get layout info
layout = m_listLayoutCB.GetNext(pos);
// request data
if (!ArrangeLayoutCallback(layout))
continue;
if (::IsWindowVisible(layout.hWnd))
ClipChildWindow(layout, pRegion);
}
// fix for RTL layouts (1 pixel of horz offset)
if (pWnd->GetExStyle() & 0x00400000L/*WS_EX_LAYOUTRTL*/)
pRegion->OffsetRgn(-1,0);
}
void CResizableLayout::EraseBackground(CDC * pDC)
{
HWND hWnd = GetResizableWnd()->GetSafeHwnd();
// retrieve the background brush
HBRUSH hBrush = NULL;
// is this a dialog box?
// (using class atom is quickier than using the class name)
ATOM atomWndClass = (ATOM)::GetClassLong(hWnd, GCW_ATOM);
if (atomWndClass == (ATOM)0x8002)
{
// send a message to the dialog box
hBrush = (HBRUSH)::SendMessage(hWnd, WM_CTLCOLORDLG,
(WPARAM)pDC->GetSafeHdc(), (LPARAM)hWnd);
}
else
{
// take the background brush from the window's class
hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCL_HBRBACKGROUND);
}
// fill the clipped background
CRgn rgn;
GetClippingRegion(&rgn);
::FillRgn(pDC->GetSafeHdc(), rgn, hBrush);
}
// support legacy code (will disappear in future versions)
void CResizableLayout::ClipChildren(CDC * pDC)
{
CRgn rgn;
GetClippingRegion(&rgn);
// the clipping region is in device units
rgn.OffsetRgn(-pDC->GetWindowOrg());
pDC->SelectClipRgn(&rgn);
}
void CResizableLayout::GetTotalClientRect(LPRECT lpRect)
{
GetResizableWnd()->GetClientRect(lpRect);
}
BOOL CResizableLayout::NeedsRefresh( const CResizableLayout::LayoutInfo & layout,
const CRect & rectOld, const CRect & rectNew)
{
if (layout.bMsgSupport)
{
REFRESHPROPERTY refresh;
refresh.rcOld = rectOld;
refresh.rcNew = rectNew;
if (Send_NeedsRefresh(layout.hWnd, &refresh))
return refresh.bNeedsRefresh;
}
int nDiffWidth = (rectNew.Width() - rectOld.Width());
int nDiffHeight = (rectNew.Height() - rectOld.Height());
// is the same size?
if (nDiffWidth == 0 && nDiffHeight == 0)
return FALSE;
// optimistic, no need to refresh
BOOL bRefresh = FALSE;
// window classes that need refresh when resized
if (layout.sWndClass == WC_STATIC)
{
DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);
switch (style & SS_TYPEMASK)
{
case SS_LEFT:
case SS_CENTER:
case SS_RIGHT:
// word-wrapped text
bRefresh = bRefresh || (nDiffWidth != 0);
// vertically centered text
if (style & SS_CENTERIMAGE)
bRefresh = bRefresh || (nDiffHeight != 0);
break;
case SS_LEFTNOWORDWRAP:
// text with ellipsis
if (style & SS_ELLIPSISMASK)
bRefresh = bRefresh || (nDiffWidth != 0);
// vertically centered text
if (style & SS_CENTERIMAGE)
bRefresh = bRefresh || (nDiffHeight != 0);
break;
case SS_ENHMETAFILE:
case SS_BITMAP:
case SS_ICON:
// images
case SS_BLACKFRAME:
case SS_GRAYFRAME:
case SS_WHITEFRAME:
case SS_ETCHEDFRAME:
// and frames
bRefresh = TRUE;
break;
}
}
// window classes that don't redraw client area correctly
// when the hor scroll pos changes due to a resizing
BOOL bHScroll = FALSE;
if (layout.sWndClass == WC_LISTBOX)
bHScroll = TRUE;
// fix for horizontally scrollable windows
if (bHScroll && (nDiffWidth > 0))
{
// get max scroll position
SCROLLINFO info;
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info))
{
// subtract the page size
info.nMax -= __max(info.nPage-1,0);
}
// resizing will cause the text to scroll on the right
// because the scrollbar is going beyond the right limit
if ((info.nMax > 0) && (info.nPos + nDiffWidth > info.nMax))
{
// needs repainting, due to horiz scrolling
bRefresh = TRUE;
}
}
return bRefresh;
}
BOOL CResizableLayout::LikesClipping( const CResizableLayout::LayoutInfo & layout)
{
if (layout.bMsgSupport)
{
CLIPPINGPROPERTY clipping;
if (Send_LikesClipping(layout.hWnd, &clipping))
return clipping.bLikesClipping;
}
DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);
// skip windows that wants background repainted
if (layout.sWndClass == TOOLBARCLASSNAME && (style & TBSTYLE_TRANSPARENT))
return FALSE;
else if (layout.sWndClass == WC_BUTTON)
{
CRect rect;
switch (style & _BS_TYPEMASK)
{
case BS_GROUPBOX:
return FALSE;
case BS_OWNERDRAW:
// ownerdraw buttons must return correct hittest code
// to notify their transparency to the system and this library
::GetWindowRect(layout.hWnd, &rect);
if ( HTTRANSPARENT == ::SendMessage(layout.hWnd,
WM_NCHITTEST, 0, MAKELPARAM(rect.left, rect.top)) )
return FALSE;
break;
}
return TRUE;
}
else if (layout.sWndClass == WC_STATIC)
{
switch (style & SS_TYPEMASK)
{
case SS_LEFT:
case SS_CENTER:
case SS_RIGHT:
case SS_SIMPLE:
case SS_LEFTNOWORDWRAP:
// text
case SS_BLACKRECT:
case SS_GRAYRECT:
case SS_WHITERECT:
// filled rects
case SS_ETCHEDHORZ:
case SS_ETCHEDVERT:
// etched lines
case SS_BITMAP:
// bitmaps
return TRUE;
break;
case SS_ICON:
case SS_ENHMETAFILE:
if (style & SS_CENTERIMAGE)
return FALSE;
return TRUE;
break;
default:
return FALSE;
}
}
// assume the others like clipping
return TRUE;
}
void CResizableLayout::CalcNewChildPosition( const CResizableLayout::LayoutInfo & layout,
const CRect & rectParent, CRect & rectChild, UINT & uFlags)
{
CWnd* pParent = GetResizableWnd();
::GetWindowRect(layout.hWnd, &rectChild);
::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
CRect rectNew;
// calculate new top-left corner
rectNew.left = layout.sizeMarginTL.cx + rectParent.Width() * layout.sizeTypeTL.cx / 100;
rectNew.top = layout.sizeMarginTL.cy + rectParent.Height() * layout.sizeTypeTL.cy / 100;
// calculate new bottom-right corner
rectNew.right = layout.sizeMarginBR.cx + rectParent.Width() * layout.sizeTypeBR.cx / 100;
rectNew.bottom = layout.sizeMarginBR.cy + rectParent.Height() * layout.sizeTypeBR.cy / 100;
// adjust position, if client area has been scrolled
rectNew.OffsetRect(rectParent.TopLeft());
// get the refresh property
BOOL bRefresh = layout.properties.bAskRefresh ?
NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh;
// set flags
uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION;
if (bRefresh)
uFlags |= SWP_NOCOPYBITS;
if (rectNew.TopLeft() == rectChild.TopLeft())
uFlags |= SWP_NOMOVE;
if (rectNew.Size() == rectChild.Size())
uFlags |= SWP_NOSIZE;
// update rect
rectChild = rectNew;
}
void CResizableLayout::InitResizeProperties(CResizableLayout::LayoutInfo & layout)
{
// check if custom window supports this library
// (properties must be correctly set by the window)
layout.bMsgSupport = Send_QueryProperties(layout.hWnd, &layout.properties);
// default properties
if (!layout.bMsgSupport)
{
// clipping property is assumed as static
layout.properties.bAskClipping = FALSE;
layout.properties.bCachedLikesClipping = LikesClipping(layout);
// refresh property is assumed as dynamic
layout.properties.bAskRefresh = TRUE;
}
}
#if
!defined(AFX_RESIZABLEMINMAX_H__INCLUDED_)
#define AFX_RESIZABLEMINMAX_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CResizableMinMax
{
// Attributes
private:
// flags
BOOL m_bUseMaxTrack;
BOOL m_bUseMinTrack;
BOOL m_bUseMaxRect;
POINT m_ptMinTrackSize; // min tracking size
POINT m_ptMaxTrackSize; // max tracking size
POINT m_ptMaxPos; // maximized position
POINT m_ptMaxSize; // maximized size
public:
CResizableMinMax();
virtual ~CResizableMinMax();
protected:
void MinMaxInfo(LPMINMAXINFO lpMMI);
void SetMaximizedRect(const CRect& rc); // set window rect when maximized
void ResetMaximizedRect(); // reset to default maximized rect
void SetMinTrackSize(const CSize& size); // set minimum tracking size
void ResetMinTrackSize(); // reset to default minimum tracking size
void SetMaxTrackSize(const CSize& size); // set maximum tracking size
void ResetMaxTrackSize(); // reset to default maximum tracking size
} ;
#endif // !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_)
#define AFX_RESIZABLEMINMAX_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CResizableMinMax
{
// Attributes
private:
// flags
BOOL m_bUseMaxTrack;
BOOL m_bUseMinTrack;
BOOL m_bUseMaxRect;
POINT m_ptMinTrackSize; // min tracking size
POINT m_ptMaxTrackSize; // max tracking size
POINT m_ptMaxPos; // maximized position
POINT m_ptMaxSize; // maximized size
public:
CResizableMinMax();
virtual ~CResizableMinMax();
protected:
void MinMaxInfo(LPMINMAXINFO lpMMI);
void SetMaximizedRect(const CRect& rc); // set window rect when maximized
void ResetMaximizedRect(); // reset to default maximized rect
void SetMinTrackSize(const CSize& size); // set minimum tracking size
void ResetMinTrackSize(); // reset to default minimum tracking size
void SetMaxTrackSize(const CSize& size); // set maximum tracking size
void ResetMaxTrackSize(); // reset to default maximum tracking size
} ;
#endif // !defined(AFX_RESIZABLEMINMAX_H__INCLUDED_)
#include
"
stdafx.h
"
#include " ResizableMinMax.h "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CResizableMinMax::CResizableMinMax()
{
m_bUseMinTrack = FALSE;
m_bUseMaxTrack = FALSE;
m_bUseMaxRect = FALSE;
}
CResizableMinMax:: ~ CResizableMinMax()
{
}
void CResizableMinMax::MinMaxInfo(LPMINMAXINFO lpMMI)
{
if (m_bUseMinTrack)
lpMMI->ptMinTrackSize = m_ptMinTrackSize;
if (m_bUseMaxTrack)
lpMMI->ptMaxTrackSize = m_ptMaxTrackSize;
if (m_bUseMaxRect)
{
lpMMI->ptMaxPosition = m_ptMaxPos;
lpMMI->ptMaxSize = m_ptMaxSize;
}
}
void CResizableMinMax::SetMaximizedRect( const CRect & rc)
{
m_bUseMaxRect = TRUE;
m_ptMaxPos = rc.TopLeft();
m_ptMaxSize.x = rc.Width();
m_ptMaxSize.y = rc.Height();
}
void CResizableMinMax::ResetMaximizedRect()
{
m_bUseMaxRect = FALSE;
}
void CResizableMinMax::SetMinTrackSize( const CSize & size)
{
m_bUseMinTrack = TRUE;
m_ptMinTrackSize.x = size.cx;
m_ptMinTrackSize.y = size.cy;
}
void CResizableMinMax::ResetMinTrackSize()
{
m_bUseMinTrack = FALSE;
}
void CResizableMinMax::SetMaxTrackSize( const CSize & size)
{
m_bUseMaxTrack = TRUE;
m_ptMaxTrackSize.x = size.cx;
m_ptMaxTrackSize.y = size.cy;
}
void CResizableMinMax::ResetMaxTrackSize()
{
m_bUseMaxTrack = FALSE;
}
#include " ResizableMinMax.h "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CResizableMinMax::CResizableMinMax()
{
m_bUseMinTrack = FALSE;
m_bUseMaxTrack = FALSE;
m_bUseMaxRect = FALSE;
}
CResizableMinMax:: ~ CResizableMinMax()
{
}
void CResizableMinMax::MinMaxInfo(LPMINMAXINFO lpMMI)
{
if (m_bUseMinTrack)
lpMMI->ptMinTrackSize = m_ptMinTrackSize;
if (m_bUseMaxTrack)
lpMMI->ptMaxTrackSize = m_ptMaxTrackSize;
if (m_bUseMaxRect)
{
lpMMI->ptMaxPosition = m_ptMaxPos;
lpMMI->ptMaxSize = m_ptMaxSize;
}
}
void CResizableMinMax::SetMaximizedRect( const CRect & rc)
{
m_bUseMaxRect = TRUE;
m_ptMaxPos = rc.TopLeft();
m_ptMaxSize.x = rc.Width();
m_ptMaxSize.y = rc.Height();
}
void CResizableMinMax::ResetMaximizedRect()
{
m_bUseMaxRect = FALSE;
}
void CResizableMinMax::SetMinTrackSize( const CSize & size)
{
m_bUseMinTrack = TRUE;
m_ptMinTrackSize.x = size.cx;
m_ptMinTrackSize.y = size.cy;
}
void CResizableMinMax::ResetMinTrackSize()
{
m_bUseMinTrack = FALSE;
}
void CResizableMinMax::SetMaxTrackSize( const CSize & size)
{
m_bUseMaxTrack = TRUE;
m_ptMaxTrackSize.x = size.cx;
m_ptMaxTrackSize.y = size.cy;
}
void CResizableMinMax::ResetMaxTrackSize()
{
m_bUseMaxTrack = FALSE;
}
#if
!defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_)
#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
typedef struct tagRESIZEPROPERTIES
{
// wether to ask for resizing properties every time
BOOL bAskClipping;
BOOL bAskRefresh;
// otherwise, use the cached properties
BOOL bCachedLikesClipping;
BOOL bCachedNeedsRefresh;
// initialize with valid data
tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE) {}
} RESIZEPROPERTIES, * PRESIZEPROPERTIES, * LPRESIZEPROPERTIES;
typedef struct tagCLIPPINGPROPERTY
{
BOOL bLikesClipping;
// initialize with valid data
tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {}
} CLIPPINGPROPERTY, * PCLIPPINGPROPERTY, * LPCLIPPINGPROPERTY;
typedef struct tagREFRESHPROPERTY
{
BOOL bNeedsRefresh;
RECT rcOld;
RECT rcNew;
// initialize with valid data
tagREFRESHPROPERTY() : bNeedsRefresh(TRUE) {}
} REFRESHPROPERTY, * PREFRESHPROPERTY, * LPREFRESHPROPERTY;
#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_)
#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
typedef struct tagRESIZEPROPERTIES
{
// wether to ask for resizing properties every time
BOOL bAskClipping;
BOOL bAskRefresh;
// otherwise, use the cached properties
BOOL bCachedLikesClipping;
BOOL bCachedNeedsRefresh;
// initialize with valid data
tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE) {}
} RESIZEPROPERTIES, * PRESIZEPROPERTIES, * LPRESIZEPROPERTIES;
typedef struct tagCLIPPINGPROPERTY
{
BOOL bLikesClipping;
// initialize with valid data
tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {}
} CLIPPINGPROPERTY, * PCLIPPINGPROPERTY, * LPCLIPPINGPROPERTY;
typedef struct tagREFRESHPROPERTY
{
BOOL bNeedsRefresh;
RECT rcOld;
RECT rcNew;
// initialize with valid data
tagREFRESHPROPERTY() : bNeedsRefresh(TRUE) {}
} REFRESHPROPERTY, * PREFRESHPROPERTY, * LPREFRESHPROPERTY;
#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_)
#if
!defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_)
#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
typedef struct tagRESIZEPROPERTIES
{
// wether to ask for resizing properties every time
BOOL bAskClipping;
BOOL bAskRefresh;
// otherwise, use the cached properties
BOOL bCachedLikesClipping;
BOOL bCachedNeedsRefresh;
// initialize with valid data
tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE) {}
} RESIZEPROPERTIES, * PRESIZEPROPERTIES, * LPRESIZEPROPERTIES;
typedef struct tagCLIPPINGPROPERTY
{
BOOL bLikesClipping;
// initialize with valid data
tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {}
} CLIPPINGPROPERTY, * PCLIPPINGPROPERTY, * LPCLIPPINGPROPERTY;
typedef struct tagREFRESHPROPERTY
{
BOOL bNeedsRefresh;
RECT rcOld;
RECT rcNew;
// initialize with valid data
tagREFRESHPROPERTY() : bNeedsRefresh(TRUE) {}
} REFRESHPROPERTY, * PREFRESHPROPERTY, * LPREFRESHPROPERTY;
#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_)
#define AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
typedef struct tagRESIZEPROPERTIES
{
// wether to ask for resizing properties every time
BOOL bAskClipping;
BOOL bAskRefresh;
// otherwise, use the cached properties
BOOL bCachedLikesClipping;
BOOL bCachedNeedsRefresh;
// initialize with valid data
tagRESIZEPROPERTIES() : bAskClipping(TRUE), bAskRefresh(TRUE) {}
} RESIZEPROPERTIES, * PRESIZEPROPERTIES, * LPRESIZEPROPERTIES;
typedef struct tagCLIPPINGPROPERTY
{
BOOL bLikesClipping;
// initialize with valid data
tagCLIPPINGPROPERTY() : bLikesClipping(FALSE) {}
} CLIPPINGPROPERTY, * PCLIPPINGPROPERTY, * LPCLIPPINGPROPERTY;
typedef struct tagREFRESHPROPERTY
{
BOOL bNeedsRefresh;
RECT rcOld;
RECT rcNew;
// initialize with valid data
tagREFRESHPROPERTY() : bNeedsRefresh(TRUE) {}
} REFRESHPROPERTY, * PREFRESHPROPERTY, * LPREFRESHPROPERTY;
#endif // !defined(AFX_RESIZABLEMSGSUPPORT_H__INCLUDED_)
//
registered message to communicate with the library
// (defined so that in the same executable it is initialized only once)
const UINT WMU_RESIZESUPPORT = ::RegisterWindowMessage(_T( " WMU_RESIZESUPPORT " ));
// if the message is implemented the returned value must be non-zero
// the default window procedure returns zero for unhandled messages
// wParam is one of the following RSZSUP_* values, lParam as specified
#define RSZSUP_QUERYPROPERTIES 101 // lParam = LPRESIZEPROPERTIES
#define RSZSUP_LIKESCLIPPING 102 // lParam = LPCLIPPINGPROPERTY
#define RSZSUP_NEEDSREFRESH 103 // lParam = LPREFRESHPROPERTY
/////
// utility functions
inline BOOL Send_QueryProperties(HWND hWnd, LPRESIZEPROPERTIES pResizeProperties)
{
ASSERT(::IsWindow(hWnd));
return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT,
RSZSUP_QUERYPROPERTIES, (LPARAM)pResizeProperties));
}
inline BOOL Send_LikesClipping(HWND hWnd, LPCLIPPINGPROPERTY pClippingProperty)
{
ASSERT(::IsWindow(hWnd));
return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT,
RSZSUP_LIKESCLIPPING, (LPARAM)pClippingProperty));
}
inline BOOL Send_NeedsRefresh(HWND hWnd, LPREFRESHPROPERTY pRefreshProperty)
{
ASSERT(::IsWindow(hWnd));
return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT,
RSZSUP_NEEDSREFRESH, (LPARAM)pRefreshProperty));
}
// (defined so that in the same executable it is initialized only once)
const UINT WMU_RESIZESUPPORT = ::RegisterWindowMessage(_T( " WMU_RESIZESUPPORT " ));
// if the message is implemented the returned value must be non-zero
// the default window procedure returns zero for unhandled messages
// wParam is one of the following RSZSUP_* values, lParam as specified
#define RSZSUP_QUERYPROPERTIES 101 // lParam = LPRESIZEPROPERTIES
#define RSZSUP_LIKESCLIPPING 102 // lParam = LPCLIPPINGPROPERTY
#define RSZSUP_NEEDSREFRESH 103 // lParam = LPREFRESHPROPERTY
/////
// utility functions
inline BOOL Send_QueryProperties(HWND hWnd, LPRESIZEPROPERTIES pResizeProperties)
{
ASSERT(::IsWindow(hWnd));
return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT,
RSZSUP_QUERYPROPERTIES, (LPARAM)pResizeProperties));
}
inline BOOL Send_LikesClipping(HWND hWnd, LPCLIPPINGPROPERTY pClippingProperty)
{
ASSERT(::IsWindow(hWnd));
return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT,
RSZSUP_LIKESCLIPPING, (LPARAM)pClippingProperty));
}
inline BOOL Send_NeedsRefresh(HWND hWnd, LPREFRESHPROPERTY pRefreshProperty)
{
ASSERT(::IsWindow(hWnd));
return (0 != SendMessage(hWnd, WMU_RESIZESUPPORT,
RSZSUP_NEEDSREFRESH, (LPARAM)pRefreshProperty));
}
#include
"
ResizableLayout.h
"
/////
// CResizablePage window
class CResizablePage : public CPropertyPage, public CResizableLayout
{
DECLARE_DYNCREATE(CResizablePage)
// Construction
public:
CResizablePage();
CResizablePage(UINT nIDTemplate, UINT nIDCaption = 0);
CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption = 0);
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CResizablePage)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CResizablePage();
// callable from derived classes
protected:
virtual CWnd* GetResizableWnd()
{
// make the layout know its parent window
return this;
};
// Generated message map functions
protected:
//{{AFX_MSG(CResizablePage)
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
} ;
/////
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_RESIZABLEPAGE_H__INCLUDED_)
/////
// CResizablePage window
class CResizablePage : public CPropertyPage, public CResizableLayout
{
DECLARE_DYNCREATE(CResizablePage)
// Construction
public:
CResizablePage();
CResizablePage(UINT nIDTemplate, UINT nIDCaption = 0);
CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption = 0);
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CResizablePage)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CResizablePage();
// callable from derived classes
protected:
virtual CWnd* GetResizableWnd()
{
// make the layout know its parent window
return this;
};
// Generated message map functions
protected:
//{{AFX_MSG(CResizablePage)
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
} ;
/////
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_RESIZABLEPAGE_H__INCLUDED_)
#include
"
stdafx.h
"
#include " ResizablePage.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////
// CResizablePage
IMPLEMENT_DYNCREATE(CResizablePage, CPropertyPage)
CResizablePage::CResizablePage()
{
}
CResizablePage::CResizablePage(UINT nIDTemplate, UINT nIDCaption)
: CPropertyPage(nIDTemplate, nIDCaption)
{
}
CResizablePage::CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption)
: CPropertyPage(lpszTemplateName, nIDCaption)
{
}
CResizablePage:: ~ CResizablePage()
{
}
BEGIN_MESSAGE_MAP(CResizablePage, CPropertyPage)
// {{AFX_MSG_MAP(CResizablePage)
ON_WM_SIZE()
ON_WM_ERASEBKGND()
// }}AFX_MSG_MAP
END_MESSAGE_MAP()
/////
// CResizablePage message handlers
void CResizablePage::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
ArrangeLayout();
}
BOOL CResizablePage::OnEraseBkgnd(CDC * pDC)
{
// Windows XP doesn't like clipping regions ...try this!
EraseBackground(pDC);
return TRUE;
/* ClipChildren(pDC); // old-method (for safety)
return CPropertyPage::OnEraseBkgnd(pDC);
*/
}
#include " ResizablePage.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////
// CResizablePage
IMPLEMENT_DYNCREATE(CResizablePage, CPropertyPage)
CResizablePage::CResizablePage()
{
}
CResizablePage::CResizablePage(UINT nIDTemplate, UINT nIDCaption)
: CPropertyPage(nIDTemplate, nIDCaption)
{
}
CResizablePage::CResizablePage(LPCTSTR lpszTemplateName, UINT nIDCaption)
: CPropertyPage(lpszTemplateName, nIDCaption)
{
}
CResizablePage:: ~ CResizablePage()
{
}
BEGIN_MESSAGE_MAP(CResizablePage, CPropertyPage)
// {{AFX_MSG_MAP(CResizablePage)
ON_WM_SIZE()
ON_WM_ERASEBKGND()
// }}AFX_MSG_MAP
END_MESSAGE_MAP()
/////
// CResizablePage message handlers
void CResizablePage::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
ArrangeLayout();
}
BOOL CResizablePage::OnEraseBkgnd(CDC * pDC)
{
// Windows XP doesn't like clipping regions ...try this!
EraseBackground(pDC);
return TRUE;
/* ClipChildren(pDC); // old-method (for safety)
return CPropertyPage::OnEraseBkgnd(pDC);
*/
}
#include
"
ResizableLayout.h
"
#include " ResizableGrip.h "
#include " ResizableMinMax.h "
#include " ResizableState.h "
/////
// ResizableSheet.h : header file
//
class CResizableSheet : public CPropertySheet, public CResizableLayout,
public CResizableGrip, public CResizableMinMax,
public CResizableState
{
DECLARE_DYNAMIC(CResizableSheet)
// Construction
public:
CResizableSheet();
CResizableSheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0);
CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0);
// Attributes
private:
// support for temporarily hiding the grip
DWORD m_dwGripTempState;
// flags
BOOL m_bEnableSaveRestore;
BOOL m_bRectOnly;
BOOL m_bSavePage;
// layout vars
CSize m_sizePageTL, m_sizePageBR;
// internal status
CString m_sSection; // section name (identifies a parent window)
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CResizableSheet)
public:
virtual BOOL OnInitDialog();
//}}AFX_VIRTUAL
protected:
// Implementation
public:
void RefreshLayout();
virtual ~CResizableSheet();
// used internally
private:
void PresetLayout();
void PrivateConstruct();
void SavePage();
void LoadPage();
BOOL IsWizard() { return (m_psh.dwFlags & PSH_WIZARD); }
// callable from derived classes
protected:
// section to use in app's profile
void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE,
BOOL bWithPage = FALSE);
int GetMinWidth(); // minimum width to display all buttons
virtual CWnd* GetResizableWnd()
{
// make the layout know its parent window
return this;
};
// Generated message map functions
protected:
virtual BOOL ArrangeLayoutCallback(LayoutInfo& layout);
//{{AFX_MSG(CResizableSheet)
afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
afx_msg BOOL OnPageChanging(NMHDR* pNotifyStruct, LRESULT* pResult);
DECLARE_MESSAGE_MAP()
} ;
/////
#endif // AFX_RESIZABLESHEET_H__INCLUDED_
#include " ResizableGrip.h "
#include " ResizableMinMax.h "
#include " ResizableState.h "
/////
// ResizableSheet.h : header file
//
class CResizableSheet : public CPropertySheet, public CResizableLayout,
public CResizableGrip, public CResizableMinMax,
public CResizableState
{
DECLARE_DYNAMIC(CResizableSheet)
// Construction
public:
CResizableSheet();
CResizableSheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0);
CResizableSheet(LPCTSTR pszCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0);
// Attributes
private:
// support for temporarily hiding the grip
DWORD m_dwGripTempState;
// flags
BOOL m_bEnableSaveRestore;
BOOL m_bRectOnly;
BOOL m_bSavePage;
// layout vars
CSize m_sizePageTL, m_sizePageBR;
// internal status
CString m_sSection; // section name (identifies a parent window)
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CResizableSheet)
public:
virtual BOOL OnInitDialog();
//}}AFX_VIRTUAL
protected:
// Implementation
public:
void RefreshLayout();
virtual ~CResizableSheet();
// used internally
private:
void PresetLayout();
void PrivateConstruct();
void SavePage();
void LoadPage();
BOOL IsWizard() { return (m_psh.dwFlags & PSH_WIZARD); }
// callable from derived classes
protected:
// section to use in app's profile
void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE,
BOOL bWithPage = FALSE);
int GetMinWidth(); // minimum width to display all buttons
virtual CWnd* GetResizableWnd()
{
// make the layout know its parent window
return this;
};
// Generated message map functions
protected:
virtual BOOL ArrangeLayoutCallback(LayoutInfo& layout);
//{{AFX_MSG(CResizableSheet)
afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
afx_msg BOOL OnPageChanging(NMHDR* pNotifyStruct, LRESULT* pResult);
DECLARE_MESSAGE_MAP()
} ;
/////
#endif // AFX_RESIZABLESHEET_H__INCLUDED_
#include
"
stdafx.h
"
#include " ResizableSheet.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////
// CResizableSheet
IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)
inline void CResizableSheet::PrivateConstruct()
{
m_bEnableSaveRestore = FALSE;
m_bSavePage = FALSE;
m_dwGripTempState = 1;
}
CResizableSheet::CResizableSheet()
{
PrivateConstruct();
}
CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd * pParentWnd, UINT iSelectPage)
: CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
PrivateConstruct();
}
CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd * pParentWnd, UINT iSelectPage)
: CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
PrivateConstruct();
}
CResizableSheet:: ~ CResizableSheet()
{
}
BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
// {{AFX_MSG_MAP(CResizableSheet)
ON_WM_GETMINMAXINFO()
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
// }}AFX_MSG_MAP
ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)
END_MESSAGE_MAP()
/////
// CResizableSheet message handlers
int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
return -1;
// keep client area
CRect rect;
GetClientRect(&rect);
// set resizable style
ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
// adjust size to reflect new style
::AdjustWindowRectEx(&rect, GetStyle(),
::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED|
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION);
// create and init the size-grip
if (!CreateSizeGrip())
return -1;
return 0;
}
BOOL CResizableSheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
// set the initial size as the min track size
CRect rc;
GetWindowRect(&rc);
SetMinTrackSize(rc.Size());
// initialize layout
PresetLayout();
// prevent flickering
GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
return bResult;
}
void CResizableSheet::OnDestroy()
{
if (m_bEnableSaveRestore)
{
SaveWindowRect(m_sSection, m_bRectOnly);
SavePage();
}
RemoveAllAnchors();
CPropertySheet::OnDestroy();
}
// maps an index to a button ID and vice-versa
static UINT _propButtons[] =
{
IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
} ;
const int _propButtonsCount = sizeof (_propButtons) / sizeof (UINT);
// horizontal line in wizard mode
#define ID_WIZLINE ID_WIZFINISH+1
void CResizableSheet::PresetLayout()
{
if (IsWizard()) // wizard mode
{
// hide tab control
GetTabControl()->ShowWindow(SW_HIDE);
AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);
}
else // tab mode
{
AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);
}
// add a callback for active page (which can change at run-time)
AddAnchorCallback(1);
// use *total* parent size to have correct margins
CRect rectPage, rectSheet;
GetTotalClientRect(&rectSheet);
GetActivePage()->GetWindowRect(&rectPage);
::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);
// pre-calculate margins
m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();
m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();
// add all possible buttons, if they exist
for (int i = 0; i < _propButtonsCount; i++)
{
if (NULL != GetDlgItem(_propButtons[i]))
AddAnchor(_propButtons[i], BOTTOM_RIGHT);
}
}
BOOL CResizableSheet::ArrangeLayoutCallback(LayoutInfo & layout)
{
if (layout.nCallbackID != 1) // we only added 1 callback
return CResizableLayout::ArrangeLayoutCallback(layout);
// set layout info for active page
layout.hWnd = (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0);
if (!::IsWindow(layout.hWnd))
return FALSE;
// set margins
if (IsWizard()) // wizard mode
{
// use pre-calculated margins
layout.sizeMarginTL = m_sizePageTL;
layout.sizeMarginBR = m_sizePageBR;
}
else // tab mode
{
CTabCtrl* pTab = GetTabControl();
ASSERT(pTab != NULL);
// get tab position after resizing and calc page rect
CRect rectPage, rectSheet;
GetTotalClientRect(&rectSheet);
VERIFY(GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage));
pTab->AdjustRect(FALSE, &rectPage);
// set margins
layout.sizeMarginTL = rectPage.TopLeft() - rectSheet.TopLeft();
layout.sizeMarginBR = rectPage.BottomRight() - rectSheet.BottomRight();
}
// set anchor types
layout.sizeTypeTL = TOP_LEFT;
layout.sizeTypeBR = BOTTOM_RIGHT;
// use this layout info
return TRUE;
}
void CResizableSheet::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
return; // arrangement not needed
if (nType == SIZE_MAXIMIZED)
HideSizeGrip(&m_dwGripTempState);
else
ShowSizeGrip(&m_dwGripTempState);
// update grip and layout
UpdateSizeGrip();
ArrangeLayout();
}
BOOL CResizableSheet::OnPageChanging(NMHDR * /*pNotifyStruct*/ , LRESULT * /*pResult*/ )
{
// update new wizard page
// active page changes after this notification
PostMessage(WM_SIZE);
return FALSE; // continue routing
}
BOOL CResizableSheet::OnEraseBkgnd(CDC * pDC)
{
// Windows XP doesn't like clipping regions ...try this!
EraseBackground(pDC);
return TRUE;
/* ClipChildren(pDC); // old-method (for safety)
return CPropertySheet::OnEraseBkgnd(pDC);
*/
}
void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR * lpMMI)
{
MinMaxInfo(lpMMI);
}
// protected members
int CResizableSheet::GetMinWidth()
{
CWnd* pWnd = NULL;
CRect rectWnd, rectSheet;
GetTotalClientRect(&rectSheet);
int max = 0, min = rectSheet.Width();
// search for leftmost and rightmost button margins
for (int i = 0; i < 7; i++)
{
pWnd = GetDlgItem(_propButtons[i]);
// exclude not present or hidden buttons
if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))
continue;
// left position is relative to the right border
// of the parent window (negative value)
pWnd->GetWindowRect(&rectWnd);
::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);
int left = rectSheet.right - rectWnd.left;
int right = rectSheet.right - rectWnd.right;
if (left > max)
max = left;
if (right < min)
min = right;
}
// sizing border width
int border = GetSystemMetrics(SM_CXSIZEFRAME);
// compute total width
return max + min + 2*border;
}
// NOTE: this must be called after all the other settings
// to have the window and its controls displayed properly
void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)
{
m_sSection = pszSection;
m_bSavePage = bWithPage;
m_bEnableSaveRestore = TRUE;
m_bRectOnly = bRectOnly;
// restore immediately
LoadWindowRect(pszSection, bRectOnly);
LoadPage();
}
// private memebers
// used to save/restore active page
// either in the registry or a private .INI file
// depending on your application settings
#define ACTIVEPAGE _T("ActivePage")
void CResizableSheet::SavePage()
{
if (!m_bSavePage)
return;
// saves active page index, zero (the first) if problems
// cannot use GetActivePage, because it always fails
CTabCtrl *pTab = GetTabControl();
int page = 0;
if (pTab != NULL)
page = pTab->GetCurSel();
if (page < 0)
page = 0;
AfxGetApp()->WriteProfileInt(m_sSection, ACTIVEPAGE, page);
}
void CResizableSheet::LoadPage()
{
// restore active page, zero (the first) if not found
int page = AfxGetApp()->GetProfileInt(m_sSection, ACTIVEPAGE, 0);
if (m_bSavePage)
{
SetActivePage(page);
ArrangeLayout(); // needs refresh
}
}
void CResizableSheet::RefreshLayout()
{
SendMessage(WM_SIZE);
}
#include " ResizableSheet.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////
// CResizableSheet
IMPLEMENT_DYNAMIC(CResizableSheet, CPropertySheet)
inline void CResizableSheet::PrivateConstruct()
{
m_bEnableSaveRestore = FALSE;
m_bSavePage = FALSE;
m_dwGripTempState = 1;
}
CResizableSheet::CResizableSheet()
{
PrivateConstruct();
}
CResizableSheet::CResizableSheet(UINT nIDCaption, CWnd * pParentWnd, UINT iSelectPage)
: CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
PrivateConstruct();
}
CResizableSheet::CResizableSheet(LPCTSTR pszCaption, CWnd * pParentWnd, UINT iSelectPage)
: CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
PrivateConstruct();
}
CResizableSheet:: ~ CResizableSheet()
{
}
BEGIN_MESSAGE_MAP(CResizableSheet, CPropertySheet)
// {{AFX_MSG_MAP(CResizableSheet)
ON_WM_GETMINMAXINFO()
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_ERASEBKGND()
// }}AFX_MSG_MAP
ON_NOTIFY_REFLECT_EX(PSN_SETACTIVE, OnPageChanging)
END_MESSAGE_MAP()
/////
// CResizableSheet message handlers
int CResizableSheet::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
return -1;
// keep client area
CRect rect;
GetClientRect(&rect);
// set resizable style
ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
// adjust size to reflect new style
::AdjustWindowRectEx(&rect, GetStyle(),
::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED|
SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREPOSITION);
// create and init the size-grip
if (!CreateSizeGrip())
return -1;
return 0;
}
BOOL CResizableSheet::OnInitDialog()
{
BOOL bResult = CPropertySheet::OnInitDialog();
// set the initial size as the min track size
CRect rc;
GetWindowRect(&rc);
SetMinTrackSize(rc.Size());
// initialize layout
PresetLayout();
// prevent flickering
GetTabControl()->ModifyStyle(0, WS_CLIPSIBLINGS);
return bResult;
}
void CResizableSheet::OnDestroy()
{
if (m_bEnableSaveRestore)
{
SaveWindowRect(m_sSection, m_bRectOnly);
SavePage();
}
RemoveAllAnchors();
CPropertySheet::OnDestroy();
}
// maps an index to a button ID and vice-versa
static UINT _propButtons[] =
{
IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP,
ID_WIZBACK, ID_WIZNEXT, ID_WIZFINISH
} ;
const int _propButtonsCount = sizeof (_propButtons) / sizeof (UINT);
// horizontal line in wizard mode
#define ID_WIZLINE ID_WIZFINISH+1
void CResizableSheet::PresetLayout()
{
if (IsWizard()) // wizard mode
{
// hide tab control
GetTabControl()->ShowWindow(SW_HIDE);
AddAnchor(ID_WIZLINE, BOTTOM_LEFT, BOTTOM_RIGHT);
}
else // tab mode
{
AddAnchor(AFX_IDC_TAB_CONTROL, TOP_LEFT, BOTTOM_RIGHT);
}
// add a callback for active page (which can change at run-time)
AddAnchorCallback(1);
// use *total* parent size to have correct margins
CRect rectPage, rectSheet;
GetTotalClientRect(&rectSheet);
GetActivePage()->GetWindowRect(&rectPage);
::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectPage, 2);
// pre-calculate margins
m_sizePageTL = rectPage.TopLeft() - rectSheet.TopLeft();
m_sizePageBR = rectPage.BottomRight() - rectSheet.BottomRight();
// add all possible buttons, if they exist
for (int i = 0; i < _propButtonsCount; i++)
{
if (NULL != GetDlgItem(_propButtons[i]))
AddAnchor(_propButtons[i], BOTTOM_RIGHT);
}
}
BOOL CResizableSheet::ArrangeLayoutCallback(LayoutInfo & layout)
{
if (layout.nCallbackID != 1) // we only added 1 callback
return CResizableLayout::ArrangeLayoutCallback(layout);
// set layout info for active page
layout.hWnd = (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0);
if (!::IsWindow(layout.hWnd))
return FALSE;
// set margins
if (IsWizard()) // wizard mode
{
// use pre-calculated margins
layout.sizeMarginTL = m_sizePageTL;
layout.sizeMarginBR = m_sizePageBR;
}
else // tab mode
{
CTabCtrl* pTab = GetTabControl();
ASSERT(pTab != NULL);
// get tab position after resizing and calc page rect
CRect rectPage, rectSheet;
GetTotalClientRect(&rectSheet);
VERIFY(GetAnchorPosition(pTab->m_hWnd, rectSheet, rectPage));
pTab->AdjustRect(FALSE, &rectPage);
// set margins
layout.sizeMarginTL = rectPage.TopLeft() - rectSheet.TopLeft();
layout.sizeMarginBR = rectPage.BottomRight() - rectSheet.BottomRight();
}
// set anchor types
layout.sizeTypeTL = TOP_LEFT;
layout.sizeTypeBR = BOTTOM_RIGHT;
// use this layout info
return TRUE;
}
void CResizableSheet::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (nType == SIZE_MAXHIDE || nType == SIZE_MAXSHOW)
return; // arrangement not needed
if (nType == SIZE_MAXIMIZED)
HideSizeGrip(&m_dwGripTempState);
else
ShowSizeGrip(&m_dwGripTempState);
// update grip and layout
UpdateSizeGrip();
ArrangeLayout();
}
BOOL CResizableSheet::OnPageChanging(NMHDR * /*pNotifyStruct*/ , LRESULT * /*pResult*/ )
{
// update new wizard page
// active page changes after this notification
PostMessage(WM_SIZE);
return FALSE; // continue routing
}
BOOL CResizableSheet::OnEraseBkgnd(CDC * pDC)
{
// Windows XP doesn't like clipping regions ...try this!
EraseBackground(pDC);
return TRUE;
/* ClipChildren(pDC); // old-method (for safety)
return CPropertySheet::OnEraseBkgnd(pDC);
*/
}
void CResizableSheet::OnGetMinMaxInfo(MINMAXINFO FAR * lpMMI)
{
MinMaxInfo(lpMMI);
}
// protected members
int CResizableSheet::GetMinWidth()
{
CWnd* pWnd = NULL;
CRect rectWnd, rectSheet;
GetTotalClientRect(&rectSheet);
int max = 0, min = rectSheet.Width();
// search for leftmost and rightmost button margins
for (int i = 0; i < 7; i++)
{
pWnd = GetDlgItem(_propButtons[i]);
// exclude not present or hidden buttons
if (pWnd == NULL || !(pWnd->GetStyle() & WS_VISIBLE))
continue;
// left position is relative to the right border
// of the parent window (negative value)
pWnd->GetWindowRect(&rectWnd);
::MapWindowPoints(NULL, m_hWnd, (LPPOINT)&rectWnd, 2);
int left = rectSheet.right - rectWnd.left;
int right = rectSheet.right - rectWnd.right;
if (left > max)
max = left;
if (right < min)
min = right;
}
// sizing border width
int border = GetSystemMetrics(SM_CXSIZEFRAME);
// compute total width
return max + min + 2*border;
}
// NOTE: this must be called after all the other settings
// to have the window and its controls displayed properly
void CResizableSheet::EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly, BOOL bWithPage)
{
m_sSection = pszSection;
m_bSavePage = bWithPage;
m_bEnableSaveRestore = TRUE;
m_bRectOnly = bRectOnly;
// restore immediately
LoadWindowRect(pszSection, bRectOnly);
LoadPage();
}
// private memebers
// used to save/restore active page
// either in the registry or a private .INI file
// depending on your application settings
#define ACTIVEPAGE _T("ActivePage")
void CResizableSheet::SavePage()
{
if (!m_bSavePage)
return;
// saves active page index, zero (the first) if problems
// cannot use GetActivePage, because it always fails
CTabCtrl *pTab = GetTabControl();
int page = 0;
if (pTab != NULL)
page = pTab->GetCurSel();
if (page < 0)
page = 0;
AfxGetApp()->WriteProfileInt(m_sSection, ACTIVEPAGE, page);
}
void CResizableSheet::LoadPage()
{
// restore active page, zero (the first) if not found
int page = AfxGetApp()->GetProfileInt(m_sSection, ACTIVEPAGE, 0);
if (m_bSavePage)
{
SetActivePage(page);
ArrangeLayout(); // needs refresh
}
}
void CResizableSheet::RefreshLayout()
{
SendMessage(WM_SIZE);
}
#if
!defined(AFX_RESIZABLESTATE_H__INCLUDED_)
#define AFX_RESIZABLESTATE_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CResizableState
{
protected:
// non-zero if successful
BOOL LoadWindowRect(LPCTSTR pszSection, BOOL bRectOnly);
BOOL SaveWindowRect(LPCTSTR pszSection, BOOL bRectOnly);
virtual CWnd* GetResizableWnd() = 0;
public:
CResizableState();
virtual ~CResizableState();
} ;
#endif // !defined(AFX_RESIZABLESTATE_H__INCLUDED_)
#define AFX_RESIZABLESTATE_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CResizableState
{
protected:
// non-zero if successful
BOOL LoadWindowRect(LPCTSTR pszSection, BOOL bRectOnly);
BOOL SaveWindowRect(LPCTSTR pszSection, BOOL bRectOnly);
virtual CWnd* GetResizableWnd() = 0;
public:
CResizableState();
virtual ~CResizableState();
} ;
#endif // !defined(AFX_RESIZABLESTATE_H__INCLUDED_)
#include
"
stdafx.h
"
#include " ResizableState.h "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CResizableState::CResizableState()
{
}
CResizableState:: ~ CResizableState()
{
}
// used to save/restore window's size and position
// either in the registry or a private .INI file
// depending on your application settings
#define PLACEMENT_ENT _T("WindowPlacement")
#define PLACEMENT_FMT _T("%d,%d,%d,%d,%d,%d")
BOOL CResizableState::SaveWindowRect(LPCTSTR pszSection, BOOL bRectOnly)
{
CString data;
WINDOWPLACEMENT wp;
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
wp.length = sizeof(WINDOWPLACEMENT);
if (!GetResizableWnd()->GetWindowPlacement(&wp))
return FALSE;
RECT& rc = wp.rcNormalPosition; // alias
if (bRectOnly) // save size/pos only (normal state)
{
// use screen coordinates
GetResizableWnd()->GetWindowRect(&rc);
data.Format(PLACEMENT_FMT, rc.left, rc.top,
rc.right, rc.bottom, SW_NORMAL, 0);
}
else // save also min/max state
{
// use workspace coordinates
data.Format(PLACEMENT_FMT, rc.left, rc.top,
rc.right, rc.bottom, wp.showCmd, wp.flags);
}
return AfxGetApp()->WriteProfileString(pszSection, PLACEMENT_ENT, data);
}
BOOL CResizableState::LoadWindowRect(LPCTSTR pszSection, BOOL bRectOnly)
{
CString data;
WINDOWPLACEMENT wp;
data = AfxGetApp()->GetProfileString(pszSection, PLACEMENT_ENT);
if (data.IsEmpty()) // never saved before
return FALSE;
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
wp.length = sizeof(WINDOWPLACEMENT);
if (!GetResizableWnd()->GetWindowPlacement(&wp))
return FALSE;
RECT& rc = wp.rcNormalPosition; // alias
if (_stscanf(data, PLACEMENT_FMT, &rc.left, &rc.top,
&rc.right, &rc.bottom, &wp.showCmd, &wp.flags) == 6)
{
if (bRectOnly) // restore size/pos only
{
CRect rect(rc);
return GetResizableWnd()->SetWindowPos(NULL, rect.left, rect.top,
rect.Width(), rect.Height(), SWP_NOACTIVATE | SWP_NOZORDER |
SWP_NOREPOSITION);
}
else // restore also min/max state
{
return GetResizableWnd()->SetWindowPlacement(&wp);
}
}
return FALSE;
}
#include " ResizableState.h "
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CResizableState::CResizableState()
{
}
CResizableState:: ~ CResizableState()
{
}
// used to save/restore window's size and position
// either in the registry or a private .INI file
// depending on your application settings
#define PLACEMENT_ENT _T("WindowPlacement")
#define PLACEMENT_FMT _T("%d,%d,%d,%d,%d,%d")
BOOL CResizableState::SaveWindowRect(LPCTSTR pszSection, BOOL bRectOnly)
{
CString data;
WINDOWPLACEMENT wp;
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
wp.length = sizeof(WINDOWPLACEMENT);
if (!GetResizableWnd()->GetWindowPlacement(&wp))
return FALSE;
RECT& rc = wp.rcNormalPosition; // alias
if (bRectOnly) // save size/pos only (normal state)
{
// use screen coordinates
GetResizableWnd()->GetWindowRect(&rc);
data.Format(PLACEMENT_FMT, rc.left, rc.top,
rc.right, rc.bottom, SW_NORMAL, 0);
}
else // save also min/max state
{
// use workspace coordinates
data.Format(PLACEMENT_FMT, rc.left, rc.top,
rc.right, rc.bottom, wp.showCmd, wp.flags);
}
return AfxGetApp()->WriteProfileString(pszSection, PLACEMENT_ENT, data);
}
BOOL CResizableState::LoadWindowRect(LPCTSTR pszSection, BOOL bRectOnly)
{
CString data;
WINDOWPLACEMENT wp;
data = AfxGetApp()->GetProfileString(pszSection, PLACEMENT_ENT);
if (data.IsEmpty()) // never saved before
return FALSE;
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
wp.length = sizeof(WINDOWPLACEMENT);
if (!GetResizableWnd()->GetWindowPlacement(&wp))
return FALSE;
RECT& rc = wp.rcNormalPosition; // alias
if (_stscanf(data, PLACEMENT_FMT, &rc.left, &rc.top,
&rc.right, &rc.bottom, &wp.showCmd, &wp.flags) == 6)
{
if (bRectOnly) // restore size/pos only
{
CRect rect(rc);
return GetResizableWnd()->SetWindowPos(NULL, rect.left, rect.top,
rect.Width(), rect.Height(), SWP_NOACTIVATE | SWP_NOZORDER |
SWP_NOREPOSITION);
}
else // restore also min/max state
{
return GetResizableWnd()->SetWindowPlacement(&wp);
}
}
return FALSE;
}
#pragma
once
// CCmdUIDialog dialog
#include < afxdlgs.h >
class CCmdUIDialog : public CDialog
{
DECLARE_DYNAMIC(CCmdUIDialog)
public:
CCmdUIDialog();
CCmdUIDialog(UINT nIDTemplate, CWnd* pParent = NULL);
CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = NULL);
virtual ~CCmdUIDialog();
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
afx_msg void OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu);
} ;
// CCmdUIPropertyPage
class CCmdUIPropertyPage : public CPropertyPage
{
DECLARE_DYNAMIC(CCmdUIPropertyPage)
public:
CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0); // standard constructor
virtual ~CCmdUIPropertyPage();
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
} ;
// CCmdUIDialog dialog
#include < afxdlgs.h >
class CCmdUIDialog : public CDialog
{
DECLARE_DYNAMIC(CCmdUIDialog)
public:
CCmdUIDialog();
CCmdUIDialog(UINT nIDTemplate, CWnd* pParent = NULL);
CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd* pParent = NULL);
virtual ~CCmdUIDialog();
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
afx_msg void OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu);
} ;
// CCmdUIPropertyPage
class CCmdUIPropertyPage : public CPropertyPage
{
DECLARE_DYNAMIC(CCmdUIPropertyPage)
public:
CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption = 0); // standard constructor
virtual ~CCmdUIPropertyPage();
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
} ;
#include
"
stdafx.h
"
#include < afxpriv.h >
#include " CmdUI.h "
// CCmdUIDialog dialog
IMPLEMENT_DYNAMIC(CCmdUIDialog, CDialog)
CCmdUIDialog::CCmdUIDialog()
{
}
CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd * pParent /*=NULL*/ )
: CDialog(nIDTemplate, pParent)
{
}
CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd * pParentWnd)
: CDialog(lpszTemplateName, pParentWnd)
{
}
CCmdUIDialog:: ~ CCmdUIDialog()
{
}
LRESULT CCmdUIDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG)
{
SendMessage(WM_KICKIDLE);
}
return(ret);
}
BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
ON_WM_INITMENUPOPUP()
END_MESSAGE_MAP()
// CCmdUIDialog message handlers
void CCmdUIDialog::OnKickIdle()
{
UpdateDialogControls(this, false);
// TODO: maybe we should send this call to modeless child cdialogs too
}
// Q242577
void CCmdUIDialog::OnInitMenuPopup(CMenu * pPopupMenu, UINT nIndex,BOOL bSysMenu)
{
ASSERT(pPopupMenu != NULL);
// Check the enabled state of various menu items.
CCmdUI state;
state.m_pMenu = pPopupMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
// Determine if menu is popup in top-level menu and set m_pOther to
// it if so (m_pParentMenu == NULL indicates that it is secondary popup).
HMENU hParentMenu;
if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)
state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup.
else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
{
CWnd* pParent = this;
// Child windows don't have menus--need to go to the top!
if (pParent != NULL &&
(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
{
int nIndexMax = ::GetMenuItemCount(hParentMenu);
for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
{
if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)
{
// When popup is found, m_pParentMenu is containing menu.
state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
break;
}
}
}
}
state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
if (state.m_nID == 0)
continue; // Menu separator or invalid cmd - ignore it.
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if (state.m_nID == (UINT)-1)
{
// Possibly a popup menu, route to first item of that popup.
state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
if (state.m_pSubMenu == NULL ||
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // First item of popup can't be routed to.
}
state.DoUpdate(this, TRUE); // Popups are never auto disabled.
}
else
{
// Normal menu item.
// Auto enable/disable if frame window has m_bAutoMenuEnable
// set and command is _not_ a system command.
state.m_pSubMenu = NULL;
state.DoUpdate(this, FALSE);
}
// Adjust for menu deletions and additions.
UINT nCount = pPopupMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}
// CCmdUIPropertyPage
IMPLEMENT_DYNAMIC(CCmdUIPropertyPage, CPropertyPage)
CCmdUIPropertyPage::CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption)
: CPropertyPage(nIDTemplate, nIDCaption)
{
}
CCmdUIPropertyPage:: ~ CCmdUIPropertyPage()
{
}
LRESULT CCmdUIPropertyPage::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_COMMAND)
{
switch(HIWORD(wParam))
{
case BN_CLICKED: case CBN_SELCHANGE: case EN_CHANGE:
SetModified();
default:;
}
}
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG)
{
SendMessage(WM_KICKIDLE);
}
return(ret);
}
BEGIN_MESSAGE_MAP(CCmdUIPropertyPage, CPropertyPage)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
END_MESSAGE_MAP()
// CCmdUIPropertyPage message handlers
void CCmdUIPropertyPage::OnKickIdle()
{
UpdateDialogControls(this, false);
// TODO: maybe we should send this call to modeless child cPropertyPages too
}
#include < afxpriv.h >
#include " CmdUI.h "
// CCmdUIDialog dialog
IMPLEMENT_DYNAMIC(CCmdUIDialog, CDialog)
CCmdUIDialog::CCmdUIDialog()
{
}
CCmdUIDialog::CCmdUIDialog(UINT nIDTemplate, CWnd * pParent /*=NULL*/ )
: CDialog(nIDTemplate, pParent)
{
}
CCmdUIDialog::CCmdUIDialog(LPCTSTR lpszTemplateName, CWnd * pParentWnd)
: CDialog(lpszTemplateName, pParentWnd)
{
}
CCmdUIDialog:: ~ CCmdUIDialog()
{
}
LRESULT CCmdUIDialog::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG)
{
SendMessage(WM_KICKIDLE);
}
return(ret);
}
BEGIN_MESSAGE_MAP(CCmdUIDialog, CDialog)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
ON_WM_INITMENUPOPUP()
END_MESSAGE_MAP()
// CCmdUIDialog message handlers
void CCmdUIDialog::OnKickIdle()
{
UpdateDialogControls(this, false);
// TODO: maybe we should send this call to modeless child cdialogs too
}
// Q242577
void CCmdUIDialog::OnInitMenuPopup(CMenu * pPopupMenu, UINT nIndex,BOOL bSysMenu)
{
ASSERT(pPopupMenu != NULL);
// Check the enabled state of various menu items.
CCmdUI state;
state.m_pMenu = pPopupMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
// Determine if menu is popup in top-level menu and set m_pOther to
// it if so (m_pParentMenu == NULL indicates that it is secondary popup).
HMENU hParentMenu;
if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)
state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup.
else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
{
CWnd* pParent = this;
// Child windows don't have menus--need to go to the top!
if (pParent != NULL &&
(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
{
int nIndexMax = ::GetMenuItemCount(hParentMenu);
for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
{
if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)
{
// When popup is found, m_pParentMenu is containing menu.
state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
break;
}
}
}
}
state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
if (state.m_nID == 0)
continue; // Menu separator or invalid cmd - ignore it.
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if (state.m_nID == (UINT)-1)
{
// Possibly a popup menu, route to first item of that popup.
state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
if (state.m_pSubMenu == NULL ||
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // First item of popup can't be routed to.
}
state.DoUpdate(this, TRUE); // Popups are never auto disabled.
}
else
{
// Normal menu item.
// Auto enable/disable if frame window has m_bAutoMenuEnable
// set and command is _not_ a system command.
state.m_pSubMenu = NULL;
state.DoUpdate(this, FALSE);
}
// Adjust for menu deletions and additions.
UINT nCount = pPopupMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}
// CCmdUIPropertyPage
IMPLEMENT_DYNAMIC(CCmdUIPropertyPage, CPropertyPage)
CCmdUIPropertyPage::CCmdUIPropertyPage(UINT nIDTemplate, UINT nIDCaption)
: CPropertyPage(nIDTemplate, nIDCaption)
{
}
CCmdUIPropertyPage:: ~ CCmdUIPropertyPage()
{
}
LRESULT CCmdUIPropertyPage::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_COMMAND)
{
switch(HIWORD(wParam))
{
case BN_CLICKED: case CBN_SELCHANGE: case EN_CHANGE:
SetModified();
default:;
}
}
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG)
{
SendMessage(WM_KICKIDLE);
}
return(ret);
}
BEGIN_MESSAGE_MAP(CCmdUIPropertyPage, CPropertyPage)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
END_MESSAGE_MAP()
// CCmdUIPropertyPage message handlers
void CCmdUIPropertyPage::OnKickIdle()
{
UpdateDialogControls(this, false);
// TODO: maybe we should send this call to modeless child cPropertyPages too
}
#include
"
ResizableLayout.h
"
#include " ResizableGrip.h "
#include " ResizableMinMax.h "
#include " ResizableState.h "
#include " ..CmdUICmdUI.h "
/////
// CResizableDialog window
class CResizableDialog : public CCmdUIDialog, public CResizableLayout,
public CResizableGrip, public CResizableMinMax,
public CResizableState
{
// Construction
public:
CResizableDialog();
CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);
// Attributes
private:
// support for temporarily hiding the grip
DWORD m_dwGripTempState;
// flags
BOOL m_bEnableSaveRestore;
BOOL m_bRectOnly;
// internal status
CString m_sSection; // section name (identifies a parent window)
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CResizableDialog)
protected:
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CResizableDialog();
// used internally
private:
void PrivateConstruct();
// callable from derived classes
protected:
// section to use in app's profile
void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE);
virtual CWnd* GetResizableWnd()
{
// make the layout know its parent window
return this;
};
// Generated message map functions
protected:
//{{AFX_MSG(CResizableDialog)
afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
} ;
/////
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_)
#include " ResizableGrip.h "
#include " ResizableMinMax.h "
#include " ResizableState.h "
#include " ..CmdUICmdUI.h "
/////
// CResizableDialog window
class CResizableDialog : public CCmdUIDialog, public CResizableLayout,
public CResizableGrip, public CResizableMinMax,
public CResizableState
{
// Construction
public:
CResizableDialog();
CResizableDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);
CResizableDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);
// Attributes
private:
// support for temporarily hiding the grip
DWORD m_dwGripTempState;
// flags
BOOL m_bEnableSaveRestore;
BOOL m_bRectOnly;
// internal status
CString m_sSection; // section name (identifies a parent window)
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CResizableDialog)
protected:
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CResizableDialog();
// used internally
private:
void PrivateConstruct();
// callable from derived classes
protected:
// section to use in app's profile
void EnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE);
virtual CWnd* GetResizableWnd()
{
// make the layout know its parent window
return this;
};
// Generated message map functions
protected:
//{{AFX_MSG(CResizableDialog)
afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
} ;
/////
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_RESIZABLEDIALOG_H__INCLUDED_)