1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/layout.cpp
3 // Purpose: Constraint layout system classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // =============================================================================
14 // =============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/layout.h"
32 #include "wx/window.h"
34 #include "wx/dialog.h"
35 #include "wx/msgdlg.h"
40 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
41 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
44 inline void wxGetAsIs(wxWindowBase
* win
, int* w
, int* h
)
47 // The old way. Works for me.
52 // Vadim's change. Breaks wxPython's LayoutAnchors
53 win
->GetBestSize(w
, h
);
57 // Proposed compromise. Doesn't work.
59 win
->GetSize(&sw
, &sh
);
60 win
->GetBestSize(&bw
, &bh
);
69 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
72 relationship
= wxUnconstrained
;
78 otherWin
= (wxWindowBase
*) NULL
;
81 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindowBase
*otherW
, wxEdge otherE
, int val
, int marg
)
85 // If Set is called by the user with wxSameAs then call SameAs to do
86 // it since it will actually use wxPercent instead.
87 SameAs(otherW
, otherE
, marg
);
95 if ( rel
== wxPercentOf
)
107 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase
*sibling
, int marg
)
109 Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
);
112 void wxIndividualLayoutConstraint::RightOf(wxWindowBase
*sibling
, int marg
)
114 Set(wxRightOf
, sibling
, wxRight
, 0, marg
);
117 void wxIndividualLayoutConstraint::Above(wxWindowBase
*sibling
, int marg
)
119 Set(wxAbove
, sibling
, wxTop
, 0, marg
);
122 void wxIndividualLayoutConstraint::Below(wxWindowBase
*sibling
, int marg
)
124 Set(wxBelow
, sibling
, wxBottom
, 0, marg
);
128 // 'Same edge' alignment
130 void wxIndividualLayoutConstraint::SameAs(wxWindowBase
*otherW
, wxEdge edge
, int marg
)
132 Set(wxPercentOf
, otherW
, edge
, 100, marg
);
135 // The edge is a percentage of the other window's edge
136 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase
*otherW
, wxEdge wh
, int per
)
138 Set(wxPercentOf
, otherW
, wh
, per
);
142 // Edge has absolute value
144 void wxIndividualLayoutConstraint::Absolute(int val
)
147 relationship
= wxAbsolute
;
150 // Reset constraint if it mentions otherWin
151 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase
*otherW
)
153 if (otherW
== otherWin
)
156 relationship
= wxAsIs
;
161 otherWin
= (wxWindowBase
*) NULL
;
168 // Try to satisfy constraint
169 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindowBase
*win
)
171 if (relationship
== wxAbsolute
)
181 switch (relationship
)
185 // We can know this edge if: otherWin is win's
186 // parent, or otherWin has a satisfied constraint,
187 // or otherWin has no constraint.
188 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
191 value
= edgePos
- margin
;
200 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
203 value
= edgePos
+ margin
;
212 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
215 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
222 case wxUnconstrained
:
224 // We know the left-hand edge position if we know
225 // the right-hand edge and we know the width; OR if
226 // we know the centre and the width.
227 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
229 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
233 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
235 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
245 win
->GetPosition(&value
, &y
);
256 switch (relationship
)
260 // We can know this edge if: otherWin is win's
261 // parent, or otherWin has a satisfied constraint,
262 // or otherWin has no constraint.
263 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
266 value
= edgePos
- margin
;
275 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
278 value
= edgePos
+ margin
;
287 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
290 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
297 case wxUnconstrained
:
299 // We know the right-hand edge position if we know the
300 // left-hand edge and we know the width, OR if we know the
301 // centre edge and the width.
302 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
304 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
308 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
310 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
321 wxGetAsIs(win
, &w
, &h
);
322 win
->GetPosition(&x
, &y
);
334 switch (relationship
)
338 // We can know this edge if: otherWin is win's
339 // parent, or otherWin has a satisfied constraint,
340 // or otherWin has no constraint.
341 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
344 value
= edgePos
- margin
;
353 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
356 value
= edgePos
+ margin
;
365 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
368 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
375 case wxUnconstrained
:
377 // We know the top edge position if we know the bottom edge
378 // and we know the height; OR if we know the centre edge and
380 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
382 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
386 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
388 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
398 win
->GetPosition(&x
, &value
);
409 switch (relationship
)
413 // We can know this edge if: otherWin is win's parent,
414 // or otherWin has a satisfied constraint, or
415 // otherWin has no constraint.
416 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
419 value
= edgePos
+ margin
;
428 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
431 value
= edgePos
- margin
;
440 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
443 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
450 case wxUnconstrained
:
452 // We know the bottom edge position if we know the top edge
453 // and we know the height; OR if we know the centre edge and
455 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
457 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
461 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
463 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
474 wxGetAsIs(win
, &w
, &h
);
475 win
->GetPosition(&x
, &y
);
487 switch (relationship
)
491 // We can know this edge if: otherWin is win's parent, or
492 // otherWin has a satisfied constraint, or otherWin has no
494 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
497 value
= edgePos
- margin
;
506 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
509 value
= edgePos
+ margin
;
518 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
521 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
528 case wxUnconstrained
:
530 // We know the centre position if we know
531 // the left-hand edge and we know the width, OR
532 // the right-hand edge and the width
533 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
535 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
539 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
541 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
555 switch (relationship
)
559 // We can know this edge if: otherWin is win's parent,
560 // or otherWin has a satisfied constraint, or otherWin
561 // has no constraint.
562 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
565 value
= edgePos
- margin
;
574 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
577 value
= edgePos
+ margin
;
586 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
589 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
596 case wxUnconstrained
:
598 // We know the centre position if we know
599 // the top edge and we know the height, OR
600 // the bottom edge and the height.
601 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
603 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
607 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
609 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
623 switch (relationship
)
627 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
630 value
= (int)(edgePos
*(((float)percent
)*0.01));
642 wxGetAsIs(win
, &value
, &h
);
648 case wxUnconstrained
:
650 // We know the width if we know the left edge and the right edge, OR
651 // if we know the left edge and the centre, OR
652 // if we know the right edge and the centre
653 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
655 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
659 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
661 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
665 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
667 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
681 switch (relationship
)
685 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
688 value
= (int)(edgePos
*(((float)percent
)*0.01));
700 wxGetAsIs(win
, &w
, &value
);
706 case wxUnconstrained
:
708 // We know the height if we know the top edge and the bottom edge, OR
709 // if we know the top edge and the centre, OR
710 // if we know the bottom edge and the centre
711 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
713 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
717 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
719 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
723 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
725 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
743 // Get the value of this edge or dimension, or if this is not determinable, -1.
744 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
745 wxWindowBase
*thisWin
,
746 wxWindowBase
*other
) const
748 // If the edge or dimension belongs to the parent, then we know the
749 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
750 // button (but the button's true parent is a panel, not the sizer)
751 if (other
->GetChildren().Find((wxWindow
*)thisWin
))
766 other
->GetClientSizeConstraint(&w
, &h
);
772 other
->GetClientSizeConstraint(&w
, &h
);
778 other
->GetClientSizeConstraint(&w
, &h
);
784 other
->GetClientSizeConstraint(&w
, &h
);
791 other
->GetClientSizeConstraint(&w
, &h
);
792 if (which
== wxCentreX
)
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
->left
.GetDone())
811 return constr
->left
.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
->top
.GetDone())
830 return constr
->top
.GetValue();
837 other
->GetPosition(&x
, &y
);
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
->right
.GetDone())
849 return constr
->right
.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
->bottom
.GetDone())
869 return constr
->bottom
.GetValue();
876 other
->GetPosition(&x
, &y
);
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
->width
.GetDone())
889 return constr
->width
.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
->height
.GetDone())
908 return constr
->height
.GetValue();
915 other
->GetSize(&w
, &h
);
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
->centreX
.GetDone())
927 return constr
->centreX
.GetValue();
934 other
->GetPosition(&x
, &y
);
935 other
->GetSize(&w
, &h
);
936 return (int)(x
+ (w
/2));
941 wxLayoutConstraints
*constr
= other
->GetConstraints();
942 // If no constraints, it means the window is not dependent
943 // on anything, and therefore we know its value immediately
946 if (constr
->centreY
.GetDone())
947 return constr
->centreY
.GetValue();
954 other
->GetPosition(&x
, &y
);
955 other
->GetSize(&w
, &h
);
956 return (int)(y
+ (h
/2));
965 wxLayoutConstraints::wxLayoutConstraints()
967 left
.SetEdge(wxLeft
);
969 right
.SetEdge(wxRight
);
970 bottom
.SetEdge(wxBottom
);
971 centreX
.SetEdge(wxCentreX
);
972 centreY
.SetEdge(wxCentreY
);
973 width
.SetEdge(wxWidth
);
974 height
.SetEdge(wxHeight
);
977 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase
*win
, int *nChanges
)
981 bool done
= width
.GetDone();
982 bool newDone
= (done
? true : width
.SatisfyConstraint(this, win
));
986 done
= height
.GetDone();
987 newDone
= (done
? true : height
.SatisfyConstraint(this, win
));
991 done
= left
.GetDone();
992 newDone
= (done
? true : left
.SatisfyConstraint(this, win
));
996 done
= top
.GetDone();
997 newDone
= (done
? true : top
.SatisfyConstraint(this, win
));
1001 done
= right
.GetDone();
1002 newDone
= (done
? true : right
.SatisfyConstraint(this, win
));
1003 if (newDone
!= done
)
1006 done
= bottom
.GetDone();
1007 newDone
= (done
? true : bottom
.SatisfyConstraint(this, win
));
1008 if (newDone
!= done
)
1011 done
= centreX
.GetDone();
1012 newDone
= (done
? true : centreX
.SatisfyConstraint(this, win
));
1013 if (newDone
!= done
)
1016 done
= centreY
.GetDone();
1017 newDone
= (done
? true : centreY
.SatisfyConstraint(this, win
));
1018 if (newDone
!= done
)
1021 *nChanges
= noChanges
;
1023 return AreSatisfied();
1026 #endif // wxUSE_CONSTRAINTS