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"
26 #include "wx/window.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
33 #include "wx/layout.h"
35 #if !USE_SHARED_LIBRARY
36 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
37 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
38 IMPLEMENT_DYNAMIC_CLASS(wxSizer
, wxObject
)
39 IMPLEMENT_DYNAMIC_CLASS(wxRowColSizer
, wxSizer
)
40 IMPLEMENT_DYNAMIC_CLASS(wxSpacingSizer
, wxSizer
)
45 - Non shrink-to-fit row-col behaviour.
46 - Give justification styles, so can e.g. centre
47 the rows & cols, distribute the available space...
48 - Shrink-to-fit: should resize outer window (e.g. dialog box)
49 if directly associated with this kind of window.
50 - How to deal with a rowcol that stretches in one direction
51 but shrinks-to-fit in other. E.g. a horizontal toolbar: the width
52 stretches to fit the frame, but the height is constant
53 or wraps around contents. The algorithm currently assumes
54 both dimensions have the same behaviour. Could assume a constant
55 height (absolute value).
56 - rowcol where each row or column is aligned (length of
57 largest element determines spacing)
59 - Analyze aesthetic dialog boxes and implement using sizers.
60 - What reuseable components can we provide? E.g. Ok/Cancel/Help
62 - use wxStaticItems for aesthetic dialogs.
66 // Find margin sizes if a sizer, or zero otherwise
67 int wxSizerMarginX(wxWindow
*win
)
69 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
71 wxSizer
*sizer
= (wxSizer
*)win
;
72 return sizer
->GetBorderX();
78 int wxSizerMarginY(wxWindow
*win
)
80 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
82 wxSizer
*sizer
= (wxSizer
*)win
;
83 return sizer
->GetBorderY();
90 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
92 myEdge
= wxTop
; relationship
= wxUnconstrained
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
93 done
= FALSE
; otherWin
= (wxWindow
*) NULL
;
96 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
100 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindow
*otherW
, wxEdge otherE
, int val
, int marg
)
102 relationship
= rel
; otherWin
= otherW
; otherEdge
= otherE
; value
= val
; margin
= marg
;
105 void wxIndividualLayoutConstraint::LeftOf(wxWindow
*sibling
, int marg
)
106 { Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
); }
108 void wxIndividualLayoutConstraint::RightOf(wxWindow
*sibling
, int marg
)
109 { Set(wxRightOf
, sibling
, wxRight
, 0, marg
); }
111 void wxIndividualLayoutConstraint::Above(wxWindow
*sibling
, int marg
)
112 { Set(wxAbove
, sibling
, wxTop
, 0, marg
); }
114 void wxIndividualLayoutConstraint::Below(wxWindow
*sibling
, int marg
)
115 { Set(wxBelow
, sibling
, wxBottom
, 0, marg
); }
118 // 'Same edge' alignment
120 void wxIndividualLayoutConstraint::SameAs(wxWindow
*otherW
, wxEdge edge
, int marg
)
121 { Set(wxPercentOf
, otherW
, edge
, 0, marg
); percent
= 100; }
123 // The edge is a percentage of the other window's edge
124 void wxIndividualLayoutConstraint::PercentOf(wxWindow
*otherW
, wxEdge wh
, int per
)
125 { otherWin
= otherW
; relationship
= wxPercentOf
; percent
= per
;
130 // Edge has absolute value
132 void wxIndividualLayoutConstraint::Absolute(int val
)
133 { value
= val
; relationship
= wxAbsolute
; }
135 // Reset constraint if it mentions otherWin
136 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindow
*otherW
)
138 if (otherW
== otherWin
)
140 myEdge
= wxTop
; relationship
= wxAsIs
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
141 otherWin
= (wxWindow
*) NULL
;
148 // Try to satisfy constraint
149 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindow
*win
)
151 if (relationship
== wxAbsolute
)
161 switch (relationship
)
165 // We can know this edge if: otherWin is win's parent,
166 // or otherWin has a satisfied constraint, or
167 // otherWin has no constraint.
168 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
171 value
= edgePos
- margin
;
180 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
183 value
= edgePos
+ margin
;
192 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
195 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
202 case wxUnconstrained
:
204 // We know the left-hand edge position if we know
205 // the right-hand edge and we know the width; OR if we know the centre and the width.
206 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
208 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
212 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
214 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
224 win
->GetPosition(&value
, &y
);
235 switch (relationship
)
239 // We can know this edge if: otherWin is win's parent,
240 // or otherWin has a satisfied constraint, or
241 // otherWin has no constraint.
242 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
245 value
= edgePos
- margin
;
254 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
257 value
= edgePos
+ margin
;
266 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
269 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
276 case wxUnconstrained
:
278 // We know the right-hand edge position if we know
279 // the left-hand edge and we know the width, OR if we know the
280 // centre edge and the width.
281 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
283 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
287 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
289 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
300 win
->GetSize(&w
, &h
);
301 win
->GetPosition(&x
, &y
);
313 switch (relationship
)
317 // We can know this edge if: otherWin is win's parent,
318 // or otherWin has a satisfied constraint, or
319 // otherWin has no constraint.
320 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
323 value
= edgePos
- margin
;
332 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
335 value
= edgePos
+ margin
;
344 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
347 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
354 case wxUnconstrained
:
356 // We know the top edge position if we know
357 // the bottom edge and we know the height; OR if we know the centre
358 // edge and the height.
359 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
361 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
365 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
367 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
377 win
->GetPosition(&x
, &value
);
388 switch (relationship
)
392 // We can know this edge if: otherWin is win's parent,
393 // or otherWin has a satisfied constraint, or
394 // otherWin has no constraint.
395 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
398 value
= edgePos
+ margin
;
407 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
410 value
= edgePos
- margin
;
419 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
422 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
429 case wxUnconstrained
:
431 // We know the bottom edge position if we know
432 // the top edge and we know the height; OR if we know the
433 // centre edge and the height.
434 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
436 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
440 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
442 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
453 win
->GetSize(&w
, &h
);
454 win
->GetPosition(&x
, &y
);
466 switch (relationship
)
470 // We can know this edge if: otherWin is win's parent,
471 // or otherWin has a satisfied constraint, or
472 // otherWin has no constraint.
473 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
476 value
= edgePos
- margin
;
485 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
488 value
= edgePos
+ margin
;
497 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
500 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
507 case wxUnconstrained
:
509 // We know the centre position if we know
510 // the left-hand edge and we know the width, OR
511 // the right-hand edge and the width
512 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
514 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
518 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
520 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
534 switch (relationship
)
538 // We can know this edge if: otherWin is win's parent,
539 // or otherWin has a satisfied constraint, or
540 // otherWin has no constraint.
541 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
544 value
= edgePos
- margin
;
553 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
556 value
= edgePos
+ margin
;
565 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
568 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
575 case wxUnconstrained
:
577 // We know the centre position if we know
578 // the top edge and we know the height, OR
579 // the bottom edge and the height.
580 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
582 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
586 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
588 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
602 switch (relationship
)
606 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
609 value
= (int)(edgePos
*(((float)percent
)*0.01));
621 win
->GetSize(&value
, &h
);
627 case wxUnconstrained
:
629 // We know the width if we know the left edge and the right edge, OR
630 // if we know the left edge and the centre, OR
631 // if we know the right edge and the centre
632 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
634 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
638 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
640 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
644 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
646 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
660 switch (relationship
)
664 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
667 value
= (int)(edgePos
*(((float)percent
)*0.01));
679 win
->GetSize(&w
, &value
);
685 case wxUnconstrained
:
687 // We know the height if we know the top edge and the bottom edge, OR
688 // if we know the top edge and the centre, OR
689 // if we know the bottom edge and the centre
690 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
692 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
696 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
698 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
702 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
704 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
722 // Get the value of this edge or dimension, or if this
723 // is not determinable, -1.
724 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
726 wxWindow
*other
) const
728 // If the edge or dimension belongs to the parent, then we
729 // know the dimension is obtainable immediately.
730 // E.g. a wxExpandSizer may contain a button (but the button's
731 // true parent is a panel, not the sizer)
732 if (other
->GetChildren().Member(thisWin
))
738 return wxSizerMarginX(other
);
742 return wxSizerMarginY(other
);
747 other
->GetClientSizeConstraint(&w
, &h
);
748 return w
- wxSizerMarginX(other
);
753 other
->GetClientSizeConstraint(&w
, &h
);
754 return h
- wxSizerMarginY(other
);
759 other
->GetClientSizeConstraint(&w
, &h
);
760 return w
- 2*wxSizerMarginX(other
);
765 other
->GetClientSizeConstraint(&w
, &h
);
766 return h
- 2*wxSizerMarginY(other
);
772 other
->GetClientSizeConstraint(&w
, &h
);
773 if (which
== wxCentreX
)
786 wxLayoutConstraints
*constr
= other
->GetConstraints();
787 // If no constraints, it means the window is not dependent
788 // on anything, and therefore we know its value immediately
791 if (constr
->left
.GetDone())
792 return constr
->left
.GetValue();
799 other
->GetPosition(&x
, &y
);
805 wxLayoutConstraints
*constr
= other
->GetConstraints();
806 // If no constraints, it means the window is not dependent
807 // on anything, and therefore we know its value immediately
810 if (constr
->top
.GetDone())
811 return constr
->top
.GetValue();
818 other
->GetPosition(&x
, &y
);
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
->right
.GetDone())
830 return constr
->right
.GetValue();
837 other
->GetPosition(&x
, &y
);
838 other
->GetSize(&w
, &h
);
844 wxLayoutConstraints
*constr
= other
->GetConstraints();
845 // If no constraints, it means the window is not dependent
846 // on anything, and therefore we know its value immediately
849 if (constr
->bottom
.GetDone())
850 return constr
->bottom
.GetValue();
857 other
->GetPosition(&x
, &y
);
858 other
->GetSize(&w
, &h
);
864 wxLayoutConstraints
*constr
= other
->GetConstraints();
865 // If no constraints, it means the window is not dependent
866 // on anything, and therefore we know its value immediately
869 if (constr
->width
.GetDone())
870 return constr
->width
.GetValue();
877 other
->GetSize(&w
, &h
);
883 wxLayoutConstraints
*constr
= other
->GetConstraints();
884 // If no constraints, it means the window is not dependent
885 // on anything, and therefore we know its value immediately
888 if (constr
->height
.GetDone())
889 return constr
->height
.GetValue();
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
->centreX
.GetDone())
908 return constr
->centreX
.GetValue();
915 other
->GetPosition(&x
, &y
);
916 other
->GetSize(&w
, &h
);
917 return (int)(x
+ (w
/2));
922 wxLayoutConstraints
*constr
= other
->GetConstraints();
923 // If no constraints, it means the window is not dependent
924 // on anything, and therefore we know its value immediately
927 if (constr
->centreY
.GetDone())
928 return constr
->centreY
.GetValue();
935 other
->GetPosition(&x
, &y
);
936 other
->GetSize(&w
, &h
);
937 return (int)(y
+ (h
/2));
946 wxLayoutConstraints::wxLayoutConstraints()
948 left
.SetEdge(wxLeft
);
950 right
.SetEdge(wxRight
);
951 bottom
.SetEdge(wxBottom
);
952 centreX
.SetEdge(wxCentreX
);
953 centreY
.SetEdge(wxCentreY
);
954 width
.SetEdge(wxWidth
);
955 height
.SetEdge(wxHeight
);
958 wxLayoutConstraints::~wxLayoutConstraints()
962 bool wxLayoutConstraints::SatisfyConstraints(wxWindow
*win
, int *nChanges
)
966 bool done
= width
.GetDone();
967 bool newDone
= (done
? TRUE
: width
.SatisfyConstraint(this, win
));
971 done
= height
.GetDone();
972 newDone
= (done
? TRUE
: height
.SatisfyConstraint(this, win
));
976 done
= left
.GetDone();
977 newDone
= (done
? TRUE
: left
.SatisfyConstraint(this, win
));
981 done
= top
.GetDone();
982 newDone
= (done
? TRUE
: top
.SatisfyConstraint(this, win
));
986 done
= right
.GetDone();
987 newDone
= (done
? TRUE
: right
.SatisfyConstraint(this, win
));
991 done
= bottom
.GetDone();
992 newDone
= (done
? TRUE
: bottom
.SatisfyConstraint(this, win
));
996 done
= centreX
.GetDone();
997 newDone
= (done
? TRUE
: centreX
.SatisfyConstraint(this, win
));
1001 done
= centreY
.GetDone();
1002 newDone
= (done
? TRUE
: centreY
.SatisfyConstraint(this, win
));
1003 if (newDone
!= done
)
1006 *nChanges
= noChanges
;
1008 return AreSatisfied();
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
);
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);
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((wxWindow
*) NULL
);
1216 RemoveSizerChild(win
);
1222 if (m_sizerParent
) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
1224 m_sizerParent
->SetSizer((wxSizer
*) NULL
);
1225 m_sizerParent
= (wxWindow
*) 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::DoSetSize(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::GetSize(int *w
, int *h
) const
1311 void wxSizer::GetPosition(int *x
, int *y
) const
1317 bool wxSizer::LayoutPhase1(int *noChanges
)
1320 switch (sizerBehaviour
)
1326 wxMessageBox(_("wxExpandSizer has no parent!"), _("Sizer error"), wxOK
);
1330 // Set the size to fill the parent client area
1332 m_sizerParent
->GetClientSize(&pw
, &ph
);
1333 SetSize(GetBorderX(), GetBorderY(), pw
- 2*GetBorderX(), ph
- 2*GetBorderY());
1334 wxLayoutConstraints
*constr
= GetConstraints();
1336 // Fill in the constraints
1339 constr
->left
.SetValue(0); constr
->left
.SetDone(TRUE
);
1340 constr
->top
.SetValue(0); constr
->right
.SetDone(TRUE
);
1341 constr
->width
.SetValue(pw
); constr
->width
.SetDone(TRUE
);
1342 constr
->height
.SetValue(ph
); constr
->height
.SetDone(TRUE
);
1350 wxLayoutConstraints
*constr
= GetConstraints();
1354 // Force the constraint to have as-is width and height
1355 // if we're in shrink-to-fit mode, because if left unconstrained,
1356 // SatisfyConstraints will fail. The shrink-to-fit option
1357 // essentially specifies the width and height as 'whatever I calculate'.
1358 constr
->width
.AsIs();
1359 constr
->height
.AsIs();
1363 // Find the bounding box and set own size
1367 wxNode
*node
= GetChildren().First();
1370 int x
, y
, width
, height
;
1371 wxWindow
*win
= (wxWindow
*)node
->Data();
1372 win
->GetSizeConstraint(&width
, &height
);
1373 win
->GetPositionConstraint(&x
, &y
);
1374 if ((x
+width
) > maxX
)
1376 if ((y
+height
) > maxY
)
1377 maxY
= (y
+ height
);
1379 node
= node
->Next();
1381 SetSize(GetBorderX(), GetBorderY(), maxX
, maxY
);
1383 // If this is the only sizer for the parent, size the parent to this sizer.
1384 if ( m_sizerParent
&& (m_sizerParent
->GetSizer() == this) )
1385 m_sizerParent
->SetClientSize(maxX
+ 2*GetBorderX(), maxY
+ 2*GetBorderY());
1392 wxLayoutConstraints
*constr
= GetConstraints();
1395 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1398 int x
= constr
->left
.GetValue();
1399 int y
= constr
->top
.GetValue();
1400 int w
= constr
->width
.GetValue();
1401 int h
= constr
->height
.GetValue();
1402 SetSize(x
, y
, w
, h
);
1415 bool wxSizer::LayoutPhase2(int *noChanges
)
1419 switch (sizerBehaviour
)
1430 wxLayoutConstraints
*constr
= GetConstraints();
1433 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1436 int x
= constr
->left
.GetValue();
1437 int y
= constr
->top
.GetValue();
1450 // Is this a dumb fix for lack of constraint evaluation?
1451 wxLayoutConstraints
*constr
= GetConstraints();
1454 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1457 int x
= constr
->left
.GetValue();
1458 int y
= constr
->top
.GetValue();
1459 int w
= constr
->width
.GetValue();
1460 int h
= constr
->height
.GetValue();
1461 SetSize(x
, y
, w
, h
);
1476 wxRowColSizer::wxRowColSizer()
1484 wxRowColSizer::wxRowColSizer(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1486 Create(parent
, rc
, n
, behav
);
1489 bool wxRowColSizer::Create(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1491 wxSizer::Create(parent
, behav
);
1501 wxRowColSizer::~wxRowColSizer()
1505 bool wxRowColSizer::LayoutPhase1(int *noChanges
)
1508 wxLayoutConstraints
*constr
= GetConstraints();
1512 // Force the constraint to have as-is width and height
1513 // if we're in shrink-to-fit mode, because if left unconstrained,
1514 // SatisfyConstraints will fail. The shrink-to-fit option
1515 // essentially specifies the width and height as 'whatever I calculate'.
1516 if (sizerBehaviour
== wxSizerShrink
)
1518 constr
->width
.AsIs();
1519 constr
->height
.AsIs();
1522 // Only evaluate the constraints FIRST if we're NOT
1523 // in shrink-to-fit mode, i.e. we want to size the rowcol
1524 // first, then lay the children out in the space we've calculated.
1525 if (sizerBehaviour
!= wxSizerShrink
)
1527 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1530 int x
= constr
->left
.GetValue();
1531 int y
= constr
->top
.GetValue();
1532 int w
= constr
->width
.GetValue();
1533 int h
= constr
->height
.GetValue();
1534 SetSize(x
, y
, w
, h
);
1539 // Continue to do the rest of the phase when the constraints have been
1540 // satisfied, i.e. we're on the last iteration of phase 1 and
1541 // can now do the actual rowcol laying out.
1545 // If we ARE in shrink-to-fit mode, we must now
1546 // calculate the child sizes BEFORE laying out in rows or columns.
1547 if (sizerBehaviour
== wxSizerShrink
)
1552 // WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
1553 // CHECK CONSTRAINTS IF ANY...
1556 int currentX
= borderX
;
1557 int currentY
= borderY
;
1558 int maxX
= currentX
;
1559 int maxY
= currentY
;
1561 wxNode
*node
= GetChildren().First();
1564 wxWindow
*win
= (wxWindow
*)node
->Data();
1565 int childWidth
, childHeight
;
1566 if (win
->GetConstraints() &&
1567 win
->GetConstraints()->width
.GetDone() &&
1568 win
->GetConstraints()->height
.GetDone())
1570 childWidth
= win
->GetConstraints()->width
.GetValue();
1571 childHeight
= win
->GetConstraints()->height
.GetValue();
1574 win
->GetSize(&childWidth
, &childHeight
);
1576 win
->MoveConstraint(currentX
, currentY
);
1578 if ((currentX
+ childWidth
) > maxX
)
1579 maxX
= (currentX
+ childWidth
);
1580 if ((currentY
+ childHeight
) > maxY
)
1581 maxY
= (currentY
+ childHeight
);
1585 currentX
+= childWidth
+ xSpacing
;
1588 // Reset to start of row
1589 if (noCols
== rowOrColSize
)
1592 currentY
+= childHeight
+ ySpacing
;
1598 currentY
+= childHeight
+ ySpacing
;
1601 // Reset to start of col
1602 if (noRows
== rowOrColSize
)
1605 currentX
+= childWidth
+ xSpacing
;
1610 node
= node
->Next();
1615 SetSize(-1, -1, maxX
, maxY
);
1620 bool wxRowColSizer::LayoutPhase2(int *noChanges
)
1624 // If shrink-to-fit, it's only at Phase 2 that we know the size of
1625 // the wxRowColSizer, and now we can evaluate the
1626 // constraints and pass result back up to parent.
1627 // This implements a depth-first strategy
1628 if (sizerBehaviour
== wxSizerShrink
)
1630 wxLayoutConstraints
*constr
= GetConstraints();
1633 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1636 int x
= constr
->left
.GetValue();
1637 int y
= constr
->top
.GetValue();
1646 // Lay out the children: breadth-first strategy.
1660 wxSpacingSizer::wxSpacingSizer()
1664 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
)
1669 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1671 Create(parent
, rel
, other
, spacing
);
1674 bool wxSpacingSizer::Create(wxWindow
*parent
)
1676 wxSizer::Create(parent
);
1680 bool wxSpacingSizer::Create(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1682 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1684 wxSizer::Create(parent
);
1689 c
->width
.Absolute (spacing
);
1690 c
->top
.SameAs (other
, wxTop
);
1691 c
->bottom
.SameAs (other
, wxBottom
);
1692 c
->right
.LeftOf (other
);
1695 c
->width
.Absolute (spacing
);
1696 c
->top
.SameAs (other
, wxTop
);
1697 c
->bottom
.SameAs (other
, wxBottom
);
1698 c
->left
.RightOf (other
);
1701 c
->height
.Absolute (spacing
);
1702 c
->left
.SameAs (other
, wxLeft
);
1703 c
->right
.SameAs (other
, wxRight
);
1704 c
->top
.Below (other
);
1707 c
->height
.Absolute (spacing
);
1708 c
->left
.SameAs (other
, wxLeft
);
1709 c
->right
.SameAs (other
, wxRight
);
1710 c
->bottom
.Above (other
);
1721 wxSpacingSizer::~wxSpacingSizer()