1 /////////////////////////////////////////////////////////////////////////////
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"
34 #include "wx/window.h"
36 #include "wx/dialog.h"
37 #include "wx/msgdlg.h"
41 #include "wx/layout.h"
43 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
44 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
48 inline void wxGetAsIs(wxWindowBase
* win
, int* w
, int* h
)
51 // The old way. Works for me.
56 // Vadim's change. Breaks wxPython's LayoutAnchors
57 win
->GetBestSize(w
, h
);
61 // Proposed compromise. Doesn't work.
63 win
->GetSize(&sw
, &sh
);
64 win
->GetBestSize(&bw
, &bh
);
73 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
76 relationship
= wxUnconstrained
;
82 otherWin
= (wxWindowBase
*) NULL
;
85 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindowBase
*otherW
, wxEdge otherE
, int val
, int marg
)
89 // If Set is called by the user with wxSameAs then call SameAs to do
90 // it since it will actually use wxPercent instead.
91 SameAs(otherW
, otherE
, marg
);
99 if ( rel
== wxPercentOf
)
111 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase
*sibling
, int marg
)
113 Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
);
116 void wxIndividualLayoutConstraint::RightOf(wxWindowBase
*sibling
, int marg
)
118 Set(wxRightOf
, sibling
, wxRight
, 0, marg
);
121 void wxIndividualLayoutConstraint::Above(wxWindowBase
*sibling
, int marg
)
123 Set(wxAbove
, sibling
, wxTop
, 0, marg
);
126 void wxIndividualLayoutConstraint::Below(wxWindowBase
*sibling
, int marg
)
128 Set(wxBelow
, sibling
, wxBottom
, 0, marg
);
132 // 'Same edge' alignment
134 void wxIndividualLayoutConstraint::SameAs(wxWindowBase
*otherW
, wxEdge edge
, int marg
)
136 Set(wxPercentOf
, otherW
, edge
, 100, marg
);
139 // The edge is a percentage of the other window's edge
140 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase
*otherW
, wxEdge wh
, int per
)
142 Set(wxPercentOf
, otherW
, wh
, per
);
146 // Edge has absolute value
148 void wxIndividualLayoutConstraint::Absolute(int val
)
151 relationship
= wxAbsolute
;
154 // Reset constraint if it mentions otherWin
155 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase
*otherW
)
157 if (otherW
== otherWin
)
160 relationship
= wxAsIs
;
165 otherWin
= (wxWindowBase
*) NULL
;
172 // Try to satisfy constraint
173 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindowBase
*win
)
175 if (relationship
== wxAbsolute
)
185 switch (relationship
)
189 // We can know this edge if: otherWin is win's
190 // parent, or otherWin has a satisfied constraint,
191 // or otherWin has no constraint.
192 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
195 value
= edgePos
- margin
;
204 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
207 value
= edgePos
+ margin
;
216 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
219 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
226 case wxUnconstrained
:
228 // We know the left-hand edge position if we know
229 // the right-hand edge and we know the width; OR if
230 // we know the centre and the width.
231 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
233 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
237 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
239 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
249 win
->GetPosition(&value
, &y
);
260 switch (relationship
)
264 // We can know this edge if: otherWin is win's
265 // parent, or otherWin has a satisfied constraint,
266 // or otherWin has no constraint.
267 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
270 value
= edgePos
- margin
;
279 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
282 value
= edgePos
+ margin
;
291 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
294 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
301 case wxUnconstrained
:
303 // We know the right-hand edge position if we know the
304 // left-hand edge and we know the width, OR if we know the
305 // centre edge and the width.
306 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
308 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
312 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
314 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
325 wxGetAsIs(win
, &w
, &h
);
326 win
->GetPosition(&x
, &y
);
338 switch (relationship
)
342 // We can know this edge if: otherWin is win's
343 // parent, or otherWin has a satisfied constraint,
344 // or otherWin has no constraint.
345 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
348 value
= edgePos
- margin
;
357 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
360 value
= edgePos
+ margin
;
369 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
372 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
379 case wxUnconstrained
:
381 // We know the top edge position if we know the bottom edge
382 // and we know the height; OR if we know the centre edge and
384 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
386 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
390 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
392 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
402 win
->GetPosition(&x
, &value
);
413 switch (relationship
)
417 // We can know this edge if: otherWin is win's parent,
418 // or otherWin has a satisfied constraint, or
419 // otherWin has no constraint.
420 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
423 value
= edgePos
+ margin
;
432 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
435 value
= edgePos
- margin
;
444 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
447 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
454 case wxUnconstrained
:
456 // We know the bottom edge position if we know the top edge
457 // and we know the height; OR if we know the centre edge and
459 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
461 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
465 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
467 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
478 wxGetAsIs(win
, &w
, &h
);
479 win
->GetPosition(&x
, &y
);
491 switch (relationship
)
495 // We can know this edge if: otherWin is win's parent, or
496 // otherWin has a satisfied constraint, or otherWin has no
498 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
501 value
= edgePos
- margin
;
510 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
513 value
= edgePos
+ margin
;
522 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
525 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
532 case wxUnconstrained
:
534 // We know the centre position if we know
535 // the left-hand edge and we know the width, OR
536 // the right-hand edge and the width
537 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
539 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
543 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
545 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
559 switch (relationship
)
563 // We can know this edge if: otherWin is win's parent,
564 // or otherWin has a satisfied constraint, or otherWin
565 // has no constraint.
566 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
569 value
= edgePos
- margin
;
578 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
581 value
= edgePos
+ margin
;
590 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
593 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
600 case wxUnconstrained
:
602 // We know the centre position if we know
603 // the top edge and we know the height, OR
604 // the bottom edge and the height.
605 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
607 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
611 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
613 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
627 switch (relationship
)
631 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
634 value
= (int)(edgePos
*(((float)percent
)*0.01));
646 wxGetAsIs(win
, &value
, &h
);
652 case wxUnconstrained
:
654 // We know the width if we know the left edge and the right edge, OR
655 // if we know the left edge and the centre, OR
656 // if we know the right edge and the centre
657 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
659 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
663 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
665 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
669 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
671 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
685 switch (relationship
)
689 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
692 value
= (int)(edgePos
*(((float)percent
)*0.01));
704 wxGetAsIs(win
, &w
, &value
);
710 case wxUnconstrained
:
712 // We know the height if we know the top edge and the bottom edge, OR
713 // if we know the top edge and the centre, OR
714 // if we know the bottom edge and the centre
715 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
717 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
721 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
723 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
727 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
729 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
747 // Get the value of this edge or dimension, or if this is not determinable, -1.
748 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
749 wxWindowBase
*thisWin
,
750 wxWindowBase
*other
) const
752 // If the edge or dimension belongs to the parent, then we know the
753 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
754 // button (but the button's true parent is a panel, not the sizer)
755 if (other
->GetChildren().Find((wxWindow
*)thisWin
))
770 other
->GetClientSizeConstraint(&w
, &h
);
776 other
->GetClientSizeConstraint(&w
, &h
);
782 other
->GetClientSizeConstraint(&w
, &h
);
788 other
->GetClientSizeConstraint(&w
, &h
);
795 other
->GetClientSizeConstraint(&w
, &h
);
796 if (which
== wxCentreX
)
809 wxLayoutConstraints
*constr
= other
->GetConstraints();
810 // If no constraints, it means the window is not dependent
811 // on anything, and therefore we know its value immediately
814 if (constr
->left
.GetDone())
815 return constr
->left
.GetValue();
822 other
->GetPosition(&x
, &y
);
828 wxLayoutConstraints
*constr
= other
->GetConstraints();
829 // If no constraints, it means the window is not dependent
830 // on anything, and therefore we know its value immediately
833 if (constr
->top
.GetDone())
834 return constr
->top
.GetValue();
841 other
->GetPosition(&x
, &y
);
847 wxLayoutConstraints
*constr
= other
->GetConstraints();
848 // If no constraints, it means the window is not dependent
849 // on anything, and therefore we know its value immediately
852 if (constr
->right
.GetDone())
853 return constr
->right
.GetValue();
860 other
->GetPosition(&x
, &y
);
861 other
->GetSize(&w
, &h
);
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
->bottom
.GetDone())
873 return constr
->bottom
.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
->width
.GetDone())
893 return constr
->width
.GetValue();
900 other
->GetSize(&w
, &h
);
906 wxLayoutConstraints
*constr
= other
->GetConstraints();
907 // If no constraints, it means the window is not dependent
908 // on anything, and therefore we know its value immediately
911 if (constr
->height
.GetDone())
912 return constr
->height
.GetValue();
919 other
->GetSize(&w
, &h
);
925 wxLayoutConstraints
*constr
= other
->GetConstraints();
926 // If no constraints, it means the window is not dependent
927 // on anything, and therefore we know its value immediately
930 if (constr
->centreX
.GetDone())
931 return constr
->centreX
.GetValue();
938 other
->GetPosition(&x
, &y
);
939 other
->GetSize(&w
, &h
);
940 return (int)(x
+ (w
/2));
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
->centreY
.GetDone())
951 return constr
->centreY
.GetValue();
958 other
->GetPosition(&x
, &y
);
959 other
->GetSize(&w
, &h
);
960 return (int)(y
+ (h
/2));
969 wxLayoutConstraints::wxLayoutConstraints()
971 left
.SetEdge(wxLeft
);
973 right
.SetEdge(wxRight
);
974 bottom
.SetEdge(wxBottom
);
975 centreX
.SetEdge(wxCentreX
);
976 centreY
.SetEdge(wxCentreY
);
977 width
.SetEdge(wxWidth
);
978 height
.SetEdge(wxHeight
);
981 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase
*win
, int *nChanges
)
985 bool done
= width
.GetDone();
986 bool newDone
= (done
? true : width
.SatisfyConstraint(this, win
));
990 done
= height
.GetDone();
991 newDone
= (done
? true : height
.SatisfyConstraint(this, win
));
995 done
= left
.GetDone();
996 newDone
= (done
? true : left
.SatisfyConstraint(this, win
));
1000 done
= top
.GetDone();
1001 newDone
= (done
? true : top
.SatisfyConstraint(this, win
));
1002 if (newDone
!= done
)
1005 done
= right
.GetDone();
1006 newDone
= (done
? true : right
.SatisfyConstraint(this, win
));
1007 if (newDone
!= done
)
1010 done
= bottom
.GetDone();
1011 newDone
= (done
? true : bottom
.SatisfyConstraint(this, win
));
1012 if (newDone
!= done
)
1015 done
= centreX
.GetDone();
1016 newDone
= (done
? true : centreX
.SatisfyConstraint(this, win
));
1017 if (newDone
!= done
)
1020 done
= centreY
.GetDone();
1021 newDone
= (done
? true : centreY
.SatisfyConstraint(this, win
));
1022 if (newDone
!= done
)
1025 *nChanges
= noChanges
;
1027 return AreSatisfied();
1030 #endif // wxUSE_CONSTRAINTS