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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
48 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
52 inline void wxGetAsIs(wxWindowBase
* win
, int* w
, int* h
)
55 // The old way. Works for me.
60 // Vadim's change. Breaks wxPython's LayoutAnchors
61 win
->GetBestSize(w
, h
);
65 // Proposed compromise. Doesn't work.
67 win
->GetSize(&sw
, &sh
);
68 win
->GetBestSize(&bw
, &bh
);
77 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
80 relationship
= wxUnconstrained
;
86 otherWin
= (wxWindowBase
*) NULL
;
89 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindowBase
*otherW
, wxEdge otherE
, int val
, int marg
)
93 // If Set is called by the user with wxSameAs then call SameAs to do
94 // it since it will actually use wxPercent instead.
95 SameAs(otherW
, otherE
, marg
);
103 if ( rel
== wxPercentOf
)
115 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase
*sibling
, int marg
)
117 Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
);
120 void wxIndividualLayoutConstraint::RightOf(wxWindowBase
*sibling
, int marg
)
122 Set(wxRightOf
, sibling
, wxRight
, 0, marg
);
125 void wxIndividualLayoutConstraint::Above(wxWindowBase
*sibling
, int marg
)
127 Set(wxAbove
, sibling
, wxTop
, 0, marg
);
130 void wxIndividualLayoutConstraint::Below(wxWindowBase
*sibling
, int marg
)
132 Set(wxBelow
, sibling
, wxBottom
, 0, marg
);
136 // 'Same edge' alignment
138 void wxIndividualLayoutConstraint::SameAs(wxWindowBase
*otherW
, wxEdge edge
, int marg
)
140 Set(wxPercentOf
, otherW
, edge
, 100, marg
);
143 // The edge is a percentage of the other window's edge
144 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase
*otherW
, wxEdge wh
, int per
)
146 Set(wxPercentOf
, otherW
, wh
, per
);
150 // Edge has absolute value
152 void wxIndividualLayoutConstraint::Absolute(int val
)
155 relationship
= wxAbsolute
;
158 // Reset constraint if it mentions otherWin
159 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase
*otherW
)
161 if (otherW
== otherWin
)
164 relationship
= wxAsIs
;
169 otherWin
= (wxWindowBase
*) NULL
;
176 // Try to satisfy constraint
177 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindowBase
*win
)
179 if (relationship
== wxAbsolute
)
189 switch (relationship
)
193 // We can know this edge if: otherWin is win's
194 // parent, or otherWin has a satisfied constraint,
195 // or otherWin has no constraint.
196 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
199 value
= edgePos
- margin
;
208 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
211 value
= edgePos
+ margin
;
220 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
223 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
230 case wxUnconstrained
:
232 // We know the left-hand edge position if we know
233 // the right-hand edge and we know the width; OR if
234 // we know the centre and the width.
235 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
237 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
241 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
243 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
253 win
->GetPosition(&value
, &y
);
264 switch (relationship
)
268 // We can know this edge if: otherWin is win's
269 // parent, or otherWin has a satisfied constraint,
270 // or otherWin has no constraint.
271 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
274 value
= edgePos
- margin
;
283 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
286 value
= edgePos
+ margin
;
295 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
298 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
305 case wxUnconstrained
:
307 // We know the right-hand edge position if we know the
308 // left-hand edge and we know the width, OR if we know the
309 // centre edge and the width.
310 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
312 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
316 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
318 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
329 wxGetAsIs(win
, &w
, &h
);
330 win
->GetPosition(&x
, &y
);
342 switch (relationship
)
346 // We can know this edge if: otherWin is win's
347 // parent, or otherWin has a satisfied constraint,
348 // or otherWin has no constraint.
349 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
352 value
= edgePos
- margin
;
361 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
364 value
= edgePos
+ margin
;
373 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
376 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
383 case wxUnconstrained
:
385 // We know the top edge position if we know the bottom edge
386 // and we know the height; OR if we know the centre edge and
388 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
390 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
394 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
396 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
406 win
->GetPosition(&x
, &value
);
417 switch (relationship
)
421 // We can know this edge if: otherWin is win's parent,
422 // or otherWin has a satisfied constraint, or
423 // otherWin has no constraint.
424 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
427 value
= edgePos
+ margin
;
436 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
439 value
= edgePos
- margin
;
448 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
451 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
458 case wxUnconstrained
:
460 // We know the bottom edge position if we know the top edge
461 // and we know the height; OR if we know the centre edge and
463 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
465 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
469 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
471 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
482 wxGetAsIs(win
, &w
, &h
);
483 win
->GetPosition(&x
, &y
);
495 switch (relationship
)
499 // We can know this edge if: otherWin is win's parent, or
500 // otherWin has a satisfied constraint, or otherWin has no
502 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
505 value
= edgePos
- margin
;
514 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
517 value
= edgePos
+ margin
;
526 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
529 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
536 case wxUnconstrained
:
538 // We know the centre position if we know
539 // the left-hand edge and we know the width, OR
540 // the right-hand edge and the width
541 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
543 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
547 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
549 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
563 switch (relationship
)
567 // We can know this edge if: otherWin is win's parent,
568 // or otherWin has a satisfied constraint, or otherWin
569 // has no constraint.
570 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
573 value
= edgePos
- margin
;
582 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
585 value
= edgePos
+ margin
;
594 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
597 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
604 case wxUnconstrained
:
606 // We know the centre position if we know
607 // the top edge and we know the height, OR
608 // the bottom edge and the height.
609 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
611 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
615 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
617 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
631 switch (relationship
)
635 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
638 value
= (int)(edgePos
*(((float)percent
)*0.01));
650 wxGetAsIs(win
, &value
, &h
);
656 case wxUnconstrained
:
658 // We know the width if we know the left edge and the right edge, OR
659 // if we know the left edge and the centre, OR
660 // if we know the right edge and the centre
661 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
663 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
667 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
669 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
673 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
675 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
689 switch (relationship
)
693 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
696 value
= (int)(edgePos
*(((float)percent
)*0.01));
708 wxGetAsIs(win
, &w
, &value
);
714 case wxUnconstrained
:
716 // We know the height if we know the top edge and the bottom edge, OR
717 // if we know the top edge and the centre, OR
718 // if we know the bottom edge and the centre
719 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
721 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
725 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
727 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
731 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
733 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
751 // Get the value of this edge or dimension, or if this is not determinable, -1.
752 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
753 wxWindowBase
*thisWin
,
754 wxWindowBase
*other
) const
756 // If the edge or dimension belongs to the parent, then we know the
757 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
758 // button (but the button's true parent is a panel, not the sizer)
759 if (other
->GetChildren().Find((wxWindow
*)thisWin
))
774 other
->GetClientSizeConstraint(&w
, &h
);
780 other
->GetClientSizeConstraint(&w
, &h
);
786 other
->GetClientSizeConstraint(&w
, &h
);
792 other
->GetClientSizeConstraint(&w
, &h
);
799 other
->GetClientSizeConstraint(&w
, &h
);
800 if (which
== wxCentreX
)
813 wxLayoutConstraints
*constr
= other
->GetConstraints();
814 // If no constraints, it means the window is not dependent
815 // on anything, and therefore we know its value immediately
818 if (constr
->left
.GetDone())
819 return constr
->left
.GetValue();
826 other
->GetPosition(&x
, &y
);
832 wxLayoutConstraints
*constr
= other
->GetConstraints();
833 // If no constraints, it means the window is not dependent
834 // on anything, and therefore we know its value immediately
837 if (constr
->top
.GetDone())
838 return constr
->top
.GetValue();
845 other
->GetPosition(&x
, &y
);
851 wxLayoutConstraints
*constr
= other
->GetConstraints();
852 // If no constraints, it means the window is not dependent
853 // on anything, and therefore we know its value immediately
856 if (constr
->right
.GetDone())
857 return constr
->right
.GetValue();
864 other
->GetPosition(&x
, &y
);
865 other
->GetSize(&w
, &h
);
871 wxLayoutConstraints
*constr
= other
->GetConstraints();
872 // If no constraints, it means the window is not dependent
873 // on anything, and therefore we know its value immediately
876 if (constr
->bottom
.GetDone())
877 return constr
->bottom
.GetValue();
884 other
->GetPosition(&x
, &y
);
885 other
->GetSize(&w
, &h
);
891 wxLayoutConstraints
*constr
= other
->GetConstraints();
892 // If no constraints, it means the window is not dependent
893 // on anything, and therefore we know its value immediately
896 if (constr
->width
.GetDone())
897 return constr
->width
.GetValue();
904 other
->GetSize(&w
, &h
);
910 wxLayoutConstraints
*constr
= other
->GetConstraints();
911 // If no constraints, it means the window is not dependent
912 // on anything, and therefore we know its value immediately
915 if (constr
->height
.GetDone())
916 return constr
->height
.GetValue();
923 other
->GetSize(&w
, &h
);
929 wxLayoutConstraints
*constr
= other
->GetConstraints();
930 // If no constraints, it means the window is not dependent
931 // on anything, and therefore we know its value immediately
934 if (constr
->centreX
.GetDone())
935 return constr
->centreX
.GetValue();
942 other
->GetPosition(&x
, &y
);
943 other
->GetSize(&w
, &h
);
944 return (int)(x
+ (w
/2));
949 wxLayoutConstraints
*constr
= other
->GetConstraints();
950 // If no constraints, it means the window is not dependent
951 // on anything, and therefore we know its value immediately
954 if (constr
->centreY
.GetDone())
955 return constr
->centreY
.GetValue();
962 other
->GetPosition(&x
, &y
);
963 other
->GetSize(&w
, &h
);
964 return (int)(y
+ (h
/2));
973 wxLayoutConstraints::wxLayoutConstraints()
975 left
.SetEdge(wxLeft
);
977 right
.SetEdge(wxRight
);
978 bottom
.SetEdge(wxBottom
);
979 centreX
.SetEdge(wxCentreX
);
980 centreY
.SetEdge(wxCentreY
);
981 width
.SetEdge(wxWidth
);
982 height
.SetEdge(wxHeight
);
985 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase
*win
, int *nChanges
)
989 bool done
= width
.GetDone();
990 bool newDone
= (done
? true : width
.SatisfyConstraint(this, win
));
994 done
= height
.GetDone();
995 newDone
= (done
? true : height
.SatisfyConstraint(this, win
));
999 done
= left
.GetDone();
1000 newDone
= (done
? true : left
.SatisfyConstraint(this, win
));
1001 if (newDone
!= done
)
1004 done
= top
.GetDone();
1005 newDone
= (done
? true : top
.SatisfyConstraint(this, win
));
1006 if (newDone
!= done
)
1009 done
= right
.GetDone();
1010 newDone
= (done
? true : right
.SatisfyConstraint(this, win
));
1011 if (newDone
!= done
)
1014 done
= bottom
.GetDone();
1015 newDone
= (done
? true : bottom
.SatisfyConstraint(this, win
));
1016 if (newDone
!= done
)
1019 done
= centreX
.GetDone();
1020 newDone
= (done
? true : centreX
.SatisfyConstraint(this, win
));
1021 if (newDone
!= done
)
1024 done
= centreY
.GetDone();
1025 newDone
= (done
? true : centreY
.SatisfyConstraint(this, win
));
1026 if (newDone
!= done
)
1029 *nChanges
= noChanges
;
1031 return AreSatisfied();
1034 #endif // wxUSE_CONSTRAINTS