1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/layout.cpp
3 // Purpose: Constraint layout system classes
4 // Author: Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // =============================================================================
13 // =============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
28 #include "wx/layout.h"
31 #include "wx/window.h"
33 #include "wx/dialog.h"
34 #include "wx/msgdlg.h"
39 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint
, wxObject
)
40 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints
, wxObject
)
43 inline void wxGetAsIs(wxWindowBase
* win
, int* w
, int* h
)
46 // The old way. Works for me.
51 // Vadim's change. Breaks wxPython's LayoutAnchors
52 win
->GetBestSize(w
, h
);
56 // Proposed compromise. Doesn't work.
58 win
->GetSize(&sw
, &sh
);
59 win
->GetBestSize(&bw
, &bh
);
68 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
71 relationship
= wxUnconstrained
;
80 void wxIndividualLayoutConstraint::Set(wxRelationship rel
, wxWindowBase
*otherW
, wxEdge otherE
, int val
, int marg
)
84 // If Set is called by the user with wxSameAs then call SameAs to do
85 // it since it will actually use wxPercent instead.
86 SameAs(otherW
, otherE
, marg
);
94 if ( rel
== wxPercentOf
)
106 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase
*sibling
, int marg
)
108 Set(wxLeftOf
, sibling
, wxLeft
, 0, marg
);
111 void wxIndividualLayoutConstraint::RightOf(wxWindowBase
*sibling
, int marg
)
113 Set(wxRightOf
, sibling
, wxRight
, 0, marg
);
116 void wxIndividualLayoutConstraint::Above(wxWindowBase
*sibling
, int marg
)
118 Set(wxAbove
, sibling
, wxTop
, 0, marg
);
121 void wxIndividualLayoutConstraint::Below(wxWindowBase
*sibling
, int marg
)
123 Set(wxBelow
, sibling
, wxBottom
, 0, marg
);
127 // 'Same edge' alignment
129 void wxIndividualLayoutConstraint::SameAs(wxWindowBase
*otherW
, wxEdge edge
, int marg
)
131 Set(wxPercentOf
, otherW
, edge
, 100, marg
);
134 // The edge is a percentage of the other window's edge
135 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase
*otherW
, wxEdge wh
, int per
)
137 Set(wxPercentOf
, otherW
, wh
, per
);
141 // Edge has absolute value
143 void wxIndividualLayoutConstraint::Absolute(int val
)
146 relationship
= wxAbsolute
;
149 // Reset constraint if it mentions otherWin
150 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase
*otherW
)
152 if (otherW
== otherWin
)
155 relationship
= wxAsIs
;
167 // Try to satisfy constraint
168 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints
*constraints
, wxWindowBase
*win
)
170 if (relationship
== wxAbsolute
)
180 switch (relationship
)
184 // We can know this edge if: otherWin is win's
185 // parent, or otherWin has a satisfied constraint,
186 // or otherWin has no constraint.
187 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
190 value
= edgePos
- margin
;
199 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
202 value
= edgePos
+ margin
;
211 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
214 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
221 case wxUnconstrained
:
223 // We know the left-hand edge position if we know
224 // the right-hand edge and we know the width; OR if
225 // we know the centre and the width.
226 if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
228 value
= (constraints
->right
.GetValue() - constraints
->width
.GetValue() + margin
);
232 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
234 value
= (int)(constraints
->centreX
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
244 win
->GetPosition(&value
, &y
);
255 switch (relationship
)
259 // We can know this edge if: otherWin is win's
260 // parent, or otherWin has a satisfied constraint,
261 // or otherWin has no constraint.
262 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
265 value
= edgePos
- margin
;
274 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
277 value
= edgePos
+ margin
;
286 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
289 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
296 case wxUnconstrained
:
298 // We know the right-hand edge position if we know the
299 // left-hand edge and we know the width, OR if we know the
300 // centre edge and the width.
301 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
303 value
= (constraints
->left
.GetValue() + constraints
->width
.GetValue() - margin
);
307 else if (constraints
->centreX
.GetDone() && constraints
->width
.GetDone())
309 value
= (int)(constraints
->centreX
.GetValue() + (constraints
->width
.GetValue()/2) - margin
);
320 wxGetAsIs(win
, &w
, &h
);
321 win
->GetPosition(&x
, &y
);
333 switch (relationship
)
337 // We can know this edge if: otherWin is win's
338 // parent, or otherWin has a satisfied constraint,
339 // or otherWin has no constraint.
340 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
343 value
= edgePos
- margin
;
352 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
355 value
= edgePos
+ margin
;
364 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
367 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
374 case wxUnconstrained
:
376 // We know the top edge position if we know the bottom edge
377 // and we know the height; OR if we know the centre edge and
379 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
381 value
= (constraints
->bottom
.GetValue() - constraints
->height
.GetValue() + margin
);
385 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
387 value
= (constraints
->centreY
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
397 win
->GetPosition(&x
, &value
);
408 switch (relationship
)
412 // We can know this edge if: otherWin is win's parent,
413 // or otherWin has a satisfied constraint, or
414 // otherWin has no constraint.
415 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
418 value
= edgePos
+ margin
;
427 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
430 value
= edgePos
- margin
;
439 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
442 value
= (int)(edgePos
*(((float)percent
)*0.01) - margin
);
449 case wxUnconstrained
:
451 // We know the bottom edge position if we know the top edge
452 // and we know the height; OR if we know the centre edge and
454 if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
456 value
= (constraints
->top
.GetValue() + constraints
->height
.GetValue() - margin
);
460 else if (constraints
->centreY
.GetDone() && constraints
->height
.GetDone())
462 value
= (constraints
->centreY
.GetValue() + (constraints
->height
.GetValue()/2) - margin
);
473 wxGetAsIs(win
, &w
, &h
);
474 win
->GetPosition(&x
, &y
);
486 switch (relationship
)
490 // We can know this edge if: otherWin is win's parent, or
491 // otherWin has a satisfied constraint, or otherWin has no
493 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
496 value
= edgePos
- margin
;
505 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
508 value
= edgePos
+ margin
;
517 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
520 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
527 case wxUnconstrained
:
529 // We know the centre position if we know
530 // the left-hand edge and we know the width, OR
531 // the right-hand edge and the width
532 if (constraints
->left
.GetDone() && constraints
->width
.GetDone())
534 value
= (int)(constraints
->left
.GetValue() + (constraints
->width
.GetValue()/2) + margin
);
538 else if (constraints
->right
.GetDone() && constraints
->width
.GetDone())
540 value
= (int)(constraints
->left
.GetValue() - (constraints
->width
.GetValue()/2) + margin
);
554 switch (relationship
)
558 // We can know this edge if: otherWin is win's parent,
559 // or otherWin has a satisfied constraint, or otherWin
560 // has no constraint.
561 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
564 value
= edgePos
- margin
;
573 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
576 value
= edgePos
+ margin
;
585 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
588 value
= (int)(edgePos
*(((float)percent
)*0.01) + margin
);
595 case wxUnconstrained
:
597 // We know the centre position if we know
598 // the top edge and we know the height, OR
599 // the bottom edge and the height.
600 if (constraints
->bottom
.GetDone() && constraints
->height
.GetDone())
602 value
= (int)(constraints
->bottom
.GetValue() - (constraints
->height
.GetValue()/2) + margin
);
606 else if (constraints
->top
.GetDone() && constraints
->height
.GetDone())
608 value
= (int)(constraints
->top
.GetValue() + (constraints
->height
.GetValue()/2) + margin
);
622 switch (relationship
)
626 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
629 value
= (int)(edgePos
*(((float)percent
)*0.01));
641 wxGetAsIs(win
, &value
, &h
);
647 case wxUnconstrained
:
649 // We know the width if we know the left edge and the right edge, OR
650 // if we know the left edge and the centre, OR
651 // if we know the right edge and the centre
652 if (constraints
->left
.GetDone() && constraints
->right
.GetDone())
654 value
= constraints
->right
.GetValue() - constraints
->left
.GetValue();
658 else if (constraints
->centreX
.GetDone() && constraints
->left
.GetDone())
660 value
= (int)(2*(constraints
->centreX
.GetValue() - constraints
->left
.GetValue()));
664 else if (constraints
->centreX
.GetDone() && constraints
->right
.GetDone())
666 value
= (int)(2*(constraints
->right
.GetValue() - constraints
->centreX
.GetValue()));
680 switch (relationship
)
684 int edgePos
= GetEdge(otherEdge
, win
, otherWin
);
687 value
= (int)(edgePos
*(((float)percent
)*0.01));
699 wxGetAsIs(win
, &w
, &value
);
705 case wxUnconstrained
:
707 // We know the height if we know the top edge and the bottom edge, OR
708 // if we know the top edge and the centre, OR
709 // if we know the bottom edge and the centre
710 if (constraints
->top
.GetDone() && constraints
->bottom
.GetDone())
712 value
= constraints
->bottom
.GetValue() - constraints
->top
.GetValue();
716 else if (constraints
->top
.GetDone() && constraints
->centreY
.GetDone())
718 value
= (int)(2*(constraints
->centreY
.GetValue() - constraints
->top
.GetValue()));
722 else if (constraints
->bottom
.GetDone() && constraints
->centreY
.GetDone())
724 value
= (int)(2*(constraints
->bottom
.GetValue() - constraints
->centreY
.GetValue()));
742 // Get the value of this edge or dimension, or if this is not determinable, -1.
743 int wxIndividualLayoutConstraint::GetEdge(wxEdge which
,
744 wxWindowBase
*thisWin
,
745 wxWindowBase
*other
) const
747 // If the edge or dimension belongs to the parent, then we know the
748 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
749 // button (but the button's true parent is a panel, not the sizer)
750 if (other
->GetChildren().Find((wxWindow
*)thisWin
))
765 other
->GetClientSizeConstraint(&w
, &h
);
771 other
->GetClientSizeConstraint(&w
, &h
);
777 other
->GetClientSizeConstraint(&w
, &h
);
783 other
->GetClientSizeConstraint(&w
, &h
);
790 other
->GetClientSizeConstraint(&w
, &h
);
791 if (which
== wxCentreX
)
804 wxLayoutConstraints
*constr
= other
->GetConstraints();
805 // If no constraints, it means the window is not dependent
806 // on anything, and therefore we know its value immediately
809 if (constr
->left
.GetDone())
810 return constr
->left
.GetValue();
817 other
->GetPosition(&x
, &y
);
823 wxLayoutConstraints
*constr
= other
->GetConstraints();
824 // If no constraints, it means the window is not dependent
825 // on anything, and therefore we know its value immediately
828 if (constr
->top
.GetDone())
829 return constr
->top
.GetValue();
836 other
->GetPosition(&x
, &y
);
842 wxLayoutConstraints
*constr
= other
->GetConstraints();
843 // If no constraints, it means the window is not dependent
844 // on anything, and therefore we know its value immediately
847 if (constr
->right
.GetDone())
848 return constr
->right
.GetValue();
855 other
->GetPosition(&x
, &y
);
856 other
->GetSize(&w
, &h
);
862 wxLayoutConstraints
*constr
= other
->GetConstraints();
863 // If no constraints, it means the window is not dependent
864 // on anything, and therefore we know its value immediately
867 if (constr
->bottom
.GetDone())
868 return constr
->bottom
.GetValue();
875 other
->GetPosition(&x
, &y
);
876 other
->GetSize(&w
, &h
);
882 wxLayoutConstraints
*constr
= other
->GetConstraints();
883 // If no constraints, it means the window is not dependent
884 // on anything, and therefore we know its value immediately
887 if (constr
->width
.GetDone())
888 return constr
->width
.GetValue();
895 other
->GetSize(&w
, &h
);
901 wxLayoutConstraints
*constr
= other
->GetConstraints();
902 // If no constraints, it means the window is not dependent
903 // on anything, and therefore we know its value immediately
906 if (constr
->height
.GetDone())
907 return constr
->height
.GetValue();
914 other
->GetSize(&w
, &h
);
920 wxLayoutConstraints
*constr
= other
->GetConstraints();
921 // If no constraints, it means the window is not dependent
922 // on anything, and therefore we know its value immediately
925 if (constr
->centreX
.GetDone())
926 return constr
->centreX
.GetValue();
933 other
->GetPosition(&x
, &y
);
934 other
->GetSize(&w
, &h
);
935 return (int)(x
+ (w
/2));
940 wxLayoutConstraints
*constr
= other
->GetConstraints();
941 // If no constraints, it means the window is not dependent
942 // on anything, and therefore we know its value immediately
945 if (constr
->centreY
.GetDone())
946 return constr
->centreY
.GetValue();
953 other
->GetPosition(&x
, &y
);
954 other
->GetSize(&w
, &h
);
955 return (int)(y
+ (h
/2));
964 wxLayoutConstraints::wxLayoutConstraints()
966 left
.SetEdge(wxLeft
);
968 right
.SetEdge(wxRight
);
969 bottom
.SetEdge(wxBottom
);
970 centreX
.SetEdge(wxCentreX
);
971 centreY
.SetEdge(wxCentreY
);
972 width
.SetEdge(wxWidth
);
973 height
.SetEdge(wxHeight
);
976 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase
*win
, int *nChanges
)
980 bool done
= width
.GetDone();
981 bool newDone
= (done
? true : width
.SatisfyConstraint(this, win
));
985 done
= height
.GetDone();
986 newDone
= (done
? true : height
.SatisfyConstraint(this, win
));
990 done
= left
.GetDone();
991 newDone
= (done
? true : left
.SatisfyConstraint(this, win
));
995 done
= top
.GetDone();
996 newDone
= (done
? true : top
.SatisfyConstraint(this, win
));
1000 done
= right
.GetDone();
1001 newDone
= (done
? true : right
.SatisfyConstraint(this, win
));
1002 if (newDone
!= done
)
1005 done
= bottom
.GetDone();
1006 newDone
= (done
? true : bottom
.SatisfyConstraint(this, win
));
1007 if (newDone
!= done
)
1010 done
= centreX
.GetDone();
1011 newDone
= (done
? true : centreX
.SatisfyConstraint(this, win
));
1012 if (newDone
!= done
)
1015 done
= centreY
.GetDone();
1016 newDone
= (done
? true : centreY
.SatisfyConstraint(this, win
));
1017 if (newDone
!= done
)
1020 *nChanges
= noChanges
;
1022 return AreSatisfied();
1025 #endif // wxUSE_CONSTRAINTS