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"
35 #include "wx/layout.h"
37 #if !USE_SHARED_LIBRARY
38 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
39 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
40 IMPLEMENT_DYNAMIC_CLASS(wxSizer
, wxObject
)
41 IMPLEMENT_DYNAMIC_CLASS(wxRowColSizer
, wxSizer
)
42 IMPLEMENT_DYNAMIC_CLASS(wxSpacingSizer
, wxSizer
)
47 - Non shrink-to-fit row-col behaviour.
48 - Give justification styles, so can e.g. centre
49 the rows & cols, distribute the available space...
50 - Shrink-to-fit: should resize outer window (e.g. dialog box)
51 if directly associated with this kind of window.
52 - How to deal with a rowcol that stretches in one direction
53 but shrinks-to-fit in other. E.g. a horizontal toolbar: the width
54 stretches to fit the frame, but the height is constant
55 or wraps around contents. The algorithm currently assumes
56 both dimensions have the same behaviour. Could assume a constant
57 height (absolute value).
58 - rowcol where each row or column is aligned (length of
59 largest element determines spacing)
61 - Analyze aesthetic dialog boxes and implement using sizers.
62 - What reuseable components can we provide? E.g. Ok/Cancel/Help
64 - use wxStaticItems for aesthetic dialogs.
68 // Find margin sizes if a sizer, or zero otherwise
69 int wxSizerMarginX(wxWindow
*win
)
71 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
73 wxSizer
*sizer
= (wxSizer
*)win
;
74 return sizer
->GetBorderX();
80 int wxSizerMarginY(wxWindow
*win
)
82 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
84 wxSizer
*sizer
= (wxSizer
*)win
;
85 return sizer
->GetBorderY();
92 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
94 myEdge
= wxTop
; relationship
= wxUnconstrained
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
95 done
= FALSE
; otherWin
= NULL
;
98 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
102 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindow
*otherW
, wxEdge otherE
, int val
, int marg
)
104 relationship
= rel
; otherWin
= otherW
; otherEdge
= otherE
; value
= val
; margin
= marg
;
107 void wxIndividualLayoutConstraint::LeftOf(wxWindow
*sibling
, int marg
)
108 { Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
); }
110 void wxIndividualLayoutConstraint::RightOf(wxWindow
*sibling
, int marg
)
111 { Set(wxRightOf
, sibling
, wxRight
, 0, marg
); }
113 void wxIndividualLayoutConstraint::Above(wxWindow
*sibling
, int marg
)
114 { Set(wxAbove
, sibling
, wxTop
, 0, marg
); }
116 void wxIndividualLayoutConstraint::Below(wxWindow
*sibling
, int marg
)
117 { Set(wxBelow
, sibling
, wxBottom
, 0, marg
); }
120 // 'Same edge' alignment
122 void wxIndividualLayoutConstraint::SameAs(wxWindow
*otherW
, wxEdge edge
, int marg
)
123 { Set(wxPercentOf
, otherW
, edge
, 0, marg
); percent
= 100; }
125 // The edge is a percentage of the other window's edge
126 void wxIndividualLayoutConstraint::PercentOf(wxWindow
*otherW
, wxEdge wh
, int per
)
127 { otherWin
= otherW
; relationship
= wxPercentOf
; percent
= per
;
132 // Edge has absolute value
134 void wxIndividualLayoutConstraint::Absolute(int val
)
135 { value
= val
; relationship
= wxAbsolute
; }
137 // Reset constraint if it mentions otherWin
138 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindow
*otherW
)
140 if (otherW
== otherWin
)
142 myEdge
= wxTop
; relationship
= wxAsIs
; margin
= 0; value
= 0; percent
= 0; otherEdge
= wxTop
;
150 // Try to satisfy constraint
151 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindow
*win
)
153 if (relationship
== wxAbsolute
)
163 switch (relationship
)
167 // We can know this edge if: otherWin is win's parent,
168 // or otherWin has a satisfied constraint, or
169 // otherWin has no constraint.
170 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
173 value
= edgePos
- margin
;
182 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
185 value
= edgePos
+ margin
;
194 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
197 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
204 case wxUnconstrained
:
206 // We know the left-hand edge position if we know
207 // the right-hand edge and we know the width; OR if we know the centre and the width.
208 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
210 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
214 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
216 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
226 win
->GetPosition(&value
, &y
);
237 switch (relationship
)
241 // We can know this edge if: otherWin is win's parent,
242 // or otherWin has a satisfied constraint, or
243 // otherWin has no constraint.
244 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
247 value
= edgePos
- margin
;
256 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
259 value
= edgePos
+ margin
;
268 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
271 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
278 case wxUnconstrained
:
280 // We know the right-hand edge position if we know
281 // the left-hand edge and we know the width, OR if we know the
282 // centre edge and the width.
283 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
285 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
289 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
291 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
302 win
->GetSize(&w
, &h
);
303 win
->GetPosition(&x
, &y
);
315 switch (relationship
)
319 // We can know this edge if: otherWin is win's parent,
320 // or otherWin has a satisfied constraint, or
321 // otherWin has no constraint.
322 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
325 value
= edgePos
- margin
;
334 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
337 value
= edgePos
+ margin
;
346 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
349 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
356 case wxUnconstrained
:
358 // We know the top edge position if we know
359 // the bottom edge and we know the height; OR if we know the centre
360 // edge and the height.
361 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
363 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
367 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
369 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
379 win
->GetPosition(&x
, &value
);
390 switch (relationship
)
394 // We can know this edge if: otherWin is win's parent,
395 // or otherWin has a satisfied constraint, or
396 // otherWin has no constraint.
397 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
400 value
= edgePos
+ margin
;
409 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
412 value
= edgePos
- margin
;
421 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
424 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
431 case wxUnconstrained
:
433 // We know the bottom edge position if we know
434 // the top edge and we know the height; OR if we know the
435 // centre edge and the height.
436 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
438 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
442 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
444 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
455 win
->GetSize(&w
, &h
);
456 win
->GetPosition(&x
, &y
);
468 switch (relationship
)
472 // We can know this edge if: otherWin is win's parent,
473 // or otherWin has a satisfied constraint, or
474 // otherWin has no constraint.
475 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
478 value
= edgePos
- margin
;
487 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
490 value
= edgePos
+ margin
;
499 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
502 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
509 case wxUnconstrained
:
511 // We know the centre position if we know
512 // the left-hand edge and we know the width, OR
513 // the right-hand edge and the width
514 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
516 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
520 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
522 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
536 switch (relationship
)
540 // We can know this edge if: otherWin is win's parent,
541 // or otherWin has a satisfied constraint, or
542 // otherWin has no constraint.
543 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
546 value
= edgePos
- margin
;
555 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
558 value
= edgePos
+ margin
;
567 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
570 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
577 case wxUnconstrained
:
579 // We know the centre position if we know
580 // the top edge and we know the height, OR
581 // the bottom edge and the height.
582 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
584 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
588 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
590 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
604 switch (relationship
)
608 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
611 value
= (int)(edgePos
*(((float)percent
)*0.01));
623 win
->GetSize(&value
, &h
);
629 case wxUnconstrained
:
631 // We know the width if we know the left edge and the right edge, OR
632 // if we know the left edge and the centre, OR
633 // if we know the right edge and the centre
634 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
636 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
640 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
642 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
646 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
648 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
662 switch (relationship
)
666 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
669 value
= (int)(edgePos
*(((float)percent
)*0.01));
681 win
->GetSize(&w
, &value
);
687 case wxUnconstrained
:
689 // We know the height if we know the top edge and the bottom edge, OR
690 // if we know the top edge and the centre, OR
691 // if we know the bottom edge and the centre
692 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
694 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
698 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
700 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
704 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
706 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
724 // Get the value of this edge or dimension, or if this
725 // is not determinable, -1.
726 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
728 wxWindow
*other
) const
730 // If the edge or dimension belongs to the parent, then we
731 // know the dimension is obtainable immediately.
732 // E.g. a wxExpandSizer may contain a button (but the button's
733 // true parent is a panel, not the sizer)
734 if (other
->GetChildren()->Member(thisWin
))
740 return wxSizerMarginX(other
);
744 return wxSizerMarginY(other
);
749 other
->GetClientSizeConstraint(&w
, &h
);
750 return w
- wxSizerMarginX(other
);
755 other
->GetClientSizeConstraint(&w
, &h
);
756 return h
- wxSizerMarginY(other
);
761 other
->GetClientSizeConstraint(&w
, &h
);
762 return w
- 2*wxSizerMarginX(other
);
767 other
->GetClientSizeConstraint(&w
, &h
);
768 return h
- 2*wxSizerMarginY(other
);
774 other
->GetClientSizeConstraint(&w
, &h
);
775 if (which
== wxCentreX
)
788 wxLayoutConstraints
*constr
= other
->GetConstraints();
789 // If no constraints, it means the window is not dependent
790 // on anything, and therefore we know its value immediately
793 if (constr
->left
.GetDone())
794 return constr
->left
.GetValue();
801 other
->GetPosition(&x
, &y
);
807 wxLayoutConstraints
*constr
= other
->GetConstraints();
808 // If no constraints, it means the window is not dependent
809 // on anything, and therefore we know its value immediately
812 if (constr
->top
.GetDone())
813 return constr
->top
.GetValue();
820 other
->GetPosition(&x
, &y
);
826 wxLayoutConstraints
*constr
= other
->GetConstraints();
827 // If no constraints, it means the window is not dependent
828 // on anything, and therefore we know its value immediately
831 if (constr
->right
.GetDone())
832 return constr
->right
.GetValue();
839 other
->GetPosition(&x
, &y
);
840 other
->GetSize(&w
, &h
);
846 wxLayoutConstraints
*constr
= other
->GetConstraints();
847 // If no constraints, it means the window is not dependent
848 // on anything, and therefore we know its value immediately
851 if (constr
->bottom
.GetDone())
852 return constr
->bottom
.GetValue();
859 other
->GetPosition(&x
, &y
);
860 other
->GetSize(&w
, &h
);
866 wxLayoutConstraints
*constr
= other
->GetConstraints();
867 // If no constraints, it means the window is not dependent
868 // on anything, and therefore we know its value immediately
871 if (constr
->width
.GetDone())
872 return constr
->width
.GetValue();
879 other
->GetSize(&w
, &h
);
885 wxLayoutConstraints
*constr
= other
->GetConstraints();
886 // If no constraints, it means the window is not dependent
887 // on anything, and therefore we know its value immediately
890 if (constr
->height
.GetDone())
891 return constr
->height
.GetValue();
898 other
->GetSize(&w
, &h
);
904 wxLayoutConstraints
*constr
= other
->GetConstraints();
905 // If no constraints, it means the window is not dependent
906 // on anything, and therefore we know its value immediately
909 if (constr
->centreX
.GetDone())
910 return constr
->centreX
.GetValue();
917 other
->GetPosition(&x
, &y
);
918 other
->GetSize(&w
, &h
);
919 return (int)(x
+ (w
/2));
924 wxLayoutConstraints
*constr
= other
->GetConstraints();
925 // If no constraints, it means the window is not dependent
926 // on anything, and therefore we know its value immediately
929 if (constr
->centreY
.GetDone())
930 return constr
->centreY
.GetValue();
937 other
->GetPosition(&x
, &y
);
938 other
->GetSize(&w
, &h
);
939 return (int)(y
+ (h
/2));
948 wxLayoutConstraints::wxLayoutConstraints()
950 left
.SetEdge(wxLeft
);
952 right
.SetEdge(wxRight
);
953 bottom
.SetEdge(wxBottom
);
954 centreX
.SetEdge(wxCentreX
);
955 centreY
.SetEdge(wxCentreY
);
956 width
.SetEdge(wxWidth
);
957 height
.SetEdge(wxHeight
);
960 wxLayoutConstraints::~wxLayoutConstraints()
964 bool wxLayoutConstraints::SatisfyConstraints(wxWindow
*win
, int *nChanges
)
968 bool done
= width
.GetDone();
969 bool newDone
= (done
? TRUE
: width
.SatisfyConstraint(this, win
));
973 done
= height
.GetDone();
974 newDone
= (done
? TRUE
: height
.SatisfyConstraint(this, win
));
978 done
= left
.GetDone();
979 newDone
= (done
? TRUE
: left
.SatisfyConstraint(this, win
));
983 done
= top
.GetDone();
984 newDone
= (done
? TRUE
: top
.SatisfyConstraint(this, win
));
988 done
= right
.GetDone();
989 newDone
= (done
? TRUE
: right
.SatisfyConstraint(this, win
));
993 done
= bottom
.GetDone();
994 newDone
= (done
? TRUE
: bottom
.SatisfyConstraint(this, win
));
998 done
= centreX
.GetDone();
999 newDone
= (done
? TRUE
: centreX
.SatisfyConstraint(this, win
));
1000 if (newDone
!= done
)
1003 done
= centreY
.GetDone();
1004 newDone
= (done
? TRUE
: centreY
.SatisfyConstraint(this, win
));
1005 if (newDone
!= done
)
1008 *nChanges
= noChanges
;
1010 return AreSatisfied();
1014 * Main constrained layout algorithm. Look at all the child
1015 * windows, and their constraints (if any).
1016 * The idea is to keep iterating through the constraints
1017 * until all left, right, bottom and top edges, and widths and heights,
1018 * are known (or no change occurs and we've failed to resolve all
1021 * If the user has not specified a dimension or edge, it will be
1022 * be calculated from the other known values. E.g. If we know
1023 * the right hand edge and the left hand edge, we now know the width.
1024 * The snag here is that this means we must specify absolute dimensions
1025 * twice (in constructor and in constraint), if we wish to use the
1026 * constraint notation to just set the position, for example.
1027 * Otherwise, if we only set ONE edge and no dimension, it would never
1028 * find the other edge.
1032 Mark all constraints as not done.
1035 until no change or iterations >= max iterations
1038 Calculate all constraints
1043 Set each calculated position and size
1047 bool wxOldDoLayout(wxWindow
*win
)
1049 // Make sure this isn't called recursively from below
1050 static wxList doneSoFar
;
1052 if (doneSoFar
.Member(win
))
1055 doneSoFar
.Append(win
);
1057 wxNode
*node
= win
->GetChildren()->First();
1060 wxWindow
*child
= (wxWindow
*)node
->Data();
1061 wxLayoutConstraints
*constr
= child
->GetConstraints();
1064 constr
->left
.SetDone(FALSE
);
1065 constr
->top
.SetDone(FALSE
);
1066 constr
->right
.SetDone(FALSE
);
1067 constr
->bottom
.SetDone(FALSE
);
1068 constr
->width
.SetDone(FALSE
);
1069 constr
->height
.SetDone(FALSE
);
1070 constr
->centreX
.SetDone(FALSE
);
1071 constr
->centreY
.SetDone(FALSE
);
1073 node
= node
->Next();
1075 int noIterations
= 0;
1076 int maxIterations
= 500;
1079 while ((noChanges
> 0) && (noIterations
< maxIterations
))
1082 wxNode
*node
= win
->GetChildren()->First();
1085 wxWindow
*child
= (wxWindow
*)node
->Data();
1086 wxLayoutConstraints
*constr
= child
->GetConstraints();
1089 int tempNoChanges
= 0;
1090 (void)constr
->SatisfyConstraints(child
, &tempNoChanges
);
1091 noChanges
+= tempNoChanges
;
1093 node
= node
->Next();
1098 // Would be nice to have a test here to see _which_ constraint(s)
1099 // failed, so we can print a specific diagnostic message.
1102 wxDebugMsg(_("wxWindow::Layout() failed.\n"));
1105 // Now set the sizes and positions of the children, and
1106 // recursively call Layout().
1107 node
= win
->GetChildren()->First();
1110 wxWindow
*child
= (wxWindow
*)node
->Data();
1111 wxLayoutConstraints
*constr
= child
->GetConstraints();
1112 if (constr
&& constr
->left
.GetDone() && constr
->right
.GetDone() &&
1113 constr
->width
.GetDone() && constr
->height
.GetDone())
1115 int x
= constr
->left
.GetValue();
1116 int y
= constr
->top
.GetValue();
1117 int w
= constr
->width
.GetValue();
1118 int h
= constr
->height
.GetValue();
1120 // If we don't want to resize this window, just move it...
1121 if ((constr
->width
.GetRelationship() != wxAsIs
) ||
1122 (constr
->height
.GetRelationship() != wxAsIs
))
1124 // _Should_ call Layout() recursively.
1125 child
->SetSize(x
, y
, w
, h
);
1134 node
= node
->Next();
1136 doneSoFar
.DeleteObject(win
);
1143 sizerBehaviour
= wxSizerNone
;
1152 wxSizer::wxSizer(wxWindow
*parent
, wxSizerBehaviour behav
)
1154 Create(parent
, behav
);
1157 bool wxSizer::Create(wxWindow
*parent
, wxSizerBehaviour behav
)
1159 sizerBehaviour
= behav
;
1162 m_sizerParent
= parent
;
1168 // A normal window can have just one top-level sizer
1169 // associated with it.
1170 if (!parent
->IsKindOf(CLASSINFO(wxSizer
)))
1172 parent
->SetSizer(this);
1175 ((wxSizer
*)parent
)->AddSizerChild(this);
1177 switch (sizerBehaviour
)
1181 // Defines a set of constraints
1182 // to expand the sizer to fit the parent window
1183 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1185 c
->left
.SameAs(parent
, wxLeft
, 0);
1186 c
->top
.SameAs(parent
, wxTop
, 0);
1187 c
->right
.SameAs(parent
, wxRight
, 0);
1188 c
->bottom
.SameAs(parent
, wxBottom
, 0);
1204 // Remove all children without deleting them,
1205 // or ~wxbWindow will delete proper windows _twice_
1206 wxNode
*node
= GetChildren()->First();
1209 wxNode
*next
= node
->Next();
1210 wxWindow
*win
= (wxWindow
*)node
->Data();
1211 if (!win
->IsKindOf(CLASSINFO(wxSizer
)))
1214 win
->SetSizerParent(NULL
);
1218 RemoveSizerChild(win
);
1224 if (m_sizerParent
) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
1226 m_sizerParent
->SetSizer(NULL
);
1227 m_sizerParent
= NULL
;
1232 void wxSizer::SetBorder(int x
, int y
)
1236 /* No: the margin is for inside, not outside (expansion)
1238 if ( GetConstraints() )
1240 GetConstraints()->left.SetMargin(x);
1241 GetConstraints()->right.SetMargin(x);
1242 GetConstraints()->top.SetMargin(y);
1243 GetConstraints()->bottom.SetMargin(y);
1249 void wxSizer::AddSizerChild(wxWindow
*child
)
1251 child
->SetSizerParent(this);
1252 GetChildren()->Append(child
);
1254 // Add some constraints for the purpose of storing
1255 // the relative position of the window/sizer
1256 // during layout calculations.
1257 if (!child
->GetConstraints())
1259 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1265 child
->GetSize(&w
, &h
);
1266 c
->width
.SetValue(w
);
1267 c
->height
.SetValue(h
);
1269 child
->SetConstraints(c
);
1273 void wxSizer::RemoveSizerChild(wxWindow
*child
)
1275 GetChildren()->DeleteObject(child
);
1278 void wxSizer::SetSize(int x
, int y
, int w
, int h
, int WXUNUSED(flags
))
1280 wxLayoutConstraints
*constr
= GetConstraints();
1285 constr
->left
.SetValue(x
);
1291 constr
->top
.SetValue(y
);
1297 constr
->width
.SetValue(w
);
1303 constr
->height
.SetValue(h
);
1307 void wxSizer::Move(int x
, int y
)
1309 wxLayoutConstraints
*constr
= GetConstraints();
1314 constr
->left
.SetValue(x
);
1320 constr
->top
.SetValue(y
);
1324 void wxSizer::GetSize(int *w
, int *h
) const
1330 void wxSizer::GetPosition(int *x
, int *y
) const
1336 bool wxSizer::LayoutPhase1(int *noChanges
)
1339 switch (sizerBehaviour
)
1345 wxMessageBox(_("wxExpandSizer has no parent!"), _("Sizer error"), wxOK
);
1349 // Set the size to fill the parent client area
1351 m_sizerParent
->GetClientSize(&pw
, &ph
);
1352 SetSize(GetBorderX(), GetBorderY(), pw
- 2*GetBorderX(), ph
- 2*GetBorderY());
1353 wxLayoutConstraints
*constr
= GetConstraints();
1355 // Fill in the constraints
1358 constr
->left
.SetValue(0); constr
->left
.SetDone(TRUE
);
1359 constr
->top
.SetValue(0); constr
->right
.SetDone(TRUE
);
1360 constr
->width
.SetValue(pw
); constr
->width
.SetDone(TRUE
);
1361 constr
->height
.SetValue(ph
); constr
->height
.SetDone(TRUE
);
1369 wxLayoutConstraints
*constr
= GetConstraints();
1373 // Force the constraint to have as-is width and height
1374 // if we're in shrink-to-fit mode, because if left unconstrained,
1375 // SatisfyConstraints will fail. The shrink-to-fit option
1376 // essentially specifies the width and height as 'whatever I calculate'.
1377 constr
->width
.AsIs();
1378 constr
->height
.AsIs();
1382 // Find the bounding box and set own size
1385 wxNode
*node
= GetChildren()->First();
1388 int x
, y
, width
, height
;
1389 wxWindow
*win
= (wxWindow
*)node
->Data();
1390 win
->GetSizeConstraint(&width
, &height
);
1391 win
->GetPositionConstraint(&x
, &y
);
1392 if ((x
+width
) > maxX
)
1394 if ((y
+height
) > maxY
)
1395 maxY
= (y
+ height
);
1396 node
= node
->Next();
1398 SetSize(GetBorderX(), GetBorderY(), maxX
, maxY
);
1400 // If this is the only sizer for the parent, size the parent to this sizer.
1401 if ( m_sizerParent
&& (m_sizerParent
->GetSizer() == this) )
1402 m_sizerParent
->SetClientSize(maxX
+ 2*GetBorderX(), maxY
+ 2*GetBorderY());
1409 wxLayoutConstraints
*constr
= GetConstraints();
1412 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1415 int x
= constr
->left
.GetValue();
1416 int y
= constr
->top
.GetValue();
1417 int w
= constr
->width
.GetValue();
1418 int h
= constr
->height
.GetValue();
1419 SetSize(x
, y
, w
, h
);
1432 bool wxSizer::LayoutPhase2(int *noChanges
)
1436 switch (sizerBehaviour
)
1447 wxLayoutConstraints
*constr
= GetConstraints();
1450 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1453 int x
= constr
->left
.GetValue();
1454 int y
= constr
->top
.GetValue();
1467 // Is this a dumb fix for lack of constraint evaluation?
1468 wxLayoutConstraints
*constr
= GetConstraints();
1471 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1474 int x
= constr
->left
.GetValue();
1475 int y
= constr
->top
.GetValue();
1476 int w
= constr
->width
.GetValue();
1477 int h
= constr
->height
.GetValue();
1478 SetSize(x
, y
, w
, h
);
1493 wxRowColSizer::wxRowColSizer()
1501 wxRowColSizer::wxRowColSizer(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1503 Create(parent
, rc
, n
, behav
);
1506 bool wxRowColSizer::Create(wxWindow
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1508 wxSizer::Create(parent
, behav
);
1518 wxRowColSizer::~wxRowColSizer()
1522 void wxRowColSizer::SetSize(int x
, int y
, int w
, int h
, int flags
)
1524 wxSizer::SetSize(x
, y
, w
, h
, flags
);
1527 bool wxRowColSizer::LayoutPhase1(int *noChanges
)
1530 wxLayoutConstraints
*constr
= GetConstraints();
1534 // Force the constraint to have as-is width and height
1535 // if we're in shrink-to-fit mode, because if left unconstrained,
1536 // SatisfyConstraints will fail. The shrink-to-fit option
1537 // essentially specifies the width and height as 'whatever I calculate'.
1538 if (sizerBehaviour
== wxSizerShrink
)
1540 constr
->width
.AsIs();
1541 constr
->height
.AsIs();
1544 // Only evaluate the constraints FIRST if we're NOT
1545 // in shrink-to-fit mode, i.e. we want to size the rowcol
1546 // first, then lay the children out in the space we've calculated.
1547 if (sizerBehaviour
!= wxSizerShrink
)
1549 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1552 int x
= constr
->left
.GetValue();
1553 int y
= constr
->top
.GetValue();
1554 int w
= constr
->width
.GetValue();
1555 int h
= constr
->height
.GetValue();
1556 SetSize(x
, y
, w
, h
);
1561 // Continue to do the rest of the phase when the constraints have been
1562 // satisfied, i.e. we're on the last iteration of phase 1 and
1563 // can now do the actual rowcol laying out.
1567 // If we ARE in shrink-to-fit mode, we must now
1568 // calculate the child sizes BEFORE laying out in rows or columns.
1569 if (sizerBehaviour
== wxSizerShrink
)
1574 // WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
1575 // CHECK CONSTRAINTS IF ANY...
1578 int currentX
= borderX
;
1579 int currentY
= borderY
;
1580 int maxX
= currentX
;
1581 int maxY
= currentY
;
1583 wxNode
*node
= GetChildren()->First();
1586 wxWindow
*win
= (wxWindow
*)node
->Data();
1587 int childWidth
, childHeight
;
1588 if (win
->GetConstraints() &&
1589 win
->GetConstraints()->width
.GetDone() &&
1590 win
->GetConstraints()->height
.GetDone())
1592 childWidth
= win
->GetConstraints()->width
.GetValue();
1593 childHeight
= win
->GetConstraints()->height
.GetValue();
1596 win
->GetSize(&childWidth
, &childHeight
);
1598 win
->MoveConstraint(currentX
, currentY
);
1600 if ((currentX
+ childWidth
) > maxX
)
1601 maxX
= (currentX
+ childWidth
);
1602 if ((currentY
+ childHeight
) > maxY
)
1603 maxY
= (currentY
+ childHeight
);
1607 currentX
+= childWidth
+ xSpacing
;
1610 // Reset to start of row
1611 if (noCols
== rowOrColSize
)
1614 currentY
+= childHeight
+ ySpacing
;
1620 currentY
+= childHeight
+ ySpacing
;
1623 // Reset to start of col
1624 if (noRows
== rowOrColSize
)
1627 currentX
+= childWidth
+ xSpacing
;
1632 node
= node
->Next();
1637 SetSize(-1, -1, maxX
, maxY
);
1642 bool wxRowColSizer::LayoutPhase2(int *noChanges
)
1646 // If shrink-to-fit, it's only at Phase 2 that we know the size of
1647 // the wxRowColSizer, and now we can evaluate the
1648 // constraints and pass result back up to parent.
1649 // This implements a depth-first strategy
1650 if (sizerBehaviour
== wxSizerShrink
)
1652 wxLayoutConstraints
*constr
= GetConstraints();
1655 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1658 int x
= constr
->left
.GetValue();
1659 int y
= constr
->top
.GetValue();
1668 // Lay out the children: breadth-first strategy.
1682 wxSpacingSizer::wxSpacingSizer()
1686 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
)
1691 wxSpacingSizer::wxSpacingSizer(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1693 Create(parent
, rel
, other
, spacing
);
1696 bool wxSpacingSizer::Create(wxWindow
*parent
)
1698 wxSizer::Create(parent
);
1702 bool wxSpacingSizer::Create(wxWindow
*parent
, wxRelationship rel
, wxWindow
*other
, int spacing
)
1704 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1706 wxSizer::Create(parent
);
1711 c
->width
.Absolute (spacing
);
1712 c
->top
.SameAs (other
, wxTop
);
1713 c
->bottom
.SameAs (other
, wxBottom
);
1714 c
->right
.LeftOf (other
);
1717 c
->width
.Absolute (spacing
);
1718 c
->top
.SameAs (other
, wxTop
);
1719 c
->bottom
.SameAs (other
, wxBottom
);
1720 c
->left
.RightOf (other
);
1723 c
->height
.Absolute (spacing
);
1724 c
->left
.SameAs (other
, wxLeft
);
1725 c
->right
.SameAs (other
, wxRight
);
1726 c
->top
.Below (other
);
1729 c
->height
.Absolute (spacing
);
1730 c
->left
.SameAs (other
, wxLeft
);
1731 c
->right
.SameAs (other
, wxRight
);
1732 c
->bottom
.Above (other
);
1743 wxSpacingSizer::~wxSpacingSizer()