git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1191 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1733 lines
43 KiB
C++
1733 lines
43 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: layout.cpp
|
|
// Purpose: Constraint layout system classes
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 04/01/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Julian Smart and Markus Holzem
|
|
// Licence: wxWindows license
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "layout.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include "wx/defs.h"
|
|
|
|
#if wxUSE_CONSTRAINTS
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/window.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/dialog.h"
|
|
#include "wx/msgdlg.h"
|
|
#include <wx/intl.h>
|
|
#endif
|
|
|
|
#include "wx/layout.h"
|
|
|
|
#if !USE_SHARED_LIBRARY
|
|
IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint, wxObject)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints, wxObject)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxSizer, wxObject)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxRowColSizer, wxSizer)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxSpacingSizer, wxSizer)
|
|
#endif
|
|
|
|
/*
|
|
TODO:
|
|
- Non shrink-to-fit row-col behaviour.
|
|
- Give justification styles, so can e.g. centre
|
|
the rows & cols, distribute the available space...
|
|
- Shrink-to-fit: should resize outer window (e.g. dialog box)
|
|
if directly associated with this kind of window.
|
|
- How to deal with a rowcol that stretches in one direction
|
|
but shrinks-to-fit in other. E.g. a horizontal toolbar: the width
|
|
stretches to fit the frame, but the height is constant
|
|
or wraps around contents. The algorithm currently assumes
|
|
both dimensions have the same behaviour. Could assume a constant
|
|
height (absolute value).
|
|
- rowcol where each row or column is aligned (length of
|
|
largest element determines spacing)
|
|
- Groupbox sizer
|
|
- Analyze aesthetic dialog boxes and implement using sizers.
|
|
- What reuseable components can we provide? E.g. Ok/Cancel/Help
|
|
group of buttons.
|
|
- use wxStaticItems for aesthetic dialogs.
|
|
|
|
*/
|
|
|
|
// Find margin sizes if a sizer, or zero otherwise
|
|
int wxSizerMarginX(wxWindow *win)
|
|
{
|
|
if ( win->IsKindOf(CLASSINFO(wxSizer)) )
|
|
{
|
|
wxSizer *sizer = (wxSizer *)win;
|
|
return sizer->GetBorderX();
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int wxSizerMarginY(wxWindow *win)
|
|
{
|
|
if ( win->IsKindOf(CLASSINFO(wxSizer)) )
|
|
{
|
|
wxSizer *sizer = (wxSizer *)win;
|
|
return sizer->GetBorderY();
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
|
|
{
|
|
myEdge = wxTop; relationship = wxUnconstrained; margin = 0; value = 0; percent = 0; otherEdge = wxTop;
|
|
done = FALSE; otherWin = (wxWindow *) NULL;
|
|
}
|
|
|
|
wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
|
|
{
|
|
}
|
|
|
|
void wxIndividualLayoutConstraint::Set(wxRelationship rel, wxWindow *otherW, wxEdge otherE, int val, int marg)
|
|
{
|
|
relationship = rel; otherWin = otherW; otherEdge = otherE; value = val; margin = marg;
|
|
}
|
|
|
|
void wxIndividualLayoutConstraint::LeftOf(wxWindow *sibling, int marg)
|
|
{ Set(wxLeftOf, sibling, wxLeft, 0, marg); }
|
|
|
|
void wxIndividualLayoutConstraint::RightOf(wxWindow *sibling, int marg)
|
|
{ Set(wxRightOf, sibling, wxRight, 0, marg); }
|
|
|
|
void wxIndividualLayoutConstraint::Above(wxWindow *sibling, int marg)
|
|
{ Set(wxAbove, sibling, wxTop, 0, marg); }
|
|
|
|
void wxIndividualLayoutConstraint::Below(wxWindow *sibling, int marg)
|
|
{ Set(wxBelow, sibling, wxBottom, 0, marg); }
|
|
|
|
//
|
|
// 'Same edge' alignment
|
|
//
|
|
void wxIndividualLayoutConstraint::SameAs(wxWindow *otherW, wxEdge edge, int marg)
|
|
{ Set(wxPercentOf, otherW, edge, 0, marg); percent = 100; }
|
|
|
|
// The edge is a percentage of the other window's edge
|
|
void wxIndividualLayoutConstraint::PercentOf(wxWindow *otherW, wxEdge wh, int per)
|
|
{ otherWin = otherW; relationship = wxPercentOf; percent = per;
|
|
otherEdge = wh;
|
|
}
|
|
|
|
//
|
|
// Edge has absolute value
|
|
//
|
|
void wxIndividualLayoutConstraint::Absolute(int val)
|
|
{ value = val; relationship = wxAbsolute; }
|
|
|
|
// Reset constraint if it mentions otherWin
|
|
bool wxIndividualLayoutConstraint::ResetIfWin(wxWindow *otherW)
|
|
{
|
|
if (otherW == otherWin)
|
|
{
|
|
myEdge = wxTop; relationship = wxAsIs; margin = 0; value = 0; percent = 0; otherEdge = wxTop;
|
|
otherWin = (wxWindow *) NULL;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
// Try to satisfy constraint
|
|
bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints *constraints, wxWindow *win)
|
|
{
|
|
if (relationship == wxAbsolute)
|
|
{
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
switch (myEdge)
|
|
{
|
|
case wxLeft:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxLeftOf:
|
|
{
|
|
// We can know this edge if: otherWin is win's parent,
|
|
// or otherWin has a satisfied constraint, or
|
|
// otherWin has no constraint.
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos - margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxRightOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos + margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the left-hand edge position if we know
|
|
// the right-hand edge and we know the width; OR if we know the centre and the width.
|
|
if (constraints->right.GetDone() && constraints->width.GetDone())
|
|
{
|
|
value = (constraints->right.GetValue() - constraints->width.GetValue() + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->centreX.GetDone() && constraints->width.GetDone())
|
|
{
|
|
value = (int)(constraints->centreX.GetValue() - (constraints->width.GetValue()/2) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxAsIs:
|
|
{
|
|
int y;
|
|
win->GetPosition(&value, &y);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxRight:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxLeftOf:
|
|
{
|
|
// We can know this edge if: otherWin is win's parent,
|
|
// or otherWin has a satisfied constraint, or
|
|
// otherWin has no constraint.
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos - margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxRightOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos + margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01) - margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the right-hand edge position if we know
|
|
// the left-hand edge and we know the width, OR if we know the
|
|
// centre edge and the width.
|
|
if (constraints->left.GetDone() && constraints->width.GetDone())
|
|
{
|
|
value = (constraints->left.GetValue() + constraints->width.GetValue() - margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->centreX.GetDone() && constraints->width.GetDone())
|
|
{
|
|
value = (int)(constraints->centreX.GetValue() + (constraints->width.GetValue()/2) - margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxAsIs:
|
|
{
|
|
int x, y;
|
|
int w, h;
|
|
win->GetSize(&w, &h);
|
|
win->GetPosition(&x, &y);
|
|
value = x + w;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxTop:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxAbove:
|
|
{
|
|
// We can know this edge if: otherWin is win's parent,
|
|
// or otherWin has a satisfied constraint, or
|
|
// otherWin has no constraint.
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos - margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxBelow:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos + margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the top edge position if we know
|
|
// the bottom edge and we know the height; OR if we know the centre
|
|
// edge and the height.
|
|
if (constraints->bottom.GetDone() && constraints->height.GetDone())
|
|
{
|
|
value = (constraints->bottom.GetValue() - constraints->height.GetValue() + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->centreY.GetDone() && constraints->height.GetDone())
|
|
{
|
|
value = (constraints->centreY.GetValue() - (constraints->height.GetValue()/2) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxAsIs:
|
|
{
|
|
int x;
|
|
win->GetPosition(&x, &value);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxBottom:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxAbove:
|
|
{
|
|
// We can know this edge if: otherWin is win's parent,
|
|
// or otherWin has a satisfied constraint, or
|
|
// otherWin has no constraint.
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos + margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxBelow:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos - margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01) - margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the bottom edge position if we know
|
|
// the top edge and we know the height; OR if we know the
|
|
// centre edge and the height.
|
|
if (constraints->top.GetDone() && constraints->height.GetDone())
|
|
{
|
|
value = (constraints->top.GetValue() + constraints->height.GetValue() - margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->centreY.GetDone() && constraints->height.GetDone())
|
|
{
|
|
value = (constraints->centreY.GetValue() + (constraints->height.GetValue()/2) - margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxAsIs:
|
|
{
|
|
int x, y;
|
|
int w, h;
|
|
win->GetSize(&w, &h);
|
|
win->GetPosition(&x, &y);
|
|
value = h + y;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxCentreX:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxLeftOf:
|
|
{
|
|
// We can know this edge if: otherWin is win's parent,
|
|
// or otherWin has a satisfied constraint, or
|
|
// otherWin has no constraint.
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos - margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxRightOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos + margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the centre position if we know
|
|
// the left-hand edge and we know the width, OR
|
|
// the right-hand edge and the width
|
|
if (constraints->left.GetDone() && constraints->width.GetDone())
|
|
{
|
|
value = (int)(constraints->left.GetValue() + (constraints->width.GetValue()/2) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->right.GetDone() && constraints->width.GetDone())
|
|
{
|
|
value = (int)(constraints->left.GetValue() - (constraints->width.GetValue()/2) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxCentreY:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxAbove:
|
|
{
|
|
// We can know this edge if: otherWin is win's parent,
|
|
// or otherWin has a satisfied constraint, or
|
|
// otherWin has no constraint.
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos - margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxBelow:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = edgePos + margin;
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the centre position if we know
|
|
// the top edge and we know the height, OR
|
|
// the bottom edge and the height.
|
|
if (constraints->bottom.GetDone() && constraints->height.GetDone())
|
|
{
|
|
value = (int)(constraints->bottom.GetValue() - (constraints->height.GetValue()/2) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->top.GetDone() && constraints->height.GetDone())
|
|
{
|
|
value = (int)(constraints->top.GetValue() + (constraints->height.GetValue()/2) + margin);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxWidth:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01));
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxAsIs:
|
|
{
|
|
if (win)
|
|
{
|
|
int h;
|
|
win->GetSize(&value, &h);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the width if we know the left edge and the right edge, OR
|
|
// if we know the left edge and the centre, OR
|
|
// if we know the right edge and the centre
|
|
if (constraints->left.GetDone() && constraints->right.GetDone())
|
|
{
|
|
value = constraints->right.GetValue() - constraints->left.GetValue();
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->centreX.GetDone() && constraints->left.GetDone())
|
|
{
|
|
value = (int)(2*(constraints->centreX.GetValue() - constraints->left.GetValue()));
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->centreX.GetDone() && constraints->right.GetDone())
|
|
{
|
|
value = (int)(2*(constraints->right.GetValue() - constraints->centreX.GetValue()));
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case wxHeight:
|
|
{
|
|
switch (relationship)
|
|
{
|
|
case wxPercentOf:
|
|
{
|
|
int edgePos = GetEdge(otherEdge, win, otherWin);
|
|
if (edgePos != -1)
|
|
{
|
|
value = (int)(edgePos*(((float)percent)*0.01));
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
case wxAsIs:
|
|
{
|
|
if (win)
|
|
{
|
|
int w;
|
|
win->GetSize(&w, &value);
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else return FALSE;
|
|
}
|
|
case wxUnconstrained:
|
|
{
|
|
// We know the height if we know the top edge and the bottom edge, OR
|
|
// if we know the top edge and the centre, OR
|
|
// if we know the bottom edge and the centre
|
|
if (constraints->top.GetDone() && constraints->bottom.GetDone())
|
|
{
|
|
value = constraints->bottom.GetValue() - constraints->top.GetValue();
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->top.GetDone() && constraints->centreY.GetDone())
|
|
{
|
|
value = (int)(2*(constraints->centreY.GetValue() - constraints->top.GetValue()));
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else if (constraints->bottom.GetDone() && constraints->centreY.GetDone())
|
|
{
|
|
value = (int)(2*(constraints->bottom.GetValue() - constraints->centreY.GetValue()));
|
|
done = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the value of this edge or dimension, or if this
|
|
// is not determinable, -1.
|
|
int wxIndividualLayoutConstraint::GetEdge(wxEdge which,
|
|
wxWindow *thisWin,
|
|
wxWindow *other) const
|
|
{
|
|
// If the edge or dimension belongs to the parent, then we
|
|
// know the dimension is obtainable immediately.
|
|
// E.g. a wxExpandSizer may contain a button (but the button's
|
|
// true parent is a panel, not the sizer)
|
|
if (other->GetChildren().Member(thisWin))
|
|
{
|
|
switch (which)
|
|
{
|
|
case wxLeft:
|
|
{
|
|
return wxSizerMarginX(other);
|
|
}
|
|
case wxTop:
|
|
{
|
|
return wxSizerMarginY(other);
|
|
}
|
|
case wxRight:
|
|
{
|
|
int w, h;
|
|
other->GetClientSizeConstraint(&w, &h);
|
|
return w - wxSizerMarginX(other);
|
|
}
|
|
case wxBottom:
|
|
{
|
|
int w, h;
|
|
other->GetClientSizeConstraint(&w, &h);
|
|
return h - wxSizerMarginY(other);
|
|
}
|
|
case wxWidth:
|
|
{
|
|
int w, h;
|
|
other->GetClientSizeConstraint(&w, &h);
|
|
return w - 2*wxSizerMarginX(other);
|
|
}
|
|
case wxHeight:
|
|
{
|
|
int w, h;
|
|
other->GetClientSizeConstraint(&w, &h);
|
|
return h - 2*wxSizerMarginY(other);
|
|
}
|
|
case wxCentreX:
|
|
case wxCentreY:
|
|
{
|
|
int w, h;
|
|
other->GetClientSizeConstraint(&w, &h);
|
|
if (which == wxCentreX)
|
|
return (int)(w/2);
|
|
else
|
|
return (int)(h/2);
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
switch (which)
|
|
{
|
|
case wxLeft:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->left.GetDone())
|
|
return constr->left.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int x, y;
|
|
other->GetPosition(&x, &y);
|
|
return x;
|
|
}
|
|
}
|
|
case wxTop:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->top.GetDone())
|
|
return constr->top.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int x, y;
|
|
other->GetPosition(&x, &y);
|
|
return y;
|
|
}
|
|
}
|
|
case wxRight:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->right.GetDone())
|
|
return constr->right.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int x, y, w, h;
|
|
other->GetPosition(&x, &y);
|
|
other->GetSize(&w, &h);
|
|
return (int)(x + w);
|
|
}
|
|
}
|
|
case wxBottom:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->bottom.GetDone())
|
|
return constr->bottom.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int x, y, w, h;
|
|
other->GetPosition(&x, &y);
|
|
other->GetSize(&w, &h);
|
|
return (int)(y + h);
|
|
}
|
|
}
|
|
case wxWidth:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->width.GetDone())
|
|
return constr->width.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int w, h;
|
|
other->GetSize(&w, &h);
|
|
return w;
|
|
}
|
|
}
|
|
case wxHeight:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->height.GetDone())
|
|
return constr->height.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int w, h;
|
|
other->GetSize(&w, &h);
|
|
return h;
|
|
}
|
|
}
|
|
case wxCentreX:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->centreX.GetDone())
|
|
return constr->centreX.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int x, y, w, h;
|
|
other->GetPosition(&x, &y);
|
|
other->GetSize(&w, &h);
|
|
return (int)(x + (w/2));
|
|
}
|
|
}
|
|
case wxCentreY:
|
|
{
|
|
wxLayoutConstraints *constr = other->GetConstraints();
|
|
// If no constraints, it means the window is not dependent
|
|
// on anything, and therefore we know its value immediately
|
|
if (constr)
|
|
{
|
|
if (constr->centreY.GetDone())
|
|
return constr->centreY.GetValue();
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
int x, y, w, h;
|
|
other->GetPosition(&x, &y);
|
|
other->GetSize(&w, &h);
|
|
return (int)(y + (h/2));
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
wxLayoutConstraints::wxLayoutConstraints()
|
|
{
|
|
left.SetEdge(wxLeft);
|
|
top.SetEdge(wxTop);
|
|
right.SetEdge(wxRight);
|
|
bottom.SetEdge(wxBottom);
|
|
centreX.SetEdge(wxCentreX);
|
|
centreY.SetEdge(wxCentreY);
|
|
width.SetEdge(wxWidth);
|
|
height.SetEdge(wxHeight);
|
|
}
|
|
|
|
wxLayoutConstraints::~wxLayoutConstraints()
|
|
{
|
|
}
|
|
|
|
bool wxLayoutConstraints::SatisfyConstraints(wxWindow *win, int *nChanges)
|
|
{
|
|
int noChanges = 0;
|
|
|
|
bool done = width.GetDone();
|
|
bool newDone = (done ? TRUE : width.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = height.GetDone();
|
|
newDone = (done ? TRUE : height.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = left.GetDone();
|
|
newDone = (done ? TRUE : left.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = top.GetDone();
|
|
newDone = (done ? TRUE : top.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = right.GetDone();
|
|
newDone = (done ? TRUE : right.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = bottom.GetDone();
|
|
newDone = (done ? TRUE : bottom.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = centreX.GetDone();
|
|
newDone = (done ? TRUE : centreX.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
done = centreY.GetDone();
|
|
newDone = (done ? TRUE : centreY.SatisfyConstraint(this, win));
|
|
if (newDone != done)
|
|
noChanges ++;
|
|
|
|
*nChanges = noChanges;
|
|
|
|
return AreSatisfied();
|
|
}
|
|
|
|
/*
|
|
* Main constrained layout algorithm. Look at all the child
|
|
* windows, and their constraints (if any).
|
|
* The idea is to keep iterating through the constraints
|
|
* until all left, right, bottom and top edges, and widths and heights,
|
|
* are known (or no change occurs and we've failed to resolve all
|
|
* constraints).
|
|
*
|
|
* If the user has not specified a dimension or edge, it will be
|
|
* be calculated from the other known values. E.g. If we know
|
|
* the right hand edge and the left hand edge, we now know the width.
|
|
* The snag here is that this means we must specify absolute dimensions
|
|
* twice (in constructor and in constraint), if we wish to use the
|
|
* constraint notation to just set the position, for example.
|
|
* Otherwise, if we only set ONE edge and no dimension, it would never
|
|
* find the other edge.
|
|
*
|
|
* Algorithm:
|
|
|
|
Mark all constraints as not done.
|
|
|
|
iterations = 0;
|
|
until no change or iterations >= max iterations
|
|
For each child:
|
|
{
|
|
Calculate all constraints
|
|
}
|
|
iterations ++;
|
|
|
|
For each child
|
|
Set each calculated position and size
|
|
|
|
*/
|
|
|
|
bool wxOldDoLayout(wxWindow *win)
|
|
{
|
|
// Make sure this isn't called recursively from below
|
|
static wxList doneSoFar;
|
|
|
|
if (doneSoFar.Member(win))
|
|
return TRUE;
|
|
|
|
doneSoFar.Append(win);
|
|
|
|
wxNode *node = win->GetChildren().First();
|
|
while (node)
|
|
{
|
|
wxWindow *child = (wxWindow *)node->Data();
|
|
wxLayoutConstraints *constr = child->GetConstraints();
|
|
if (constr)
|
|
{
|
|
constr->left.SetDone(FALSE);
|
|
constr->top.SetDone(FALSE);
|
|
constr->right.SetDone(FALSE);
|
|
constr->bottom.SetDone(FALSE);
|
|
constr->width.SetDone(FALSE);
|
|
constr->height.SetDone(FALSE);
|
|
constr->centreX.SetDone(FALSE);
|
|
constr->centreY.SetDone(FALSE);
|
|
}
|
|
node = node->Next();
|
|
}
|
|
int noIterations = 0;
|
|
int maxIterations = 500;
|
|
int noChanges = 1;
|
|
|
|
while ((noChanges > 0) && (noIterations < maxIterations))
|
|
{
|
|
noChanges = 0;
|
|
wxNode *node = win->GetChildren().First();
|
|
while (node)
|
|
{
|
|
wxWindow *child = (wxWindow *)node->Data();
|
|
wxLayoutConstraints *constr = child->GetConstraints();
|
|
if (constr)
|
|
{
|
|
int tempNoChanges = 0;
|
|
(void)constr->SatisfyConstraints(child, &tempNoChanges);
|
|
noChanges += tempNoChanges;
|
|
}
|
|
node = node->Next();
|
|
}
|
|
noIterations ++;
|
|
}
|
|
/*
|
|
// Would be nice to have a test here to see _which_ constraint(s)
|
|
// failed, so we can print a specific diagnostic message.
|
|
if (noFailures > 0)
|
|
{
|
|
wxDebugMsg(_("wxWindow::Layout() failed.\n"));
|
|
}
|
|
*/
|
|
// Now set the sizes and positions of the children, and
|
|
// recursively call Layout().
|
|
node = win->GetChildren().First();
|
|
while (node)
|
|
{
|
|
wxWindow *child = (wxWindow *)node->Data();
|
|
wxLayoutConstraints *constr = child->GetConstraints();
|
|
if (constr && constr->left.GetDone() && constr->right.GetDone() &&
|
|
constr->width.GetDone() && constr->height.GetDone())
|
|
{
|
|
int x = constr->left.GetValue();
|
|
int y = constr->top.GetValue();
|
|
int w = constr->width.GetValue();
|
|
int h = constr->height.GetValue();
|
|
|
|
// If we don't want to resize this window, just move it...
|
|
if ((constr->width.GetRelationship() != wxAsIs) ||
|
|
(constr->height.GetRelationship() != wxAsIs))
|
|
{
|
|
// _Should_ call Layout() recursively.
|
|
child->SetSize(x, y, w, h);
|
|
}
|
|
else
|
|
{
|
|
child->Move(x, y);
|
|
}
|
|
}
|
|
else
|
|
child->Layout();
|
|
node = node->Next();
|
|
}
|
|
doneSoFar.DeleteObject(win);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
wxSizer::wxSizer()
|
|
{
|
|
sizerBehaviour = wxSizerNone;
|
|
borderX = 2;
|
|
borderY = 2;
|
|
sizerX = 0;
|
|
sizerY = 0;
|
|
sizerWidth = 0;
|
|
sizerHeight = 0;
|
|
}
|
|
|
|
wxSizer::wxSizer(wxWindow *parent, wxSizerBehaviour behav)
|
|
{
|
|
Create(parent, behav);
|
|
}
|
|
|
|
bool wxSizer::Create(wxWindow *parent, wxSizerBehaviour behav)
|
|
{
|
|
sizerBehaviour = behav;
|
|
borderX = 2;
|
|
borderY = 2;
|
|
m_sizerParent = parent;
|
|
sizerX = 0;
|
|
sizerY = 0;
|
|
sizerWidth = 0;
|
|
sizerHeight = 0;
|
|
|
|
// A normal window can have just one top-level sizer
|
|
// associated with it.
|
|
if (!parent->IsKindOf(CLASSINFO(wxSizer)))
|
|
{
|
|
parent->SetSizer(this);
|
|
}
|
|
else
|
|
((wxSizer *)parent)->AddSizerChild(this);
|
|
|
|
switch (sizerBehaviour)
|
|
{
|
|
case wxSizerExpand:
|
|
{
|
|
// Defines a set of constraints
|
|
// to expand the sizer to fit the parent window
|
|
wxLayoutConstraints *c = new wxLayoutConstraints;
|
|
|
|
c->left.SameAs(parent, wxLeft, 0);
|
|
c->top.SameAs(parent, wxTop, 0);
|
|
c->right.SameAs(parent, wxRight, 0);
|
|
c->bottom.SameAs(parent, wxBottom, 0);
|
|
|
|
SetConstraints(c);
|
|
break;
|
|
}
|
|
case wxSizerShrink:
|
|
case wxSizerNone:
|
|
default:
|
|
{
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
wxSizer::~wxSizer()
|
|
{
|
|
// Remove all children without deleting them,
|
|
// or ~wxbWindow will delete proper windows _twice_
|
|
wxNode *node = GetChildren().First();
|
|
while (node)
|
|
{
|
|
wxNode *next = node->Next();
|
|
wxWindow *win = (wxWindow *)node->Data();
|
|
if (!win->IsKindOf(CLASSINFO(wxSizer)))
|
|
{
|
|
delete node;
|
|
win->SetSizerParent((wxWindow *) NULL);
|
|
}
|
|
else
|
|
{
|
|
RemoveSizerChild(win);
|
|
delete win;
|
|
}
|
|
node = next;
|
|
}
|
|
|
|
if (m_sizerParent) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
|
|
{
|
|
m_sizerParent->SetSizer((wxSizer *) NULL);
|
|
m_sizerParent = (wxWindow *) NULL;
|
|
}
|
|
|
|
}
|
|
|
|
void wxSizer::SetBorder(int x, int y)
|
|
{
|
|
borderX = x;
|
|
borderY = y;
|
|
/* No: the margin is for inside, not outside (expansion)
|
|
|
|
if ( GetConstraints() )
|
|
{
|
|
GetConstraints()->left.SetMargin(x);
|
|
GetConstraints()->right.SetMargin(x);
|
|
GetConstraints()->top.SetMargin(y);
|
|
GetConstraints()->bottom.SetMargin(y);
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
void wxSizer::AddSizerChild(wxWindow *child)
|
|
{
|
|
child->SetSizerParent(this);
|
|
GetChildren().Append(child);
|
|
|
|
// Add some constraints for the purpose of storing
|
|
// the relative position of the window/sizer
|
|
// during layout calculations.
|
|
if (!child->GetConstraints())
|
|
{
|
|
wxLayoutConstraints *c = new wxLayoutConstraints;
|
|
c->left.AsIs();
|
|
c->top.AsIs();
|
|
c->width.AsIs();
|
|
c->height.AsIs();
|
|
int w, h;
|
|
child->GetSize(&w, &h);
|
|
c->width.SetValue(w);
|
|
c->height.SetValue(h);
|
|
|
|
child->SetConstraints(c);
|
|
}
|
|
}
|
|
|
|
void wxSizer::RemoveSizerChild(wxWindow *child)
|
|
{
|
|
GetChildren().DeleteObject(child);
|
|
}
|
|
|
|
void wxSizer::SetSize(int x, int y, int w, int h, int WXUNUSED(flags))
|
|
{
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
if (x != -1)
|
|
{
|
|
sizerX = x;
|
|
if (constr)
|
|
constr->left.SetValue(x);
|
|
}
|
|
if (y != -1)
|
|
{
|
|
sizerY = y;
|
|
if (constr)
|
|
constr->top.SetValue(y);
|
|
}
|
|
if (w != -1)
|
|
{
|
|
sizerWidth = w;
|
|
if (constr)
|
|
constr->width.SetValue(w);
|
|
}
|
|
if (h != -1)
|
|
{
|
|
sizerHeight = h;
|
|
if (constr)
|
|
constr->height.SetValue(h);
|
|
}
|
|
}
|
|
|
|
void wxSizer::GetSize(int *w, int *h) const
|
|
{
|
|
*w = sizerWidth;
|
|
*h = sizerHeight;
|
|
}
|
|
|
|
void wxSizer::GetPosition(int *x, int *y) const
|
|
{
|
|
*x = sizerX;
|
|
*y = sizerY;
|
|
}
|
|
|
|
bool wxSizer::LayoutPhase1(int *noChanges)
|
|
{
|
|
*noChanges = 0;
|
|
switch (sizerBehaviour)
|
|
{
|
|
case wxSizerExpand:
|
|
{
|
|
if (!m_sizerParent)
|
|
{
|
|
wxMessageBox(_("wxExpandSizer has no parent!"), _("Sizer error"), wxOK);
|
|
return TRUE;
|
|
}
|
|
|
|
// Set the size to fill the parent client area
|
|
int pw, ph;
|
|
m_sizerParent->GetClientSize(&pw, &ph);
|
|
SetSize(GetBorderX(), GetBorderY(), pw - 2*GetBorderX(), ph - 2*GetBorderY());
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
|
|
// Fill in the constraints
|
|
if (constr)
|
|
{
|
|
constr->left.SetValue(0); constr->left.SetDone(TRUE);
|
|
constr->top.SetValue(0); constr->right.SetDone(TRUE);
|
|
constr->width.SetValue(pw); constr->width.SetDone(TRUE);
|
|
constr->height.SetValue(ph); constr->height.SetDone(TRUE);
|
|
}
|
|
|
|
return TRUE;
|
|
break;
|
|
}
|
|
case wxSizerShrink:
|
|
{
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
|
|
if (constr)
|
|
{
|
|
// Force the constraint to have as-is width and height
|
|
// if we're in shrink-to-fit mode, because if left unconstrained,
|
|
// SatisfyConstraints will fail. The shrink-to-fit option
|
|
// essentially specifies the width and height as 'whatever I calculate'.
|
|
constr->width.AsIs();
|
|
constr->height.AsIs();
|
|
}
|
|
DoPhase(1);
|
|
DoPhase(2);
|
|
// Find the bounding box and set own size
|
|
int maxX = 0;
|
|
int maxY = 0;
|
|
wxNode *node = GetChildren().First();
|
|
while (node)
|
|
{
|
|
int x, y, width, height;
|
|
wxWindow *win = (wxWindow *)node->Data();
|
|
win->GetSizeConstraint(&width, &height);
|
|
win->GetPositionConstraint(&x, &y);
|
|
if ((x+width) > maxX)
|
|
maxX = (x + width);
|
|
if ((y+height) > maxY)
|
|
maxY = (y + height);
|
|
node = node->Next();
|
|
}
|
|
SetSize(GetBorderX(), GetBorderY(), maxX, maxY);
|
|
|
|
// If this is the only sizer for the parent, size the parent to this sizer.
|
|
if ( m_sizerParent && (m_sizerParent->GetSizer() == this) )
|
|
m_sizerParent->SetClientSize(maxX + 2*GetBorderX(), maxY + 2*GetBorderY());
|
|
|
|
return TRUE;
|
|
break;
|
|
}
|
|
case wxSizerNone:
|
|
{
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
if (constr)
|
|
{
|
|
bool success = constr->SatisfyConstraints(this, noChanges);
|
|
if (success)
|
|
{
|
|
int x = constr->left.GetValue();
|
|
int y = constr->top.GetValue();
|
|
int w = constr->width.GetValue();
|
|
int h = constr->height.GetValue();
|
|
SetSize(x, y, w, h);
|
|
}
|
|
return success;
|
|
}
|
|
else
|
|
return TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
bool wxSizer::LayoutPhase2(int *noChanges)
|
|
{
|
|
*noChanges = 0;
|
|
|
|
switch (sizerBehaviour)
|
|
{
|
|
case wxSizerExpand:
|
|
{
|
|
// Layout children
|
|
DoPhase(1);
|
|
DoPhase(2);
|
|
return TRUE;
|
|
}
|
|
case wxSizerShrink:
|
|
{
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
if (constr)
|
|
{
|
|
bool success = constr->SatisfyConstraints(this, noChanges);
|
|
if (success)
|
|
{
|
|
int x = constr->left.GetValue();
|
|
int y = constr->top.GetValue();
|
|
Move(x, y);
|
|
}
|
|
return success;
|
|
}
|
|
break;
|
|
}
|
|
case wxSizerNone:
|
|
{
|
|
// Layout children
|
|
DoPhase(1);
|
|
DoPhase(2);
|
|
|
|
// Is this a dumb fix for lack of constraint evaluation?
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
if (constr)
|
|
{
|
|
bool success = constr->SatisfyConstraints(this, noChanges);
|
|
if (success)
|
|
{
|
|
int x = constr->left.GetValue();
|
|
int y = constr->top.GetValue();
|
|
int w = constr->width.GetValue();
|
|
int h = constr->height.GetValue();
|
|
SetSize(x, y, w, h);
|
|
}
|
|
return success;
|
|
}
|
|
else
|
|
return TRUE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* wxRowColSizer
|
|
*/
|
|
|
|
wxRowColSizer::wxRowColSizer()
|
|
{
|
|
rowOrCol = TRUE;
|
|
rowOrColSize = 20;
|
|
xSpacing = 2;
|
|
ySpacing = 2;
|
|
}
|
|
|
|
wxRowColSizer::wxRowColSizer(wxWindow *parent, bool rc, int n, wxSizerBehaviour behav)
|
|
{
|
|
Create(parent, rc, n, behav);
|
|
}
|
|
|
|
bool wxRowColSizer::Create(wxWindow *parent, bool rc, int n, wxSizerBehaviour behav)
|
|
{
|
|
wxSizer::Create(parent, behav);
|
|
|
|
rowOrCol = rc;
|
|
rowOrColSize = n;
|
|
xSpacing = 2;
|
|
ySpacing = 2;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
wxRowColSizer::~wxRowColSizer()
|
|
{
|
|
}
|
|
|
|
void wxRowColSizer::SetSize(int x, int y, int w, int h, int flags)
|
|
{
|
|
wxSizer::SetSize(x, y, w, h, flags);
|
|
}
|
|
|
|
bool wxRowColSizer::LayoutPhase1(int *noChanges)
|
|
{
|
|
*noChanges = 0;
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
|
|
if (constr)
|
|
{
|
|
// Force the constraint to have as-is width and height
|
|
// if we're in shrink-to-fit mode, because if left unconstrained,
|
|
// SatisfyConstraints will fail. The shrink-to-fit option
|
|
// essentially specifies the width and height as 'whatever I calculate'.
|
|
if (sizerBehaviour == wxSizerShrink)
|
|
{
|
|
constr->width.AsIs();
|
|
constr->height.AsIs();
|
|
}
|
|
|
|
// Only evaluate the constraints FIRST if we're NOT
|
|
// in shrink-to-fit mode, i.e. we want to size the rowcol
|
|
// first, then lay the children out in the space we've calculated.
|
|
if (sizerBehaviour != wxSizerShrink)
|
|
{
|
|
bool success = constr->SatisfyConstraints(this, noChanges);
|
|
if (success)
|
|
{
|
|
int x = constr->left.GetValue();
|
|
int y = constr->top.GetValue();
|
|
int w = constr->width.GetValue();
|
|
int h = constr->height.GetValue();
|
|
SetSize(x, y, w, h);
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
// Continue to do the rest of the phase when the constraints have been
|
|
// satisfied, i.e. we're on the last iteration of phase 1 and
|
|
// can now do the actual rowcol laying out.
|
|
}
|
|
}
|
|
|
|
// If we ARE in shrink-to-fit mode, we must now
|
|
// calculate the child sizes BEFORE laying out in rows or columns.
|
|
if (sizerBehaviour == wxSizerShrink)
|
|
{
|
|
DoPhase(1);
|
|
DoPhase(2);
|
|
|
|
// WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
|
|
// CHECK CONSTRAINTS IF ANY...
|
|
int noRows = 0;
|
|
int noCols = 0;
|
|
int currentX = borderX;
|
|
int currentY = borderY;
|
|
int maxX = currentX;
|
|
int maxY = currentY;
|
|
|
|
wxNode *node = GetChildren().First();
|
|
while (node)
|
|
{
|
|
wxWindow *win = (wxWindow *)node->Data();
|
|
int childWidth, childHeight;
|
|
if (win->GetConstraints() &&
|
|
win->GetConstraints()->width.GetDone() &&
|
|
win->GetConstraints()->height.GetDone())
|
|
{
|
|
childWidth = win->GetConstraints()->width.GetValue();
|
|
childHeight = win->GetConstraints()->height.GetValue();
|
|
}
|
|
else
|
|
win->GetSize(&childWidth, &childHeight);
|
|
|
|
win->MoveConstraint(currentX, currentY);
|
|
|
|
if ((currentX + childWidth) > maxX)
|
|
maxX = (currentX + childWidth);
|
|
if ((currentY + childHeight) > maxY)
|
|
maxY = (currentY + childHeight);
|
|
|
|
if (rowOrCol)
|
|
{
|
|
currentX += childWidth + xSpacing;
|
|
noCols ++;
|
|
|
|
// Reset to start of row
|
|
if (noCols == rowOrColSize)
|
|
{
|
|
currentX = borderX;
|
|
currentY += childHeight + ySpacing;
|
|
noCols = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentY += childHeight + ySpacing;
|
|
noRows ++;
|
|
|
|
// Reset to start of col
|
|
if (noRows == rowOrColSize)
|
|
{
|
|
currentY = borderY;
|
|
currentX += childWidth + xSpacing;
|
|
noRows = 0;
|
|
}
|
|
}
|
|
|
|
node = node->Next();
|
|
}
|
|
maxX += borderX;
|
|
maxY += borderY;
|
|
|
|
SetSize(-1, -1, maxX, maxY);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool wxRowColSizer::LayoutPhase2(int *noChanges)
|
|
{
|
|
*noChanges = 0;
|
|
|
|
// If shrink-to-fit, it's only at Phase 2 that we know the size of
|
|
// the wxRowColSizer, and now we can evaluate the
|
|
// constraints and pass result back up to parent.
|
|
// This implements a depth-first strategy
|
|
if (sizerBehaviour == wxSizerShrink)
|
|
{
|
|
wxLayoutConstraints *constr = GetConstraints();
|
|
if (constr)
|
|
{
|
|
bool success = constr->SatisfyConstraints(this, noChanges);
|
|
if (success)
|
|
{
|
|
int x = constr->left.GetValue();
|
|
int y = constr->top.GetValue();
|
|
Move(x, y);
|
|
}
|
|
return success;
|
|
}
|
|
else return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Lay out the children: breadth-first strategy.
|
|
DoPhase(1);
|
|
DoPhase(2);
|
|
|
|
// Space them
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* wxSpacingSizer
|
|
*/
|
|
|
|
wxSpacingSizer::wxSpacingSizer()
|
|
{
|
|
}
|
|
|
|
wxSpacingSizer::wxSpacingSizer(wxWindow *parent)
|
|
{
|
|
Create(parent);
|
|
}
|
|
|
|
wxSpacingSizer::wxSpacingSizer(wxWindow *parent, wxRelationship rel, wxWindow *other, int spacing)
|
|
{
|
|
Create(parent, rel, other, spacing);
|
|
}
|
|
|
|
bool wxSpacingSizer::Create(wxWindow *parent)
|
|
{
|
|
wxSizer::Create(parent);
|
|
return TRUE;
|
|
}
|
|
|
|
bool wxSpacingSizer::Create(wxWindow *parent, wxRelationship rel, wxWindow *other, int spacing)
|
|
{
|
|
wxLayoutConstraints *c = new wxLayoutConstraints;
|
|
|
|
wxSizer::Create(parent);
|
|
|
|
switch ( rel )
|
|
{
|
|
case wxLeftOf :
|
|
c->width.Absolute (spacing);
|
|
c->top.SameAs (other, wxTop);
|
|
c->bottom.SameAs (other, wxBottom);
|
|
c->right.LeftOf (other);
|
|
break;
|
|
case wxRightOf :
|
|
c->width.Absolute (spacing);
|
|
c->top.SameAs (other, wxTop);
|
|
c->bottom.SameAs (other, wxBottom);
|
|
c->left.RightOf (other);
|
|
break;
|
|
case wxBelow :
|
|
c->height.Absolute (spacing);
|
|
c->left.SameAs (other, wxLeft);
|
|
c->right.SameAs (other, wxRight);
|
|
c->top.Below (other);
|
|
break;
|
|
case wxAbove :
|
|
c->height.Absolute (spacing);
|
|
c->left.SameAs (other, wxLeft);
|
|
c->right.SameAs (other, wxRight);
|
|
c->bottom.Above (other);
|
|
break;
|
|
|
|
default :
|
|
break;
|
|
}
|
|
SetConstraints(c);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
wxSpacingSizer::~wxSpacingSizer()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
#endif
|