www.pudn.com > fastplayer-0.1.zip > ETSLayout.cpp, change:2000-08-05,size:86634b


//////////////////////////////////////////// 
//         ___ ____ _________________     // 
//        / _/_  _// _______________/     // 
//       / _/ / / / /  ___ ___ ____       // 
//      /__/ /_/ / / /   // _/_  _/       // 
//     _________/ / / / // _/ / /         // 
// (c) 1998-2000_/ /___//_/  /_/          // 
//                                        // 
//////////////////////////////////////////// 
//          all rights reserved           // 
//////////////////////////////////////////// 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutDialog 
// 
// A class for smart layouting of Dialogs and such 
// 
// USAGE: See LayoutMgr.html 
// 
// AUTHOR: Erwin Tratar <tr@et-soft.de> 
// 
// DISCLAIMER: 
// 
// This Sourcecode and all accompaning material is ©1998-1999 Erwin Tratar.  
// All rights reserved. 
// 
// The source code may be used in compiled form in any way you desire  
// (including usage in commercial applications), providing that your  
// application adds essential code (i.e. it is not only a wrapper) to the  
// functionality found here 
// 
// Redistribution of the sourcecode itself, publication in any media or  
// inclusion in a library requires the authors expressed written consent. 
// You may not sale this code for profit. 
// 
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. USE IT  
// AT YOUR OWN RISK! THE AUTHOR ACCEPTS NO LIABILITY FOR ANY DAMAGE/LOSS OF  
// BUSINESS THAT THIS PRODUCT MAY CAUSE. 
// 
// 
// HISTORY:  
// 1998/05/1	Initial Release 
// 1998/05/13	Added ability to have a Pane with a control 
// 1998/05/13	Added better support for TabControls 
// 1998/05/14	automatically set Icon to IDR_MAINFRAME 
// 1998/05/19	no flicker on restoring position in OnInitialUpdate 
//				Changed procedure for load/save, see constructor 
// 1998/10/02	Added support for Maximum (tracking) size 
// 1998/10/02	Much improved handling regarding RELATIVE/GREEDY 
//              /w critical minimum size 
// 1998/10/02	turn on/off gripper at lower right corner 
// 1998/10/05   Support for user defined minimum size for items 
//              (was hardcoded 5 before) 
// 1998/10/07   Fix for FormViews 
// 1998/10/31	Support for SECDialogBar/CDialogBar 
// 1998/10/31	simplified interface 
// 1998/10/31	Advanced positioning options 
// 1998/10/31	Added paneNull for empty Pane (former: NULL) 
// 1998/11/20	Swapped ETSLayoutDialog constructor parameters 
// 1998/11/20	Added Pane::addItemSpaceBetween  
//				[Leo Zelevinsky] 
// 1998/11/24	Added fixup for greedy panes 
// 1998/11/24	addItemSpaceBetween now subtracts 2*nDefaultBorder 
// 1998/11/24	addGrowing() added as a shortcut for a paneNull 
// 1998/11/24	simplified interface: no more PaneBase:: / Pane::  
//				needed 
// 1998/11/24	added FILL_* Modes 
// 1998/11/24	improved maximum size handling for greedy panes 
// 1998/11/25	Fixup of greedy panes caused infinite loop in some  
//				cases 
// 1999/01/07	addItemSpaceLike() added 
// 1999/04/03   Fixed ETSLayoutFormView memory leak 
// 1999/04/07   Fixed ALIGN_xCENTER 
// 1999/04/08   New simple stream-interface added 
// 1999/04/09   Added support for an empty Status-Bar for resizing  
//              instead of a gripper in the lower right corner 
//              [Andreas Kapust] 
// 1999/04/11   New code for much less flickering, OnEraseBkgnd() 
//              overidden for this task 
// 1999/05/12   Split Layout code into understandable pieces and adding 
//              a lot of comments 
// 1999/06/20   ABSOLUTE_X + ALIGN_FILL_X expands item if there is any 
//              left space (after all Abs/Rel/Greedy processing is done) 
// 1999/10/06   Changed Load() and Save() to use WINDOWPLACEMENT 
//              [Keith Bussell] 
// 1999/11/18   Added possibility to add panes of the same orientation 
//              to another pane. This merges both panes in one big 
//              pane with the same orientation 
// 1999/11/18   Added support for BCGDialogBar (only with BCG > 4.52!) 
// 1999/11/25   Addes support for PropertyPages/Sheets. Uses some code 
//              of a code submission from Anreas Kapust 
// 1999/11/25   Renamed classes to ETSLayoutXXX 
// 1999/11/25   Use CreateRoot() and Root() instead of m_pRootPane in 
//              derived class. 
// 1999/11/26   Added autopointer support. No need to use normal pointers 
//              when defining layout anymore. Changed m_pRootPane to  
//              m_RootPane 
// 1999/11/26   Bug in Fixup Greedy II with multiple GREEDY panes and one 
//              of them min/max limited 
// 1999/11/28   Fixed PaneTab::getConstrainVert() for ABSOLUTE_VERT 
// 1999/11/28   Fixed itemFixed() 
// 1999/11/28   Changed DWORD modeResize Arguments to layModeResize for  
//              better type safety. Added typesafe operator| 
// 1999/12/04   Don't reposition window in UpdateLayout if it's a child 
//              (as a child Dialog or PropertyPage) 
// 1999/12/04   Erase Backgroung with GCL_HBRBACKGROUND (if available)  
// 1999/12/04   itemSpaceXXX() adds a NORESIZE item instead of ABSOLUTE_XXX 
//              this will fix unwanted growing in secondary direction 
// 
// Version: 1.0 [1999/12/04] Initial Article on CodeProject 
// 
// 1999/12/10   Erase Backgroung within TabCtrl was 'fixed' badly. Reverted to 
//              old working code 
// 2000/02/02   When the Dialog is child of a View the class works correctly 
//              now [Didier BULTIAUW] 
// 2000/02/15   Combo-Boxes were not working correctly (in all modes!) 
// 2000/02/17   aligned SpinButton Controls (with buddy) now handled  
//              automatically 
//              !! do not add such a control to the layout !! it is always 
//              reattached to its buddy. 
// 2000/02/17   changed some cotrol class names to the defined constants 
// 
// Version: 1.1 [2000/02/17] 
// 
// 2000/02/25   Fixed auto alignment of SpinButton Controls to only affect  
//              visible ones 
// 2000/02/27   Put all the classes into the namespace 'ETSLayout' 
// 2000/03/07   Fixed growing Dialog after minimizing and restoring 
// 2000/05/22   Whole Statusbar (Gripper) is not excluded anymore in EraseBkgnd() 
//              instead only the triangular Gripper is excluded 
// 2000/05/31   Fix for PropertySheets with PSH_WIZARDHASFINISH [Thömmi] 
// 2000/05/31   Fix for UpDown-Controls with EditCtrl Buddy in PropertyPages. 
//              These were not repositioned every time the page is being show 
//              until the first resize 
// 2000/07/28   Problems with resizing ActiveX Controls fixed [Micheal Chapman] 
// 2000/07/28   Some strings were not properly wrapped with _T() 
// 2000/08/03   Check for BS_GROUPBOX was not correct as BS_GROUPBOX is more than one Bit 
// 2000/08/03   New override AddMainArea added to ETSLayoutPropertySheet in order to  
//              have a hook for additional controls in a PropertySheet (besides the Tab) 
// 2000/08/03   New override AddButtons added to ETSLayoutPropertySheet in order to  
//              have a hook for additional controls in the bottem pane of a PropertySheet 
// 2000/08/03   Removed the need for DECLARE_LAYOUT 
// 
// Version: 1.2 [2000/08/05] 
 
#define OEMRESOURCE 
#include	<windows.h> 
 
#include "stdafx.h" 
#include "ETSLayout.h" 
 
using namespace ETSLayout; 
#pragma warning(disable: 4097 4610 4510 4100) 
 
 
#ifndef OBM_SIZE 
#define	OBM_SIZE		32766 
// 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 
 
static UINT auIDStatusBar[] =  
{  
  ID_SEPARATOR 
}; 
 
const int ERASE_GROUP_BORDER	= 10; 
const int FIXUP_CUTOFF	= 5; 
const int TAB_SPACE = 5; 
 
// the _NULL-Pane 
CWnd* ETSLayoutMgr::paneNull = 0; 
 
void ETSLayoutMgr::Layout(CRect& rcClient) 
{ 
	if(rcClient.Height() && rcClient.Width()  && m_RootPane.IsValid())	\ 
		m_RootPane->resizeTo(rcClient);									\ 
} 
 
 
ETSLayoutMgr::CPane ETSLayoutMgr::pane( layOrientation orientation, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/,  
									   int sizeBorder /*=nDefaultBorder*/, int sizeExtraBorder /*=0*/,  
									   int sizeSecondary /*=0*/) 
{ 
	Pane* pPane = new Pane ( this, orientation, sizeBorder, sizeExtraBorder ); 
	pPane->m_sizeSecondary = sizeSecondary; 
	pPane->m_modeResize    = modeResize; 
 
	return CPane(pPane); 
} 
 
ETSLayoutMgr::CPane ETSLayoutMgr::paneTab( CTabCtrl* pTab, layOrientation orientation,  
										  ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeBorder /*=nDefaultBorder*/,  
										  int sizeExtraBorder /*=0*/, int sizeSecondary /*=0*/) 
{ 
	Pane* pPane = new PaneTab ( pTab, this, orientation, sizeBorder, sizeExtraBorder ); 
	pPane->m_sizeSecondary = sizeSecondary; 
	pPane->m_modeResize    = modeResize; 
 
	return CPane(pPane); 
} 
 
 
ETSLayoutMgr::CPane ETSLayoutMgr::paneCtrl( CWnd* pCtrl, layOrientation orientation,  
										   ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeBorder /*=nDefaultBorder*/,  
										   int sizeExtraBorder /*=0*/, int sizeTopExtra /*=0*/,  
										   int sizeSecondary /*=0*/) 
{ 
	Pane* pPane = new PaneCtrl ( pCtrl, this, orientation, sizeBorder, sizeExtraBorder, sizeTopExtra ); 
	pPane->m_sizeSecondary = sizeSecondary; 
	pPane->m_modeResize    = modeResize; 
 
	return CPane(pPane); 
} 
 
ETSLayoutMgr::CPane ETSLayoutMgr::paneCtrl( UINT nID, layOrientation orientation, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/,  
										   int sizeBorder /*=nDefaultBorder*/, int sizeExtraBorder /*=0*/, 
										   int sizeTopExtra /*=0*/, int sizeSecondary /*=0*/) 
{ 
	Pane* pPane = new PaneCtrl ( nID, this, orientation, sizeBorder, sizeExtraBorder, sizeTopExtra ); 
	pPane->m_sizeSecondary = sizeSecondary; 
	pPane->m_modeResize    = modeResize; 
 
	return CPane(pPane); 
} 
 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::item(UINT nID, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeX /*=0*/, int sizeY /*=0*/,  
										   int sizeXMin /*=-1*/, int sizeYMin /*=-1*/) 
{ 
	return new PaneItem( nID, this, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); 
} 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::item(CWnd* pWnd, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, 
										   int sizeX /*=0*/, int sizeY /*=0*/, int sizeXMin /*=-1*/,  
										   int sizeYMin /*=-1*/) 
{ 
	return new PaneItem( pWnd, this, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); 
} 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemFixed(layOrientation orientation, int sizePrimary) 
{ 
	CPaneBase p = new PaneItem(paneNull, this, NORESIZE, (orientation==HORIZONTAL)?sizePrimary:0, (orientation==VERTICAL)?sizePrimary:0); 
	return p; 
} 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemGrowing(layOrientation orientation) 
{ 
	return new PaneItem(paneNull, this, (orientation==HORIZONTAL)?ABSOLUTE_VERT:ABSOLUTE_HORZ, 0, 0, -nDefaultBorder, -nDefaultBorder); 
} 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceBetween( layOrientation orientation, CWnd* pWndFirst, CWnd* pWndSecond ) 
{ 
	if( orientation == HORIZONTAL ) { 
		// I'm interested in horizontal spacing 
 
		CRect rLeft, rRight; 
		pWndFirst->GetWindowRect(&rLeft); 
		pWndSecond->GetWindowRect(&rRight); 
 
		int sizeX = rRight.left - rLeft.right; 
	 
		if( sizeX < 0 ) { 
			// compare top to top 
			sizeX = rRight.left - rLeft.left; 
		} 
		else { 
			sizeX -= 2*nDefaultBorder; 
		} 
 
		return new PaneItem(paneNull, this, NORESIZE, sizeX, 0); 
	} 
	else { 
		// I'm interested in vertical spacing 
		CRect rTop, rBot; 
		pWndFirst->GetWindowRect(&rTop); 
		pWndSecond->GetWindowRect(&rBot); 
 
		int sizeY = rBot.top - rTop.bottom; 
 
		if( sizeY < 0 ) { 
			// compare top to top 
			sizeY = sizeY = rBot.top - rTop.top; 
		} 
		else { 
			sizeY -= 2*nDefaultBorder; 
		} 
 
		return new PaneItem(paneNull, this, NORESIZE, 0, sizeY); 
	} 
} 
 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceBetween( layOrientation orientation, UINT nIDFirst, UINT nIDSecond ) 
{ 
	CWnd *pFirst	= GetWnd()->GetDlgItem(nIDFirst); 
	CWnd *pSecond	= GetWnd()->GetDlgItem(nIDSecond); 
 
	ASSERT( pFirst && pSecond ); 
 
	return itemSpaceBetween( orientation, pFirst, pSecond ); 
} 
 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceLike( layOrientation orientation, CWnd* pWnd ) 
{ 
	CRect rRect; 
	pWnd->GetWindowRect(&rRect); 
 
	if( orientation == HORIZONTAL ) { 
		// I'm interested in horizontal spacing 
		return new PaneItem(paneNull, this, NORESIZE, rRect.Width(), 0); 
	} 
	else { 
		// I'm interested in vertical spacing 
		return new PaneItem(paneNull, this, NORESIZE, 0, rRect.Height() ); 
	} 
 
} 
 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::itemSpaceLike( layOrientation orientation, UINT nID ) 
{ 
	CWnd *pWnd	= GetWnd()->GetDlgItem(nID); 
	ASSERT( pWnd ); 
 
	return itemSpaceLike( orientation, pWnd ); 
} 
 
 
 
ETSLayoutMgr::~ETSLayoutMgr() 
{ 
} 
 
void ETSLayoutMgr::UpdateLayout() 
{ 
	if(!m_RootPane) 
		return; 
 
	// Check constraints 
	CRect rcClient = GetRect(); 
 
	if( m_pWnd->IsKindOf( RUNTIME_CLASS( CDialog ) ) && !(m_pWnd->GetStyle()&WS_CHILD) ) { 
		CRect rcWindow; 
		m_pWnd->GetWindowRect(rcWindow); 
 
		// Added by Didier BULTIAUW 
        CWnd* parentWnd = m_pWnd->GetParent(); 
        if( (parentWnd != 0) && parentWnd->IsKindOf(RUNTIME_CLASS(CView)) ) 
        { 
			CRect rcParent; 
            parentWnd->GetWindowRect(rcParent); 
            rcWindow.OffsetRect(-rcParent.left,-rcParent.top); 
        } 
		// end add 
 
		CRect rcBorder = rcWindow; 
		rcBorder -= rcClient; 
 
		// Min and Max info 
		int minWidth	= m_RootPane->getMinConstrainHorz() + rcBorder.Width()  + 2*m_sizeRootBorders.cx; 
		int minHeight	= m_RootPane->getMinConstrainVert() + rcBorder.Height() + 2*m_sizeRootBorders.cy; 
		int maxWidth	= m_RootPane->getMaxConstrainHorz(); 
		if(maxWidth != -1) { 
			maxWidth += rcBorder.Width()  + 2*m_sizeRootBorders.cx; 
			maxWidth = max(maxWidth, minWidth); 
		} 
		int maxHeight	= m_RootPane->getMaxConstrainVert(); 
		if(maxHeight != -1) { 
			maxHeight += rcBorder.Height() + 2*m_sizeRootBorders.cy; 
			maxHeight = max(maxHeight, minHeight); 
		} 
 
		if(rcWindow.Width() < minWidth) 
			rcWindow.right = rcWindow.left + minWidth; 
		if(rcWindow.Height() < minHeight) 
			rcWindow.bottom = rcWindow.top + minHeight; 
 
		if(maxWidth != -1  && rcWindow.Width() > maxWidth) 
			rcWindow.right = rcWindow.left + maxWidth; 
		if(maxHeight != -1 && rcWindow.Height() > maxHeight) 
			rcWindow.bottom = rcWindow.top + maxHeight; 
 
		m_pWnd->MoveWindow(rcWindow); 
	} 
	// Do the Layout 
	rcClient = GetRect(); 
 
	// Add a Border around the rootPane 
	rcClient.top	+= m_sizeRootBorders.cy; 
	rcClient.bottom -= m_sizeRootBorders.cy; 
	rcClient.left	+= m_sizeRootBorders.cx; 
	rcClient.right	-= m_sizeRootBorders.cx; 
 
	if(GetWnd()->IsWindowVisible()) { 
		// Avoid ugly artifacts 
		//GetWnd()->SetRedraw(FALSE); 
		Layout(rcClient); 
		//GetWnd()->SetRedraw(TRUE); 
	} 
	else 
		Layout(rcClient); 
 
	// Take special care of SpinButtons (Up-Down Controls) with Buddy set, enumerate 
	// all childs: 
	CWnd* pWndChild = GetWnd()->GetWindow(GW_CHILD); 
	TCHAR szClassName[ MAX_PATH ]; 
	while(pWndChild) 
	{ 
		::GetClassName( pWndChild->GetSafeHwnd(), szClassName, MAX_PATH ); 
		DWORD dwStyle = pWndChild->GetStyle(); 
 
		// is it a SpinButton? 
		if( _tcscmp(szClassName, UPDOWN_CLASS)==0 && ::IsWindowVisible(pWndChild->GetSafeHwnd()) ) { 
			HWND hwndBuddy = (HWND)::SendMessage( pWndChild->GetSafeHwnd(), UDM_GETBUDDY, 0, 0); 
			if( hwndBuddy != 0 && (dwStyle&(UDS_ALIGNRIGHT|UDS_ALIGNLEFT)) != 0 ) 
			{ 
				// reset Buddy 
				::SendMessage( pWndChild->GetSafeHwnd(), UDM_SETBUDDY, (WPARAM)hwndBuddy, 0); 
			} 
		} 
		 
 
		pWndChild = pWndChild->GetWindow(GW_HWNDNEXT); 
	} 
 
 
	GetWnd()->Invalidate(); 
} 
 
 
bool ETSLayoutMgr::Save(LPCTSTR lpstrRegKey) 
{ 
    CRect rcWnd; 
 
    if(IsWindow(GetWnd()->m_hWnd)) 
    { 
        WINDOWPLACEMENT wp; 
        if(GetWnd()->GetWindowPlacement(&wp)) 
        { 
            // Make sure we don't pop up  
            // minimized the next time 
            if(wp.showCmd != SW_SHOWMAXIMIZED) 
                wp.showCmd = SW_SHOWNORMAL; 
 
            AfxGetApp()->WriteProfileBinary(lpstrRegKey,  
                _T("WindowPlacement"),  
                reinterpret_cast<LPBYTE>(&wp), sizeof(wp)); 
        } 
    } 
    return true; 
} 
 
bool ETSLayoutMgr::Load(LPCTSTR lpstrRegKey) 
{ 
    LPBYTE pbtData = 0; 
    UINT nSize = 0; 
    if(AfxGetApp()->GetProfileBinary(lpstrRegKey, 
        _T("WindowPlacement"), &pbtData, &nSize)) 
    { 
        WINDOWPLACEMENT* pwp =  
            reinterpret_cast<WINDOWPLACEMENT*>(pbtData); 
		 
        ASSERT(nSize == sizeof(WINDOWPLACEMENT)); 
        if(nSize == sizeof(WINDOWPLACEMENT)) 
            GetWnd()->SetWindowPlacement(reinterpret_cast<WINDOWPLACEMENT*>(pbtData)); 
 
        delete [] pbtData; 
    } 
    return true; 
} 
 
 
void ETSLayoutMgr::EraseBkgnd(CDC* pDC) 
{ 
	CRect	rcClient; 
	GetWnd()->GetClientRect( rcClient ); 
 
	CRgn	rgn; 
	rgn.CreateRectRgnIndirect(rcClient); 
    TRACE("CreateRgn (%d,%d,%d,%d)\n", rcClient.left, rcClient.top, rcClient.right, rcClient.bottom ); 
 
	CRgn    rgnRect; 
	rgnRect.CreateRectRgn(0,0,0,0); 
 
	CRect	rcChild; 
	CWnd* pWndChild = GetWnd()->GetWindow( GW_CHILD ); 
 
	TCHAR szClassName[ MAX_PATH ]; 
 
    pDC->SelectClipRgn(NULL); 
     
	while( pWndChild ) { 
		 
		pWndChild->GetWindowRect(rcChild); 
		GetWnd()->ScreenToClient( rcChild ); 
 
		rgnRect.SetRectRgn( rcChild ); 
	 
		::GetClassName( pWndChild->GetSafeHwnd(), szClassName, MAX_PATH ); 
		DWORD dwStyle = pWndChild->GetStyle(); 
 
		// doesn't make sense for hidden children 
		if( dwStyle & WS_VISIBLE ) { 
 
            // Fix: BS_GROUPBOX is more than one Bit, extend check to (dwStyle & BS_GROUPBOX)==BS_GROUPBOX [ET] 
			if( _tcscmp(szClassName,_T("Button"))==0 && (dwStyle & BS_GROUPBOX)==BS_GROUPBOX ) { 
				// it is a group-box, ignore completely 
			} 
			else if( _tcscmp(szClassName,WC_TABCONTROL )==0 ) { 
				// ignore Tab-Control's inside rect 
				static_cast<CTabCtrl*>(pWndChild)->AdjustRect(FALSE,rcChild); 
 
				CRgn rgnContent; 
				rgnContent.CreateRectRgnIndirect(rcChild); 
 
				rgnRect.CombineRgn( &rgnRect, &rgnContent, RGN_DIFF ); 
				rgn.CombineRgn( &rgn, &rgnRect, RGN_DIFF ); 
			} 
			else if( _tcscmp(szClassName,STATUSCLASSNAME)==0 ) { 
 
				CPoint ptTriangleGrip[3]; 
				ptTriangleGrip[0] = CPoint(rcChild.right,rcChild.top); 
				ptTriangleGrip[1] = CPoint(rcChild.right,rcChild.bottom); 
				ptTriangleGrip[2] = CPoint(rcChild.right-rcChild.Height(),rcChild.bottom); 
 
				CRgn rgnGripper; 
				rgnGripper.CreatePolygonRgn(ptTriangleGrip,3, WINDING); 
 
				rgn.CombineRgn( &rgn, &rgnGripper, RGN_DIFF ); 
 
			} 
			else { 
				rgn.CombineRgn( &rgn, &rgnRect, RGN_DIFF ); 
			} 
		} 
 
		pWndChild = pWndChild->GetNextWindow(); 
	} 
 
 
	HBRUSH hBrBack = (HBRUSH) ::GetClassLong(GetWnd()->GetSafeHwnd(), GCL_HBRBACKGROUND) ; 
	if( hBrBack == 0 ) 
		hBrBack = ::GetSysColorBrush(COLOR_BTNFACE); 
 
	pDC->FillRgn( &rgn,  
		CBrush::FromHandle( hBrBack ) 
		); 
	 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutMgr::PaneItem implementation 
 
 
ETSLayoutMgr::PaneItem::PaneItem(CWnd* pWnd, ETSLayoutMgr* pMgr, ETSLayoutMgr::layResizeMode modeResize/*=GREEDY*/ 
								 , int sizeX/*=0*/, int sizeY/*=0*/ 
								 , int sizeXMin/*=-1*/, int sizeYMin/*=-1*/ ) : PaneBase( pMgr ) 
{ 
	m_modeResize	= modeResize; 
	m_hwndCtrl		= pWnd->GetSafeHwnd(); 
 
	m_sizeX			= 0; 
	m_sizeY			= 0; 
 
	m_bComboSpecial = false; 
 
	m_sizeXMin		= sizeXMin; 
	m_sizeYMin		= sizeYMin; 
 
	if(!m_hwndCtrl) {			// only Dummy! 
		m_sizeX = sizeX; 
		m_sizeY = sizeY; 
	} 
	else { 
		CRect rcControl; 
		::GetWindowRect(m_hwndCtrl, &rcControl); 
 
		if(sizeX == 0) { 
			m_sizeX			= rcControl.Width(); 
		} 
		else { 
			m_sizeX = sizeX; 
		} 
		if( m_sizeXMin == -1 ) { 
			// do not make smaller than current size 
			m_sizeXMin		= rcControl.Width(); 
		} 
 
		if(sizeY == 0) { 
			m_sizeY			= rcControl.Height(); 
		} 
		else { 
			m_sizeY = sizeY; 
		} 
		if( m_sizeYMin == -1 ) { 
			// do not make smaller than current size 
			m_sizeYMin		= rcControl.Height(); 
		} 
 
		TCHAR szClassName[ MAX_PATH ]; 
		::GetClassName( m_hwndCtrl, szClassName, MAX_PATH ); 
 
		// special treatment for combo-boxes 
		if( _tcscmp(szClassName,_T("ComboBox"))==0 || _tcscmp(szClassName,WC_COMBOBOXEX)==0) { 
			m_bComboSpecial = true; 
		} 
	} 
} 
 
ETSLayoutMgr::PaneItem::PaneItem( UINT nID, ETSLayoutMgr* pMgr, ETSLayoutMgr::layResizeMode modeResize/*=GREEDY*/ 
								 , int sizeX/*=0*/, int sizeY/*=0*/ 
								 , int sizeXMin/*=-1*/, int sizeYMin/*=-1*/ ) : PaneBase( pMgr ) 
{ 
	CWnd* pWnd		= pMgr->GetWnd()->GetDlgItem(nID); 
	m_hwndCtrl		= pWnd->GetSafeHwnd(); 
 
	m_sizeX			= 0; 
	m_sizeY			= 0; 
 
	m_bComboSpecial = false; 
 
	m_modeResize	= modeResize; 
 
	m_sizeXMin = sizeXMin; 
	m_sizeYMin = sizeYMin; 
 
	if(!m_hwndCtrl) {			// only Dummy! 
		m_sizeX = sizeX; 
		m_sizeY = sizeY; 
	} 
	else { 
		CRect rcControl; 
		::GetWindowRect(m_hwndCtrl, &rcControl); 
 
		if(sizeX == 0) { 
			m_sizeX			= rcControl.Width(); 
		} 
		else { 
			m_sizeX = sizeX; 
		} 
		if( m_sizeXMin == -1 ) { 
			// do not make smaller than current size 
			m_sizeXMin		= rcControl.Width(); 
		} 
 
		if(sizeY == 0) { 
			m_sizeY			= rcControl.Height(); 
		} 
		else { 
			m_sizeY = sizeY; 
		} 
		if( m_sizeYMin == -1 ) { 
			// do not make smaller than current size 
			m_sizeYMin		= rcControl.Height(); 
		} 
 
		TCHAR szClassName[ MAX_PATH ]; 
		::GetClassName( m_hwndCtrl, szClassName, MAX_PATH ); 
 
		// special treatment for combo-boxes 
		if( _tcscmp(szClassName,_T("ComboBox"))==0 || _tcscmp(szClassName,WC_COMBOBOXEX)==0) { 
			m_bComboSpecial = true; 
		} 
	} 
} 
 
int ETSLayoutMgr::PaneItem::getConstrainHorz(int sizeParent)  
{ 
	if( m_modeResize & ABSOLUTE_HORZ) { 
		return m_sizeX;	 
	} 
	if(m_modeResize & RELATIVE_HORZ) { 
		return (sizeParent * m_sizeX) / 100;	 
	} 
	return -1; 
} 
 
int ETSLayoutMgr::PaneItem::getConstrainVert(int sizeParent)  
{ 
	if(m_modeResize & ABSOLUTE_VERT) { 
		return m_sizeY;	 
	} 
	if(m_modeResize & RELATIVE_VERT) { 
		return (sizeParent * m_sizeY) / 100;	 
	} 
	return -1; 
} 
 
int ETSLayoutMgr::PaneItem::getMinConstrainHorz()  
{ 
	if(m_modeResize & ABSOLUTE_HORZ) { 
		return m_sizeX;	 
	} 
	return max(nMinConstrain,m_sizeXMin); 
} 
 
int ETSLayoutMgr::PaneItem::getMinConstrainVert()  
{ 
	if(m_modeResize & ABSOLUTE_VERT) { 
		return m_sizeY;	 
	} 
	return max(nMinConstrain,m_sizeYMin); 
} 
 
int ETSLayoutMgr::PaneItem::getMaxConstrainHorz()  
{ 
	if(m_modeResize & ABSOLUTE_HORZ) { 
		return m_sizeX;	 
	} 
	return -1; 
} 
 
int ETSLayoutMgr::PaneItem::getMaxConstrainVert()  
{ 
	if(m_modeResize & ABSOLUTE_VERT) { 
		return m_sizeY;	 
	} 
	return -1;	 
} 
 
bool ETSLayoutMgr::PaneItem::resizeTo(CRect& rcNewArea)  
{ 
	if(m_hwndCtrl) { 
 
		CRect rcWnd; 
		::GetWindowRect( m_hwndCtrl, rcWnd ); 
 
		if( !(m_modeResize & ALIGN_FILL_HORZ) && m_modeResize & ABSOLUTE_HORZ ) { 
 
 
			if( (m_modeResize & ALIGN_HCENTER) == ALIGN_HCENTER ) { 
				rcNewArea.OffsetRect( (rcNewArea.Width() - rcWnd.Width())/2, 0 );  
			} 
			else if( m_modeResize & ALIGN_RIGHT ) { 
				rcNewArea.OffsetRect( rcNewArea.Width() - rcWnd.Width(), 0 );  
			} 
 
			rcNewArea.right = rcNewArea.left + rcWnd.Width(); 
		} 
		if( !(m_modeResize & ALIGN_FILL_VERT) && m_modeResize & ABSOLUTE_VERT ) { 
 
 
			if( (m_modeResize & ALIGN_VCENTER) == ALIGN_VCENTER ) { 
				rcNewArea.OffsetRect( 0, (rcNewArea.Height()-rcWnd.Height())/2 );  
			} 
			else if( m_modeResize & ALIGN_BOTTOM ) { 
				rcNewArea.OffsetRect( 0, rcNewArea.Height() - rcWnd.Height());  
			} 
 
			rcNewArea.bottom = rcNewArea.top + rcWnd.Height(); 
 
		} 
 
		DWORD dwStyle = ::GetWindowLong( m_hwndCtrl, GWL_STYLE ); 
 
		// special treatment for combo-boxes 
		if( m_bComboSpecial && (dwStyle & CBS_DROPDOWN) ) { 
			// keep height (though only fully visible when dropped down) 
			rcNewArea.bottom = rcNewArea.top + rcWnd.Height(); 
		} 
 
    // FIX: ::MoveWindow would case problems with some ActiveX Controls [Micheal Chapman] 
    CWnd* pTempWnd = CWnd::FromHandle( m_hwndCtrl ); 
    pTempWnd->MoveWindow( rcNewArea.left, rcNewArea.top, rcNewArea.Width(), rcNewArea.Height() ); 
 
		if( m_bComboSpecial && !(dwStyle & CBS_DROPDOWN) && !(dwStyle & CBS_NOINTEGRALHEIGHT) ) { 
 
			// Keep CB Size = Edit + LB ( if not CBS_NOINTEGRALHEIGHT) 
 
			::GetWindowRect( m_hwndCtrl, rcWnd ); 
 
			CRect rcListBox; 
			HWND hwndListBox = ::GetDlgItem(m_hwndCtrl, 1000); // ListBox of CB 
			if( hwndListBox != 0 ) 
			{ 
				::GetWindowRect( hwndListBox, rcListBox ); 
				rcWnd.bottom = rcListBox.bottom; 
 
				rcNewArea.bottom = rcNewArea.top + rcWnd.Height(); 
 
        // FIX: ::MoveWindow would case problems with some ActiveX Controls [Micheal Chapman] 
        CWnd* pTempWnd = CWnd::FromHandle( m_hwndCtrl ); 
        pTempWnd->MoveWindow( rcNewArea.left, rcNewArea.top, rcNewArea.Width(), rcNewArea.Height(), true ); 
			} 
		} 
 
		::RedrawWindow(m_hwndCtrl,0,0, RDW_INVALIDATE | RDW_UPDATENOW );  
 
	} 
	return true; 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutMgr::PaneTab implementation 
 
 
ETSLayoutMgr::PaneTab::PaneTab( CTabCtrl* pTab, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /*= nDefaultBorder*/, int sizeExtraBorder /*= 0*/ ) 
: ETSLayoutMgr::Pane(pMgr, orientation, sizeBorder, sizeExtraBorder)  
{ 
	ASSERT(pTab); 
	m_pTab = pTab; 
} 
 
int ETSLayoutMgr::PaneTab::getConstrainHorz(int sizeParent) 
{ 
	CRect rcTab; 
	m_pTab->AdjustRect(TRUE, &rcTab); 
 
	if(rcTab.Width() > sizeParent) 
		return rcTab.Width(); 
 
	return Pane::getConstrainHorz(sizeParent /*- rcTab.Width()*/); 
} 
 
int ETSLayoutMgr::PaneTab::getConstrainVert(int sizeParent) 
{ 
	CRect rcTab; 
	m_pTab->AdjustRect(TRUE, &rcTab); 
 
	if( m_modeResize & ABSOLUTE_VERT ) { 
		return m_sizeSecondary + rcTab.Height(); 
	} 
 
	if(rcTab.Height() > sizeParent) 
		return rcTab.Height(); 
 
	return Pane::getConstrainVert(sizeParent /*- rcTab.Height()*/); 
} 
 
int ETSLayoutMgr::PaneTab::getMinConstrainHorz() 
{ 
	CRect rcTab(0,0,0,0); 
	m_pTab->AdjustRect(TRUE, &rcTab); 
 
	return Pane::getMinConstrainHorz() + rcTab.Width() ; 
} 
 
int ETSLayoutMgr::PaneTab::getMinConstrainVert() 
{ 
	CRect rcTab(0,0,0,0); 
	m_pTab->AdjustRect(TRUE, &rcTab); 
 
	return Pane::getMinConstrainVert() + rcTab.Height(); 
} 
 
int ETSLayoutMgr::PaneTab::getMaxConstrainHorz() 
{ 
	CRect rcTab(0,0,0,0); 
	m_pTab->AdjustRect(TRUE, &rcTab); 
 
	int paneMax = Pane::getMaxConstrainHorz(); 
	return (paneMax != -1) ? paneMax + rcTab.Width() : -1; 
} 
 
int ETSLayoutMgr::PaneTab::getMaxConstrainVert() 
{ 
	CRect rcTab(0,0,0,0); 
	m_pTab->AdjustRect(TRUE, &rcTab); 
 
	int paneMax = Pane::getMaxConstrainVert(); 
	return (paneMax != -1) ? paneMax + rcTab.Height() : -1; 
} 
 
bool ETSLayoutMgr::PaneTab::resizeTo(CRect& rcNewArea) 
{ 
	m_pTab->MoveWindow(rcNewArea); 
	m_pTab->AdjustRect(FALSE,rcNewArea); 
 
	return Pane::resizeTo(rcNewArea); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutMgr::PaneCtrl implementation 
 
 
ETSLayoutMgr::PaneCtrl::PaneCtrl( CWnd* pCtrl, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /*= nDefaultBorder*/, int sizeExtraBorder /*= 0*/, int sizeTopExtra /*= 0*/ ) 
: ETSLayoutMgr::Pane(pMgr, orientation, sizeBorder, sizeExtraBorder) 
{ 
	m_sizeTopExtra = sizeTopExtra; 
 
	ASSERT(pCtrl); 
	m_hwndCtrl = pCtrl->GetSafeHwnd(); 
} 
 
ETSLayoutMgr::PaneCtrl::PaneCtrl( UINT nID, ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /*= nDefaultBorder*/, int sizeExtraBorder /*= 0*/, int sizeTopExtra /*= 0*/ ) 
: ETSLayoutMgr::Pane(pMgr, orientation, sizeBorder, sizeExtraBorder) 
{ 
	m_sizeTopExtra = sizeTopExtra; 
 
	m_hwndCtrl = ::GetDlgItem(pMgr->GetWnd()->GetSafeHwnd(), nID); 
	ASSERT(m_hwndCtrl); 
} 
 
int ETSLayoutMgr::PaneCtrl::getConstrainHorz(int sizeParent) 
{ 
	return Pane::getConstrainHorz(sizeParent) ; 
} 
 
int ETSLayoutMgr::PaneCtrl::getConstrainVert(int sizeParent) 
{ 
	return Pane::getConstrainVert(sizeParent); 
} 
 
int ETSLayoutMgr::PaneCtrl::getMinConstrainHorz() 
{ 
	return Pane::getMinConstrainHorz(); 
} 
 
int ETSLayoutMgr::PaneCtrl::getMinConstrainVert() 
{ 
	return Pane::getMinConstrainVert() + m_sizeTopExtra; 
} 
 
int ETSLayoutMgr::PaneCtrl::getMaxConstrainHorz() 
{ 
	int paneMax = Pane::getMaxConstrainHorz(); 
	return ( paneMax == -1) ? -1 : paneMax ; 
} 
 
int ETSLayoutMgr::PaneCtrl::getMaxConstrainVert() 
{ 
	int paneMax = Pane::getMaxConstrainVert(); 
	return ( paneMax == -1) ? -1 : paneMax + m_sizeTopExtra; 
} 
 
bool ETSLayoutMgr::PaneCtrl::resizeTo(CRect& rcNewArea) 
{ 
  // FIX: ::MoveWindow would case problems with some ActiveX Controls [Micheal Chapman] 
  CWnd* pTempWnd = CWnd::FromHandle( m_hwndCtrl ); 
  pTempWnd->MoveWindow( rcNewArea.left, rcNewArea.top, rcNewArea.Width(), rcNewArea.Height(), true ); 
 
  ::RedrawWindow(m_hwndCtrl,0,0, RDW_INVALIDATE | RDW_UPDATENOW |RDW_ERASE);  
	rcNewArea.top	+= m_sizeTopExtra; 
	return Pane::resizeTo(rcNewArea); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutMgr::Pane implementation 
 
ETSLayoutMgr::Pane::Pane( ETSLayoutMgr* pMgr, layOrientation orientation, int sizeBorder /* = nDefaultBorder */, int sizeExtraBorder /*= 0*/)  
: PaneBase(pMgr) 
{ 
	m_Orientation	= orientation; 
	m_sizeBorder	= sizeBorder; 
	m_sizeSecondary	= 0; 
	m_modeResize	= 0; 
	m_sizeExtraBorder= sizeExtraBorder; 
} 
 
 
ETSLayoutMgr::Pane::~Pane()  
{ 
} 
 
 
bool ETSLayoutMgr::Pane::addItem( CWnd* pWnd, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeX /*=0*/, int sizeY /*=0*/, int sizeXMin /*=0*/, int sizeYMin /*=0*/) 
{ 
	CPaneBase pItem = new PaneItem( pWnd, m_pMgr, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); 
	return addPane( pItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItem( UINT nID, ETSLayoutMgr::layResizeMode modeResize /*=GREEDY*/, int sizeX /*=0*/, int sizeY /*=0*/, int sizeXMin /*=0*/, int sizeYMin /*=0*/) 
{ 
	CPaneBase pItem = new PaneItem( nID, m_pMgr, modeResize, sizeX, sizeY, sizeXMin, sizeYMin); 
	return addPane( pItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItemFixed(int size) 
{ 
	CPaneBase pNewItem = m_pMgr->itemFixed(m_Orientation, size); 
	return addPane( pNewItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItemGrowing() 
{ 
	CPaneBase pNewItem = m_pMgr->itemGrowing(m_Orientation); 
	return addPane( pNewItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItemSpaceBetween( CWnd* pWndFirst, CWnd* pWndSecond ) 
{ 
	CPaneBase pNewItem = m_pMgr->itemSpaceBetween(m_Orientation, pWndFirst, pWndSecond); 
	return addPane( pNewItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItemSpaceBetween( UINT nIDFirst, UINT nIDSecond ) 
{ 
	CPaneBase pNewItem = m_pMgr->itemSpaceBetween(m_Orientation, nIDFirst, nIDSecond); 
	return addPane( pNewItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItemSpaceLike( CWnd* pWnd ) 
{ 
	CPaneBase pNewItem = m_pMgr->itemSpaceLike(m_Orientation, pWnd); 
	return addPane( pNewItem ); 
} 
 
bool ETSLayoutMgr::Pane::addItemSpaceLike( UINT nID ) 
{ 
	CPaneBase pNewItem = m_pMgr->itemSpaceLike(m_Orientation, nID); 
	return addPane( pNewItem ); 
} 
 
bool ETSLayoutMgr::Pane::addPane( CPane pSubpane, ETSLayoutMgr::layResizeMode modeResize, int sizeSecondary /* = 0 */)  
{ 
	if( pSubpane->getOrientation() == m_Orientation) 
	{ 
		// wrap in subpane of opposite orientation 
		CPane pPaneWrap = new Pane(m_pMgr, m_Orientation==HORIZONTAL?VERTICAL:HORIZONTAL,0,0); 
		pPaneWrap->addPane( pSubpane  ); 
 
		addPane( pPaneWrap, modeResize, sizeSecondary ); 
	} 
	else 
	{ 
		pSubpane->m_modeResize = modeResize; 
 
		if(m_Orientation==HORIZONTAL && (modeResize & ABSOLUTE_HORZ) ) { 
			if(sizeSecondary == 0) { 
				pSubpane->m_sizeSecondary = pSubpane->getMinConstrainHorz(); 
			} 
		} 
		else if(m_Orientation==HORIZONTAL && (modeResize & RELATIVE_HORZ) ) { 
			pSubpane->m_sizeSecondary = sizeSecondary; 
		} 
		else if(m_Orientation==VERTICAL && (modeResize & ABSOLUTE_VERT) ) { 
			if(sizeSecondary == 0) { 
				pSubpane->m_sizeSecondary = pSubpane->getMinConstrainVert(); 
			} 
		} 
		else if(m_Orientation==VERTICAL && (modeResize & RELATIVE_VERT) ) { 
			pSubpane->m_sizeSecondary = sizeSecondary; 
		} 
 
		m_paneItems.Add(pSubpane); 
	} 
 
	return true; 
} 
 
bool ETSLayoutMgr::Pane::addPane( CPaneBase pItem )  
{ 
	m_paneItems.Add(pItem); 
	return true; 
} 
 
int ETSLayoutMgr::Pane::getConstrainHorz(int sizeParent)  
{ 
	ASSERT( m_Orientation == VERTICAL); 
 
	if( m_modeResize & RELATIVE_HORZ ) { 
		return (sizeParent * m_sizeSecondary) / 100; 
	} 
	else if( m_modeResize & ABSOLUTE_HORZ ){ 
		return m_sizeSecondary; 
	} 
	else 
		return 0; 
} 
 
 
int ETSLayoutMgr::Pane::getConstrainVert(int sizeParent)  
{ 
	ASSERT( m_Orientation == HORIZONTAL); 
 
	if( m_modeResize & RELATIVE_VERT ) { 
		return (sizeParent * m_sizeSecondary) / 100; 
	} 
	else if( m_modeResize & ABSOLUTE_VERT ) { 
		return m_sizeSecondary; 
	} 
	else { 
		return 0; 
	} 
} 
 
int ETSLayoutMgr::Pane::getMaxConstrainHorz()  
{ 
	if(m_Orientation == HORIZONTAL) { 
		int nMaxConstr = -1; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
 
			int nConstrain = pItem->getMaxConstrainHorz(); 
			if(nConstrain == -1) 
				return -1; 
 
			nMaxConstr += nConstrain; 
		} 
		return (nMaxConstr == -1) ? -1 : nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; 
	} 
	else if( m_modeResize & ABSOLUTE_HORZ && m_sizeSecondary!=0) { 
		return m_sizeSecondary; // + 2*m_sizeExtraBorder; 
	} 
	else { 
		int nMaxConstr = -1; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
 
			int nConstrain = pItem->getMaxConstrainHorz(); 
 
			if( nConstrain == -1) 
				return -1; 
			else 
				nMaxConstr = max(nMaxConstr, nConstrain); 
 
		} 
		return (nMaxConstr == -1) ? -1 : nMaxConstr + 2*m_sizeExtraBorder; 
	} 
} 
 
int ETSLayoutMgr::Pane::getMaxConstrainVert()  
{ 
	if(m_Orientation == VERTICAL) { 
		int nMaxConstr = -1; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
 
			int nConstrain = pItem->getMaxConstrainVert(); 
			if(nConstrain == -1) 
				return -1; 
 
			nMaxConstr += nConstrain; 
		} 
		return (nMaxConstr == -1) ? -1 : nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; 
	} 
	else if( m_modeResize & ABSOLUTE_VERT && m_sizeSecondary!=0) { 
		return m_sizeSecondary; // + 2*m_sizeExtraBorder; 
	} 
	else { 
		int nMaxConstr = -1; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
 
			int nConstrain = pItem->getMaxConstrainVert(); 
 
			if( nConstrain == -1) 
				return -1; 
			else 
				nMaxConstr = max(nMaxConstr, nConstrain); 
 
		} 
		return (nMaxConstr == -1) ? -1 : nMaxConstr + 2*m_sizeExtraBorder; 
	} 
} 
 
int ETSLayoutMgr::Pane::getMinConstrainHorz()  
{ 
	if(m_Orientation == HORIZONTAL) { 
		int nMaxConstr = 0; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
			nMaxConstr += max(nMinConstrain, pItem->getMinConstrainHorz()); 
		} 
		return nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; 
	} 
	else if( m_modeResize & ABSOLUTE_HORZ && m_sizeSecondary!=0) { 
		return m_sizeSecondary; // + 2*m_sizeExtraBorder; 
	} 
	else { 
		int nMaxConstr = 0; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
			int nConstrain = pItem->getMinConstrainHorz(); 
			nMaxConstr = max(nMaxConstr, nConstrain); 
		} 
		return nMaxConstr + 2*m_sizeExtraBorder; 
	} 
} 
 
int ETSLayoutMgr::Pane::getMinConstrainVert()  
{ 
	if(m_Orientation == VERTICAL) { 
		int nMaxConstr = 0; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
			nMaxConstr += max(nMinConstrain, pItem->getMinConstrainVert()); 
		} 
		return nMaxConstr + (m_paneItems.GetUpperBound()*m_sizeBorder) + 2*m_sizeExtraBorder; 
	} 
	else if( m_modeResize & ABSOLUTE_VERT && m_sizeSecondary!=0) { 
		return m_sizeSecondary; // + 2*m_sizeExtraBorder; 
	} 
	else { 
		int nMaxConstr = 0; 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
			int nConstrain = pItem->getMinConstrainVert(); 
			nMaxConstr = max(nMaxConstr, nConstrain); 
		} 
		return nMaxConstr + 2*m_sizeExtraBorder; 
	} 
} 
 
 
int ETSLayoutMgr::Pane::resizeToAbsolute(int& availSpace, CArray<int,int>& sizePrimary,  
										 CArray<int,int>& sizeMin, CArray<int,int>& sizeMax) 
{ 
	// count all greedy items as returnvalue 
	int nGreedy = 0; 
 
	// first, subtract all absoulute items from available space 
	for(int i=0; i<m_paneItems.GetSize(); ++i) { 
		CPaneBase pItem = m_paneItems[i]; 
 
		if( m_Orientation == HORIZONTAL ) { 
 
			// for absolute items subtract their size from available space 
			if(pItem->modeResize() & ABSOLUTE_HORZ) { 
				availSpace -= (sizePrimary[i] = pItem->getConstrainHorz(0)); 
			} 
 
			// count Greedy items for later 
			if(!(pItem->modeResize() & ABSOLUTE_HORZ) && !(pItem->modeResize() & RELATIVE_HORZ)) { 
				nGreedy++; 
			} 
 
			sizeMin[i] = pItem->getMinConstrainHorz(); 
			sizeMax[i] = pItem->getMaxConstrainHorz(); 
		} 
		else { 
 
			// for absolute items subtract their size from available space 
			if(pItem->modeResize() & ABSOLUTE_VERT) { 
				availSpace -= (sizePrimary[i] = pItem->getConstrainVert(0)); 
			} 
 
			// count Greedy items for later 
			if(!(pItem->modeResize() & ABSOLUTE_VERT) && !(pItem->modeResize() & RELATIVE_VERT)) { 
				nGreedy++; 
			} 
 
			sizeMin[i] = pItem->getMinConstrainVert(); 
			sizeMax[i] = pItem->getMaxConstrainVert(); 
		} 
 
	} 
 
	// Must not be negative !! 
	availSpace = max(availSpace, 0); 
 
	return nGreedy; 
} 
 
bool ETSLayoutMgr::Pane::resizeToRelative(int& availSpace, CArray<int,int>& sizePrimary, 
										 CArray<int,int>& sizeMin, CArray<int,int>& sizeMax) 
{ 
	// Then all relative items as percentage of left space (as of now after 
	// all absolute items are subtracted 
 
	int availRel = availSpace;	// At the beginning all of remaining space is available. We want all 
								// operation to be relative to the left space at this moment, so we 
								// save this amount here. Then we safly can lower availSpace 
 
	int relDiff = 0;			// The cumulated difference between first proposed size and 
								// eventual maximum/minimum size. This amount has to be 
								// saved in some other place (i.e. where relativ items/subpane 
								// are not limited by min/max 
	 
	int relLeft = 0;			// The cumulated amout of space that can be saved by 
								// shrinking the items/panes up to the minimum 
	 
	int relCount = 0;			// Actually allocated item/subpane's cumulated primary sizes  
								// of non-limited items/subpanes (these can be modified in fixup) 
								// needed for equally distribution of differences amoung non-limited 
								// relative items/subpanes 
 
	for(int i=0; i<m_paneItems.GetSize(); ++i) { 
		CPaneBase pItem = m_paneItems[i]; 
 
		// For all relative items in primary direction 
		if( (m_Orientation==HORIZONTAL && pItem->modeResize() & RELATIVE_HORZ) 
			|| 
			(m_Orientation==VERTICAL   && pItem->modeResize() & RELATIVE_VERT) ) 
		{ 
			// minimum item/subpane size in primary direction (pixels) 
			int nSizeRelMin = sizeMin[i]; 
 
			// maximum item/subpane size in primary direction (pixels) 
			int nSizeRelMax = sizeMax[i]; 
 
			// Relative size in primary direction (pixels) 
			int nSizeRel	= (m_Orientation==HORIZONTAL)  
									?  
									(pItem->getConstrainHorz(availRel))  
									: 
									(pItem->getConstrainVert(availRel)); 
 
			if( nSizeRel < nSizeRelMin) { 
				// The item/pane is shrinked too small! 
				// We will grow it to it's minimum-size. In order not to modify 
				// this item later when fixing up set the size to the negative 
				// minimum size 
				sizePrimary[i]	= -nSizeRelMin; 
 
				// As we grew one item/subpane we have to shrink another one. 
				// We keep count on how much space we needed to grow the item 
				// to it's minimum size 
				relDiff += ( nSizeRelMin - nSizeRel ); 
			} 
			else if(  nSizeRelMax != -1 && nSizeRel > nSizeRelMax) { 
				// if there's a maximum size (nSizeRelMax != -1) and our item/subpane 
				// is to be resized over that amount correct it.  In order not to modify 
				// this item later when fixing up set the size to the negative 
				// maximum size 
				sizePrimary[i]	= -nSizeRelMax; 
 
				// As we shrinked one item/subpane we have to grow another one. 
				// We keep count on how much space we needed to grow the item 
				// to it's maximum size. 
				relDiff += ( nSizeRelMax - nSizeRel ); 
			} 
			else { 
				// this is the normal case: neither are we minimum limited nor maximum 
				// limited 
 
				// As this item/subpane is larger that it's minimum we could later (if 
				// necessary for fixup) shrink it for the difference amount of pixels 
				relLeft	+= ( nSizeRel - nSizeRelMin ); 
 
				// Set the primary size of this item/pane. Can later be modified by fixup 
				sizePrimary[i]	= nSizeRel; 
 
				// Add this item/subpane's primary size to the count of already allocated 
				// cumulated size of non-limited items/subpanes (these can be modified in fixup) 
				relCount	+= nSizeRel; 
			} 
 
			// decrease available space by used space in this step 
			availSpace	-= nSizeRel; 
		} 
	} 
 
	// We now have the situation that some items/subpanes had to be adjusted for cumulated 
	// relDiff pixels (positive value means more space taken than indicated by percentage of 
	// left space). On the other hand we have some items/subpanes which were not limited (in  
	// their current dimensions) but could be if necessary up to relLeft pixels.  
	if(relLeft < relDiff && availSpace >= (relDiff-relLeft) ){		 
 
		// If it's not possible to shrink other (relative) panes in order to distribute the 
		// difference because the left for shrinking (relLeft) is too small we need to aquire 
		// more space from the globally left space (if available at all) 
		availSpace -= (relDiff-relLeft); 
		relDiff = relLeft; 
	} 
 
	// At this point we should have some space left (at least not be negative with the leftover 
	// space) and on the other hand there's enough space for the limit-difference to be distributed 
//	ASSERT( availSpace >= 0 && relLeft >= relDiff); 
 
	// Fixup Relative: 
	// Distribute (if anecessary) relDiff on other (not limited) relative items/subpanes  
	// (if available - if not later just grow the limited panes) 
	while( relDiff != 0 && relCount >= 0 ) { 
 
		// in every iteration there must be some space distributed (of the difference) or it could  
		// come to endless looping. Save the amount of space actually distributed in this iteration 
		int relDist = 0; 
 
		for(i=0; i<m_paneItems.GetSize(); ++i) { 
			 
			CPaneBase pItem = m_paneItems[i]; 
 
 
			// For all relative items in primary direction which were NOT limited 
			if( (m_Orientation==HORIZONTAL && (pItem->modeResize() & RELATIVE_HORZ) && sizePrimary[i] > 0) 
				|| 
				(m_Orientation==VERTICAL   && (pItem->modeResize() & RELATIVE_VERT) && sizePrimary[i] > 0) ) 
			{ 
				// keep a flag for termination of this iteration 
				bool bLast = false; 
 
				// the difference should be distributed amoung all non-limited items/subpanes equally. 
				// nDiff is the amount for the current item/subpane 
				int nDiff = (relDiff * sizePrimary[i]) / relCount; 
 
				// if it's a too small value just add it to the current pane and break iteration 
				if( abs(relDiff) <= FIXUP_CUTOFF ) { 
					// take it all in this step 
					nDiff = relDiff; 
 
					// set break flag 
					bLast = true; 
				} 
 
				// calculate the new size for the current item/subpane 
				int nNewSize = sizePrimary[i] - nDiff; 
			 
				if( nNewSize < sizeMin[i] ) { 
					// oh, we are limited here. Revise our plan: 
 
					// Not all of the space could be saved, add the actually possible space 
					// to the sum 
					relDist += ( sizePrimary[i] - sizeMin[i] ); 
 
					// set it to the minimum possible size 
					sizePrimary[i] = -sizeMin[i]; 
 
					// as this item/subpane is now limited it's occupied space doesn't count 
					// for relCount anymore 
					relCount-= ( sizePrimary[i] ); 
				} 
				else { 
					// account the difference of the sizes in relDist and set new size 
					relDist += ( sizePrimary[i] - nNewSize ); 
					sizePrimary[i] = nNewSize; 
 
					// if it's the last one break now 
					if(bLast) 
						break; 
				} 
			} 
		} 
		// Distributed some relDiff-space in every iteration 
//		ASSERT(relDist != 0);	 
		relDiff -= relDist; 
 
		if( relDist == 0 ) 
			break; 
	} 
 
	// Fixup Relative: invert all negative (limited) sized to correct value 
	for(i=0; i<m_paneItems.GetSize(); ++i) { 
		CPaneBase pItem = m_paneItems[i]; 
		if( (m_Orientation==HORIZONTAL && (pItem->modeResize() & RELATIVE_HORZ) && sizePrimary[i] < 0) 
			|| 
			(m_Orientation==VERTICAL   && (pItem->modeResize() & RELATIVE_VERT) && sizePrimary[i] < 0) ) 
		{ 
			sizePrimary[i] *= -1; 
		} 
	} 
 
	return true; 
} 
 
bool ETSLayoutMgr::Pane::resizeToGreedy(int& availSpace, int nGreedy, CArray<int,int>& sizePrimary,  
									   CArray<int,int>& sizeMin, CArray<int,int>& sizeMax) 
{ 
	// Now resize all Greedy items/subpanes equally among the remaining space 
	int greedyDiff = 0;			// The cumulated difference between first proposed size and 
								// eventual maximum/minimum size. This amount has to be 
								// saved in some other place (i.e. where items/subpane 
								// are not limited by min/max 
	 
	int greedyLeft = 0;			// The cumulated amount of space that can be saved by 
								// shrinking the items/panes up to the minimum 
	 
	int greedyCount = 0;		// Actually allocated item/subpane's cumulated primary sizes  
								// of non-limited items/subpanes (these can be modified in fixup) 
								// needed for equally distribution of differences amoung non-limited 
								// items/subpanes 
 
	for(int i=0; i<m_paneItems.GetSize(); ++i) { 
		CPaneBase pItem = m_paneItems[i]; 
 
 
		if( (m_Orientation==HORIZONTAL  
				&& !(pItem->modeResize()&ABSOLUTE_HORZ)  
				&& !(pItem->modeResize()&RELATIVE_HORZ) 
			) 
			|| 
			(m_Orientation==VERTICAL    
				&& !(pItem->modeResize()&ABSOLUTE_VERT)  
				&& !(pItem->modeResize()&RELATIVE_VERT) 
			)  
		) 
		{ 
 
			// All greedy items get an equal portion of the left space 
			int nSize		= availSpace / nGreedy; 
 
			// minimum item/subpane size in primary direction (pixels) 
			int nSizeMin	= sizeMin[i]; 
 
			// maximum item/subpane size in primary direction (pixels) 
			int nSizeMax	= sizeMax[i]; 
 
 
			// the last gets the all of the remaining space 
			if( nGreedy == 1 ) 
				nSize = availSpace;						 
 
			if( nSize < nSizeMin) { 
				// The item/pane is shrinked too small! 
				// We will grow it to it's minimum-size. In order not to modify 
				// this item later when fixing up set the size to the negative 
				// minimum size 
				sizePrimary[i]	= -nSizeMin; 
 
				// As we grew one item/subpane we have to shrink another one. 
				// We keep count on how much space we needed to grow the item 
				// to it's minimum size 
				greedyDiff		+= ( nSizeMin - nSize ); 
			} 
			else if( nSizeMax != -1 && nSize > nSizeMax) { 
				// if there's a maximum size (nSizeRelMax != -1) and our item/subpane 
				// is to be resized over that amount correct it.  In order not to modify 
				// this item later when fixing up set the size to the negative 
				// maximum size 
				sizePrimary[i]	= -nSizeMax; 
 
				// As we shrinked one item/subpane we have to grow another one. 
				// We keep count on how much space we needed to grow the item 
				// to it's maximum size. 
				greedyDiff		+= ( nSizeMax - nSize ); 
			} 
			else { 
 
				// this is the normal case: neither are we minimum limited nor maximum 
				// limited 
 
				// As this item/subpane is larger that it's minimum we could later (if 
				// necessary for fixup) shrink it for the difference amount of pixels 
				greedyLeft		+= ( nSize - nSizeMin ); 
 
				// Set the primary size of this item/pane. Can later be modified by fixup 
				sizePrimary[i]	= nSize; 
 
				// Add this item/subpane's primary size to the count of already allocated 
				// cumulated size of non-limited items/subpanes (these can be modified in fixup) 
				greedyCount		+= nSize; 
			} 
 
			// decrease available space by used space in this step 
			availSpace	-= nSize; 
 
			// one greedy item/subpane complete 
			--nGreedy; 
		} 
	} 
 
 
	// Fixup Greedy I 
	// Distribute (if anecessary) greedyDiff on other (not limited) greedy items/subpanes  
	// (if available - if not later just grow the limited panes) 
 
	// at least on not limited item present 
	bool bAtLeastOne = true; 
 
	while( bAtLeastOne && greedyDiff != 0 && greedyCount > 0) { 
 
		// in every iteration there must be some space distributed (of the difference) or it could  
		// come to endless looping. Save the amount of space actually distributed in this iteration 
		int greedyDist = 0; 
 
		// at least on not limited item present 
		bAtLeastOne = false; 
 
		for(i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
 
 
			if( (m_Orientation==HORIZONTAL  
					&& !(pItem->modeResize()&ABSOLUTE_HORZ)  
					&& !(pItem->modeResize()&RELATIVE_HORZ) 
					&& sizePrimary[i] > 0 
				)	 
				|| 
				(m_Orientation==VERTICAL    
					&& !(pItem->modeResize()&ABSOLUTE_VERT)  
					&& !(pItem->modeResize()&RELATIVE_VERT) 
					&& sizePrimary[i] > 0  
				) 
			) 
			{ 
	 			// keep a flag for termination of this iteration 
				bool bLast = false; 
 
				// the difference should be distributed among all non-limited items/subpanes equally. 
				// nDiff is the amount for the current item/subpane 
				int nDiff = (greedyDiff * sizePrimary[i]) / greedyCount; 
 
				// if it's a too small value just add it to the current pane and break iteration 
				if( abs(greedyDiff) <= FIXUP_CUTOFF || nDiff == 0) { 
					// take it all in this step 
					nDiff = greedyDiff; 
 
					// set break flag 
					bLast = true; 
				} 
 
				// calculate the new size for the current item/subpane 
				int nNewSize = sizePrimary[i] - nDiff; 
			 
				if( nNewSize < sizeMin[i] ) { 
					// oh, we are limited here. Revise our plan: 
 
					if( sizePrimary[i] != sizeMin[i] ) 
						bAtLeastOne = true; 
 
					// Not all of the space could be saved, add the actually possible space 
					// to the sum 
					greedyDist += ( sizePrimary[i] - sizeMin[i] ); 
 
					// set it to the minimum possible size 
					sizePrimary[i] = sizeMin[i]; 
 
					// as this item/subpane is now limited its occupied space doesn't count 
					// for relCount anymore 
					greedyCount -= ( sizePrimary[i] ); 
				} 
				else { 
					// yes, there is one 
					bAtLeastOne = true; 
 
					// account the difference of the sizes in relDist and set new size 
					greedyDist += ( sizePrimary[i] - nNewSize ); 
					sizePrimary[i] = nNewSize; 
 
					// if it's the last one break now 
					if(bLast) 
						break; 
				} 
			} 
		} 
		// Distributed some greedyDiff-space in every iteration 
		ASSERT(!bAtLeastOne || greedyDist != 0 || greedyCount<=0); 
		greedyDiff -= greedyDist; 
	} 
 
 
	// Fixup Greedy II 
	if( greedyDiff < 0 ) { 
		// still difference, some space left 
 
		// are there any items which are minimum-limited where we can give more space? 
		for(i=0; i<m_paneItems.GetSize() && greedyDiff!=0; ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
 
			if( (m_Orientation==HORIZONTAL  
					&& !(pItem->modeResize()&ABSOLUTE_HORZ)  
					&& !(pItem->modeResize()&RELATIVE_HORZ) 
				)	 
				|| 
				(m_Orientation==VERTICAL    
					&& !(pItem->modeResize()&ABSOLUTE_VERT)  
					&& !(pItem->modeResize()&RELATIVE_VERT) 
				) 
			) 
			{ 
				if( sizePrimary[i] == -sizeMin[i] ) { 
					// fill this one up as much as possible 
					if( sizeMax[i] == -1) { 
						// all fits in 
						sizePrimary[i] += greedyDiff; 
						greedyDiff = 0; 
					} 
					else { 
						sizePrimary[i] += -min( -greedyDiff, sizeMax[i]-sizeMin[i]); 
						greedyDiff     -= -min( -greedyDiff, sizeMax[i]-sizeMin[i]); 
					} 
				} 
			} 
		} 
	} 
 
 
	// Fixup Greedy III: invert all negative (limited) sized to correct value 
	for(i=0; i<m_paneItems.GetSize(); ++i) { 
		CPaneBase pItem = m_paneItems[i]; 
 
		if( (m_Orientation==HORIZONTAL  
				&& !(pItem->modeResize() & ABSOLUTE_HORZ)  
				&& !(pItem->modeResize() & RELATIVE_HORZ)  
				&& sizePrimary[i] < 0 
				&& sizeMin[i] >= 0 
			) 
			|| 
			(m_Orientation==VERTICAL    
				&& !(pItem->modeResize() & ABSOLUTE_VERT)  
				&& !(pItem->modeResize() & RELATIVE_VERT)  
				&& sizePrimary[i] < 0 
				&& sizeMin[i] >= 0 
			)  
		) 
		{ 
			if(sizePrimary[i] < 0) 
				sizePrimary[i] *= -1; 
		} 
	} 
 
	return true; 
} 
 
 
bool ETSLayoutMgr::Pane::resizeTo(CRect& rcNewArea)  
{ 
	// There must be some items or subpanes 
	ASSERT(m_paneItems.GetSize()); 
 
	// This Array holds the size in primary direction for each item/subpane 
	CArray<int,int>	sizePrimary; 
	sizePrimary.SetSize(m_paneItems.GetSize()); 
 
	// This Array holds information about the minimum size in primary direction 
	CArray<int,int>	sizeMin; 
	sizeMin.SetSize(m_paneItems.GetSize()); 
 
	// This Array holds information about the maximum size in primary direction 
	CArray<int,int>	sizeMax; 
	sizeMax.SetSize(m_paneItems.GetSize()); 
 
 
	// How much space is actually available, subtract all borders between items 
	int availSpace = (m_Orientation == HORIZONTAL ? rcNewArea.Width() : rcNewArea.Height() ) - (m_paneItems.GetUpperBound()*m_sizeBorder); 
	 
	// If there is some Extra border (on top/bottem resp. left/right) subtract it too 
	availSpace -= 2*m_sizeExtraBorder; 
 
	// Add the extra Border to top/bottem resp. left/right 
	if(m_Orientation == HORIZONTAL) { 
		rcNewArea.top		+= m_sizeExtraBorder; 
		rcNewArea.bottom	-= m_sizeExtraBorder; 
	} 
	else { 
		rcNewArea.left		+= m_sizeExtraBorder; 
		rcNewArea.right		-= m_sizeExtraBorder; 
	} 
 
	// Counts the number of greedy items/subpanes 
	int nGreedy = resizeToAbsolute(availSpace, sizePrimary, sizeMin, sizeMax ); 
 
	if(nGreedy == -1) 
		return false; 
 
	if(! resizeToRelative(availSpace, sizePrimary, sizeMin, sizeMax ) ) 
		return false; 
 
	if(! resizeToGreedy(availSpace, nGreedy, sizePrimary, sizeMin, sizeMax ) ) 
		return false; 
 
 
	// If there is any left space and there are ALIGN_FILL_* Items to assign it 
	// equally among them 
	if( availSpace > 0 ) { 
		// Count possible Items 
		int nFillItems = 0; 
 
		for(int i=0; i<m_paneItems.GetSize(); ++i) { 
			CPaneBase pItem = m_paneItems[i]; 
			if( m_Orientation == HORIZONTAL  
				&& (pItem->modeResize() & ABSOLUTE_HORZ )  
				&& (pItem->modeResize() & ALIGN_FILL_HORZ) 
			 
				|| 
				 
				(pItem->modeResize() & ABSOLUTE_VERT )  
				&& (pItem->modeResize() & ALIGN_FILL_VERT)  
			) 
			{ 
				++nFillItems; 
			} 
		} 
 
		if( nFillItems > 0 ) { 
			// okay, there are nFillItems, make them all availSpace/nFillItems bigger 
			for(int i=0; i<m_paneItems.GetSize(); ++i) { 
				CPaneBase pItem = m_paneItems[i]; 
 
				if( m_Orientation == HORIZONTAL  
					&& (pItem->modeResize() & ABSOLUTE_HORZ )  
					&& (pItem->modeResize() & ALIGN_FILL_HORZ) 
				 
					|| 
					 
					(pItem->modeResize() & ABSOLUTE_VERT )  
					&& (pItem->modeResize() & ALIGN_FILL_VERT)  
				) 
				{ 
 
					if( nFillItems == 1 ) { 
						// the last one gets all the rest 
						sizePrimary[i]	+= availSpace; 
						availSpace		= 0; 
						--nFillItems; 
					} 
					else { 
						sizePrimary[i]	+= availSpace/nFillItems; 
						availSpace		-= availSpace/nFillItems; 
						--nFillItems; 
					} 
 
				} 
			} 
		} 
 
	} 
 
	// Now reposition all items: 
 
	// starting offset 
	int nOffset = (m_Orientation==HORIZONTAL ? rcNewArea.left : rcNewArea.top ) + m_sizeExtraBorder; 
	for(int i=0; i<m_paneItems.GetSize(); ++i) { 
		CPaneBase pItem = m_paneItems[i]; 
 
		// Calculate rect of item/subpane 
		CRect rcPane; 
		 
		if( m_Orientation==HORIZONTAL ) { 
			rcPane.SetRect(nOffset, rcNewArea.top, nOffset+sizePrimary[i], rcNewArea.bottom); 
		} 
		else { 
			rcPane.SetRect(rcNewArea.left, nOffset, rcNewArea.right, nOffset+sizePrimary[i]); 
		} 
 
		// do the resizing! 
		pItem->resizeTo( rcPane ); 
 
		// go to the next position (old pos + size + border) 
		ASSERT(sizePrimary[i] >= 0); 
		nOffset += m_sizeBorder + sizePrimary[i]; 
	}				 
 
 
	return true;			 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutDialog dialog 
 
#pragma warning(disable: 4355) 
ETSLayoutDialog::ETSLayoutDialog(UINT nID, CWnd* pParent /*=NULL*/, LPCTSTR strName /*=NULL*/, bool bGripper /*=true*/) 
	: CBaseDialog(nID, pParent), ETSLayoutMgr( this ) 
{ 
	//{{AFX_DATA_INIT(ETSLayoutDialog) 
		// NOTE: the ClassWizard will add member initialization here 
	//}}AFX_DATA_INIT 
	m_bGripper	= bGripper; 
 
	if(strName) 
		m_strRegStore = strName; 
} 
#pragma warning(default: 4355) 
 
BEGIN_MESSAGE_MAP(ETSLayoutDialog, CBaseDialog) 
	//{{AFX_MSG_MAP(ETSLayoutDialog) 
	ON_WM_SIZE() 
	ON_WM_GETMINMAXINFO() 
	ON_WM_ERASEBKGND() 
	ON_WM_DESTROY() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutDialog message handlers 
 
BOOL ETSLayoutDialog::OnEraseBkgnd(CDC* pDC)  
{ 
	EraseBkgnd(pDC); 
	return true; 
} 
 
void ETSLayoutDialog::OnSize(UINT nType, int cx, int cy)  
{ 
	CBaseDialog::OnSize(nType, cx, cy); 
 
	if( abs(cx) + abs(cy) > 0)  
	{ 
		// Reposition Size Marker 
		// Re-Layout all controls 
		UpdateLayout(); 
		RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); 
	} 
 
} 
 
void ETSLayoutDialog::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)  
{ 
	if(m_RootPane.IsValid()) { 
 
		CRect rcClient = GetRect(); 
		if( rcClient.Height() > 0 || rcClient.Width() > 0 ) 
		{ 
 
			CRect rcWnd; 
			GetWindowRect(rcWnd); 
			 
			// How much do Window and Client differ 
			int nDiffHorz = rcWnd.Width() - rcClient.Width(); 
			int nDiffVert = rcWnd.Height() - rcClient.Height(); 
 
			// Take into account that there is a border around the rootPane 
			lpMMI->ptMinTrackSize = CPoint(m_RootPane->getMinConstrainHorz() + nDiffHorz + 2*m_sizeRootBorders.cx, 
				m_RootPane->getMinConstrainVert() + nDiffVert + 2*m_sizeRootBorders.cy); 
 
			int maxWidth = m_RootPane->getMaxConstrainHorz(); 
			int maxHeight = m_RootPane->getMaxConstrainVert(); 
 
			if( maxWidth != -1 ) { 
				lpMMI->ptMaxTrackSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; 
				lpMMI->ptMaxSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; 
			} 
 
			if( maxHeight != -1 ) { 
				lpMMI->ptMaxTrackSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; 
				lpMMI->ptMaxSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; 
			} 
		} 
	} 
} 
 
 
CRect ETSLayoutDialog::GetRect()  
{  
	CRect r;  
	GetClientRect(r); 
 
	if( m_bGripper )  
	{ 
		if( ::IsWindow(m_StatusBar.GetSafeHwnd()) )  
		{ 
			CRect rcSizeIcon; 
			m_StatusBar.GetWindowRect( rcSizeIcon); 
			r.bottom -= (rcSizeIcon.Height() - m_sizeRootBorders.cy - 5); 
		} 
	} 
 
	return r;  
} 
 
 
BOOL ETSLayoutDialog::OnInitDialog()  
{ 
	CBaseDialog::OnInitDialog(); 
 
    // Ensure that the dialog is resizable 
    this->ModifyStyle(0, WS_THICKFRAME); 
 
	if(!m_strRegStore.IsEmpty()) { 
		Load(m_strRegStore); 
	}	 
 
#ifdef _AUTO_SET_ICON 
	POSITION pos = AfxGetApp()->GetFirstDocTemplatePosition(); 
	if(pos) { 
 
		class ETSPseudoDocTemplate : public CDocTemplate 
		{ 
			friend class ETSLayoutDialog; 
		}; 
 
		ETSPseudoDocTemplate* pDocT = (ETSPseudoDocTemplate*) AfxGetApp()->GetNextDocTemplate(pos); 
		SetIcon( AfxGetApp()->LoadIcon(pDocT->m_nIDResource) ,FALSE); 
	} 
#endif 
	 
	// Sizing icon 
	if(m_bGripper) 
	{ 
		if(m_StatusBar.Create(m_pWnd)) 
		{                            
			m_StatusBar.SetIndicators(auIDStatusBar, sizeof(auIDStatusBar) / sizeof(UINT)); 
			m_StatusBar.SetWindowText(_T(""));		 
			m_StatusBar.SetPaneStyle( 0, SBPS_STRETCH | SBPS_NOBORDERS ); 
			m_pWnd -> RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); 
		}              
		else 
			AfxMessageBox(_T("Error - Statusbar")); 
 
	} 
	return TRUE;  // return TRUE unless you set the focus to a control 
	              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
void ETSLayoutDialog::OnDestroy()  
{ 
	// Store size/position 
	if(!m_strRegStore.IsEmpty()) { 
		Save(m_strRegStore); 
	}	 
 
	// manually delete layout definition if object is reused 
	m_RootPane = 0; 
 
	CBaseDialog::OnDestroy(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutDialog dialog 
 
#pragma warning(disable: 4355) 
#ifdef CS_HELP 
ETSLayoutDialogBar::ETSLayoutDialogBar(UINT nID ) 
	: CBaseDialogBar( nID ), ETSLayoutMgr( this ) 
#else 
ETSLayoutDialogBar::ETSLayoutDialogBar() 
	: ETSLayoutMgr( this ) 
#endif 
{ 
	//{{AFX_DATA_INIT(ETSLayoutDialogBar) 
		// NOTE: the ClassWizard will add member initialization here 
	//}}AFX_DATA_INIT 
	m_bInitialized = false; 
	setRootBorders(0,0); 
} 
#pragma warning(default: 4355) 
 
BEGIN_MESSAGE_MAP(ETSLayoutDialogBar, CBaseDialogBar) 
	//{{AFX_MSG_MAP(ETSLayoutDialogBar) 
	ON_WM_SIZE() 
	ON_WM_GETMINMAXINFO() 
	ON_WM_DESTROY() 
	ON_WM_ERASEBKGND() 
	ON_MESSAGE(WM_INITDIALOG, OnInitDialog) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutDialogBar message handlers 
 
LRESULT ETSLayoutDialogBar::OnInitDialog(WPARAM, LPARAM) 
{ 
	Default(); 
	Initialize(); 
	return TRUE; 
} 
 
void ETSLayoutDialogBar::UpdateLayout() 
{ 
	ETSLayoutMgr::UpdateLayout(); 
 
	if(m_RootPane.IsValid()) { 
		CRect rcClient = GetRect(); 
 
		CRect rcWnd; 
		GetWindowRect(rcWnd); 
			 
		// How much do Window and Client differ 
		CSize sizeDiff( rcWnd.Width() - rcClient.Width(), rcWnd.Height() - rcClient.Height()); 
 
		// Take into account that there is a border around the rootPane 
//		m_szMin = CSize(m_RootPane->getMinConstrainHorz() + sizeDiff.cx + 2*m_sizeRootBorders.cx, 
//			m_RootPane->getMinConstrainVert() + sizeDiff.cy + 2*m_sizeRootBorders.cy); 
	} 
} 
 
CSize ETSLayoutDialogBar::CalcDynamicLayout(int nLength, DWORD dwMode) 
{ 
	CSize sizeRet =  CBaseDialogBar::CalcDynamicLayout(nLength, dwMode); 
 
	CSize sizeMin = sizeRet; 
	CSize sizeMax = sizeRet; 
 
	if(m_RootPane.IsValid()) { 
		CRect rcClient = GetRect(); 
 
		CRect rcWnd; 
		GetWindowRect(rcWnd); 
			 
		// How much do Window and Client differ 
		CSize sizeDiff( rcWnd.Width() - rcClient.Width(), rcWnd.Height() - rcClient.Height()); 
 
		// Take into account that there is a border around the rootPane 
//		sizeMin = CSize(m_RootPane->getMinConstrainHorz() + sizeDiff.cx + 2*m_sizeRootBorders.cx, 
//			m_RootPane->getMinConstrainVert() + sizeDiff.cy + 2*m_sizeRootBorders.cy); 
 
 
		int maxWidth = m_RootPane->getMaxConstrainHorz(); 
		int maxHeight = m_RootPane->getMaxConstrainVert(); 
 
		if( maxWidth != -1 ) { 
			sizeMax.cx = maxWidth + sizeDiff.cy + 2*m_sizeRootBorders.cx; 
		} 
 
		if( maxHeight != -1 ) { 
			sizeMax.cy = maxHeight + sizeDiff.cy + 2*m_sizeRootBorders.cy; 
		} 
	} 
 
	if( IsFloating() || !(dwMode&LM_HORZ)) 
	{ 
		sizeRet.cx = min( sizeRet.cx, sizeMax.cx ); 
	} 
	if( IsFloating() || (dwMode&LM_HORZ)) 
	{ 
		sizeRet.cy = min( sizeRet.cy, sizeMax.cy ); 
	} 
 
	sizeRet.cx = max( sizeRet.cx, sizeMin.cx ); 
	sizeRet.cy = max( sizeRet.cy, sizeMin.cy ); 
 
	return sizeRet; 
} 
 
BOOL ETSLayoutDialogBar::OnEraseBkgnd(CDC* pDC)  
{ 
	EraseBkgnd(pDC); 
	return true; 
} 
 
 
void ETSLayoutDialogBar::OnSize(UINT nType, int cx, int cy)  
{ 
	CBaseDialogBar::OnSize(nType, cx, cy); 
 
	if( abs(cx) + abs(cy) > 0) 
	{ 
		// Re-Layout all controls 
		UpdateLayout(); 
	} 
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); 
 
} 
 
 
CRect ETSLayoutDialogBar::GetRect()  
{  
	CRect r;  
	GetClientRect(r); 
 
	if( IsFloating() ) 
		r.DeflateRect(4,4); 
 
	return r;  
} 
 
 
void ETSLayoutDialogBar::OnDestroy()  
{ 
	// Store size/position on your own! 
	CBaseDialogBar::OnDestroy(); 
} 
 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutFormView dialog 
 
IMPLEMENT_DYNAMIC(ETSLayoutFormView, CFormView) 
 
#pragma warning(disable: 4355) 
ETSLayoutFormView::ETSLayoutFormView(UINT nID, LPCTSTR strName /*=NULL*/) 
	: CBaseFormView(nID), ETSLayoutMgr( this ) 
{ 
	if(strName) 
		m_strRegStore = strName; 
} 
#pragma warning(default: 4355) 
 
BEGIN_MESSAGE_MAP(ETSLayoutFormView, CBaseFormView) 
	//{{AFX_MSG_MAP(ETSLayoutFormView) 
	ON_WM_SIZE() 
	ON_WM_GETMINMAXINFO() 
	ON_WM_ERASEBKGND() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutFormView message handlers 
 
BOOL ETSLayoutFormView::OnEraseBkgnd(CDC* pDC)  
{ 
	EraseBkgnd(pDC); 
	return true; 
} 
 
 
void ETSLayoutFormView::OnSize(UINT nType, int cx, int cy)  
{ 
//	CBaseFormView::OnSize(nType, cx, cy); 
	SetScrollSizes(MM_TEXT, CSize(cx,cy)); 
	if( abs(cx) + abs(cy) > 0) { 
		// Re-Layout all controls 
		UpdateLayout(); 
	} 
//	MoveWindow(0,0,cx,cy); 
} 
 
/* 
void ETSLayoutFormView::UpdateLayout() 
{ 
	ETSLayoutMgr::UpdateLayout(); 
 
	if(m_RootPane.IsValid()) { 
		// Force MainFrame to re-layout 
		CFrameWnd* pFrame = static_cast<CFrameWnd*>(GetParent()); 
		if(pFrame) { 
 
			CRect rcWnd; 
			pFrame->GetWindowRect(rcWnd); 
			pFrame->MoveWindow(rcWnd); 
			pFrame->RecalcLayout(); 
 
		} 
		return; 
	} 
} 
*/ 
 
void ETSLayoutFormView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)  
{ 
	// To use this you'll have to modify your CMainFrame: 
	// 
	// 1) Add a handler for WM_GETMINMAXINFO() 
	// 2) Let this handler be: 
	// void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)  
	// { 
	// 	CFrameWnd::OnGetMinMaxInfo(lpMMI); 
	//  
	// 	if( GetActiveView() && GetActiveView()->IsKindOf( RUNTIME_CLASS(ETSLayoutFormView) ) ) { 
	// 		GetActiveView()->SendMessage( WM_GETMINMAXINFO, 0, (LPARAM) lpMMI ); 
	// 	} 
	// } 
	// 3) Add "#include "dialogmgr.h" to MainFrm.cpp 
 
	if(m_RootPane.IsValid()) { 
		CRect rcClient = GetRect(); 
 
		CRect rcWnd; 
		GetParent()->GetWindowRect(rcWnd); 
	 
		// How much do Window and Client differ 
		rcWnd-=rcClient; 
 
		// Take into account that there is a border around the rootPane 
		lpMMI->ptMinTrackSize = CPoint(m_RootPane->getMinConstrainHorz() + rcWnd.Width() + 2*m_sizeRootBorders.cx, 
			m_RootPane->getMinConstrainVert() + rcWnd.Height() + 2*m_sizeRootBorders.cy); 
 
		int maxWidth = m_RootPane->getMaxConstrainHorz(); 
		int maxHeight = m_RootPane->getMaxConstrainVert(); 
 
		if( maxWidth != -1 ) { 
			lpMMI->ptMaxTrackSize.x = maxWidth + rcWnd.Width()+ 2*m_sizeRootBorders.cx; 
			lpMMI->ptMaxSize.x = maxWidth + rcWnd.Width()+ 2*m_sizeRootBorders.cx; 
		} 
 
		if( maxHeight != -1 ) { 
			lpMMI->ptMaxTrackSize.y = maxHeight + rcWnd.Height() + 2*m_sizeRootBorders.cy; 
			lpMMI->ptMaxSize.y = maxHeight + rcWnd.Height() + 2*m_sizeRootBorders.cy; 
		} 
	} 
} 
 
ETSLayoutFormView::~ETSLayoutFormView()  
{ 
	// Cleanup 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutPropertyPage 
 
#ifdef CS_HELP 
	IMPLEMENT_DYNCREATE(ETSLayoutPropertyPage, ETSCSHelpPropPage) 
#else 
	IMPLEMENT_DYNCREATE(ETSLayoutPropertyPage, CPropertyPage) 
#endif 
 
#pragma warning(disable: 4355) 
ETSLayoutPropertyPage::ETSLayoutPropertyPage( ) : ETSLayoutMgr( this ) 
{ 
	m_bLockMove = false; 
	m_bResetBuddyOnNextTimeVisible = true; 
} 
 
ETSLayoutPropertyPage::ETSLayoutPropertyPage( UINT nIDTemplate, UINT nIDCaption /*= 0*/ ) 
	: CBasePropertyPage(nIDTemplate, nIDCaption), ETSLayoutMgr( this ) 
{ 
	m_bLockMove = false; 
	m_bResetBuddyOnNextTimeVisible = true; 
} 
 
ETSLayoutPropertyPage::ETSLayoutPropertyPage( LPCTSTR lpszTemplateName, UINT nIDCaption /*= 0*/ ) 
	: CBasePropertyPage(lpszTemplateName, nIDCaption), ETSLayoutMgr( this ) 
{ 
	m_bLockMove = false; 
	m_bResetBuddyOnNextTimeVisible = true; 
} 
#pragma warning(default: 4355) 
 
ETSLayoutPropertyPage::~ETSLayoutPropertyPage() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(ETSLayoutPropertyPage, CBasePropertyPage) 
	//{{AFX_MSG_MAP(ETSLayoutPropertyPage) 
	ON_WM_SIZE() 
	ON_WM_GETMINMAXINFO() 
	ON_WM_ERASEBKGND() 
	ON_WM_WINDOWPOSCHANGING() 
	ON_WM_DESTROY() 
	ON_WM_WINDOWPOSCHANGED() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// Behandlungsroutinen für Nachrichten ETSLayoutPropertyPage  
 
 
 
void ETSLayoutPropertyPage::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)  
{ 
	CBasePropertyPage::OnWindowPosChanged(lpwndpos); 
	 
	// This code is needed in order to reset the buddy after this page has 
	// been activated. At least on Win2k this is not done thru normal resizing, 
	// as the page is not visible when first layouted. And without the page 
	// being visible it's not possible to tell if the attached buddy is visible 
	// or not (at least I don't know any way to do so) 
 
	if( ::IsWindowVisible( GetWnd()->GetSafeHwnd() ) ) 
	{ 
		if( m_bResetBuddyOnNextTimeVisible )  
		{ 
			// Take special care of SpinButtons (Up-Down Controls) with Buddy set, enumerate 
			// all childs: 
			CWnd* pWndChild = GetWnd()->GetWindow(GW_CHILD); 
			TCHAR szClassName[ MAX_PATH ]; 
			while(pWndChild) 
			{ 
				::GetClassName( pWndChild->GetSafeHwnd(), szClassName, MAX_PATH ); 
				DWORD dwStyle = pWndChild->GetStyle(); 
 
				// is it a SpinButton? 
				if( _tcscmp(szClassName, UPDOWN_CLASS)==0 && ::IsWindowVisible(pWndChild->GetSafeHwnd()) ) { 
					HWND hwndBuddy = (HWND)::SendMessage( pWndChild->GetSafeHwnd(), UDM_GETBUDDY, 0, 0); 
					if( hwndBuddy != 0 && (dwStyle&(UDS_ALIGNRIGHT|UDS_ALIGNLEFT)) != 0 ) 
					{ 
						// reset Buddy 
						::SendMessage( pWndChild->GetSafeHwnd(), UDM_SETBUDDY, (WPARAM)hwndBuddy, 0); 
					} 
				} 
				 
 
				pWndChild = pWndChild->GetWindow(GW_HWNDNEXT); 
			} 
 
			m_bResetBuddyOnNextTimeVisible = false; 
		} 
	}	 
	else 
	{ 
		// has been hidden again 
		m_bResetBuddyOnNextTimeVisible = true; 
	} 
} 
 
void ETSLayoutPropertyPage::OnWindowPosChanging( WINDOWPOS* lpwndpos ) 
{ 
	// In WizardMode the System calls SetWindowPos with the  
	// original size at every activation. This could cause 
	// some flicker in certain circumstances. Therefore we lock 
	// moving the page and unlock it only if _we_ move the page 
	if( m_bLockMove) 
	{ 
		lpwndpos->flags |= SWP_NOMOVE | SWP_NOSIZE; 
	} 
	CBasePropertyPage::OnWindowPosChanging( lpwndpos ); 
} 
 
BOOL ETSLayoutPropertyPage::OnEraseBkgnd(CDC* pDC)  
{ 
	EraseBkgnd(pDC); 
	return true; 
} 
 
void ETSLayoutPropertyPage::OnDestroy()  
{ 
	// manually delete layout definition if object is reused 
	m_RootPane = 0; 
 
	CBasePropertyPage::OnDestroy(); 
} 
 
void ETSLayoutPropertyPage::OnSize(UINT nType, int cx, int cy)  
{ 
	CBasePropertyPage::OnSize(nType, cx, cy); 
	 
	if( abs(cx) + abs(cy) > 0)  
	{ 
		// Re-Layout all controls 
		UpdateLayout(); 
	}	 
} 
 
void ETSLayoutPropertyPage::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)  
{ 
	if(m_RootPane.IsValid()) { 
		CRect rcClient = GetRect(); 
 
		CRect rcWnd; 
		GetWindowRect(rcWnd); 
		 
		// How much do Window and Client differ 
		int nDiffHorz = rcWnd.Width() - rcClient.Width(); 
		int nDiffVert = rcWnd.Height() - rcClient.Height(); 
 
		// Take into account that there is a border around the rootPane 
		lpMMI->ptMinTrackSize = CPoint(m_RootPane->getMinConstrainHorz() + nDiffHorz + 2*m_sizeRootBorders.cx, 
			m_RootPane->getMinConstrainVert() + nDiffVert + 2*m_sizeRootBorders.cy); 
 
		int maxWidth = m_RootPane->getMaxConstrainHorz(); 
		int maxHeight = m_RootPane->getMaxConstrainVert(); 
 
		if( maxWidth != -1 ) { 
			lpMMI->ptMaxTrackSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; 
			lpMMI->ptMaxSize.x = maxWidth + nDiffHorz + 2*m_sizeRootBorders.cx; 
		} 
 
		if( maxHeight != -1 ) { 
			lpMMI->ptMaxTrackSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; 
			lpMMI->ptMaxSize.y = maxHeight + nDiffVert + 2*m_sizeRootBorders.cy; 
		} 
	} 
} 
 
 
CRect ETSLayoutPropertyPage::GetRect()  
{  
	CRect r;  
	GetClientRect(r); 
	return r;  
} 
 
 
BOOL ETSLayoutPropertyPage::OnInitDialog()  
{ 
	CBasePropertyPage::OnInitDialog(); 
	UpdateLayout(); 
 
	ETSLayoutPropertySheet* pSheet = (ETSLayoutPropertySheet*) GetParent(); 
 
	ASSERT_KINDOF( ETSLayoutPropertySheet, pSheet); 
	if(pSheet) 
	{ 
		if(pSheet->IsWizard()) 
		{ 
			m_bLockMove = true; 
		} 
	} 
 
	return TRUE; 
} 
 
BOOL ETSLayoutPropertyPage::OnSetActive()  
{ 
	ETSLayoutPropertySheet* pSheet = (ETSLayoutPropertySheet*) GetParent(); 
 
	ASSERT_KINDOF( ETSLayoutPropertySheet, pSheet); 
	if(pSheet) 
	{ 
		if(pSheet->IsWizard()) 
		{ 
			// In WizardMode the System calls SetWindowPos with the  
			// original size on Page Activation. This will position the 
			// page at the correct position 
			m_bLockMove = false; 
			MoveWindow(pSheet->m_rcPage); 
			m_bLockMove = true; 
		} 
	} 
 
	UpdateLayout();	 
 
	return CBasePropertyPage::OnSetActive(); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// ETSLayoutPropertySheet 
 
IMPLEMENT_DYNAMIC(ETSLayoutPropertySheet, CPropertySheet) 
 
#pragma warning(disable: 4355) 
ETSLayoutPropertySheet::ETSLayoutPropertySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage,  
											   LPCTSTR strName /*=NULL*/, bool bGripper/*=true*/) 
	: CPropertySheet(nIDCaption, pParentWnd, iSelectPage), ETSLayoutMgr( this ) 
{ 
	Init(strName, bGripper); 
} 
 
ETSLayoutPropertySheet::ETSLayoutPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage,  
											   LPCTSTR strName /*=NULL*/, bool bGripper/*=true*/) 
	: CPropertySheet(pszCaption, pParentWnd, iSelectPage), ETSLayoutMgr( this ) 
{ 
	Init(strName, bGripper); 
} 
#pragma warning(default: 4355) 
 
void ETSLayoutPropertySheet::Init(LPCTSTR strName, bool bGripper) 
{ 
	m_bGripper	= bGripper; 
	if(strName) 
		m_strRegStore = strName; 
 
	m_bAutoDestroy	= false; 
	m_bAutoDestroyPages	= false; 
	m_bModelessButtons = false; 
} 
 
ETSLayoutPropertySheet::~ETSLayoutPropertySheet() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(ETSLayoutPropertySheet, CPropertySheet) 
	//{{AFX_MSG_MAP(ETSLayoutPropertySheet) 
	ON_WM_CREATE() 
	ON_WM_SIZE() 
	ON_WM_GETMINMAXINFO() 
	ON_WM_DESTROY() 
	ON_WM_ERASEBKGND() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// Behandlungsroutinen für Nachrichten ETSLayoutPropertySheet  
 
BOOL ETSLayoutPropertySheet::OnEraseBkgnd(CDC* pDC)  
{ 
	EraseBkgnd(pDC); 
	return true; 
} 
 
 
int ETSLayoutPropertySheet::OnCreate(LPCREATESTRUCT lpCreateStruct)  
{ 
	if (CPropertySheet::OnCreate(lpCreateStruct) == -1) 
		return -1; 
 
	ModifyStyle(0,WS_THICKFRAME| WS_SYSMENU); 
	return 0; 
} 
 
 
void ETSLayoutPropertySheet::Resize(int cx, int cy) 
{ 
	if( abs(cx) + abs(cy) > 0 && m_RootPane.IsValid() )  
	{ 
		UpdateLayout(); 
 
		// Fix for PSH_WIZARDHASFINISH [Thömmi] 
		if (IsWizard() && !(m_psh.dwFlags & PSH_WIZARDHASFINISH) ) 
		{ 
			// manual reposition of the FINISH button 
			// can not be done with normaly layouting because it 
			// shares position with the NEXT button 
			CWnd *pWndFinish; 
			pWndFinish=GetDlgItem(ID_WIZFINISH); 
 
			if(pWndFinish) 
			{ 
				CRect rcWnd; 
				GetDlgItem(ID_WIZNEXT)->GetWindowRect(&rcWnd); 
				ScreenToClient(&rcWnd); 
				pWndFinish->MoveWindow(rcWnd); 
				pWndFinish->RedrawWindow(0,0, RDW_INVALIDATE | RDW_UPDATENOW ); 
			} 
		} 
 
		// reposition Gripper 
		if(m_bGripper) 
			RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); 
 
		CPropertyPage* pPage = (CPropertyPage*)GetActivePage(); 
 
		if(pPage) 
		{ 
			CRect rcWnd; 
			GetTabControl()->GetWindowRect(&rcWnd); 
			ScreenToClient(&rcWnd); 
 
			if(!IsWizard()) { 
				// get inside of tab 
				GetTabControl()->AdjustRect(FALSE, &rcWnd); 
			} 
			else 
			{ 
				rcWnd.bottom += 5; 
			} 
 
			// we need this size in WizardMode in order to  
			// reposition newly activated page correctly 
			m_rcPage = rcWnd; 
			 
			if( IsWizard() && pPage->IsKindOf(RUNTIME_CLASS(ETSLayoutPropertyPage)) ) 
			{ 
				ETSLayoutPropertyPage* pEtsPage = reinterpret_cast<ETSLayoutPropertyPage*>(pPage); 
 
				pEtsPage->m_bLockMove = false; 
				pEtsPage->MoveWindow(m_rcPage); 
				pEtsPage->m_bLockMove = true; 
			} 
			else  
			{ 
				pPage->MoveWindow(m_rcPage); 
			} 
			 
		} 
 
		if(IsWindowVisible()) 
		{ 
			RedrawWindow(0,0, RDW_INVALIDATE|RDW_UPDATENOW ); 
 
			if(!IsWizard()) 
				GetTabControl()->RedrawWindow(0,0, RDW_INVALIDATE|RDW_UPDATENOW ); 
		} 
	} 
} 
 
void ETSLayoutPropertySheet::OnSize(UINT nType, int cx, int cy)  
{ 
	CPropertySheet::OnSize(nType, cx, cy); 
	Resize(cx,cy); 
} 
 
// IDs of all PropertySheet controls 
long _PropertySheetIDs[] = 
{ 
	ID_WIZBACK, 
	ID_WIZNEXT,  
	ID_WIZFINISH, 
	IDOK,  
	IDCANCEL, 
	ID_APPLY_NOW,  
	IDHELP 
}; 
 
void ETSLayoutPropertySheet::AddMainArea(CPane paneRoot, CPaneBase itemTab) 
{ 
    // the default is: Whole main Area is covered by the TabCtrl 
    paneRoot << itemTab; 
} 
 
void ETSLayoutPropertySheet::AddButtons(CPane paneBottom) 
{ 
	// first item greedy to keep others right 
	paneBottom->addItem (paneNull, GREEDY); 
 
 
	// add all Controls to the layouting 
	bool bFirst = true; 
	for(int i = 0; i < (sizeof(_PropertySheetIDs) / sizeof(long)) ; i++) 
	{ 
		// Prevent movement of finish button, if it is not shown explicitly [Thömmi] 
		if( IsWizard()  
			&& _PropertySheetIDs[i] == ID_WIZFINISH  
			&& !(m_psh.dwFlags & PSH_WIZARDHASFINISH) )  
		{ 
			continue; 
		} 
 
		CWnd* pWnd = GetDlgItem(_PropertySheetIDs[i]); 
 
		if(pWnd) 
		{ 
 
			if(!(m_psh.dwFlags & PSH_HASHELP) && _PropertySheetIDs[i] == IDHELP) 
			{ 
				// don't insert 
				continue; 
			} 
 
			if((m_psh.dwFlags & PSH_NOAPPLYNOW) && _PropertySheetIDs[i] == ID_APPLY_NOW) 
			{ 
				// don't insert 
				continue; 
			} 
 
			// space before first one and between BACK & NEXT 
			if( IsWizard() ) 
			{ 
				if( !bFirst && !(_PropertySheetIDs[i]==ID_WIZNEXT) ) 
				{ 
					paneBottom->addItem(paneNull, NORESIZE,12,0,0,0); 
				} 
			} 
 
			pWnd->ShowWindow(true); 
			paneBottom->addItem(_PropertySheetIDs[i], NORESIZE);			 
			bFirst = false; 
		} 
	} 
 
} 
 
BOOL ETSLayoutPropertySheet::OnInitDialog()  
{ 
	BOOL bRet = CPropertySheet::OnInitDialog(); 
 
	ASSERT(!m_RootPane); 
 
	// Save initial rect 
	GetWindowRect(&m_rcStart); 
 
	CPropertyPage* pPage = CPropertySheet::GetActivePage(); 
	ASSERT(pPage); 
 
	CRect rcPage; 
	pPage->GetClientRect(&rcPage); 
 
	CreateRoot(VERTICAL); 
	ASSERT(m_RootPane); 
 
	// Add Tabcontrol to root pane 
	m_ItemTab = item( GetTabControl(), GREEDY, 0, 0, 0, 0); 
    AddMainArea(m_RootPane, m_ItemTab); 
 
	// Tabcontrol is invisible in WizardMode 
	if(IsWizard()) 
	{ 
		GetTabControl()->ShowWindow(false); 
	} 
 
	// add horizontal line in WizardMode 
	if(IsWizard() && GetDlgItem(ID_WIZFINISH+1)) 
	{ 
		m_RootPane << item(ID_WIZFINISH+1, ABSOLUTE_VERT, 0, 0, 0, 0); 
	} 
 
	if( IsWizard() || !m_bModeless || m_bModelessButtons ) 
	{ 
		// No spaces in WizardMode in order to keep BACK & NEXT together 
		CPane bottomPane = pane(HORIZONTAL, ABSOLUTE_VERT, IsWizard() ? 0 : 5); 
 
        AddButtons(bottomPane); 
		// add bottom (button) pane if any controls were added 
        if(bottomPane->m_paneItems.GetSize() > 0) { 
    		m_RootPane << bottomPane; 
        } 
	} 
 
 
 
	// some Space between Buttons und Gripper 
	if(m_bGripper) 
	{ 
		m_RootPane->addItem(paneNull, ABSOLUTE_VERT,0,2); 
 
		if(m_StatusBar.Create(m_pWnd)) 
		{                            
			m_StatusBar.SetIndicators(auIDStatusBar, 
				sizeof(auIDStatusBar) / sizeof(UINT)); 
			m_StatusBar.SetWindowText(_T(""));		 
			RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0); 
		}              
		else 
		{ 
			AfxMessageBox(_T("Error - Statusbar")); 
		} 
	} 
 
	if(!m_strRegStore.IsEmpty()) 
	{ 
		Load(m_strRegStore); 
	}	 
 
	Resize(1,1); // Fix. for 95/98/NT difference 
 
	CRect rcWnd; 
	GetWindowRect( & rcWnd ); 
	MoveWindow( rcWnd ); 
 
	return bRet; 
} 
 
 
void ETSLayoutPropertySheet::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)  
{ 
	if(m_RootPane.IsValid() && GetTabControl() != 0 )  
	{ 
		CRect rcWnd; 
		GetWindowRect(rcWnd);		 
 
		CRect rcClient = GetRect(); 
		rcWnd-=rcClient; 
 
		// ask for MinMax of all pages 
		CSize sizePageMax(0,0); 
		CSize sizePageMin(0,0); 
		for( int nPage=0; nPage<GetPageCount(); ++nPage) 
		{ 
			CPropertyPage* pPage = GetPage(nPage); 
			ASSERT(pPage); 
			if( pPage ) 
			{ 
				MINMAXINFO mmi; 
				memset(&mmi, 0, sizeof(mmi)); 
 
				if( IsWindow(pPage->GetSafeHwnd()) ) 
				{ 
					pPage->SendMessage(WM_GETMINMAXINFO, 0, (LPARAM) &mmi); 
 
					if(mmi.ptMaxTrackSize.x != 0) 
					{ 
						sizePageMax.cx = min(sizePageMax.cx, mmi.ptMaxTrackSize.x); 
					} 
					if(mmi.ptMaxTrackSize.y != 0) 
					{ 
						sizePageMax.cy = min(sizePageMax.cy, mmi.ptMaxTrackSize.y); 
					} 
					if(mmi.ptMinTrackSize.x != 0) 
					{ 
						sizePageMin.cx = max(sizePageMin.cx, mmi.ptMinTrackSize.x); 
					} 
					if(mmi.ptMinTrackSize.y != 0) 
					{ 
						sizePageMin.cy = max(sizePageMin.cy, mmi.ptMinTrackSize.y); 
					} 
				} 
			} 
		} 
		static_cast<PaneItem*>( m_ItemTab.GetPaneBase() )->m_sizeXMin = sizePageMin.cx; 
		static_cast<PaneItem*>( m_ItemTab.GetPaneBase() )->m_sizeYMin = sizePageMin.cy; 
 
		// calculate the needed size of the tabctrl in non-wizard-mode 
		CRect rcItem(0,0,0,0); 
		if(!IsWizard()) 
		{ 
			GetTabControl()->AdjustRect( TRUE, rcItem ); 
		} 
 
		lpMMI->ptMinTrackSize.x = m_RootPane->getMinConstrainHorz() + rcWnd.Width() + 2*m_sizeRootBorders.cx 
					+ rcItem.Width(); 
 
		lpMMI->ptMinTrackSize.y = m_RootPane->getMinConstrainVert() + rcWnd.Height() + 2*m_sizeRootBorders.cy  
				+ rcItem.Height(); 
 
		// never smaller than inital size! 
		lpMMI->ptMinTrackSize.x = max(lpMMI->ptMinTrackSize.x, m_rcStart.Width() ); 
		lpMMI->ptMinTrackSize.y = max(lpMMI->ptMinTrackSize.y, m_rcStart.Height() ); 
 
		// Rest like ETSLayoutMgr 
 
		int maxWidth = m_RootPane->getMaxConstrainHorz(); 
		int maxHeight = m_RootPane->getMaxConstrainVert(); 
 
		if( maxWidth != -1 )  
		{ 
			lpMMI->ptMaxSize.x = sizePageMax.cx + rcWnd.Width()+ 2*m_sizeRootBorders.cx + rcItem.Width() ; 
		} 
 
		if( maxHeight != -1 )  
		{ 
			lpMMI->ptMaxSize.y = sizePageMax.cy + rcWnd.Height() + 2*m_sizeRootBorders.cy + rcItem.Width() ; 
		} 
 
		lpMMI->ptMaxTrackSize = lpMMI->ptMaxSize; 
 
	} 
} 
 
 
void ETSLayoutPropertySheet::OnDestroy()  
{ 
	// Store size/position 
	if(!m_strRegStore.IsEmpty())  
	{ 
		Save(m_strRegStore); 
	}	 
	m_RootPane = 0; 
 
	CPropertySheet::OnDestroy(); 
} 
 
void ETSLayoutPropertySheet::PostNcDestroy() 
{ 
	if(m_bAutoDestroyPages) 
	{ 
		// walk all pages and destry them 
		for( int nPage=0; nPage<GetPageCount(); ++nPage) 
		{ 
			CPropertyPage* pPage = GetPage(nPage); 
			ASSERT(pPage); 
			if( pPage ) 
			{ 
				delete pPage; 
			} 
		} 
	} 
 
	if(m_bAutoDestroy) 
		delete this; 
} 
 
 
 
/** 
 * CPane represents an autopointer to a PaneBase. Use this and you won't have to worry 
 * about cleaning up any Panes. Also this autopointer lets you return Pane objects 
 * from function without using pointers (at least you won't see them :) ) 
 */ 
ETSLayoutMgr::PaneHolder::PaneHolder(PaneBase* pPane ) 
{ 
 
	ASSERT( pPane ); 
	m_pPane = pPane; 
 
	// Implicitly AddRef() 
	m_nRefCount = 1; 
} 
 
ETSLayoutMgr::PaneHolder::~PaneHolder() 
{ 
	ASSERT( m_pPane ); 
	ASSERT( m_nRefCount == 0 ); 
 
	delete m_pPane; 
} 
 
void ETSLayoutMgr::PaneHolder::AddRef() 
{ 
	InterlockedIncrement( &m_nRefCount ); 
} 
 
void ETSLayoutMgr::PaneHolder::Release() 
{ 
	if( InterlockedDecrement( &m_nRefCount ) <= 0 ) 
	{ 
		// no more references on me, so destroy myself 
		delete this; 
	} 
} 
 
ETSLayoutMgr::CPaneBase::CPaneBase( ) 
{ 
	// MUST be initialized later 
	m_pPaneHolder = 0; 
} 
 
ETSLayoutMgr::CPaneBase::CPaneBase( PaneBase* pPane ) 
{ 
	m_pPaneHolder = 0; 
	 
	if( pPane != 0) 
		operator=( pPane ); 
} 
 
ETSLayoutMgr::CPaneBase::CPaneBase( const CPaneBase& other ) 
{ 
	m_pPaneHolder = 0; 
	operator=(other); 
} 
 
ETSLayoutMgr::CPaneBase::~CPaneBase() 
{ 
	if(m_pPaneHolder) 
		m_pPaneHolder->Release(); 
} 
 
void ETSLayoutMgr::CPaneBase::operator=( PaneBase* pPane ) 
{ 
	if(m_pPaneHolder) 
	{ 
		m_pPaneHolder->Release(); 
		m_pPaneHolder = 0; 
	} 
 
	if( pPane != 0 ) 
		m_pPaneHolder = new PaneHolder( pPane ); 
} 
 
void ETSLayoutMgr::CPaneBase::operator=( const CPaneBase& other ) 
{ 
	ASSERT( other.m_pPaneHolder ); 
 
	if(m_pPaneHolder) 
	{ 
		m_pPaneHolder->Release(); 
		m_pPaneHolder = 0; 
	} 
 
	other.m_pPaneHolder->AddRef(); 
	m_pPaneHolder = other.m_pPaneHolder; 
} 
 
ETSLayoutMgr::PaneBase* ETSLayoutMgr::CPaneBase::operator->() const 
{ 
	ASSERT(m_pPaneHolder); 
 
	if(!m_pPaneHolder) 
		return 0; 
 
	return (m_pPaneHolder->m_pPane); 
} 
 
 
 
ETSLayoutMgr::CPane::CPane( ) 
{ 
} 
 
ETSLayoutMgr::CPane::CPane( Pane* pPane ) : ETSLayoutMgr::CPaneBase( static_cast<PaneBase*>(pPane) ) 
{ 
} 
 
ETSLayoutMgr::CPane::CPane( const CPane& other ) 
{ 
	operator=(other); 
} 
 
ETSLayoutMgr::CPane::~CPane() 
{ 
} 
 
void ETSLayoutMgr::CPane::operator=( Pane* pPane ) 
{ 
	CPaneBase::operator=(pPane); 
} 
 
void ETSLayoutMgr::CPane::operator=( const ETSLayoutMgr::CPane& other ) 
{ 
	ASSERT( other.m_pPaneHolder ); 
 
	if(m_pPaneHolder) 
	{ 
		m_pPaneHolder->Release(); 
		m_pPaneHolder = 0; 
	} 
 
	other.m_pPaneHolder->AddRef(); 
	m_pPaneHolder = other.m_pPaneHolder; 
} 
 
ETSLayoutMgr::Pane* ETSLayoutMgr::CPane::operator->() const 
{ 
	ASSERT(m_pPaneHolder); 
 
	if(!m_pPaneHolder) 
		return 0; 
 
	return reinterpret_cast<Pane*>(m_pPaneHolder->m_pPane); 
} 
 
ETSLayoutMgr::CPaneBase ETSLayoutMgr::CPane::ConvertBase() const 
{ 
	ASSERT(m_pPaneHolder); 
	return CPaneBase( m_pPaneHolder->m_pPane ); 
} 
 
ETSLayoutMgr::CPane& ETSLayoutMgr::CPane::operator<< ( const ETSLayoutMgr::CPane pPane ) 
{ 
	GetPane()->addPane( pPane, (ETSLayoutMgr::layResizeMode)pPane->m_modeResize, pPane->m_sizeSecondary); 
	return (*this); 
} 
 
ETSLayoutMgr::CPane& ETSLayoutMgr::CPane::operator<< ( const ETSLayoutMgr::CPaneBase pItem ) 
{ 
	GetPane()->addPane( pItem ); 
	return (*this); 
}