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;
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;
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