1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Constraint layout system classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // =============================================================================
14 // =============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #pragma implementation "layout.h"
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
33 #include "wx/window.h"
35 #include "wx/dialog.h"
36 #include "wx/msgdlg.h"
40 #include "wx/layout.h"
42 #if !USE_SHARED_LIBRARY
43 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
44 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
45 IMPLEMENT_DYNAMIC_CLASS(wxSizer
, wxObject
)
46 IMPLEMENT_DYNAMIC_CLASS(wxRowColSizer
, wxSizer
)
47 IMPLEMENT_DYNAMIC_CLASS(wxSpacingSizer
, wxSizer
)
52 - Non shrink-to-fit row-col behaviour.
53 - Give justification styles, so can e.g. centre
54 the rows & cols, distribute the available space...
55 - Shrink-to-fit: should resize outer window (e.g. dialog box)
56 if directly associated with this kind of window.
57 - How to deal with a rowcol that stretches in one direction
58 but shrinks-to-fit in other. E.g. a horizontal toolbar: the width
59 stretches to fit the frame, but the height is constant
60 or wraps around contents. The algorithm currently assumes
61 both dimensions have the same behaviour. Could assume a constant
62 height (absolute value).
63 - rowcol where each row or column is aligned (length of
64 largest element determines spacing)
66 - Analyze aesthetic dialog boxes and implement using sizers.
67 - What reuseable components can we provide? E.g. Ok/Cancel/Help
69 - use wxStaticItems for aesthetic dialogs.
73 // Find margin sizes if a sizer, or zero otherwise
74 int wxSizerMarginX(wxWindowBase
*win
)
76 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
78 wxSizer
*sizer
= (wxSizer
*)win
;
79 return sizer
->GetBorderX();
85 int wxSizerMarginY(wxWindowBase
*win
)
87 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
89 wxSizer
*sizer
= (wxSizer
*)win
;
90 return sizer
->GetBorderY();
97 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
100 relationship
= wxUnconstrained
;
106 otherWin
= (wxWindowBase
*) NULL
;
109 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
113 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindowBase
*otherW
, wxEdge otherE
, int val
, int marg
)
122 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase
*sibling
, int marg
)
124 Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
);
127 void wxIndividualLayoutConstraint::RightOf(wxWindowBase
*sibling
, int marg
)
129 Set(wxRightOf
, sibling
, wxRight
, 0, marg
);
132 void wxIndividualLayoutConstraint::Above(wxWindowBase
*sibling
, int marg
)
134 Set(wxAbove
, sibling
, wxTop
, 0, marg
);
137 void wxIndividualLayoutConstraint::Below(wxWindowBase
*sibling
, int marg
)
139 Set(wxBelow
, sibling
, wxBottom
, 0, marg
);
143 // 'Same edge' alignment
145 void wxIndividualLayoutConstraint::SameAs(wxWindowBase
*otherW
, wxEdge edge
, int marg
)
147 Set(wxPercentOf
, otherW
, edge
, 0, marg
);
151 // The edge is a percentage of the other window's edge
152 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase
*otherW
, wxEdge wh
, int per
)
155 relationship
= wxPercentOf
;
162 // Edge has absolute value
164 void wxIndividualLayoutConstraint::Absolute(int val
)
166 value
= val
; relationship
= wxAbsolute
;
169 // Reset constraint if it mentions otherWin
170 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase
*otherW
)
172 if (otherW
== otherWin
)
175 relationship
= wxAsIs
;
180 otherWin
= (wxWindowBase
*) NULL
;
187 // Try to satisfy constraint
188 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindowBase
*win
)
190 if (relationship
== wxAbsolute
)
200 switch (relationship
)
204 // We can know this edge if: otherWin is win's
205 // parent, or otherWin has a satisfied constraint,
206 // or otherWin has no constraint.
207 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
210 value
= edgePos
- margin
;
219 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
222 value
= edgePos
+ margin
;
231 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
234 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
241 case wxUnconstrained
:
243 // We know the left-hand edge position if we know
244 // the right-hand edge and we know the width; OR if
245 // we know the centre and the width.
246 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
248 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
252 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
254 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
264 win
->GetPosition(&value
, &y
);
275 switch (relationship
)
279 // We can know this edge if: otherWin is win's
280 // parent, or otherWin has a satisfied constraint,
281 // or otherWin has no constraint.
282 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
285 value
= edgePos
- margin
;
294 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
297 value
= edgePos
+ margin
;
306 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
309 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
316 case wxUnconstrained
:
318 // We know the right-hand edge position if we know the
319 // left-hand edge and we know the width, OR if we know the
320 // centre edge and the width.
321 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
323 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
327 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
329 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
340 win
->GetSize(&w
, &h
);
341 win
->GetPosition(&x
, &y
);
353 switch (relationship
)
357 // We can know this edge if: otherWin is win's
358 // parent, or otherWin has a satisfied constraint,
359 // or otherWin has no constraint.
360 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
363 value
= edgePos
- margin
;
372 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
375 value
= edgePos
+ margin
;
384 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
387 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
394 case wxUnconstrained
:
396 // We know the top edge position if we know the bottom edge
397 // and we know the height; OR if we know the centre edge and
399 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
401 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
405 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
407 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
417 win
->GetPosition(&x
, &value
);
428 switch (relationship
)
432 // We can know this edge if: otherWin is win's parent,
433 // or otherWin has a satisfied constraint, or
434 // otherWin has no constraint.
435 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
438 value
= edgePos
+ margin
;
447 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
450 value
= edgePos
- margin
;
459 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
462 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
469 case wxUnconstrained
:
471 // We know the bottom edge position if we know the top edge
472 // and we know the height; OR if we know the centre edge and
474 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
476 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
480 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
482 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
493 win
->GetSize(&w
, &h
);
494 win
->GetPosition(&x
, &y
);
506 switch (relationship
)
510 // We can know this edge if: otherWin is win's parent, or
511 // otherWin has a satisfied constraint, or otherWin has no
513 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
516 value
= edgePos
- margin
;
525 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
528 value
= edgePos
+ margin
;
537 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
540 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
547 case wxUnconstrained
:
549 // We know the centre position if we know
550 // the left-hand edge and we know the width, OR
551 // the right-hand edge and the width
552 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
554 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
558 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
560 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
574 switch (relationship
)
578 // We can know this edge if: otherWin is win's parent,
579 // or otherWin has a satisfied constraint, or otherWin
580 // has no constraint.
581 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
584 value
= edgePos
- margin
;
593 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
596 value
= edgePos
+ margin
;
605 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
608 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
615 case wxUnconstrained
:
617 // We know the centre position if we know
618 // the top edge and we know the height, OR
619 // the bottom edge and the height.
620 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
622 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
626 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
628 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
642 switch (relationship
)
646 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
649 value
= (int)(edgePos
*(((float)percent
)*0.01));
661 win
->GetSize(&value
, &h
);
667 case wxUnconstrained
:
669 // We know the width if we know the left edge and the right edge, OR
670 // if we know the left edge and the centre, OR
671 // if we know the right edge and the centre
672 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
674 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
678 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
680 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
684 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
686 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
700 switch (relationship
)
704 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
707 value
= (int)(edgePos
*(((float)percent
)*0.01));
719 win
->GetSize(&w
, &value
);
725 case wxUnconstrained
:
727 // We know the height if we know the top edge and the bottom edge, OR
728 // if we know the top edge and the centre, OR
729 // if we know the bottom edge and the centre
730 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
732 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
736 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
738 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
742 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
744 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
762 // Get the value of this edge or dimension, or if this is not determinable, -1.
763 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
764 wxWindowBase
*thisWin
,
765 wxWindowBase
*other
) const
767 // If the edge or dimension belongs to the parent, then we know the
768 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
769 // button (but the button's true parent is a panel, not the sizer)
770 if (other
->GetChildren().Find(thisWin
))
776 return wxSizerMarginX(other
);
780 return wxSizerMarginY(other
);
785 other
->GetClientSizeConstraint(&w
, &h
);
786 return w
- wxSizerMarginX(other
);
791 other
->GetClientSizeConstraint(&w
, &h
);
792 return h
- wxSizerMarginY(other
);
797 other
->GetClientSizeConstraint(&w
, &h
);
798 return w
- 2*wxSizerMarginX(other
);
803 other
->GetClientSizeConstraint(&w
, &h
);
804 return h
- 2*wxSizerMarginY(other
);
810 other
->GetClientSizeConstraint(&w
, &h
);
811 if (which
== wxCentreX
)
824 wxLayoutConstraints
*constr
= other
->GetConstraints();
825 // If no constraints, it means the window is not dependent
826 // on anything, and therefore we know its value immediately
829 if (constr
->left
.GetDone())
830 return constr
->left
.GetValue();
837 other
->GetPosition(&x
, &y
);
843 wxLayoutConstraints
*constr
= other
->GetConstraints();
844 // If no constraints, it means the window is not dependent
845 // on anything, and therefore we know its value immediately
848 if (constr
->top
.GetDone())
849 return constr
->top
.GetValue();
856 other
->GetPosition(&x
, &y
);
862 wxLayoutConstraints
*constr
= other
->GetConstraints();
863 // If no constraints, it means the window is not dependent
864 // on anything, and therefore we know its value immediately
867 if (constr
->right
.GetDone())
868 return constr
->right
.GetValue();
875 other
->GetPosition(&x
, &y
);
876 other
->GetSize(&w
, &h
);
882 wxLayoutConstraints
*constr
= other
->GetConstraints();
883 // If no constraints, it means the window is not dependent
884 // on anything, and therefore we know its value immediately
887 if (constr
->bottom
.GetDone())
888 return constr
->bottom
.GetValue();
895 other
->GetPosition(&x
, &y
);
896 other
->GetSize(&w
, &h
);
902 wxLayoutConstraints
*constr
= other
->GetConstraints();
903 // If no constraints, it means the window is not dependent
904 // on anything, and therefore we know its value immediately
907 if (constr
->width
.GetDone())
908 return constr
->width
.GetValue();
915 other
->GetSize(&w
, &h
);
921 wxLayoutConstraints
*constr
= other
->GetConstraints();
922 // If no constraints, it means the window is not dependent
923 // on anything, and therefore we know its value immediately
926 if (constr
->height
.GetDone())
927 return constr
->height
.GetValue();
934 other
->GetSize(&w
, &h
);
940 wxLayoutConstraints
*constr
= other
->GetConstraints();
941 // If no constraints, it means the window is not dependent
942 // on anything, and therefore we know its value immediately
945 if (constr
->centreX
.GetDone())
946 return constr
->centreX
.GetValue();
953 other
->GetPosition(&x
, &y
);
954 other
->GetSize(&w
, &h
);
955 return (int)(x
+ (w
/2));
960 wxLayoutConstraints
*constr
= other
->GetConstraints();
961 // If no constraints, it means the window is not dependent
962 // on anything, and therefore we know its value immediately
965 if (constr
->centreY
.GetDone())
966 return constr
->centreY
.GetValue();
973 other
->GetPosition(&x
, &y
);
974 other
->GetSize(&w
, &h
);
975 return (int)(y
+ (h
/2));
984 wxLayoutConstraints::wxLayoutConstraints()
986 left
.SetEdge(wxLeft
);
988 right
.SetEdge(wxRight
);
989 bottom
.SetEdge(wxBottom
);
990 centreX
.SetEdge(wxCentreX
);
991 centreY
.SetEdge(wxCentreY
);
992 width
.SetEdge(wxWidth
);
993 height
.SetEdge(wxHeight
);
996 wxLayoutConstraints::~wxLayoutConstraints()
1000 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase
*win
, int *nChanges
)
1004 bool done
= width
.GetDone();
1005 bool newDone
= (done
? TRUE
: width
.SatisfyConstraint(this, win
));
1006 if (newDone
!= done
)
1009 done
= height
.GetDone();
1010 newDone
= (done
? TRUE
: height
.SatisfyConstraint(this, win
));
1011 if (newDone
!= done
)
1014 done
= left
.GetDone();
1015 newDone
= (done
? TRUE
: left
.SatisfyConstraint(this, win
));
1016 if (newDone
!= done
)
1019 done
= top
.GetDone();
1020 newDone
= (done
? TRUE
: top
.SatisfyConstraint(this, win
));
1021 if (newDone
!= done
)
1024 done
= right
.GetDone();
1025 newDone
= (done
? TRUE
: right
.SatisfyConstraint(this, win
));
1026 if (newDone
!= done
)
1029 done
= bottom
.GetDone();
1030 newDone
= (done
? TRUE
: bottom
.SatisfyConstraint(this, win
));
1031 if (newDone
!= done
)
1034 done
= centreX
.GetDone();
1035 newDone
= (done
? TRUE
: centreX
.SatisfyConstraint(this, win
));
1036 if (newDone
!= done
)
1039 done
= centreY
.GetDone();
1040 newDone
= (done
? TRUE
: centreY
.SatisfyConstraint(this, win
));
1041 if (newDone
!= done
)
1044 *nChanges
= noChanges
;
1046 return AreSatisfied();
1050 * Main constrained layout algorithm. Look at all the child
1051 * windows, and their constraints (if any).
1052 * The idea is to keep iterating through the constraints
1053 * until all left, right, bottom and top edges, and widths and heights,
1054 * are known (or no change occurs and we've failed to resolve all
1057 * If the user has not specified a dimension or edge, it will be
1058 * be calculated from the other known values. E.g. If we know
1059 * the right hand edge and the left hand edge, we now know the width.
1060 * The snag here is that this means we must specify absolute dimensions
1061 * twice (in constructor and in constraint), if we wish to use the
1062 * constraint notation to just set the position, for example.
1063 * Otherwise, if we only set ONE edge and no dimension, it would never
1064 * find the other edge.
1068 Mark all constraints as not done.
1071 until no change or iterations >= max iterations
1074 Calculate all constraints
1079 Set each calculated position and size
1083 #if WXWIN_COMPATIBILITY
1084 bool wxOldDoLayout(wxWindowBase
*win
)
1086 // Make sure this isn't called recursively from below
1087 static wxList doneSoFar
;
1089 if (doneSoFar
.Member(win
))
1092 doneSoFar
.Append(win
);
1094 wxNode
*node
= win
->GetChildren().First();
1097 wxWindowBase
*child
= (wxWindowBase
*)node
->Data();
1098 wxLayoutConstraints
*constr
= child
->GetConstraints();
1101 constr
->left
.SetDone(FALSE
);
1102 constr
->top
.SetDone(FALSE
);
1103 constr
->right
.SetDone(FALSE
);
1104 constr
->bottom
.SetDone(FALSE
);
1105 constr
->width
.SetDone(FALSE
);
1106 constr
->height
.SetDone(FALSE
);
1107 constr
->centreX
.SetDone(FALSE
);
1108 constr
->centreY
.SetDone(FALSE
);
1110 node
= node
->Next();
1112 int noIterations
= 0;
1113 int maxIterations
= 500;
1116 while ((noChanges
> 0) && (noIterations
< maxIterations
))
1119 wxNode
*node
= win
->GetChildren().First();
1122 wxWindowBase
*child
= (wxWindowBase
*)node
->Data();
1123 wxLayoutConstraints
*constr
= child
->GetConstraints();
1126 int tempNoChanges
= 0;
1127 (void)constr
->SatisfyConstraints(child
, &tempNoChanges
);
1128 noChanges
+= tempNoChanges
;
1130 node
= node
->Next();
1135 // Would be nice to have a test here to see _which_ constraint(s)
1136 // failed, so we can print a specific diagnostic message.
1139 wxDebugMsg(_("wxWindowBase::Layout() failed.\n"));
1142 // Now set the sizes and positions of the children, and
1143 // recursively call Layout().
1144 node
= win
->GetChildren().First();
1147 wxWindowBase
*child
= (wxWindowBase
*)node
->Data();
1148 wxLayoutConstraints
*constr
= child
->GetConstraints();
1149 if (constr
&& constr
->left
.GetDone() && constr
->right
.GetDone() &&
1150 constr
->width
.GetDone() && constr
->height
.GetDone())
1152 int x
= constr
->left
.GetValue();
1153 int y
= constr
->top
.GetValue();
1154 int w
= constr
->width
.GetValue();
1155 int h
= constr
->height
.GetValue();
1157 // If we don't want to resize this window, just move it...
1158 if ((constr
->width
.GetRelationship() != wxAsIs
) ||
1159 (constr
->height
.GetRelationship() != wxAsIs
))
1161 // _Should_ call Layout() recursively.
1162 child
->SetSize(x
, y
, w
, h
);
1171 node
= node
->Next();
1173 doneSoFar
.DeleteObject(win
);
1177 #endif // WXWIN_COMPATIBILITY
1181 sizerBehaviour
= wxSizerNone
;
1190 wxSizer::wxSizer(wxWindowBase
*parent
, wxSizerBehaviour behav
)
1192 Create(parent
, behav
);
1195 bool wxSizer::Create(wxWindowBase
*parent
, wxSizerBehaviour behav
)
1197 sizerBehaviour
= behav
;
1200 m_sizerParent
= parent
;
1206 // A normal window can have just one top-level sizer
1207 // associated with it.
1208 if (!parent
->IsKindOf(CLASSINFO(wxSizer
)))
1210 parent
->SetSizer(this);
1213 ((wxSizer
*)parent
)->AddSizerChild(this);
1215 switch (sizerBehaviour
)
1219 // Defines a set of constraints
1220 // to expand the sizer to fit the parent window
1221 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1223 c
->left
.SameAs(parent
, wxLeft
, 0);
1224 c
->top
.SameAs(parent
, wxTop
, 0);
1225 c
->right
.SameAs(parent
, wxRight
, 0);
1226 c
->bottom
.SameAs(parent
, wxBottom
, 0);
1242 // Remove all children without deleting them,
1243 // or ~wxbWindow will delete proper windows _twice_
1244 wxNode
*node
= GetChildren().First();
1247 wxNode
*next
= node
->Next();
1248 wxWindowBase
*win
= (wxWindowBase
*)node
->Data();
1249 if (!win
->IsKindOf(CLASSINFO(wxSizer
)))
1252 win
->SetSizerParent((wxWindowBase
*) NULL
);
1256 RemoveSizerChild(win
);
1262 if (m_sizerParent
) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
1264 m_sizerParent
->SetSizer((wxSizer
*) NULL
);
1265 m_sizerParent
= (wxWindowBase
*) NULL
;
1270 void wxSizer::SetBorder(int x
, int y
)
1274 /* No: the margin is for inside, not outside (expansion)
1276 if ( GetConstraints() )
1278 GetConstraints()->left.SetMargin(x);
1279 GetConstraints()->right.SetMargin(x);
1280 GetConstraints()->top.SetMargin(y);
1281 GetConstraints()->bottom.SetMargin(y);
1287 void wxSizer::AddSizerChild(wxWindowBase
*child
)
1289 child
->SetSizerParent(this);
1290 GetChildren().Append(child
);
1292 // Add some constraints for the purpose of storing
1293 // the relative position of the window/sizer
1294 // during layout calculations.
1295 if (!child
->GetConstraints())
1297 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1303 child
->GetSize(&w
, &h
);
1304 c
->width
.SetValue(w
);
1305 c
->height
.SetValue(h
);
1307 child
->SetConstraints(c
);
1311 void wxSizer::RemoveSizerChild(wxWindowBase
*child
)
1313 GetChildren().DeleteObject(child
);
1316 void wxSizer::DoSetSize(int x
, int y
, int w
, int h
, int WXUNUSED(flags
))
1318 wxLayoutConstraints
*constr
= GetConstraints();
1323 constr
->left
.SetValue(x
);
1329 constr
->top
.SetValue(y
);
1335 constr
->width
.SetValue(w
);
1341 constr
->height
.SetValue(h
);
1345 void wxSizer::GetSize(int *w
, int *h
) const
1351 void wxSizer::GetPosition(int *x
, int *y
) const
1357 bool wxSizer::LayoutPhase1(int *noChanges
)
1360 switch (sizerBehaviour
)
1366 wxMessageBox(_("wxExpandSizer has no parent!"), _("Sizer error"), wxOK
);
1370 // Set the size to fill the parent client area
1372 m_sizerParent
->GetClientSize(&pw
, &ph
);
1373 SetSize(GetBorderX(), GetBorderY(), pw
- 2*GetBorderX(), ph
- 2*GetBorderY());
1374 wxLayoutConstraints
*constr
= GetConstraints();
1376 // Fill in the constraints
1379 constr
->left
.SetValue(0); constr
->left
.SetDone(TRUE
);
1380 constr
->top
.SetValue(0); constr
->right
.SetDone(TRUE
);
1381 constr
->width
.SetValue(pw
); constr
->width
.SetDone(TRUE
);
1382 constr
->height
.SetValue(ph
); constr
->height
.SetDone(TRUE
);
1390 wxLayoutConstraints
*constr
= GetConstraints();
1394 // Force the constraint to have as-is width and height
1395 // if we're in shrink-to-fit mode, because if left unconstrained,
1396 // SatisfyConstraints will fail. The shrink-to-fit option
1397 // essentially specifies the width and height as 'whatever I calculate'.
1398 constr
->width
.AsIs();
1399 constr
->height
.AsIs();
1403 // Find the bounding box and set own size
1407 wxNode
*node
= GetChildren().First();
1410 int x
, y
, width
, height
;
1411 wxWindowBase
*win
= (wxWindowBase
*)node
->Data();
1412 win
->GetSizeConstraint(&width
, &height
);
1413 win
->GetPositionConstraint(&x
, &y
);
1414 if ((x
+width
) > maxX
)
1416 if ((y
+height
) > maxY
)
1417 maxY
= (y
+ height
);
1419 node
= node
->Next();
1421 SetSize(GetBorderX(), GetBorderY(), maxX
, maxY
);
1423 // If this is the only sizer for the parent, size the parent to this sizer.
1424 if ( m_sizerParent
&& (m_sizerParent
->GetSizer() == this) )
1425 m_sizerParent
->SetClientSize(maxX
+ 2*GetBorderX(), maxY
+ 2*GetBorderY());
1432 wxLayoutConstraints
*constr
= GetConstraints();
1435 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1438 int x
= constr
->left
.GetValue();
1439 int y
= constr
->top
.GetValue();
1440 int w
= constr
->width
.GetValue();
1441 int h
= constr
->height
.GetValue();
1442 SetSize(x
, y
, w
, h
);
1455 bool wxSizer::LayoutPhase2(int *noChanges
)
1459 switch (sizerBehaviour
)
1470 wxLayoutConstraints
*constr
= GetConstraints();
1473 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1476 int x
= constr
->left
.GetValue();
1477 int y
= constr
->top
.GetValue();
1490 // Is this a dumb fix for lack of constraint evaluation?
1491 wxLayoutConstraints
*constr
= GetConstraints();
1494 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1497 int x
= constr
->left
.GetValue();
1498 int y
= constr
->top
.GetValue();
1499 int w
= constr
->width
.GetValue();
1500 int h
= constr
->height
.GetValue();
1501 SetSize(x
, y
, w
, h
);
1516 wxRowColSizer::wxRowColSizer()
1524 wxRowColSizer::wxRowColSizer(wxWindowBase
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1526 Create(parent
, rc
, n
, behav
);
1529 bool wxRowColSizer::Create(wxWindowBase
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1531 wxSizer::Create(parent
, behav
);
1541 wxRowColSizer::~wxRowColSizer()
1545 bool wxRowColSizer::LayoutPhase1(int *noChanges
)
1548 wxLayoutConstraints
*constr
= GetConstraints();
1552 // Force the constraint to have as-is width and height
1553 // if we're in shrink-to-fit mode, because if left unconstrained,
1554 // SatisfyConstraints will fail. The shrink-to-fit option
1555 // essentially specifies the width and height as 'whatever I calculate'.
1556 if (sizerBehaviour
== wxSizerShrink
)
1558 constr
->width
.AsIs();
1559 constr
->height
.AsIs();
1562 // Only evaluate the constraints FIRST if we're NOT
1563 // in shrink-to-fit mode, i.e. we want to size the rowcol
1564 // first, then lay the children out in the space we've calculated.
1565 if (sizerBehaviour
!= wxSizerShrink
)
1567 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1570 int x
= constr
->left
.GetValue();
1571 int y
= constr
->top
.GetValue();
1572 int w
= constr
->width
.GetValue();
1573 int h
= constr
->height
.GetValue();
1574 SetSize(x
, y
, w
, h
);
1579 // Continue to do the rest of the phase when the constraints have been
1580 // satisfied, i.e. we're on the last iteration of phase 1 and
1581 // can now do the actual rowcol laying out.
1585 // If we ARE in shrink-to-fit mode, we must now
1586 // calculate the child sizes BEFORE laying out in rows or columns.
1587 if (sizerBehaviour
== wxSizerShrink
)
1592 // WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
1593 // CHECK CONSTRAINTS IF ANY...
1596 int currentX
= borderX
;
1597 int currentY
= borderY
;
1598 int maxX
= currentX
;
1599 int maxY
= currentY
;
1601 wxNode
*node
= GetChildren().First();
1604 wxWindowBase
*win
= (wxWindowBase
*)node
->Data();
1605 int childWidth
, childHeight
;
1606 if (win
->GetConstraints() &&
1607 win
->GetConstraints()->width
.GetDone() &&
1608 win
->GetConstraints()->height
.GetDone())
1610 childWidth
= win
->GetConstraints()->width
.GetValue();
1611 childHeight
= win
->GetConstraints()->height
.GetValue();
1614 win
->GetSize(&childWidth
, &childHeight
);
1616 win
->MoveConstraint(currentX
, currentY
);
1618 if ((currentX
+ childWidth
) > maxX
)
1619 maxX
= (currentX
+ childWidth
);
1620 if ((currentY
+ childHeight
) > maxY
)
1621 maxY
= (currentY
+ childHeight
);
1625 currentX
+= childWidth
+ xSpacing
;
1628 // Reset to start of row
1629 if (noCols
== rowOrColSize
)
1632 currentY
+= childHeight
+ ySpacing
;
1638 currentY
+= childHeight
+ ySpacing
;
1641 // Reset to start of col
1642 if (noRows
== rowOrColSize
)
1645 currentX
+= childWidth
+ xSpacing
;
1650 node
= node
->Next();
1655 SetSize(-1, -1, maxX
, maxY
);
1660 bool wxRowColSizer::LayoutPhase2(int *noChanges
)
1664 // If shrink-to-fit, it's only at Phase 2 that we know the size of
1665 // the wxRowColSizer, and now we can evaluate the
1666 // constraints and pass result back up to parent.
1667 // This implements a depth-first strategy
1668 if (sizerBehaviour
== wxSizerShrink
)
1670 wxLayoutConstraints
*constr
= GetConstraints();
1673 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1676 int x
= constr
->left
.GetValue();
1677 int y
= constr
->top
.GetValue();
1686 // Lay out the children: breadth-first strategy.
1700 wxSpacingSizer::wxSpacingSizer()
1704 wxSpacingSizer::wxSpacingSizer(wxWindowBase
*parent
)
1709 wxSpacingSizer::wxSpacingSizer(wxWindowBase
*parent
, wxRelationship rel
, wxWindowBase
*other
, int spacing
)
1711 Create(parent
, rel
, other
, spacing
);
1714 bool wxSpacingSizer::Create(wxWindowBase
*parent
)
1716 wxSizer::Create(parent
);
1720 bool wxSpacingSizer::Create(wxWindowBase
*parent
, wxRelationship rel
, wxWindowBase
*other
, int spacing
)
1722 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1724 wxSizer::Create(parent
);
1729 c
->width
.Absolute (spacing
);
1730 c
->top
.SameAs (other
, wxTop
);
1731 c
->bottom
.SameAs (other
, wxBottom
);
1732 c
->right
.LeftOf (other
);
1735 c
->width
.Absolute (spacing
);
1736 c
->top
.SameAs (other
, wxTop
);
1737 c
->bottom
.SameAs (other
, wxBottom
);
1738 c
->left
.RightOf (other
);
1741 c
->height
.Absolute (spacing
);
1742 c
->left
.SameAs (other
, wxLeft
);
1743 c
->right
.SameAs (other
, wxRight
);
1744 c
->top
.Below (other
);
1747 c
->height
.Absolute (spacing
);
1748 c
->left
.SameAs (other
, wxLeft
);
1749 c
->right
.SameAs (other
, wxRight
);
1750 c
->bottom
.Above (other
);
1761 wxSpacingSizer::~wxSpacingSizer()