1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Constraint layout system classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "layout.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
28 #include "wx/window.h"
30 #include "wx/dialog.h"
31 #include "wx/msgdlg.h"
34 #include "wx/layout.h"
36 #if !USE_SHARED_LIBRARY
37 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
38 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
39 IMPLEMENT_DYNAMIC_CLASS(wxSizer
, wxObject
)
40 IMPLEMENT_DYNAMIC_CLASS(wxRowColSizer
, wxSizer
)
41 IMPLEMENT_DYNAMIC_CLASS(wxSpacingSizer
, wxSizer
)
46 - Non shrink-to-fit row-col behaviour.
47 - Give justification styles, so can e.g. centre
48 the rows & cols, distribute the available space...
49 - Shrink-to-fit: should resize outer window (e.g. dialog box)
50 if directly associated with this kind of window.
51 - How to deal with a rowcol that stretches in one direction
52 but shrinks-to-fit in other. E.g. a horizontal toolbar: the width
53 stretches to fit the frame, but the height is constant
54 or wraps around contents. The algorithm currently assumes
55 both dimensions have the same behaviour. Could assume a constant
56 height (absolute value).
57 - rowcol where each row or column is aligned (length of
58 largest element determines spacing)
60 - Analyze aesthetic dialog boxes and implement using sizers.
61 - What reuseable components can we provide? E.g. Ok/Cancel/Help
63 - use wxStaticItems for aesthetic dialogs.
67 // Find margin sizes if a sizer, or zero otherwise
68 int wxSizerMarginX(wxWindow
*win
)
70 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
72 wxSizer
*sizer
= (wxSizer
*)win
;
73 return sizer
->GetBorderX();
79 int wxSizerMarginY(wxWindow
*win
)
81 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
83 wxSizer
*sizer
= (wxSizer
*)win
;
84 return sizer
->GetBorderY();
91 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
93 myEdge
= wxTop
; relationship
= wxUnconstrained
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
94 done
= FALSE
; otherWin
= NULL
;
97 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
101 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindow
*otherW
, wxEdge otherE
, int val
, int marg
)
103 relationship
= rel
; otherWin
= otherW
; otherEdge
= otherE
; value
= val
; margin
= marg
;
106 void wxIndividualLayoutConstraint::LeftOf(wxWindow
*sibling
, int marg
)
107 { Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
); }
109 void wxIndividualLayoutConstraint::RightOf(wxWindow
*sibling
, int marg
)
110 { Set(wxRightOf
, sibling
, wxRight
, 0, marg
); }
112 void wxIndividualLayoutConstraint::Above(wxWindow
*sibling
, int marg
)
113 { Set(wxAbove
, sibling
, wxTop
, 0, marg
); }
115 void wxIndividualLayoutConstraint::Below(wxWindow
*sibling
, int marg
)
116 { Set(wxBelow
, sibling
, wxBottom
, 0, marg
); }
119 // 'Same edge' alignment
121 void wxIndividualLayoutConstraint::SameAs(wxWindow
*otherW
, wxEdge edge
, int marg
)
122 { Set(wxPercentOf
, otherW
, edge
, 0, marg
); percent
= 100; }
124 // The edge is a percentage of the other window's edge
125 void wxIndividualLayoutConstraint::PercentOf(wxWindow
*otherW
, wxEdge wh
, int per
)
126 { otherWin
= otherW
; relationship
= wxPercentOf
; percent
= per
;
131 // Edge has absolute value
133 void wxIndividualLayoutConstraint::Absolute(int val
)
134 { value
= val
; relationship
= wxAbsolute
; }
136 // Reset constraint if it mentions otherWin
137 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindow
*otherW
)
139 if (otherW
== otherWin
)
141 myEdge
= wxTop
; relationship
= wxAsIs
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
149 // Try to satisfy constraint
150 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindow
*win
)
152 if (relationship
== wxAbsolute
)
162 switch (relationship
)
166 // We can know this edge if: otherWin is win's parent,
167 // or otherWin has a satisfied constraint, or
168 // otherWin has no constraint.
169 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
172 value
= edgePos
- margin
;
181 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
184 value
= edgePos
+ margin
;
193 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
196 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
203 case wxUnconstrained
:
205 // We know the left-hand edge position if we know
206 // the right-hand edge and we know the width; OR if we know the centre and the width.
207 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
209 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
213 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
215 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
225 win
->GetPosition(&value
, &y
);
236 switch (relationship
)
240 // We can know this edge if: otherWin is win's parent,
241 // or otherWin has a satisfied constraint, or
242 // otherWin has no constraint.
243 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
246 value
= edgePos
- margin
;
255 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
258 value
= edgePos
+ margin
;
267 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
270 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
277 case wxUnconstrained
:
279 // We know the right-hand edge position if we know
280 // the left-hand edge and we know the width, OR if we know the
281 // centre edge and the width.
282 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
284 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
288 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
290 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
301 win
->GetSize(&w
, &h
);
302 win
->GetPosition(&x
, &y
);
314 switch (relationship
)
318 // We can know this edge if: otherWin is win's parent,
319 // or otherWin has a satisfied constraint, or
320 // otherWin has no constraint.
321 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
324 value
= edgePos
- margin
;
333 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
336 value
= edgePos
+ margin
;
345 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
348 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
355 case wxUnconstrained
:
357 // We know the top edge position if we know
358 // the bottom edge and we know the height; OR if we know the centre
359 // edge and the height.
360 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
362 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
366 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
368 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
378 win
->GetPosition(&x
, &value
);
389 switch (relationship
)
393 // We can know this edge if: otherWin is win's parent,
394 // or otherWin has a satisfied constraint, or
395 // otherWin has no constraint.
396 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
399 value
= edgePos
+ margin
;
408 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
411 value
= edgePos
- margin
;
420 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
423 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
430 case wxUnconstrained
:
432 // We know the bottom edge position if we know
433 // the top edge and we know the height; OR if we know the
434 // centre edge and the height.
435 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
437 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
441 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
443 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
454 win
->GetSize(&w
, &h
);
455 win
->GetPosition(&x
, &y
);
467 switch (relationship
)
471 // We can know this edge if: otherWin is win's parent,
472 // or otherWin has a satisfied constraint, or
473 // otherWin has no constraint.
474 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
477 value
= edgePos
- margin
;
486 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
489 value
= edgePos
+ margin
;
498 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
501 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
508 case wxUnconstrained
:
510 // We know the centre position if we know
511 // the left-hand edge and we know the width, OR
512 // the right-hand edge and the width
513 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
515 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
519 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
521 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
535 switch (relationship
)
539 // We can know this edge if: otherWin is win's parent,
540 // or otherWin has a satisfied constraint, or
541 // otherWin has no constraint.
542 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
545 value
= edgePos
- margin
;
554 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
557 value
= edgePos
+ margin
;
566 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
569 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
576 case wxUnconstrained
:
578 // We know the centre position if we know
579 // the top edge and we know the height, OR
580 // the bottom edge and the height.
581 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
583 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
587 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
589 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
603 switch (relationship
)
607 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
610 value
= (int)(edgePos
*(((float)percent
)*0.01));
622 win
->GetSize(&value
, &h
);
628 case wxUnconstrained
:
630 // We know the width if we know the left edge and the right edge, OR
631 // if we know the left edge and the centre, OR
632 // if we know the right edge and the centre
633 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
635 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
639 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
641 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
645 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
647 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
661 switch (relationship
)
665 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
668 value
= (int)(edgePos
*(((float)percent
)*0.01));
680 win
->GetSize(&w
, &value
);
686 case wxUnconstrained
:
688 // We know the height if we know the top edge and the bottom edge, OR
689 // if we know the top edge and the centre, OR
690 // if we know the bottom edge and the centre
691 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
693 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
697 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
699 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
703 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
705 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
723 // Get the value of this edge or dimension, or if this
724 // is not determinable, -1.
725 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
727 wxWindow
*other
) const
729 // If the edge or dimension belongs to the parent, then we
730 // know the dimension is obtainable immediately.
731 // E.g. a wxExpandSizer may contain a button (but the button's
732 // true parent is a panel, not the sizer)
733 if (other
->GetChildren()->Member(thisWin
))
739 return wxSizerMarginX(other
);
743 return wxSizerMarginY(other
);
748 other
->GetClientSizeConstraint(&w
, &h
);
749 return w
- wxSizerMarginX(other
);
754 other
->GetClientSizeConstraint(&w
, &h
);
755 return h
- wxSizerMarginY(other
);
760 other
->GetClientSizeConstraint(&w
, &h
);
761 return w
- 2*wxSizerMarginX(other
);
766 other
->GetClientSizeConstraint(&w
, &h
);
767 return h
- 2*wxSizerMarginY(other
);
773 other
->GetClientSizeConstraint(&w
, &h
);
774 if (which
== wxCentreX
)
787 wxLayoutConstraints
*constr
= other
->GetConstraints();
788 // If no constraints, it means the window is not dependent
789 // on anything, and therefore we know its value immediately
792 if (constr
->left
.GetDone())
793 return constr
->left
.GetValue();
800 other
->GetPosition(&x
, &y
);
806 wxLayoutConstraints
*constr
= other
->GetConstraints();
807 // If no constraints, it means the window is not dependent
808 // on anything, and therefore we know its value immediately
811 if (constr
->top
.GetDone())
812 return constr
->top
.GetValue();
819 other
->GetPosition(&x
, &y
);
825 wxLayoutConstraints
*constr
= other
->GetConstraints();
826 // If no constraints, it means the window is not dependent
827 // on anything, and therefore we know its value immediately
830 if (constr
->right
.GetDone())
831 return constr
->right
.GetValue();
838 other
->GetPosition(&x
, &y
);
839 other
->GetSize(&w
, &h
);
845 wxLayoutConstraints
*constr
= other
->GetConstraints();
846 // If no constraints, it means the window is not dependent
847 // on anything, and therefore we know its value immediately
850 if (constr
->bottom
.GetDone())
851 return constr
->bottom
.GetValue();
858 other
->GetPosition(&x
, &y
);
859 other
->GetSize(&w
, &h
);
865 wxLayoutConstraints
*constr
= other
->GetConstraints();
866 // If no constraints, it means the window is not dependent
867 // on anything, and therefore we know its value immediately
870 if (constr
->width
.GetDone())
871 return constr
->width
.GetValue();
878 other
->GetSize(&w
, &h
);
884 wxLayoutConstraints
*constr
= other
->GetConstraints();
885 // If no constraints, it means the window is not dependent
886 // on anything, and therefore we know its value immediately
889 if (constr
->height
.GetDone())
890 return constr
->height
.GetValue();
897 other
->GetSize(&w
, &h
);
903 wxLayoutConstraints
*constr
= other
->GetConstraints();
904 // If no constraints, it means the window is not dependent
905 // on anything, and therefore we know its value immediately
908 if (constr
->centreX
.GetDone())
909 return constr
->centreX
.GetValue();
916 other
->GetPosition(&x
, &y
);
917 other
->GetSize(&w
, &h
);
918 return (int)(x
+ (w
/2));
923 wxLayoutConstraints
*constr
= other
->GetConstraints();
924 // If no constraints, it means the window is not dependent
925 // on anything, and therefore we know its value immediately
928 if (constr
->centreY
.GetDone())
929 return constr
->centreY
.GetValue();
936 other
->GetPosition(&x
, &y
);
937 other
->GetSize(&w
, &h
);
938 return (int)(y
+ (h
/2));
947 wxLayoutConstraints::wxLayoutConstraints()
949 left
.SetEdge(wxLeft
);
951 right
.SetEdge(wxRight
);
952 bottom
.SetEdge(wxBottom
);
953 centreX
.SetEdge(wxCentreX
);
954 centreY
.SetEdge(wxCentreY
);
955 width
.SetEdge(wxWidth
);
956 height
.SetEdge(wxHeight
);
959 wxLayoutConstraints::~wxLayoutConstraints()
963 bool wxLayoutConstraints::SatisfyConstraints(wxWindow
*win
, int *nChanges
)
967 bool done
= width
.GetDone();
968 bool newDone
= (done
? TRUE
: width
.SatisfyConstraint(this, win
));
972 done
= height
.GetDone();
973 newDone
= (done
? TRUE
: height
.SatisfyConstraint(this, win
));
977 done
= left
.GetDone();
978 newDone
= (done
? TRUE
: left
.SatisfyConstraint(this, win
));
982 done
= top
.GetDone();
983 newDone
= (done
? TRUE
: top
.SatisfyConstraint(this, win
));
987 done
= right
.GetDone();
988 newDone
= (done
? TRUE
: right
.SatisfyConstraint(this, win
));
992 done
= bottom
.GetDone();
993 newDone
= (done
? TRUE
: bottom
.SatisfyConstraint(this, win
));
997 done
= centreX
.GetDone();
998 newDone
= (done
? TRUE
: centreX
.SatisfyConstraint(this, win
));
1002 done
= centreY
.GetDone();
1003 newDone
= (done
? TRUE
: centreY
.SatisfyConstraint(this, win
));
1004 if (newDone
!= done
)
1007 *nChanges
= noChanges
;
1009 return AreSatisfied();
1013 * Main constrained layout algorithm. Look at all the child
1014 * windows, and their constraints (if any).
1015 * The idea is to keep iterating through the constraints
1016 * until all left, right, bottom and top edges, and widths and heights,
1017 * are known (or no change occurs and we've failed to resolve all
1020 * If the user has not specified a dimension or edge, it will be
1021 * be calculated from the other known values. E.g. If we know
1022 * the right hand edge and the left hand edge, we now know the width.
1023 * The snag here is that this means we must specify absolute dimensions
1024 * twice (in constructor and in constraint), if we wish to use the
1025 * constraint notation to just set the position, for example.
1026 * Otherwise, if we only set ONE edge and no dimension, it would never
1027 * find the other edge.
1031 Mark all constraints as not done.
1034 until no change or iterations >= max iterations
1037 Calculate all constraints
1042 Set each calculated position and size
1046 bool wxOldDoLayout(wxWindow
*win
)
1048 // Make sure this isn't called recursively from below
1049 static wxList doneSoFar
;
1051 if (doneSoFar
.Member(win
))
1054 doneSoFar
.Append(win
);
1056 wxNode
*node
= win
->GetChildren()->First();
1059 wxWindow
*child
= (wxWindow
*)node
->Data();
1060 wxLayoutConstraints
*constr
= child
->GetConstraints();
1063 constr
->left
.SetDone(FALSE
);
1064 constr
->top
.SetDone(FALSE
);
1065 constr
->right
.SetDone(FALSE
);
1066 constr
->bottom
.SetDone(FALSE
);
1067 constr
->width
.SetDone(FALSE
);
1068 constr
->height
.SetDone(FALSE
);
1069 constr
->centreX
.SetDone(FALSE
);
1070 constr
->centreY
.SetDone(FALSE
);
1072 node
= node
->Next();
1074 int noIterations
= 0;
1075 int maxIterations
= 500;
1078 while ((noChanges
> 0) && (noIterations
< maxIterations
))
1081 wxNode
*node
= win
->GetChildren()->First();
1084 wxWindow
*child
= (wxWindow
*)node
->Data();
1085 wxLayoutConstraints
*constr
= child
->GetConstraints();
1088 int tempNoChanges
= 0;
1089 (void)constr
->SatisfyConstraints(child
, &tempNoChanges
);
1090 noChanges
+= tempNoChanges
;
1092 node
= node
->Next();
1097 // Would be nice to have a test here to see _which_ constraint(s)
1098 // failed, so we can print a specific diagnostic message.
1101 wxDebugMsg("wxWindow::Layout() failed.\n");
1104 // Now set the sizes and positions of the children, and
1105 // recursively call Layout().
1106 node
= win
->GetChildren()->First();
1109 wxWindow
*child
= (wxWindow
*)node
->Data();
1110 wxLayoutConstraints
*constr
= child
->GetConstraints();
1111 if (constr
&& constr
->left
.GetDone() && constr
->right
.GetDone() &&
1112 constr
->width
.GetDone() && constr
->height
.GetDone())
1114 int x
= constr
->left
.GetValue();
1115 int y
= constr
->top
.GetValue();
1116 int w
= constr
->width
.GetValue();
1117 int h
= constr
->height
.GetValue();
1119 // If we don't want to resize this window, just move it...
1120 if ((constr
->width
.GetRelationship() != wxAsIs
) ||
1121 (constr
->height
.GetRelationship() != wxAsIs
))
1123 // _Should_ call Layout() recursively.
1124 child
->SetSize(x
, y
, w
, h
);
1133 node
= node
->Next();
1135 doneSoFar
.DeleteObject(win
);
1142 sizerBehaviour
= wxSizerNone
;
1151 wxSizer::wxSizer(wxWindow
*parent
, wxSizerBehaviour behav
)
1153 Create(parent
, behav
);
1156 bool wxSizer::Create(wxWindow
*parent
, wxSizerBehaviour behav
)
1158 sizerBehaviour
= behav
;
1161 m_sizerParent
= parent
;
1167 // A normal window can have just one top-level sizer
1168 // associated with it.
1169 if (!parent
->IsKindOf(CLASSINFO(wxSizer
)))
1171 parent
->SetSizer(this);
1174 ((wxSizer
*)parent
)->AddSizerChild(this);
1176 switch (sizerBehaviour
)
1180 // Defines a set of constraints
1181 // to expand the sizer to fit the parent window
1182 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1184 c
->left
.SameAs(parent
, wxLeft
, 0);
1185 c
->top
.SameAs(parent
, wxTop
, 0);
1186 c
->right
.SameAs(parent
, wxRight
, 0);
1187 c
->bottom
.SameAs(parent
, wxBottom
, 0);
1203 // Remove all children without deleting them,
1204 // or ~wxbWindow will delete proper windows _twice_
1205 wxNode
*node
= GetChildren()->First();
1208 wxNode
*next
= node
->Next();
1209 wxWindow
*win
= (wxWindow
*)node
->Data();
1210 if (!win
->IsKindOf(CLASSINFO(wxSizer
)))
1213 win
->SetSizerParent(NULL
);
1217 RemoveSizerChild(win
);
1223 if (m_sizerParent
) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
1225 m_sizerParent
->SetSizer(NULL
);
1226 m_sizerParent
= NULL
;
1231 void wxSizer::SetBorder(int x
, int y
)
1235 /* No: the margin is for inside, not outside (expansion)
1237 if ( GetConstraints() )
1239 GetConstraints()->left.SetMargin(x);
1240 GetConstraints()->right.SetMargin(x);
1241 GetConstraints()->top.SetMargin(y);
1242 GetConstraints()->bottom.SetMargin(y);
1248 void wxSizer::AddSizerChild(wxWindow
*child
)
1250 child
->SetSizerParent(this);
1251 GetChildren()->Append(child
);
1253 // Add some constraints for the purpose of storing
1254 // the relative position of the window/sizer
1255 // during layout calculations.
1256 if (!child
->GetConstraints())
1258 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1264 child
->GetSize(&w
, &h
);
1265 c
->width
.SetValue(w
);
1266 c
->height
.SetValue(h
);
1268 child
->SetConstraints(c
);
1272 void wxSizer::RemoveSizerChild(wxWindow
*child
)
1274 GetChildren()->DeleteObject(child
);
1277 void wxSizer::SetSize(int x
, int y
, int w
, int h
, int WXUNUSED(flags
))
1279 wxLayoutConstraints
*constr
= GetConstraints();
1284 constr
->left
.SetValue(x
);
1290 constr
->top
.SetValue(y
);
1296 constr
->width
.SetValue(w
);
1302 constr
->height
.SetValue(h
);
1306 void wxSizer::Move(int x
, int y
)
1308 wxLayoutConstraints
*constr
= GetConstraints();
1313 constr
->left
.SetValue(x
);
1319 constr
->top
.SetValue(y
);
1323 void wxSizer::GetSize(int *w
, int *h
) const
1329 void wxSizer::GetPosition(int *x
, int *y
) const
1335 bool wxSizer::LayoutPhase1(int *noChanges
)
1338 switch (sizerBehaviour
)
1344 wxMessageBox("wxExpandSizer has no parent!", "Sizer error", wxOK
);
1348 // Set the size to fill the parent client area
1350 m_sizerParent
->GetClientSize(&pw
, &ph
);
1351 SetSize(GetBorderX(), GetBorderY(), pw
- 2*GetBorderX(), ph
- 2*GetBorderY());
1352 wxLayoutConstraints
*constr
= GetConstraints();
1354 // Fill in the constraints
1357 constr
->left
.SetValue(0); constr
->left
.SetDone(TRUE
);
1358 constr
->top
.SetValue(0); constr
->right
.SetDone(TRUE
);
1359 constr
->width
.SetValue(pw
); constr
->width
.SetDone(TRUE
);
1360 constr
->height
.SetValue(ph
); constr
->height
.SetDone(TRUE
);
1368 wxLayoutConstraints
*constr
= GetConstraints();
1372 // Force the constraint to have as-is width and height
1373 // if we're in shrink-to-fit mode, because if left unconstrained,
1374 // SatisfyConstraints will fail. The shrink-to-fit option
1375 // essentially specifies the width and height as 'whatever I calculate'.
1376 constr
->width
.AsIs();
1377 constr
->height
.AsIs();
1381 // Find the bounding box and set own size
1384 wxNode
*node
= GetChildren()->First();
1387 int x
, y
, width
, height
;
1388 wxWindow
*win
= (wxWindow
*)node
->Data();
1389 win
->GetSizeConstraint(&width
, &height
);
1390 win
->GetPositionConstraint(&x
, &y
);
1391 if ((x
+width
) > maxX
)
1393 if ((y
+height
) > maxY
)
1394 maxY
= (y
+ height
);
1395 node
= node
->Next();
1397 SetSize(GetBorderX(), GetBorderY(), maxX
, maxY
);
1399 // If this is the only sizer for the parent, size the parent to this sizer.
1400 if ( m_sizerParent
&& (m_sizerParent
->GetSizer() == this) )
1401 m_sizerParent
->SetClientSize(maxX
+ 2*GetBorderX(), maxY
+ 2*GetBorderY());
1408 wxLayoutConstraints
*constr
= GetConstraints();
1411 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1414 int x
= constr
->left
.GetValue();
1415 int y
= constr
->top
.GetValue();
1416 int w
= constr
->width
.GetValue();
1417 int h
= constr
->height
.GetValue();
1418 SetSize(x
, y
, w
, h
);
1431 bool wxSizer::LayoutPhase2(int *noChanges
)
1435 switch (sizerBehaviour
)
1446 wxLayoutConstraints
*constr
= GetConstraints();
1449 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1452 int x
= constr
->left
.GetValue();
1453 int y
= constr
->top
.GetValue();
1466 // Is this a dumb fix for lack of constraint evaluation?
1467 wxLayoutConstraints
*constr
= GetConstraints();
1470 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1473 int x
= constr
->left
.GetValue();
1474 int y
= constr
->top
.GetValue();
1475 int w
= constr
->width
.GetValue();
1476 int h
= constr
->height
.GetValue();
1477 SetSize(x
, y
, w
, h
);
1492 wxRowColSizer::wxRowColSizer()
1500 wxRowColSizer::wxRowColSizer(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1502 Create(parent
, rc
, n
, behav
);
1505 bool wxRowColSizer::Create(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1507 wxSizer::Create(parent
, behav
);
1517 wxRowColSizer::~wxRowColSizer()
1521 void wxRowColSizer::SetSize(int x
, int y
, int w
, int h
, int flags
)
1523 wxSizer::SetSize(x
, y
, w
, h
, flags
);
1526 bool wxRowColSizer::LayoutPhase1(int *noChanges
)
1529 wxLayoutConstraints
*constr
= GetConstraints();
1533 // Force the constraint to have as-is width and height
1534 // if we're in shrink-to-fit mode, because if left unconstrained,
1535 // SatisfyConstraints will fail. The shrink-to-fit option
1536 // essentially specifies the width and height as 'whatever I calculate'.
1537 if (sizerBehaviour
== wxSizerShrink
)
1539 constr
->width
.AsIs();
1540 constr
->height
.AsIs();
1543 // Only evaluate the constraints FIRST if we're NOT
1544 // in shrink-to-fit mode, i.e. we want to size the rowcol
1545 // first, then lay the children out in the space we've calculated.
1546 if (sizerBehaviour
!= wxSizerShrink
)
1548 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1551 int x
= constr
->left
.GetValue();
1552 int y
= constr
->top
.GetValue();
1553 int w
= constr
->width
.GetValue();
1554 int h
= constr
->height
.GetValue();
1555 SetSize(x
, y
, w
, h
);
1560 // Continue to do the rest of the phase when the constraints have been
1561 // satisfied, i.e. we're on the last iteration of phase 1 and
1562 // can now do the actual rowcol laying out.
1566 // If we ARE in shrink-to-fit mode, we must now
1567 // calculate the child sizes BEFORE laying out in rows or columns.
1568 if (sizerBehaviour
== wxSizerShrink
)
1573 // WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
1574 // CHECK CONSTRAINTS IF ANY...
1577 int currentX
= borderX
;
1578 int currentY
= borderY
;
1579 int maxX
= currentX
;
1580 int maxY
= currentY
;
1582 wxNode
*node
= GetChildren()->First();
1585 wxWindow
*win
= (wxWindow
*)node
->Data();
1586 int childWidth
, childHeight
;
1587 if (win
->GetConstraints() &&
1588 win
->GetConstraints()->width
.GetDone() &&
1589 win
->GetConstraints()->height
.GetDone())
1591 childWidth
= win
->GetConstraints()->width
.GetValue();
1592 childHeight
= win
->GetConstraints()->height
.GetValue();
1595 win
->GetSize(&childWidth
, &childHeight
);
1597 win
->MoveConstraint(currentX
, currentY
);
1599 if ((currentX
+ childWidth
) > maxX
)
1600 maxX
= (currentX
+ childWidth
);
1601 if ((currentY
+ childHeight
) > maxY
)
1602 maxY
= (currentY
+ childHeight
);
1606 currentX
+= childWidth
+ xSpacing
;
1609 // Reset to start of row
1610 if (noCols
== rowOrColSize
)
1613 currentY
+= childHeight
+ ySpacing
;
1619 currentY
+= childHeight
+ ySpacing
;
1622 // Reset to start of col
1623 if (noRows
== rowOrColSize
)
1626 currentX
+= childWidth
+ xSpacing
;
1631 node
= node
->Next();
1636 SetSize(-1, -1, maxX
, maxY
);
1641 bool wxRowColSizer::LayoutPhase2(int *noChanges
)
1645 // If shrink-to-fit, it's only at Phase 2 that we know the size of
1646 // the wxRowColSizer, and now we can evaluate the
1647 // constraints and pass result back up to parent.
1648 // This implements a depth-first strategy
1649 if (sizerBehaviour
== wxSizerShrink
)
1651 wxLayoutConstraints
*constr
= GetConstraints();
1654 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1657 int x
= constr
->left
.GetValue();
1658 int y
= constr
->top
.GetValue();
1667 // Lay out the children: breadth-first strategy.
1681 wxSpacingSizer::wxSpacingSizer()
1685 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
)
1690 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1692 Create(parent
, rel
, other
, spacing
);
1695 bool wxSpacingSizer::Create(wxWindow
*parent
)
1697 wxSizer::Create(parent
);
1701 bool wxSpacingSizer::Create(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1703 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1705 wxSizer::Create(parent
);
1710 c
->width
.Absolute (spacing
);
1711 c
->top
.SameAs (other
, wxTop
);
1712 c
->bottom
.SameAs (other
, wxBottom
);
1713 c
->right
.LeftOf (other
);
1716 c
->width
.Absolute (spacing
);
1717 c
->top
.SameAs (other
, wxTop
);
1718 c
->bottom
.SameAs (other
, wxBottom
);
1719 c
->left
.RightOf (other
);
1722 c
->height
.Absolute (spacing
);
1723 c
->left
.SameAs (other
, wxLeft
);
1724 c
->right
.SameAs (other
, wxRight
);
1725 c
->top
.Below (other
);
1728 c
->height
.Absolute (spacing
);
1729 c
->left
.SameAs (other
, wxLeft
);
1730 c
->right
.SameAs (other
, wxRight
);
1731 c
->bottom
.Above (other
);
1742 wxSpacingSizer::~wxSpacingSizer()