1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Constraint layout system classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // =============================================================================
14 // =============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "layout.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
38 #include "wx/window.h"
40 #include "wx/dialog.h"
41 #include "wx/msgdlg.h"
45 #include "wx/layout.h"
47 #if !USE_SHARED_LIBRARY
48 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
49 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
50 IMPLEMENT_DYNAMIC_CLASS(wxSizer
, wxObject
)
51 IMPLEMENT_DYNAMIC_CLASS(wxRowColSizer
, wxSizer
)
52 IMPLEMENT_DYNAMIC_CLASS(wxSpacingSizer
, wxSizer
)
57 - Non shrink-to-fit row-col behaviour.
58 - Give justification styles, so can e.g. centre
59 the rows & cols, distribute the available space...
60 - Shrink-to-fit: should resize outer window (e.g. dialog box)
61 if directly associated with this kind of window.
62 - How to deal with a rowcol that stretches in one direction
63 but shrinks-to-fit in other. E.g. a horizontal toolbar: the width
64 stretches to fit the frame, but the height is constant
65 or wraps around contents. The algorithm currently assumes
66 both dimensions have the same behaviour. Could assume a constant
67 height (absolute value).
68 - rowcol where each row or column is aligned (length of
69 largest element determines spacing)
71 - Analyze aesthetic dialog boxes and implement using sizers.
72 - What reuseable components can we provide? E.g. Ok/Cancel/Help
74 - use wxStaticItems for aesthetic dialogs.
78 // Find margin sizes if a sizer, or zero otherwise
79 int wxSizerMarginX(wxWindowBase
*win
)
81 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
83 wxSizer
*sizer
= (wxSizer
*)win
;
84 return sizer
->GetBorderX();
90 int wxSizerMarginY(wxWindowBase
*win
)
92 if ( win
->IsKindOf(CLASSINFO(wxSizer
)) )
94 wxSizer
*sizer
= (wxSizer
*)win
;
95 return sizer
->GetBorderY();
102 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
105 relationship
= wxUnconstrained
;
111 otherWin
= (wxWindowBase
*) NULL
;
114 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
118 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindowBase
*otherW
, wxEdge otherE
, int val
, int marg
)
127 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase
*sibling
, int marg
)
129 Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
);
132 void wxIndividualLayoutConstraint::RightOf(wxWindowBase
*sibling
, int marg
)
134 Set(wxRightOf
, sibling
, wxRight
, 0, marg
);
137 void wxIndividualLayoutConstraint::Above(wxWindowBase
*sibling
, int marg
)
139 Set(wxAbove
, sibling
, wxTop
, 0, marg
);
142 void wxIndividualLayoutConstraint::Below(wxWindowBase
*sibling
, int marg
)
144 Set(wxBelow
, sibling
, wxBottom
, 0, marg
);
148 // 'Same edge' alignment
150 void wxIndividualLayoutConstraint::SameAs(wxWindowBase
*otherW
, wxEdge edge
, int marg
)
152 Set(wxPercentOf
, otherW
, edge
, 0, marg
);
156 // The edge is a percentage of the other window's edge
157 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase
*otherW
, wxEdge wh
, int per
)
160 relationship
= wxPercentOf
;
167 // Edge has absolute value
169 void wxIndividualLayoutConstraint::Absolute(int val
)
171 value
= val
; relationship
= wxAbsolute
;
174 // Reset constraint if it mentions otherWin
175 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase
*otherW
)
177 if (otherW
== otherWin
)
180 relationship
= wxAsIs
;
185 otherWin
= (wxWindowBase
*) NULL
;
192 // Try to satisfy constraint
193 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindowBase
*win
)
195 if (relationship
== wxAbsolute
)
205 switch (relationship
)
209 // We can know this edge if: otherWin is win's
210 // parent, or otherWin has a satisfied constraint,
211 // or otherWin has no constraint.
212 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
215 value
= edgePos
- margin
;
224 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
227 value
= edgePos
+ margin
;
236 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
239 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
246 case wxUnconstrained
:
248 // We know the left-hand edge position if we know
249 // the right-hand edge and we know the width; OR if
250 // we know the centre and the width.
251 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
253 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
257 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
259 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
269 win
->GetPosition(&value
, &y
);
280 switch (relationship
)
284 // We can know this edge if: otherWin is win's
285 // parent, or otherWin has a satisfied constraint,
286 // or otherWin has no constraint.
287 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
290 value
= edgePos
- margin
;
299 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
302 value
= edgePos
+ margin
;
311 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
314 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
321 case wxUnconstrained
:
323 // We know the right-hand edge position if we know the
324 // left-hand edge and we know the width, OR if we know the
325 // centre edge and the width.
326 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
328 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
332 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
334 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
345 win
->GetSize(&w
, &h
);
346 win
->GetPosition(&x
, &y
);
358 switch (relationship
)
362 // We can know this edge if: otherWin is win's
363 // parent, or otherWin has a satisfied constraint,
364 // or otherWin has no constraint.
365 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
368 value
= edgePos
- margin
;
377 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
380 value
= edgePos
+ margin
;
389 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
392 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
399 case wxUnconstrained
:
401 // We know the top edge position if we know the bottom edge
402 // and we know the height; OR if we know the centre edge and
404 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
406 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
410 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
412 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
422 win
->GetPosition(&x
, &value
);
433 switch (relationship
)
437 // We can know this edge if: otherWin is win's parent,
438 // or otherWin has a satisfied constraint, or
439 // otherWin has no constraint.
440 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
443 value
= edgePos
+ margin
;
452 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
455 value
= edgePos
- margin
;
464 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
467 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
474 case wxUnconstrained
:
476 // We know the bottom edge position if we know the top edge
477 // and we know the height; OR if we know the centre edge and
479 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
481 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
485 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
487 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
498 win
->GetSize(&w
, &h
);
499 win
->GetPosition(&x
, &y
);
511 switch (relationship
)
515 // We can know this edge if: otherWin is win's parent, or
516 // otherWin has a satisfied constraint, or otherWin has no
518 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
521 value
= edgePos
- margin
;
530 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
533 value
= edgePos
+ margin
;
542 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
545 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
552 case wxUnconstrained
:
554 // We know the centre position if we know
555 // the left-hand edge and we know the width, OR
556 // the right-hand edge and the width
557 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
559 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
563 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
565 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
579 switch (relationship
)
583 // We can know this edge if: otherWin is win's parent,
584 // or otherWin has a satisfied constraint, or otherWin
585 // has no constraint.
586 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
589 value
= edgePos
- margin
;
598 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
601 value
= edgePos
+ margin
;
610 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
613 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
620 case wxUnconstrained
:
622 // We know the centre position if we know
623 // the top edge and we know the height, OR
624 // the bottom edge and the height.
625 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
627 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
631 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
633 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
647 switch (relationship
)
651 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
654 value
= (int)(edgePos
*(((float)percent
)*0.01));
666 win
->GetSize(&value
, &h
);
672 case wxUnconstrained
:
674 // We know the width if we know the left edge and the right edge, OR
675 // if we know the left edge and the centre, OR
676 // if we know the right edge and the centre
677 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
679 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
683 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
685 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
689 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
691 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
705 switch (relationship
)
709 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
712 value
= (int)(edgePos
*(((float)percent
)*0.01));
724 win
->GetSize(&w
, &value
);
730 case wxUnconstrained
:
732 // We know the height if we know the top edge and the bottom edge, OR
733 // if we know the top edge and the centre, OR
734 // if we know the bottom edge and the centre
735 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
737 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
741 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
743 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
747 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
749 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
767 // Get the value of this edge or dimension, or if this is not determinable, -1.
768 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
769 wxWindowBase
*thisWin
,
770 wxWindowBase
*other
) const
772 // If the edge or dimension belongs to the parent, then we know the
773 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
774 // button (but the button's true parent is a panel, not the sizer)
775 if (other
->GetChildren().Find(thisWin
))
781 return wxSizerMarginX(other
);
785 return wxSizerMarginY(other
);
790 other
->GetClientSizeConstraint(&w
, &h
);
791 return w
- wxSizerMarginX(other
);
796 other
->GetClientSizeConstraint(&w
, &h
);
797 return h
- wxSizerMarginY(other
);
802 other
->GetClientSizeConstraint(&w
, &h
);
803 return w
- 2*wxSizerMarginX(other
);
808 other
->GetClientSizeConstraint(&w
, &h
);
809 return h
- 2*wxSizerMarginY(other
);
815 other
->GetClientSizeConstraint(&w
, &h
);
816 if (which
== wxCentreX
)
829 wxLayoutConstraints
*constr
= other
->GetConstraints();
830 // If no constraints, it means the window is not dependent
831 // on anything, and therefore we know its value immediately
834 if (constr
->left
.GetDone())
835 return constr
->left
.GetValue();
842 other
->GetPosition(&x
, &y
);
848 wxLayoutConstraints
*constr
= other
->GetConstraints();
849 // If no constraints, it means the window is not dependent
850 // on anything, and therefore we know its value immediately
853 if (constr
->top
.GetDone())
854 return constr
->top
.GetValue();
861 other
->GetPosition(&x
, &y
);
867 wxLayoutConstraints
*constr
= other
->GetConstraints();
868 // If no constraints, it means the window is not dependent
869 // on anything, and therefore we know its value immediately
872 if (constr
->right
.GetDone())
873 return constr
->right
.GetValue();
880 other
->GetPosition(&x
, &y
);
881 other
->GetSize(&w
, &h
);
887 wxLayoutConstraints
*constr
= other
->GetConstraints();
888 // If no constraints, it means the window is not dependent
889 // on anything, and therefore we know its value immediately
892 if (constr
->bottom
.GetDone())
893 return constr
->bottom
.GetValue();
900 other
->GetPosition(&x
, &y
);
901 other
->GetSize(&w
, &h
);
907 wxLayoutConstraints
*constr
= other
->GetConstraints();
908 // If no constraints, it means the window is not dependent
909 // on anything, and therefore we know its value immediately
912 if (constr
->width
.GetDone())
913 return constr
->width
.GetValue();
920 other
->GetSize(&w
, &h
);
926 wxLayoutConstraints
*constr
= other
->GetConstraints();
927 // If no constraints, it means the window is not dependent
928 // on anything, and therefore we know its value immediately
931 if (constr
->height
.GetDone())
932 return constr
->height
.GetValue();
939 other
->GetSize(&w
, &h
);
945 wxLayoutConstraints
*constr
= other
->GetConstraints();
946 // If no constraints, it means the window is not dependent
947 // on anything, and therefore we know its value immediately
950 if (constr
->centreX
.GetDone())
951 return constr
->centreX
.GetValue();
958 other
->GetPosition(&x
, &y
);
959 other
->GetSize(&w
, &h
);
960 return (int)(x
+ (w
/2));
965 wxLayoutConstraints
*constr
= other
->GetConstraints();
966 // If no constraints, it means the window is not dependent
967 // on anything, and therefore we know its value immediately
970 if (constr
->centreY
.GetDone())
971 return constr
->centreY
.GetValue();
978 other
->GetPosition(&x
, &y
);
979 other
->GetSize(&w
, &h
);
980 return (int)(y
+ (h
/2));
989 wxLayoutConstraints::wxLayoutConstraints()
991 left
.SetEdge(wxLeft
);
993 right
.SetEdge(wxRight
);
994 bottom
.SetEdge(wxBottom
);
995 centreX
.SetEdge(wxCentreX
);
996 centreY
.SetEdge(wxCentreY
);
997 width
.SetEdge(wxWidth
);
998 height
.SetEdge(wxHeight
);
1001 wxLayoutConstraints::~wxLayoutConstraints()
1005 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase
*win
, int *nChanges
)
1009 bool done
= width
.GetDone();
1010 bool newDone
= (done
? TRUE
: width
.SatisfyConstraint(this, win
));
1011 if (newDone
!= done
)
1014 done
= height
.GetDone();
1015 newDone
= (done
? TRUE
: height
.SatisfyConstraint(this, win
));
1016 if (newDone
!= done
)
1019 done
= left
.GetDone();
1020 newDone
= (done
? TRUE
: left
.SatisfyConstraint(this, win
));
1021 if (newDone
!= done
)
1024 done
= top
.GetDone();
1025 newDone
= (done
? TRUE
: top
.SatisfyConstraint(this, win
));
1026 if (newDone
!= done
)
1029 done
= right
.GetDone();
1030 newDone
= (done
? TRUE
: right
.SatisfyConstraint(this, win
));
1031 if (newDone
!= done
)
1034 done
= bottom
.GetDone();
1035 newDone
= (done
? TRUE
: bottom
.SatisfyConstraint(this, win
));
1036 if (newDone
!= done
)
1039 done
= centreX
.GetDone();
1040 newDone
= (done
? TRUE
: centreX
.SatisfyConstraint(this, win
));
1041 if (newDone
!= done
)
1044 done
= centreY
.GetDone();
1045 newDone
= (done
? TRUE
: centreY
.SatisfyConstraint(this, win
));
1046 if (newDone
!= done
)
1049 *nChanges
= noChanges
;
1051 return AreSatisfied();
1055 * Main constrained layout algorithm. Look at all the child
1056 * windows, and their constraints (if any).
1057 * The idea is to keep iterating through the constraints
1058 * until all left, right, bottom and top edges, and widths and heights,
1059 * are known (or no change occurs and we've failed to resolve all
1062 * If the user has not specified a dimension or edge, it will be
1063 * be calculated from the other known values. E.g. If we know
1064 * the right hand edge and the left hand edge, we now know the width.
1065 * The snag here is that this means we must specify absolute dimensions
1066 * twice (in constructor and in constraint), if we wish to use the
1067 * constraint notation to just set the position, for example.
1068 * Otherwise, if we only set ONE edge and no dimension, it would never
1069 * find the other edge.
1073 Mark all constraints as not done.
1076 until no change or iterations >= max iterations
1079 Calculate all constraints
1084 Set each calculated position and size
1088 #if WXWIN_COMPATIBILITY
1089 bool wxOldDoLayout(wxWindowBase
*win
)
1091 // Make sure this isn't called recursively from below
1092 static wxList doneSoFar
;
1094 if (doneSoFar
.Member(win
))
1097 doneSoFar
.Append(win
);
1099 wxNode
*node
= win
->GetChildren().First();
1102 wxWindowBase
*child
= (wxWindowBase
*)node
->Data();
1103 wxLayoutConstraints
*constr
= child
->GetConstraints();
1106 constr
->left
.SetDone(FALSE
);
1107 constr
->top
.SetDone(FALSE
);
1108 constr
->right
.SetDone(FALSE
);
1109 constr
->bottom
.SetDone(FALSE
);
1110 constr
->width
.SetDone(FALSE
);
1111 constr
->height
.SetDone(FALSE
);
1112 constr
->centreX
.SetDone(FALSE
);
1113 constr
->centreY
.SetDone(FALSE
);
1115 node
= node
->Next();
1117 int noIterations
= 0;
1118 int maxIterations
= 500;
1121 while ((noChanges
> 0) && (noIterations
< maxIterations
))
1124 wxNode
*node
= win
->GetChildren().First();
1127 wxWindowBase
*child
= (wxWindowBase
*)node
->Data();
1128 wxLayoutConstraints
*constr
= child
->GetConstraints();
1131 int tempNoChanges
= 0;
1132 (void)constr
->SatisfyConstraints(child
, &tempNoChanges
);
1133 noChanges
+= tempNoChanges
;
1135 node
= node
->Next();
1140 // Would be nice to have a test here to see _which_ constraint(s)
1141 // failed, so we can print a specific diagnostic message.
1144 wxDebugMsg(_("wxWindowBase::Layout() failed.\n"));
1147 // Now set the sizes and positions of the children, and
1148 // recursively call Layout().
1149 node
= win
->GetChildren().First();
1152 wxWindowBase
*child
= (wxWindowBase
*)node
->Data();
1153 wxLayoutConstraints
*constr
= child
->GetConstraints();
1154 if (constr
&& constr
->left
.GetDone() && constr
->right
.GetDone() &&
1155 constr
->width
.GetDone() && constr
->height
.GetDone())
1157 int x
= constr
->left
.GetValue();
1158 int y
= constr
->top
.GetValue();
1159 int w
= constr
->width
.GetValue();
1160 int h
= constr
->height
.GetValue();
1162 // If we don't want to resize this window, just move it...
1163 if ((constr
->width
.GetRelationship() != wxAsIs
) ||
1164 (constr
->height
.GetRelationship() != wxAsIs
))
1166 // _Should_ call Layout() recursively.
1167 child
->SetSize(x
, y
, w
, h
);
1176 node
= node
->Next();
1178 doneSoFar
.DeleteObject(win
);
1182 #endif // WXWIN_COMPATIBILITY
1186 sizerBehaviour
= wxSizerNone
;
1195 wxSizer::wxSizer(wxWindowBase
*parent
, wxSizerBehaviour behav
)
1197 Create(parent
, behav
);
1200 bool wxSizer::Create(wxWindowBase
*parent
, wxSizerBehaviour behav
)
1202 sizerBehaviour
= behav
;
1205 m_sizerParent
= parent
;
1211 // A normal window can have just one top-level sizer
1212 // associated with it.
1213 if (!parent
->IsKindOf(CLASSINFO(wxSizer
)))
1215 parent
->SetSizer(this);
1218 ((wxSizer
*)parent
)->AddSizerChild(this);
1220 switch (sizerBehaviour
)
1224 // Defines a set of constraints
1225 // to expand the sizer to fit the parent window
1226 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1228 c
->left
.SameAs(parent
, wxLeft
, 0);
1229 c
->top
.SameAs(parent
, wxTop
, 0);
1230 c
->right
.SameAs(parent
, wxRight
, 0);
1231 c
->bottom
.SameAs(parent
, wxBottom
, 0);
1247 // Remove all children without deleting them,
1248 // or ~wxbWindow will delete proper windows _twice_
1249 wxNode
*node
= GetChildren().First();
1252 wxNode
*next
= node
->Next();
1253 wxWindowBase
*win
= (wxWindowBase
*)node
->Data();
1254 if (!win
->IsKindOf(CLASSINFO(wxSizer
)))
1257 win
->SetSizerParent((wxWindowBase
*) NULL
);
1261 RemoveSizerChild(win
);
1267 if (m_sizerParent
) // && !m_sizerParent->IsKindOf(CLASSINFO(wxSizer)))
1269 m_sizerParent
->SetSizer((wxSizer
*) NULL
);
1270 m_sizerParent
= (wxWindowBase
*) NULL
;
1275 void wxSizer::SetBorder(int x
, int y
)
1279 /* No: the margin is for inside, not outside (expansion)
1281 if ( GetConstraints() )
1283 GetConstraints()->left.SetMargin(x);
1284 GetConstraints()->right.SetMargin(x);
1285 GetConstraints()->top.SetMargin(y);
1286 GetConstraints()->bottom.SetMargin(y);
1292 void wxSizer::AddSizerChild(wxWindowBase
*child
)
1294 child
->SetSizerParent(this);
1295 GetChildren().Append(child
);
1297 // Add some constraints for the purpose of storing
1298 // the relative position of the window/sizer
1299 // during layout calculations.
1300 if (!child
->GetConstraints())
1302 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1308 child
->GetSize(&w
, &h
);
1309 c
->width
.SetValue(w
);
1310 c
->height
.SetValue(h
);
1312 child
->SetConstraints(c
);
1316 void wxSizer::RemoveSizerChild(wxWindowBase
*child
)
1318 GetChildren().DeleteObject(child
);
1321 void wxSizer::DoSetSize(int x
, int y
, int w
, int h
, int WXUNUSED(flags
))
1323 wxLayoutConstraints
*constr
= GetConstraints();
1328 constr
->left
.SetValue(x
);
1334 constr
->top
.SetValue(y
);
1340 constr
->width
.SetValue(w
);
1346 constr
->height
.SetValue(h
);
1350 void wxSizer::DoGetSize(int *w
, int *h
) const
1356 void wxSizer::DoGetPosition(int *x
, int *y
) const
1362 bool wxSizer::LayoutPhase1(int *noChanges
)
1365 switch (sizerBehaviour
)
1371 wxMessageBox(_("wxExpandSizer has no parent!"), _("Sizer error"), wxOK
);
1375 // Set the size to fill the parent client area
1377 m_sizerParent
->GetClientSize(&pw
, &ph
);
1378 SetSize(GetBorderX(), GetBorderY(), pw
- 2*GetBorderX(), ph
- 2*GetBorderY());
1379 wxLayoutConstraints
*constr
= GetConstraints();
1381 // Fill in the constraints
1384 constr
->left
.SetValue(0); constr
->left
.SetDone(TRUE
);
1385 constr
->top
.SetValue(0); constr
->right
.SetDone(TRUE
);
1386 constr
->width
.SetValue(pw
); constr
->width
.SetDone(TRUE
);
1387 constr
->height
.SetValue(ph
); constr
->height
.SetDone(TRUE
);
1395 wxLayoutConstraints
*constr
= GetConstraints();
1399 // Force the constraint to have as-is width and height
1400 // if we're in shrink-to-fit mode, because if left unconstrained,
1401 // SatisfyConstraints will fail. The shrink-to-fit option
1402 // essentially specifies the width and height as 'whatever I calculate'.
1403 constr
->width
.AsIs();
1404 constr
->height
.AsIs();
1408 // Find the bounding box and set own size
1412 wxNode
*node
= GetChildren().First();
1415 int x
, y
, width
, height
;
1416 wxWindowBase
*win
= (wxWindowBase
*)node
->Data();
1417 win
->GetSizeConstraint(&width
, &height
);
1418 win
->GetPositionConstraint(&x
, &y
);
1419 if ((x
+width
) > maxX
)
1421 if ((y
+height
) > maxY
)
1422 maxY
= (y
+ height
);
1424 node
= node
->Next();
1426 SetSize(GetBorderX(), GetBorderY(), maxX
, maxY
);
1428 // If this is the only sizer for the parent, size the parent to this sizer.
1429 if ( m_sizerParent
&& (m_sizerParent
->GetSizer() == this) )
1430 m_sizerParent
->SetClientSize(maxX
+ 2*GetBorderX(), maxY
+ 2*GetBorderY());
1437 wxLayoutConstraints
*constr
= GetConstraints();
1440 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1443 int x
= constr
->left
.GetValue();
1444 int y
= constr
->top
.GetValue();
1445 int w
= constr
->width
.GetValue();
1446 int h
= constr
->height
.GetValue();
1447 SetSize(x
, y
, w
, h
);
1460 bool wxSizer::LayoutPhase2(int *noChanges
)
1464 switch (sizerBehaviour
)
1475 wxLayoutConstraints
*constr
= GetConstraints();
1478 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1481 int x
= constr
->left
.GetValue();
1482 int y
= constr
->top
.GetValue();
1495 // Is this a dumb fix for lack of constraint evaluation?
1496 wxLayoutConstraints
*constr
= GetConstraints();
1499 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1502 int x
= constr
->left
.GetValue();
1503 int y
= constr
->top
.GetValue();
1504 int w
= constr
->width
.GetValue();
1505 int h
= constr
->height
.GetValue();
1506 SetSize(x
, y
, w
, h
);
1521 wxRowColSizer::wxRowColSizer()
1529 wxRowColSizer::wxRowColSizer(wxWindowBase
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1531 Create(parent
, rc
, n
, behav
);
1534 bool wxRowColSizer::Create(wxWindowBase
*parent
, bool rc
, int n
, wxSizerBehaviour behav
)
1536 wxSizer::Create(parent
, behav
);
1546 wxRowColSizer::~wxRowColSizer()
1550 bool wxRowColSizer::LayoutPhase1(int *noChanges
)
1553 wxLayoutConstraints
*constr
= GetConstraints();
1557 // Force the constraint to have as-is width and height
1558 // if we're in shrink-to-fit mode, because if left unconstrained,
1559 // SatisfyConstraints will fail. The shrink-to-fit option
1560 // essentially specifies the width and height as 'whatever I calculate'.
1561 if (sizerBehaviour
== wxSizerShrink
)
1563 constr
->width
.AsIs();
1564 constr
->height
.AsIs();
1567 // Only evaluate the constraints FIRST if we're NOT
1568 // in shrink-to-fit mode, i.e. we want to size the rowcol
1569 // first, then lay the children out in the space we've calculated.
1570 if (sizerBehaviour
!= wxSizerShrink
)
1572 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1575 int x
= constr
->left
.GetValue();
1576 int y
= constr
->top
.GetValue();
1577 int w
= constr
->width
.GetValue();
1578 int h
= constr
->height
.GetValue();
1579 SetSize(x
, y
, w
, h
);
1584 // Continue to do the rest of the phase when the constraints have been
1585 // satisfied, i.e. we're on the last iteration of phase 1 and
1586 // can now do the actual rowcol laying out.
1590 // If we ARE in shrink-to-fit mode, we must now
1591 // calculate the child sizes BEFORE laying out in rows or columns.
1592 if (sizerBehaviour
== wxSizerShrink
)
1597 // WILL THE WINDOW BE SIZED CORRECTLY AT THIS POINT?
1598 // CHECK CONSTRAINTS IF ANY...
1601 int currentX
= borderX
;
1602 int currentY
= borderY
;
1603 int maxX
= currentX
;
1604 int maxY
= currentY
;
1606 wxNode
*node
= GetChildren().First();
1609 wxWindowBase
*win
= (wxWindowBase
*)node
->Data();
1610 int childWidth
, childHeight
;
1611 if (win
->GetConstraints() &&
1612 win
->GetConstraints()->width
.GetDone() &&
1613 win
->GetConstraints()->height
.GetDone())
1615 childWidth
= win
->GetConstraints()->width
.GetValue();
1616 childHeight
= win
->GetConstraints()->height
.GetValue();
1619 win
->GetSize(&childWidth
, &childHeight
);
1621 win
->MoveConstraint(currentX
, currentY
);
1623 if ((currentX
+ childWidth
) > maxX
)
1624 maxX
= (currentX
+ childWidth
);
1625 if ((currentY
+ childHeight
) > maxY
)
1626 maxY
= (currentY
+ childHeight
);
1630 currentX
+= childWidth
+ xSpacing
;
1633 // Reset to start of row
1634 if (noCols
== rowOrColSize
)
1637 currentY
+= childHeight
+ ySpacing
;
1643 currentY
+= childHeight
+ ySpacing
;
1646 // Reset to start of col
1647 if (noRows
== rowOrColSize
)
1650 currentX
+= childWidth
+ xSpacing
;
1655 node
= node
->Next();
1660 SetSize(-1, -1, maxX
, maxY
);
1665 bool wxRowColSizer::LayoutPhase2(int *noChanges
)
1669 // If shrink-to-fit, it's only at Phase 2 that we know the size of
1670 // the wxRowColSizer, and now we can evaluate the
1671 // constraints and pass result back up to parent.
1672 // This implements a depth-first strategy
1673 if (sizerBehaviour
== wxSizerShrink
)
1675 wxLayoutConstraints
*constr
= GetConstraints();
1678 bool success
= constr
->SatisfyConstraints(this, noChanges
);
1681 int x
= constr
->left
.GetValue();
1682 int y
= constr
->top
.GetValue();
1691 // Lay out the children: breadth-first strategy.
1705 wxSpacingSizer::wxSpacingSizer()
1709 wxSpacingSizer::wxSpacingSizer(wxWindowBase
*parent
)
1714 wxSpacingSizer::wxSpacingSizer(wxWindowBase
*parent
, wxRelationship rel
, wxWindowBase
*other
, int spacing
)
1716 Create(parent
, rel
, other
, spacing
);
1719 bool wxSpacingSizer::Create(wxWindowBase
*parent
)
1721 wxSizer::Create(parent
);
1725 bool wxSpacingSizer::Create(wxWindowBase
*parent
, wxRelationship rel
, wxWindowBase
*other
, int spacing
)
1727 wxLayoutConstraints
*c
= new wxLayoutConstraints
;
1729 wxSizer::Create(parent
);
1734 c
->width
.Absolute (spacing
);
1735 c
->top
.SameAs (other
, wxTop
);
1736 c
->bottom
.SameAs (other
, wxBottom
);
1737 c
->right
.LeftOf (other
);
1740 c
->width
.Absolute (spacing
);
1741 c
->top
.SameAs (other
, wxTop
);
1742 c
->bottom
.SameAs (other
, wxBottom
);
1743 c
->left
.RightOf (other
);
1746 c
->height
.Absolute (spacing
);
1747 c
->left
.SameAs (other
, wxLeft
);
1748 c
->right
.SameAs (other
, wxRight
);
1749 c
->top
.Below (other
);
1752 c
->height
.Absolute (spacing
);
1753 c
->left
.SameAs (other
, wxLeft
);
1754 c
->right
.SameAs (other
, wxRight
);
1755 c
->bottom
.Above (other
);
1766 wxSpacingSizer::~wxSpacingSizer()
1770 #endif // wxUSE_CONSTRAINTS