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(void)
93 myEdge
= wxTop
; relationship
= wxUnconstrained
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
94 done
= FALSE
; otherWin
= NULL
;
97 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint(void)
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
, wxWindow
*thisWin
, wxWindow
*other
)
727 // If the edge or dimension belongs to the parent, then we
728 // know the dimension is obtainable immediately.
729 // E.g. a wxExpandSizer may contain a button (but the button's
730 // true parent is a panel, not the sizer)
731 if (other
->GetChildren()->Member(thisWin
))
737 return wxSizerMarginX(other
);
741 return wxSizerMarginY(other
);
746 other
->GetClientSizeConstraint(&w
, &h
);
747 return w
- wxSizerMarginX(other
);
752 other
->GetClientSizeConstraint(&w
, &h
);
753 return h
- wxSizerMarginY(other
);
758 other
->GetClientSizeConstraint(&w
, &h
);
759 return w
- 2*wxSizerMarginX(other
);
764 other
->GetClientSizeConstraint(&w
, &h
);
765 return h
- 2*wxSizerMarginY(other
);
771 other
->GetClientSizeConstraint(&w
, &h
);
772 if (which
== wxCentreX
)
785 wxLayoutConstraints
*constr
= other
->GetConstraints();
786 // If no constraints, it means the window is not dependent
787 // on anything, and therefore we know its value immediately
790 if (constr
->left
.GetDone())
791 return constr
->left
.GetValue();
798 other
->GetPosition(&x
, &y
);
804 wxLayoutConstraints
*constr
= other
->GetConstraints();
805 // If no constraints, it means the window is not dependent
806 // on anything, and therefore we know its value immediately
809 if (constr
->top
.GetDone())
810 return constr
->top
.GetValue();
817 other
->GetPosition(&x
, &y
);
823 wxLayoutConstraints
*constr
= other
->GetConstraints();
824 // If no constraints, it means the window is not dependent
825 // on anything, and therefore we know its value immediately
828 if (constr
->right
.GetDone())
829 return constr
->right
.GetValue();
836 other
->GetPosition(&x
, &y
);
837 other
->GetSize(&w
, &h
);
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
->bottom
.GetDone())
849 return constr
->bottom
.GetValue();
856 other
->GetPosition(&x
, &y
);
857 other
->GetSize(&w
, &h
);
863 wxLayoutConstraints
*constr
= other
->GetConstraints();
864 // If no constraints, it means the window is not dependent
865 // on anything, and therefore we know its value immediately
868 if (constr
->width
.GetDone())
869 return constr
->width
.GetValue();
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
->height
.GetDone())
888 return constr
->height
.GetValue();
895 other
->GetSize(&w
, &h
);
901 wxLayoutConstraints
*constr
= other
->GetConstraints();
902 // If no constraints, it means the window is not dependent
903 // on anything, and therefore we know its value immediately
906 if (constr
->centreX
.GetDone())
907 return constr
->centreX
.GetValue();
914 other
->GetPosition(&x
, &y
);
915 other
->GetSize(&w
, &h
);
916 return (int)(x
+ (w
/2));
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
->centreY
.GetDone())
927 return constr
->centreY
.GetValue();
934 other
->GetPosition(&x
, &y
);
935 other
->GetSize(&w
, &h
);
936 return (int)(y
+ (h
/2));
945 wxLayoutConstraints::wxLayoutConstraints(void)
947 left
.SetEdge(wxLeft
);
949 right
.SetEdge(wxRight
);
950 bottom
.SetEdge(wxBottom
);
951 centreX
.SetEdge(wxCentreX
);
952 centreY
.SetEdge(wxCentreY
);
953 width
.SetEdge(wxWidth
);
954 height
.SetEdge(wxHeight
);
957 wxLayoutConstraints::~wxLayoutConstraints(void)
961 bool wxLayoutConstraints::SatisfyConstraints(wxWindow
*win
, int *nChanges
)
965 bool done
= width
.GetDone();
966 bool newDone
= (done
? TRUE
: width
.SatisfyConstraint(this, win
));
970 done
= height
.GetDone();
971 newDone
= (done
? TRUE
: height
.SatisfyConstraint(this, win
));
975 done
= left
.GetDone();
976 newDone
= (done
? TRUE
: left
.SatisfyConstraint(this, win
));
980 done
= top
.GetDone();
981 newDone
= (done
? TRUE
: top
.SatisfyConstraint(this, win
));
985 done
= right
.GetDone();
986 newDone
= (done
? TRUE
: right
.SatisfyConstraint(this, win
));
990 done
= bottom
.GetDone();
991 newDone
= (done
? TRUE
: bottom
.SatisfyConstraint(this, win
));
995 done
= centreX
.GetDone();
996 newDone
= (done
? TRUE
: centreX
.SatisfyConstraint(this, win
));
1000 done
= centreY
.GetDone();
1001 newDone
= (done
? TRUE
: centreY
.SatisfyConstraint(this, win
));
1002 if (newDone
!= done
)
1005 *nChanges
= noChanges
;
1007 return (left
.GetDone() && top
.GetDone() && right
.GetDone() && bottom
.GetDone() &&
1008 centreX
.GetDone() && centreY
.GetDone());
1012 * Main constrained layout algorithm. Look at all the child
1013 * windows, and their constraints (if any).
1014 * The idea is to keep iterating through the constraints
1015 * until all left, right, bottom and top edges, and widths and heights,
1016 * are known (or no change occurs and we've failed to resolve all
1019 * If the user has not specified a dimension or edge, it will be
1020 * be calculated from the other known values. E.g. If we know
1021 * the right hand edge and the left hand edge, we now know the width.
1022 * The snag here is that this means we must specify absolute dimensions
1023 * twice (in constructor and in constraint), if we wish to use the
1024 * constraint notation to just set the position, for example.
1025 * Otherwise, if we only set ONE edge and no dimension, it would never
1026 * find the other edge.
1030 Mark all constraints as not done.
1033 until no change or iterations >= max iterations
1036 Calculate all constraints
1041 Set each calculated position and size
1045 bool wxOldDoLayout(wxWindow
*win
)
1047 // Make sure this isn't called recursively from below
1048 static wxList doneSoFar
;
1050 if (doneSoFar
.Member(win
))
1053 doneSoFar
.Append(win
);
1055 wxNode
*node
= win
->GetChildren()->First();
1058 wxWindow
*child
= (wxWindow
*)node
->Data();
1059 wxLayoutConstraints
*constr
= child
->GetConstraints();
1062 constr
->left
.SetDone(FALSE
);
1063 constr
->top
.SetDone(FALSE
);
1064 constr
->right
.SetDone(FALSE
);
1065 constr
->bottom
.SetDone(FALSE
);
1066 constr
->width
.SetDone(FALSE
);
1067 constr
->height
.SetDone(FALSE
);
1068 constr
->centreX
.SetDone(FALSE
);
1069 constr
->centreY
.SetDone(FALSE
);
1071 node
= node
->Next();
1073 int noIterations
= 0;
1074 int maxIterations
= 500;
1077 while ((noChanges
> 0) && (noIterations
< maxIterations
))
1080 wxNode
*node
= win
->GetChildren()->First();
1083 wxWindow
*child
= (wxWindow
*)node
->Data();
1084 wxLayoutConstraints
*constr
= child
->GetConstraints();
1087 int tempNoChanges
= 0;
1088 (void) constr
->SatisfyConstraints(child
, &tempNoChanges
);
1089 noChanges
+= tempNoChanges
;
1091 node
= node
->Next();
1096 // Would be nice to have a test here to see _which_ constraint(s)
1097 // failed, so we can print a specific diagnostic message.
1100 wxDebugMsg("wxWindow::Layout() failed.\n");
1103 // Now set the sizes and positions of the children, and
1104 // recursively call Layout().
1105 node
= win
->GetChildren()->First();
1108 wxWindow
*child
= (wxWindow
*)node
->Data();
1109 wxLayoutConstraints
*constr
= child
->GetConstraints();
1110 if (constr
&& constr
->left
.GetDone() && constr
->right
.GetDone() &&
1111 constr
->width
.GetDone() && constr
->height
.GetDone())
1113 int x
= constr
->left
.GetValue();
1114 int y
= constr
->top
.GetValue();
1115 int w
= constr
->width
.GetValue();
1116 int h
= constr
->height
.GetValue();
1118 // If we don't want to resize this window, just move it...
1119 if ((constr
->width
.GetRelationship() != wxAsIs
) ||
1120 (constr
->height
.GetRelationship() != wxAsIs
))
1122 // _Should_ call Layout() recursively.
1123 child
->SetSize(x
, y
, w
, h
);
1132 node
= node
->Next();
1134 doneSoFar
.DeleteObject(win
);
1139 wxSizer::wxSizer(void)
1141 sizerBehaviour
= wxSizerNone
;
1150 wxSizer::wxSizer(wxWindow
*parent
, wxSizerBehaviour behav
)
1152 Create(parent
, behav
);
1155 bool wxSizer::Create(wxWindow
*parent
, wxSizerBehaviour behav
)
1157 sizerBehaviour
= behav
;
1160 m_sizerParent
= parent
;
1166 // A normal window can have just one top-level sizer
1167 // associated with it.
1168 if (!parent
->IsKindOf(CLASSINFO(wxSizer
)))
1170 parent
->SetSizer(this);
1173 ((wxSizer
*)parent
)->AddSizerChild(this);
1175 switch (sizerBehaviour
)
1179 // Defines a set of constraints
1180 // to expand the sizer to fit the parent window
1181 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1183 c
->left
.SameAs(parent
, wxLeft
, 0);
1184 c
->top
.SameAs(parent
, wxTop
, 0);
1185 c
->right
.SameAs(parent
, wxRight
, 0);
1186 c
->bottom
.SameAs(parent
, wxBottom
, 0);
1200 wxSizer::~wxSizer(void)
1202 // Remove all children without deleting them,
1203 // or ~wxbWindow will delete proper windows _twice_
1204 wxNode
*node
= GetChildren()->First();
1207 wxNode
*next
= node
->Next();
1208 wxWindow
*win
= (wxWindow
*)node
->Data();
1209 if (!win
->IsKindOf(CLASSINFO(wxSizer
)))
1212 win
->SetSizerParent(NULL
);
1216 RemoveSizerChild(win
);
1222 if (m_sizerParent
) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
1224 m_sizerParent
->SetSizer(NULL
);
1225 m_sizerParent
= NULL
;
1230 void wxSizer::SetBorder(int x
, int y
)
1234 /* No: the margin is for inside, not outside (expansion)
1236 if ( GetConstraints() )
1238 GetConstraints()->left.SetMargin(x);
1239 GetConstraints()->right.SetMargin(x);
1240 GetConstraints()->top.SetMargin(y);
1241 GetConstraints()->bottom.SetMargin(y);
1247 void wxSizer::AddSizerChild(wxWindow
*child
)
1249 child
->SetSizerParent(this);
1250 GetChildren()->Append(child
);
1252 // Add some constraints for the purpose of storing
1253 // the relative position of the window/sizer
1254 // during layout calculations.
1255 if (!child
->GetConstraints())
1257 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1263 child
->GetSize(&w
, &h
);
1264 c
->width
.SetValue(w
);
1265 c
->height
.SetValue(h
);
1267 child
->SetConstraints(c
);
1271 void wxSizer::RemoveSizerChild(wxWindow
*child
)
1273 GetChildren()->DeleteObject(child
);
1276 void wxSizer::SetSize(int x
, int y
, int w
, int h
, int WXUNUSED(flags
))
1278 wxLayoutConstraints
*constr
= GetConstraints();
1283 constr
->left
.SetValue(x
);
1289 constr
->top
.SetValue(y
);
1295 constr
->width
.SetValue(w
);
1301 constr
->height
.SetValue(h
);
1305 void wxSizer::Move(int x
, int y
)
1307 wxLayoutConstraints
*constr
= GetConstraints();
1312 constr
->left
.SetValue(x
);
1318 constr
->top
.SetValue(y
);
1322 void wxSizer::GetSize(int *w
, int *h
) const
1328 void wxSizer::GetPosition(int *x
, int *y
) const
1334 bool wxSizer::LayoutPhase1(int *noChanges
)
1337 switch (sizerBehaviour
)
1343 wxMessageBox("wxExpandSizer has no parent!", "Sizer error", wxOK
);
1347 // Set the size to fill the parent client area
1349 m_sizerParent
->GetClientSize(&pw
, &ph
);
1350 SetSize(GetBorderX(), GetBorderY(), pw
- 2*GetBorderX(), ph
- 2*GetBorderY());
1351 wxLayoutConstraints
*constr
= GetConstraints();
1353 // Fill in the constraints
1356 constr
->left
.SetValue(0); constr
->left
.SetDone(TRUE
);
1357 constr
->top
.SetValue(0); constr
->right
.SetDone(TRUE
);
1358 constr
->width
.SetValue(pw
); constr
->width
.SetDone(TRUE
);
1359 constr
->height
.SetValue(ph
); constr
->height
.SetDone(TRUE
);
1367 wxLayoutConstraints
*constr
= GetConstraints();
1371 // Force the constraint to have as-is width and height
1372 // if we're in shrink-to-fit mode, because if left unconstrained,
1373 // SatisfyConstraints will fail. The shrink-to-fit option
1374 // essentially specifies the width and height as 'whatever I calculate'.
1375 constr
->width
.AsIs();
1376 constr
->height
.AsIs();
1380 // Find the bounding box and set own size
1383 wxNode
*node
= GetChildren()->First();
1386 int x
, y
, width
, height
;
1387 wxWindow
*win
= (wxWindow
*)node
->Data();
1388 win
->GetSizeConstraint(&width
, &height
);
1389 win
->GetPositionConstraint(&x
, &y
);
1390 if ((x
+width
) > maxX
)
1392 if ((y
+height
) > maxY
)
1393 maxY
= (y
+ height
);
1394 node
= node
->Next();
1396 SetSize(GetBorderX(), GetBorderY(), maxX
, maxY
);
1398 // If this is the only sizer for the parent, size the parent to this sizer.
1399 if ( m_sizerParent
&& (m_sizerParent
->GetSizer() == this) )
1400 m_sizerParent
->SetClientSize(maxX
+ 2*GetBorderX(), maxY
+ 2*GetBorderY());
1407 wxLayoutConstraints
*constr
= GetConstraints();
1410 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1413 int x
= constr
->left
.GetValue();
1414 int y
= constr
->top
.GetValue();
1415 int w
= constr
->width
.GetValue();
1416 int h
= constr
->height
.GetValue();
1417 SetSize(x
, y
, w
, h
);
1430 bool wxSizer::LayoutPhase2(int *noChanges
)
1434 switch (sizerBehaviour
)
1445 wxLayoutConstraints
*constr
= GetConstraints();
1448 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1451 int x
= constr
->left
.GetValue();
1452 int y
= constr
->top
.GetValue();
1465 // Is this a dumb fix for lack of constraint evaluation?
1466 wxLayoutConstraints
*constr
= GetConstraints();
1469 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1472 int x
= constr
->left
.GetValue();
1473 int y
= constr
->top
.GetValue();
1474 int w
= constr
->width
.GetValue();
1475 int h
= constr
->height
.GetValue();
1476 SetSize(x
, y
, w
, h
);
1491 wxRowColSizer::wxRowColSizer(void)
1499 wxRowColSizer::wxRowColSizer(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1501 Create(parent
, rc
, n
, behav
);
1504 bool wxRowColSizer::Create(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1506 wxSizer::Create(parent
, behav
);
1516 wxRowColSizer::~wxRowColSizer(void)
1520 void wxRowColSizer::SetSize(int x
, int y
, int w
, int h
, int flags
)
1522 wxSizer::SetSize(x
, y
, w
, h
, flags
);
1525 bool wxRowColSizer::LayoutPhase1(int *noChanges
)
1528 wxLayoutConstraints
*constr
= GetConstraints();
1532 // Force the constraint to have as-is width and height
1533 // if we're in shrink-to-fit mode, because if left unconstrained,
1534 // SatisfyConstraints will fail. The shrink-to-fit option
1535 // essentially specifies the width and height as 'whatever I calculate'.
1536 if (sizerBehaviour
== wxSizerShrink
)
1538 constr
->width
.AsIs();
1539 constr
->height
.AsIs();
1542 // Only evaluate the constraints FIRST if we're NOT
1543 // in shrink-to-fit mode, i.e. we want to size the rowcol
1544 // first, then lay the children out in the space we've calculated.
1545 if (sizerBehaviour
!= wxSizerShrink
)
1547 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1550 int x
= constr
->left
.GetValue();
1551 int y
= constr
->top
.GetValue();
1552 int w
= constr
->width
.GetValue();
1553 int h
= constr
->height
.GetValue();
1554 SetSize(x
, y
, w
, h
);
1559 // Continue to do the rest of the phase when the constraints have been
1560 // satisfied, i.e. we're on the last iteration of phase 1 and
1561 // can now do the actual rowcol laying out.
1565 // If we ARE in shrink-to-fit mode, we must now
1566 // calculate the child sizes BEFORE laying out in rows or columns.
1567 if (sizerBehaviour
== wxSizerShrink
)
1572 // WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
1573 // CHECK CONSTRAINTS IF ANY...
1576 int currentX
= borderX
;
1577 int currentY
= borderY
;
1578 int maxX
= currentX
;
1579 int maxY
= currentY
;
1581 wxNode
*node
= GetChildren()->First();
1584 wxWindow
*win
= (wxWindow
*)node
->Data();
1585 int childWidth
, childHeight
;
1586 if (win
->GetConstraints() &&
1587 win
->GetConstraints()->width
.GetDone() &&
1588 win
->GetConstraints()->height
.GetDone())
1590 childWidth
= win
->GetConstraints()->width
.GetValue();
1591 childHeight
= win
->GetConstraints()->height
.GetValue();
1594 win
->GetSize(&childWidth
, &childHeight
);
1596 win
->MoveConstraint(currentX
, currentY
);
1598 if ((currentX
+ childWidth
) > maxX
)
1599 maxX
= (currentX
+ childWidth
);
1600 if ((currentY
+ childHeight
) > maxY
)
1601 maxY
= (currentY
+ childHeight
);
1605 currentX
+= childWidth
+ xSpacing
;
1608 // Reset to start of row
1609 if (noCols
== rowOrColSize
)
1612 currentY
+= childHeight
+ ySpacing
;
1618 currentY
+= childHeight
+ ySpacing
;
1621 // Reset to start of col
1622 if (noRows
== rowOrColSize
)
1625 currentX
+= childWidth
+ xSpacing
;
1630 node
= node
->Next();
1635 SetSize(-1, -1, maxX
, maxY
);
1640 bool wxRowColSizer::LayoutPhase2(int *noChanges
)
1644 // If shrink-to-fit, it's only at Phase 2 that we know the size of
1645 // the wxRowColSizer, and now we can evaluate the
1646 // constraints and pass result back up to parent.
1647 // This implements a depth-first strategy
1648 if (sizerBehaviour
== wxSizerShrink
)
1650 wxLayoutConstraints
*constr
= GetConstraints();
1653 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1656 int x
= constr
->left
.GetValue();
1657 int y
= constr
->top
.GetValue();
1666 // Lay out the children: breadth-first strategy.
1680 wxSpacingSizer::wxSpacingSizer(void)
1684 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
)
1689 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1691 Create(parent
, rel
, other
, spacing
);
1694 bool wxSpacingSizer::Create(wxWindow
*parent
)
1696 wxSizer::Create(parent
);
1700 bool wxSpacingSizer::Create(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1702 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1704 wxSizer::Create(parent
);
1709 c
->width
.Absolute (spacing
);
1710 c
->top
.SameAs (other
, wxTop
);
1711 c
->bottom
.SameAs (other
, wxBottom
);
1712 c
->right
.LeftOf (other
);
1715 c
->width
.Absolute (spacing
);
1716 c
->top
.SameAs (other
, wxTop
);
1717 c
->bottom
.SameAs (other
, wxBottom
);
1718 c
->left
.RightOf (other
);
1721 c
->height
.Absolute (spacing
);
1722 c
->left
.SameAs (other
, wxLeft
);
1723 c
->right
.SameAs (other
, wxRight
);
1724 c
->top
.Below (other
);
1727 c
->height
.Absolute (spacing
);
1728 c
->left
.SameAs (other
, wxLeft
);
1729 c
->right
.SameAs (other
, wxRight
);
1730 c
->bottom
.Above (other
);
1741 wxSpacingSizer::~wxSpacingSizer(void)