Click here to Skip to main content
15,895,833 members
Articles / Desktop Programming / MFC

Dynamic child window positioning

Rate me:
Please Sign up or sign in to vote.
4.97/5 (24 votes)
22 Feb 2000 382.6K   3.1K   97  
Describes a method to implement resizable child windows.
// cdxCDynamicWndEx.cpp: implementation of the cdxCDynamicWndEx class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "cdxCDynamicWndEx.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/////////////////////////////////////////////////////////////////////////////
// Some static variables (taken from cdxCDynamicControlsManager)
/////////////////////////////////////////////////////////////////////////////

#define	REGVAL_NOSTATE		-1
#define	REGVAL_VISIBLE		1
#define	REGVAL_HIDDEN		0
#define	REGVAL_MAXIMIZED	1
#define	REGVAL_ICONIC		0
#define	REGVAL_INVALID		0
#define	REGVAL_VALID		1

/*
 * registry value names
 * (for StoreWindowPosition()/RestoreWindowPosition())
 */

static LPCTSTR	lpszRegVal_Left		=	_T("Left"),
					lpszRegVal_Right		=	_T("Right"),
					lpszRegVal_Top			=	_T("Top"),
					lpszRegVal_Bottom		=	_T("Bottom"),
					lpszRegVal_Visible	=	_T("Visibility"),
					lpszRegVal_State		=	_T("State"),
					lpszRegVal_Valid		=	_T("(valid)");

LPCTSTR	cdxCDynamicWndEx::M_lpszAutoPosProfileSection	=	_T("WindowPositions");

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicWndEx
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicWndEx stretches windows
/////////////////////////////////////////////////////////////////////////////

static inline CString _makeFullProfile(LPCTSTR lpszBase, const CString & str)
{
	CString	s	=	lpszBase;

	if(s.GetLength() && (s[s.GetLength()-1] != _T('\\')))
		s	+=	_T('\\');

	s	+=	str;
	return s;
}

void cdxCDynamicWndEx::OnInitialized()
{
	ASSERT(IsWindow());

	if(!m_strAutoPos.IsEmpty())
	{
		if(!RestoreWindowPosition(_makeFullProfile(M_lpszAutoPosProfileSection,m_strAutoPos),rflg_all))
		{
			Window()->CenterWindow();
			StretchWindow(10);
		}
	}
}

void cdxCDynamicWndEx::OnDestroying()
{
	if(!m_strAutoPos.IsEmpty() && IsWindow())
		StoreWindowPosition(_makeFullProfile(M_lpszAutoPosProfileSection,m_strAutoPos));
}

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicWndEx stretches windows
/////////////////////////////////////////////////////////////////////////////

/*
 * stretches the window by szDelta (i.e. if szDelta is 100, the window is enlarged by 100 pixels)
 * stretching means that the center point of the window remains
 *
 * returns false if the window would be smaller than (1,1)
 *
 * NOTE: this function does NOT care of the min/max dimensions of a window
 *			Use MoveWindow() if you need to take care of it.
 *
 * STATIC
 */

bool cdxCDynamicWndEx::StretchWindow(const CSize & szDelta)
{
	if(!IsWindow())
	{
		ASSERT(false);
		return false;
	}

	CWnd	*pWnd	=	Window();

	WINDOWPLACEMENT	wpl;
	pWnd->GetWindowPlacement(&wpl);

	wpl.rcNormalPosition.left		-=	szDelta.cx / 2;
	wpl.rcNormalPosition.right		+=	(szDelta.cx + 1) / 2;
	wpl.rcNormalPosition.top		-=	szDelta.cy / 2;
	wpl.rcNormalPosition.bottom	+=	(szDelta.cy + 1) / 2;
//	wpl.flags	=	SW_SHOWNA|SW_SHOWNOACTIVATE;

	if((wpl.rcNormalPosition.left >= wpl.rcNormalPosition.right) ||
		(wpl.rcNormalPosition.top >= wpl.rcNormalPosition.bottom))
		return false;

	VERIFY( pWnd->SetWindowPos(NULL,
										wpl.rcNormalPosition.left,
										wpl.rcNormalPosition.top,
										wpl.rcNormalPosition.right - wpl.rcNormalPosition.left,
										wpl.rcNormalPosition.bottom - wpl.rcNormalPosition.top,
										SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER) );

	return true;
}

/*
 * stretch window by a percent value
 * the algorithm calculates the new size for both dimensions by:
 *
 *  newWid = oldWid + (oldWid * iAddPcnt) / 100
 *
 * NOTE: iAddPcnt may even be nagtive, but it MUST be greater than -100.
 * NOTE: this function does NOT care of the min/max dimensions of a window
 *
 * The function will return false if the new size would be empty.
 */

bool cdxCDynamicWndEx::StretchWindow(int iAddPcnt)
{
	if(!IsWindow())
	{
		ASSERT(false);
		return false;
	}

	CSize	szDelta	=	GetCurrentClientSize() + GetBorderSize();

	szDelta.cx	=	(szDelta.cx * iAddPcnt) / 100;
	szDelta.cy	=	(szDelta.cy * iAddPcnt) / 100;

	return StretchWindow(szDelta);
}


/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicWndEx registry positioning
/////////////////////////////////////////////////////////////////////////////

/*
 * stores a window's position and visiblity to the registry.
 *	return false if any error occured
 */

bool cdxCDynamicWndEx::StoreWindowPosition(LPCTSTR lpszProfile)
{
	if(!IsWindow() || !lpszProfile || !*lpszProfile)
	{
		ASSERT(false);
		return false;
	}

	CWnd	*pWnd	=	Window();

	WINDOWPLACEMENT	wpl;
	VERIFY( pWnd->GetWindowPlacement(&wpl) );

	BOOL	bVisible	=	pWnd->IsWindowVisible();
	int	iState	=	REGVAL_NOSTATE;

	if(pWnd->IsIconic())
		iState	=	REGVAL_ICONIC;
	else
		if(pWnd->IsZoomed())
			iState	=	REGVAL_MAXIMIZED;

	CWinApp	*app	=	AfxGetApp();

	if(!app->m_pszRegistryKey || !*app->m_pszRegistryKey)
	{
		TRACE(_T("*** NOTE[cdxCDynamicWndEx::StoreWindowPosition()]: To properly store and restore a window's position, please call CWinApp::SetRegistryKey() in you app's InitInstance() !\n"));
		return false;
	}

	return	app->WriteProfileInt(lpszProfile,	lpszRegVal_Valid,	REGVAL_INVALID) &&	// invalidate first
				app->WriteProfileInt(lpszProfile,	lpszRegVal_Left,		wpl.rcNormalPosition.left) &&
				app->WriteProfileInt(lpszProfile,	lpszRegVal_Right,		wpl.rcNormalPosition.right) &&
				app->WriteProfileInt(lpszProfile,	lpszRegVal_Top,		wpl.rcNormalPosition.top) &&
				app->WriteProfileInt(lpszProfile,	lpszRegVal_Bottom,	wpl.rcNormalPosition.bottom) &&
				app->WriteProfileInt(lpszProfile,	lpszRegVal_Visible,	bVisible ? REGVAL_VISIBLE : REGVAL_HIDDEN) &&
				app->WriteProfileInt(lpszProfile,	lpszRegVal_State,		iState) &&
				app->WriteProfileInt(lpszProfile,	lpszRegVal_Valid,	REGVAL_VALID);		// validate position
}

/*
 * load the registry data stored by StoreWindowPosition()
 * returns true if data have been found in the registry
 */

bool cdxCDynamicWndEx::RestoreWindowPosition(LPCTSTR lpszProfile, UINT restoreFlags)
{
	if(!IsWindow() || !lpszProfile || !*lpszProfile)
	{
		ASSERT(false);
		return false;
	}

	CWnd		*pWnd	=	Window();
	CWinApp	*app	=	AfxGetApp();

	if(!app->m_pszRegistryKey || !*app->m_pszRegistryKey)
	{
		TRACE(_T("*** NOTE[cdxCDynamicWndEx::RestoreWindowPosition()]: To properly store and restore a window's position, please call CWinApp::SetRegistryKey() in you app's InitInstance() !\n"));
		return false;
	}

	//
	// first, we check whether the position had been saved successful any time before
	//

	if( app->GetProfileInt(lpszProfile,lpszRegVal_Valid,REGVAL_INVALID) != REGVAL_VALID )
		return false;

	//
	// get old position
	//

	WINDOWPLACEMENT	wpl;
	VERIFY( pWnd->GetWindowPlacement(&wpl) );

	//
	// read registry
	//

	int	iState	=	app->GetProfileInt(lpszProfile,	lpszRegVal_State, REGVAL_NOSTATE);

	//
	// get window's previous normal position
	//

	wpl.rcNormalPosition.left		=	app->GetProfileInt(lpszProfile,	lpszRegVal_Left,		wpl.rcNormalPosition.left);
	wpl.rcNormalPosition.right		=	app->GetProfileInt(lpszProfile,	lpszRegVal_Right,		wpl.rcNormalPosition.right);
	wpl.rcNormalPosition.top		=	app->GetProfileInt(lpszProfile,	lpszRegVal_Top,		wpl.rcNormalPosition.top);
	wpl.rcNormalPosition.bottom	=	app->GetProfileInt(lpszProfile,	lpszRegVal_Bottom,	wpl.rcNormalPosition.bottom);

	if(wpl.rcNormalPosition.left > wpl.rcNormalPosition.right)
	{
		long	l	=	wpl.rcNormalPosition.right;
		wpl.rcNormalPosition.right	=	wpl.rcNormalPosition.left;
		wpl.rcNormalPosition.left	=	l;
	}
	if(wpl.rcNormalPosition.top > wpl.rcNormalPosition.bottom)
	{
		long	l	=	wpl.rcNormalPosition.bottom;
		wpl.rcNormalPosition.bottom	=	wpl.rcNormalPosition.top;
		wpl.rcNormalPosition.top	=	l;
	}

	//
	// get restore stuff
	//

	UINT	showCmd	=	SW_SHOWNA;
	
	if(restoreFlags & rflg_state)
	{
		if(iState == REGVAL_MAXIMIZED)
			showCmd	=	SW_MAXIMIZE;
		else
			if(iState == REGVAL_ICONIC)
				showCmd	=	SW_MINIMIZE;
	}

	//
	// use MoveWindow() which takes care of WM_GETMINMAXINFO
	//

	pWnd->MoveWindow(	wpl.rcNormalPosition.left,wpl.rcNormalPosition.top,
							wpl.rcNormalPosition.right - wpl.rcNormalPosition.left,
							wpl.rcNormalPosition.bottom - wpl.rcNormalPosition.top,
							showCmd == SW_SHOWNA);

	if(showCmd != SW_SHOWNA)
	{
		// read updated position

		VERIFY( pWnd->GetWindowPlacement(&wpl) );
		wpl.showCmd	=	showCmd;
		pWnd->SetWindowPlacement(&wpl);
	}
	
	//
	// get visiblity
	//

	if(restoreFlags & rflg_visibility)
	{
		int	i	=	app->GetProfileInt(lpszProfile,	lpszRegVal_Visible, REGVAL_NOSTATE);
		if(i == REGVAL_VISIBLE)
			pWnd->ShowWindow(SW_SHOW);
		else
			if(i == REGVAL_HIDDEN)
				pWnd->ShowWindow(SW_HIDE);
	}

	return true;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Other JP Morgan Chase
Hong Kong Hong Kong
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions