////////////////////////////////////////////
// ___ ____ _________________ //
// / _/_ _// _______________/ //
// / _/ / / / / ___ ___ ____ //
// /__/ /_/ / / / // _/_ _/ //
// _________/ / / / // _/ / / //
// (c) 1998-2000_/ /___//_/ /_/ //
// //
////////////////////////////////////////////
// all rights reserved //
////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// ETSLayoutDialog
//
// A class for smart layouting of Dialogs and such
//
// USAGE: See LayoutMgr.html
//
// AUTHOR: Erwin Tratar
//
// 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
#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(&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(pbtData);
ASSERT(nSize == sizeof(WINDOWPLACEMENT));
if(nSize == sizeof(WINDOWPLACEMENT))
GetWnd()->SetWindowPlacement(reinterpret_cast(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(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 = 0;
#ifdef GCL_HBRBACKGROUND
hBrBack = (HBRUSH) ::GetClassLong(GetWnd()->GetSafeHwnd(), GCL_HBRBACKGROUND) ;
#endif
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; igetMaxConstrainHorz();
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; igetMaxConstrainHorz();
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; igetMaxConstrainVert();
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; igetMaxConstrainVert();
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; igetMinConstrainHorz());
}
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; igetMinConstrainHorz();
nMaxConstr = max(nMaxConstr, nConstrain);
}
return nMaxConstr + 2*m_sizeExtraBorder;
}
}
int ETSLayoutMgr::Pane::getMinConstrainVert()
{
if(m_Orientation == VERTICAL) {
int nMaxConstr = 0;
for(int i=0; igetMinConstrainVert());
}
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; igetMinConstrainVert();
nMaxConstr = max(nMaxConstr, nConstrain);
}
return nMaxConstr + 2*m_sizeExtraBorder;
}
}
int ETSLayoutMgr::Pane::resizeToAbsolute(int& availSpace, CArray& sizePrimary,
CArray& sizeMin, CArray& sizeMax)
{
// count all greedy items as returnvalue
int nGreedy = 0;
// first, subtract all absoulute items from available space
for(int i=0; imodeResize() & 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& sizePrimary,
CArray& sizeMin, CArray& 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; imodeResize() & 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(int i=0; imodeResize() & 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(int i=0; imodeResize() & 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& sizePrimary,
CArray& sizeMin, CArray& 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; imodeResize()&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(int i=0; imodeResize()&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(int i=0; imodeResize()&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(int i=0; imodeResize() & 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 sizePrimary;
sizePrimary.SetSize(m_paneItems.GetSize());
// This Array holds information about the minimum size in primary direction
CArray sizeMin;
sizeMin.SetSize(m_paneItems.GetSize());
// This Array holds information about the maximum size in primary direction
CArray 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; imodeResize() & 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; imodeResize() & 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; iresizeTo( 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, CDialog)
//{{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, CDialogBar)
//{{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, CFormView)
//{{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(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, CPropertyPage)
//{{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(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; nPageGetSafeHwnd()) )
{
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( m_ItemTab.GetPaneBase() )->m_sizeXMin = sizePageMin.cx;
static_cast( 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; nPageRelease();
}
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(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(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);
}