// cdxCDynamicControlsManager.cpp: implementation of the cdxCDynamicControlsManager class.
//
//////////////////////////////////////////////////////////////////////

/*
 * you should define OEMRESOURCE
 * in your project settings (C/C++, General) !
 */

#include "stdafx.h"
#include "cdxCDynamicControlsManager.h"

#include	<winuser.h>
#include	<afxmt.h>

#ifndef OBM_SIZE
#define	OBM_SIZE		32766
#pragma message("*** NOTE: cdxCDynamicControlsManager.cpp: Please define OEMRESOURCE in your project settings !")
// taken from WinresRc.h
// if not used for any reason
#endif

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

/////////////////////////////////////////////////////////////////////////////
// Some static variables
/////////////////////////////////////////////////////////////////////////////

#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)");

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicControlsManager::ControlData::ControlEntry
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// construction/destruction
/////////////////////////////////////////////////////////////////////////////

cdxCDynamicControlsManager::ControlData::ControlEntry::ControlEntry(CWnd & ctrl, ControlData & rMaster)
:	m_rMaster(rMaster), m_rCtrl(ctrl)
{
	if(m_pNext = rMaster.m_pCtrl)
		m_pNext->m_pPrev	=	this;
	rMaster.m_pCtrl	=	this;
	m_pPrev				=	NULL;

	// raise total counter
	++rMaster.m_rMaster.m_iTotalCnt;
}

cdxCDynamicControlsManager::ControlData::ControlEntry::~ControlEntry()
{
	if(m_pPrev)
	{
		if(m_pPrev->m_pNext = m_pNext)
			m_pNext->m_pPrev	=	m_pPrev;
	}
	else
	{
		ASSERT( m_rMaster.m_pCtrl == this );
		if(m_rMaster.m_pCtrl = m_pNext)
			m_pNext->m_pPrev	=	NULL;
	}

	// lower
	ASSERT( m_rMaster.m_rMaster.m_iTotalCnt > 0 );
	++m_rMaster.m_rMaster.m_iTotalCnt;
}

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicControlsManager::ControlData
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// construction/destruction
/////////////////////////////////////////////////////////////////////////////

/*
 * constructor
 * copies all paramaters and gets the controls initial position using
 * GetWindowPos().
 *
 * NOTE that the constructor need ctrl.m_hWnd to exist (in contrast to
 * Add()
 */

cdxCDynamicControlsManager::ControlData::ControlData(cdxCDynamicControlsManager & rMaster, CWnd & ctrl, const PositionSetup & rPosSetup)
:	m_rMaster(rMaster), m_pCtrl(NULL),
	m_pNext(NULL), m_pPrev(NULL),
	m_posSetup(rPosSetup)
{
	ASSERT(::IsWindow(ctrl.m_hWnd));		// control must have already been created !
	ASSERT(rPosSetup.IsValid());

	//
	// get initial values
	//

	WINDOWPLACEMENT	wpl;
	VERIFY( ctrl.GetWindowPlacement(&wpl) );

	m_rectOriginal	=	wpl.rcNormalPosition;

	//
	// remember control
	//

	new ControlEntry(ctrl,*this);
	ASSERT(m_pCtrl != NULL);

	//
	// link us to the cdxCDynamicControlsManager's list
	//

	if(m_pNext = m_rMaster.m_pFirst)
		m_pNext->m_pPrev	=	this;
	m_pPrev	=	NULL;
	m_rMaster.m_pFirst	=	this;
}

/*
 * detach from list
 * The m_Ctrl deletes all children by itself
 */

cdxCDynamicControlsManager::ControlData::~ControlData()
{
	//
	// delete all control references
	//

	while(m_pCtrl)
		delete m_pCtrl;

	//
	// unlink from list
	//

	if(m_pPrev)
	{
		if(m_pPrev->m_pNext = m_pNext)
			m_pNext->m_pPrev	=	m_pPrev;
	}
	else
	{
		ASSERT(m_rMaster.m_pFirst == this);
		if(m_rMaster.m_pFirst = m_pNext)
			m_pNext->m_pPrev	=	NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicControlsManager::ControlData virtuals
/////////////////////////////////////////////////////////////////////////////

/*
 * checks whether the CWnd is part of this control data
 */

bool cdxCDynamicControlsManager::ControlData::IsMember(CWnd & ctrl) const
{
	for(const ControlEntry *pEntry = m_pCtrl; pEntry; pEntry = pEntry->GetNext())
		if(*pEntry == ctrl)
			return true;

	return false;
}

/*
 * removes a CWnd from this chain
 */

bool cdxCDynamicControlsManager::ControlData::Rem(CWnd & ctrl)
{
	for(ControlEntry *pEntry = m_pCtrl; pEntry; pEntry = pEntry->GetNext())
		if(*pEntry == ctrl)
		{
			delete pEntry;
			return true;
		}

	return false;
}

/*
 * Get current position
 */

CRect cdxCDynamicControlsManager::ControlData::GetCurrentPosition() const
{
	if(!IsUsed())
	{
		ASSERT(false);			// all sub-controls have been deleted
		return CRect(0,0,0,0);
	}

	WINDOWPLACEMENT	wpl;
	VERIFY( m_pCtrl->GetCWnd().GetWindowPlacement(&wpl) );
	return CRect(wpl.rcNormalPosition);
}

/*
 * modify initial setup
 * NOTE: this function does not move the controls.
 * You habe to call cdxCDynamicControlsManager::ReorganizeControls past
 * using this function
 */

bool cdxCDynamicControlsManager::ControlData::Modify(const CRect & rectOriginal, const PositionSetup & rSetup)
{
	if((rectOriginal.left > rectOriginal.right) ||
		(rectOriginal.top > rectOriginal.bottom) ||
		!rSetup.IsValid())
	{
		ASSERT(false);			// bad function call
		return false;
	}

	m_rectOriginal	=	rectOriginal;
	m_posSetup		=	rSetup;
	return true;
}

/////////////////////////////////////////////////////////////////////////////
// cdxCDynamicControlsManager
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// handling events from CWnd
/////////////////////////////////////////////////////////////////////////////

/*
 * this function initializes the following members:
 * m_pWnd			-	the window handle
 * m_szCurrent		-	the current window's size
 * m_szMin			-	the minimum window's size (taken from current size)
 * m_szMax			-	the maximum window's size (set to (0,0) <=> don't change maximum)
 * m_wndSizeIcon	-	the icon (if wanted)
 *
 * parameters:
 * rWnd				-	the window to supervise
 * fd					-	in which directions can we size the window (does only apply to user-sizing)
 * bSizeIcon		-	do you want a sizable icon ?
 * pBaseClientSize-	if non-zero, this defines the real (normal) size of the
 *							window relative to all furher calculations will be made.
 *							if zero, the current window's size will be taken.
 */

void cdxCDynamicControlsManager::DoInitWindow(CWnd & rWnd, Freedom fd, bool bSizeIcon, const CSize * pBaseClientSize)
{
	ASSERT(m_pWnd == NULL);					// you MUST NOT call this function twice !
	ASSERT(::IsWindow(rWnd.m_hWnd));		// rWnd MUST already exist !!

	m_pWnd		=	&rWnd;
	m_Freedom	=	fd;

	//
	// get current's window size
	//

	CRect			rect;
	m_pWnd->GetWindowRect(&rect);
	CRect			rectClient;
	m_pWnd->GetClientRect(&rectClient);

	if(!pBaseClientSize)
	{
		m_szClientRelative.cx	=	rectClient.Width();
		m_szClientRelative.cy	=	rectClient.Height();

		m_szMin.cx	=	rect.Width();
		m_szMin.cy	=	rect.Height();
	}
	else
	{
		ASSERT((pBaseClientSize->cx > 0) && (pBaseClientSize->cy > 0));

		m_szClientRelative	=	*pBaseClientSize;
		m_szMin.cx				=	m_szClientRelative.cx + (rect.Width() - rectClient.Width());
		m_szMin.cy				=	m_szClientRelative.cy + (rect.Height() - rectClient.Height());
	}

	m_szMax.cx	=	0;
	m_szMax.cy	=	0;

	//
	// set up icon if wanted
	//

	if(bSizeIcon)
	{
		VERIFY( m_pWndSizeIcon = new cdxCSizeIconCtrl );
		VERIFY( m_pWndSizeIcon->Create(m_pWnd,m_idSizeIcon) );	// creates my control; id is SIZE_CONTROL_ID

		AddSzControl(*m_pWndSizeIcon,mdRepos,mdRepos);
		m_pWndSizeIcon->ShowWindow(SW_SHOW);		// finally - show it
	}
}

/////////////////////////////////////////////////////////////////////////////

/*
 * fill in MINMAXINFO as requested
 * Call your CWnd's OnGetMinMaxInfo first !
 *
 * changed due to a but report by Michel Wassink <mww@mitutoyo.nl>
 */

void cdxCDynamicControlsManager::DoOnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
	if(IsReady() && !IsDisabled())
	{
		lpMMI->ptMinTrackSize.x	=	m_szMin.cx;
		lpMMI->ptMinTrackSize.y	=	m_szMin.cy;

		if(m_Freedom & fdHoriz)
		{
			if(m_szMax.cx)
				lpMMI->ptMaxTrackSize.x	=	m_szMax.cx;
		}
		else
			lpMMI->ptMaxTrackSize.x	=	m_szMin.cx;

		if(m_Freedom & fdVert)
		{
			if(m_szMax.cy)
				lpMMI->ptMaxTrackSize.y	=	m_szMax.cy;
		}
		else
			lpMMI->ptMaxTrackSize.y	=	m_szMin.cy;
	}
}

/*
 * handle OnSize - we can't rely on cx,cy being client dimensions
 * as stated in the documentation ...
 */

void cdxCDynamicControlsManager::DoOnSize(UINT nType, int cx, int cy)
{
	if(IsReady() && (nType != SIZE_MINIMIZED) && !IsDisabled())
		ReorganizeControls(true);
}

/*
 * free all memory
 * after having called this function, you can reuse the object
 * although I wouldn't recommend to do so :)
 */

void cdxCDynamicControlsManager::DoDestroyWindow()
{
	while(m_pFirst)
	{
		OnDeleteControlPosition(*m_pFirst);
		delete m_pFirst;
	}

	if(m_pWndSizeIcon)
	{
		if(::IsWindow(m_pWndSizeIcon->m_hWnd))
			m_pWndSizeIcon->DestroyWindow();
		delete m_pWndSizeIcon;
		m_pWndSizeIcon	=	NULL;
	}

	m_pWnd = NULL;
}

/////////////////////////////////////////////////////////////////////////////
// control positioning
/////////////////////////////////////////////////////////////////////////////

/*
 * Reposition (without current rectangle size)
 *
 * rectWin		-	window rectangle (including border)
 * rectClient	-	window rectangle (client area)
 *                Note that since release 6, rectClient.left and .top might be > zero
 *					   (for scrolling)
 * bRedraw		-	invalidate & update window
 */

void cdxCDynamicControlsManager::ReorganizeControlsAdvanced(const CRect & rectWin, CRect rectClient, bool bRedraw)
{
	ASSERT(IsReady());

	if(!GetTotalChildCnt())
		return;

	//
	// we won't go smaller with the whole window than
	// m_szMin
	//

	if(rectWin.Width() < m_szMin.cx)
		rectClient.right	+=	(m_szMin.cx - rectWin.Width());
	if(rectWin.Height() < m_szMin.cy)
		rectClient.bottom	+=	(m_szMin.cy - rectWin.Height());

	//
	// we new replace all controls
	//

	CSize	szDelta;
	szDelta.cx	=	rectClient.Width() - m_szClientRelative.cx;
	szDelta.cy	=	rectClient.Height() - m_szClientRelative.cy;

	CPoint	pntOffset	=	rectClient.TopLeft();

	// newly added code by Rodger Bernstein

	AFX_SIZEPARENTPARAMS layout;
	ControlData				*sz;
	bool						bManual	=	true;

	if(!( layout.hDWP = ::BeginDeferWindowPos(GetTotalChildCnt()) ))
	{
		TRACE(_T("*** ERROR[cdxCDynamicControlsManager::ReorganizeControlsAdvanced()]: BeginDeferWindowPos() failed.\n"));
	}
	else
	{
		for(sz = m_pFirst; sz; sz = sz->GetNext())
			sz->OnSize(szDelta, &layout, &pntOffset);

		if(!::EndDeferWindowPos(layout.hDWP))
		{
			TRACE(_T("*** ERROR[cdxCDynamicControlsManager::ReorganizeControlsAdvanced()]: EndDeferWindowPos() failed.\n"));
		}
		else
			bManual	=	false;
	}

	if(bManual)
		for(sz = m_pFirst; sz; sz = sz->GetNext())
			sz->OnSize(szDelta, NULL);

	if(bRedraw && m_pWnd->IsWindowVisible())
	{
		m_pWnd->RedrawWindow(NULL, NULL, RDW_UPDATENOW | RDW_NOERASE);
	}
}

/////////////////////////////////////////////////////////////////////////////
// misc
/////////////////////////////////////////////////////////////////////////////

/*
 * change minimum and maximum height of window.
 *
 * szMin						-	new minimum size (use GetMinSize() to leave it as being before)
 * szMax						-	new maximum size ( "  GetMaxSize() ")
 *									Set to CSize(0,0) if you don't want a maximum size.
 * bResizeIfNecessary	-	call FixWindowSize() past calculating new sizes.
 *
 * returns false if szMin and szMax are illegal (e.g. szMin > szMax)
 */

bool cdxCDynamicControlsManager::SetMinMaxSize(const CSize & szMin, const CSize & szMax, bool bResizeIfNecessary)
{
	ASSERT(IsReady());			// DoInitWindow() not called ?

	if((szMax.cx && (szMin.cx > szMax.cx)) ||
		(szMax.cy && (szMin.cy > szMax.cy)))
	{
		return false;
	}

	m_szMin	=	szMin;
	m_szMax	=	szMax;

	if(bResizeIfNecessary)
		FixWindowSize();

	return true;
}

/*
 * this function ensure that the window's size is between m_szMin and m_szMax.
 * returns true if window size has been changed
 */

bool cdxCDynamicControlsManager::FixWindowSize()
{
	ASSERT(IsReady());			// use DoInitWindow() first !

	CSize	szCurrent	=	GetWindowSize(*m_pWnd),
			szDelta;

	if(m_szMax.cx && (szCurrent.cx > m_szMax.cx))
		szDelta.cx		=	m_szMax.cx - szCurrent.cx;		// is negative
	else
		if(szCurrent.cx < m_szMin.cx)
			szDelta.cx	=	m_szMin.cx - szCurrent.cx;		// is positive
		else
			szDelta.cx	=	0;

	if(m_szMax.cy && (szCurrent.cy > m_szMax.cy))
		szDelta.cy		=	m_szMax.cy - szCurrent.cy;		// is negative
	else
		if(szCurrent.cy < m_szMin.cy)
			szDelta.cy	=	m_szMin.cy - szCurrent.cy;		// is positive
		else
			szDelta.cy	=	0;

	if(!szDelta.cx && !szDelta.cy)
		return false;			// nothing to do

	StretchWindow(*m_pWnd,szDelta);
	return true;
}

/////////////////////////////////////////////////////////////////////////////

/*
 * hide and show icon
 */

void cdxCDynamicControlsManager::HideSizeIcon()
{
	if(m_pWndSizeIcon && ::IsWindow(m_pWndSizeIcon->m_hWnd))
		m_pWndSizeIcon->ShowWindow(SW_HIDE);
}

void cdxCDynamicControlsManager::ShowSizeIcon()
{
	if(m_pWndSizeIcon && ::IsWindow(m_pWndSizeIcon->m_hWnd))
		m_pWndSizeIcon->ShowWindow(SW_SHOW);
}

/////////////////////////////////////////////////////////////////////////////
// static functions: window sizing
/////////////////////////////////////////////////////////////////////////////

/*
 * 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 cdxCDynamicControlsManager::StretchWindow(CWnd & rWnd, const CSize & szDelta)
{
	ASSERT(::IsWindow(rWnd.m_hWnd));

	WINDOWPLACEMENT	wpl;
	rWnd.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( rWnd.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.
 *
 * STATIC
 */

bool cdxCDynamicControlsManager::StretchWindow(CWnd & rWnd, int iAddPcnt)
{
	ASSERT(::IsWindow(rWnd.m_hWnd));

	CSize	szDelta	=	GetWindowSize(rWnd);

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

	return StretchWindow(rWnd,szDelta);
}

/*
 * get current window's size
 *
 * STATIC
 */

CSize cdxCDynamicControlsManager::GetWindowSize(CWnd & rWnd)
{
	ASSERT(::IsWindow(rWnd.m_hWnd));

	CRect	rect;
	rWnd.GetWindowRect(&rect);
	return CSize(rect.Width(),rect.Height());
}

/////////////////////////////////////////////////////////////////////////////
// static functions: window & registry
/////////////////////////////////////////////////////////////////////////////

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

bool cdxCDynamicControlsManager::StoreWindowPosition(CWnd & rWnd, LPCTSTR lpszProfile)
{
	ASSERT(::IsWindow(rWnd.m_hWnd) && lpszProfile && *lpszProfile);
	// can't use an empty profile section string; see CWinApp::GetProfileInt() for further information

	WINDOWPLACEMENT	wpl;
	VERIFY( rWnd.GetWindowPlacement(&wpl) );
	BOOL	bVisible	=	rWnd.IsWindowVisible();
	int	iState	=	REGVAL_NOSTATE;

	if(rWnd.IsIconic())
		iState	=	REGVAL_ICONIC;
	else
		if(rWnd.IsZoomed())
			iState	=	REGVAL_MAXIMIZED;

	return	AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_Valid,	REGVAL_INVALID) &&	// invalidate first
				AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_Left,		wpl.rcNormalPosition.left) &&
				AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_Right,		wpl.rcNormalPosition.right) &&
				AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_Top,		wpl.rcNormalPosition.top) &&
				AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_Bottom,	wpl.rcNormalPosition.bottom) &&
				AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_Visible,	bVisible ? REGVAL_VISIBLE : REGVAL_HIDDEN) &&
				AfxGetApp()->WriteProfileInt(lpszProfile,	lpszRegVal_State,		iState) &&
				AfxGetApp()->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
 *
 * STATIC
 */

bool cdxCDynamicControlsManager::RestoreWindowPosition(CWnd & rWnd, LPCTSTR lpszProfile, UINT restoreFlags)
{
	ASSERT(::IsWindow(rWnd.m_hWnd) && lpszProfile && *lpszProfile);
	// can't use an empty profile section string; see CWinApp::GetProfileInt() for further information

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

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

	//
	// get old position
	//

	WINDOWPLACEMENT	wpl;
	VERIFY( rWnd.GetWindowPlacement(&wpl) );

	//
	// read registry
	//

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

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

	wpl.rcNormalPosition.left		=	AfxGetApp()->GetProfileInt(lpszProfile,	lpszRegVal_Left,		wpl.rcNormalPosition.left);
	wpl.rcNormalPosition.right		=	AfxGetApp()->GetProfileInt(lpszProfile,	lpszRegVal_Right,		wpl.rcNormalPosition.right);
	wpl.rcNormalPosition.top		=	AfxGetApp()->GetProfileInt(lpszProfile,	lpszRegVal_Top,		wpl.rcNormalPosition.top);
	wpl.rcNormalPosition.bottom	=	AfxGetApp()->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
	//

	rWnd.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( rWnd.GetWindowPlacement(&wpl) );
		wpl.showCmd	=	showCmd;
		rWnd.SetWindowPlacement(&wpl);
	}
	
	//
	// get visiblity
	//

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

	return true;
}



syntax highlighted by Code2HTML, v. 0.9.1