STL-ification patch for wxMSW and wxGTK.
[wxWidgets.git] / src / common / layout.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: layout.cpp
3 // Purpose: Constraint layout system classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // =============================================================================
13 // declarations
14 // =============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "layout.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/defs.h"
33 #endif
34
35 #if wxUSE_CONSTRAINTS
36
37 #ifndef WX_PRECOMP
38 #include "wx/window.h"
39 #include "wx/utils.h"
40 #include "wx/dialog.h"
41 #include "wx/msgdlg.h"
42 #include "wx/intl.h"
43 #endif
44
45 #include "wx/layout.h"
46
47 IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint, wxObject)
48 IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints, wxObject)
49
50
51 wxIndividualLayoutConstraint::wxIndividualLayoutConstraint()
52 {
53 myEdge = wxTop;
54 relationship = wxUnconstrained;
55 margin = 0;
56 value = 0;
57 percent = 0;
58 otherEdge = wxTop;
59 done = FALSE;
60 otherWin = (wxWindowBase *) NULL;
61 }
62
63 wxIndividualLayoutConstraint::~wxIndividualLayoutConstraint()
64 {
65 }
66
67 void wxIndividualLayoutConstraint::Set(wxRelationship rel, wxWindowBase *otherW, wxEdge otherE, int val, int marg)
68 {
69 if (rel == wxSameAs)
70 {
71 // If Set is called by the user with wxSameAs then call SameAs to do
72 // it since it will actually use wxPercent instead.
73 SameAs(otherW, otherE, marg);
74 return;
75 }
76
77 relationship = rel;
78 otherWin = otherW;
79 otherEdge = otherE;
80
81 if ( rel == wxPercentOf )
82 {
83 percent = val;
84 }
85 else
86 {
87 value = val;
88 }
89
90 margin = marg;
91 }
92
93 void wxIndividualLayoutConstraint::LeftOf(wxWindowBase *sibling, int marg)
94 {
95 Set(wxLeftOf, sibling, wxLeft, 0, marg);
96 }
97
98 void wxIndividualLayoutConstraint::RightOf(wxWindowBase *sibling, int marg)
99 {
100 Set(wxRightOf, sibling, wxRight, 0, marg);
101 }
102
103 void wxIndividualLayoutConstraint::Above(wxWindowBase *sibling, int marg)
104 {
105 Set(wxAbove, sibling, wxTop, 0, marg);
106 }
107
108 void wxIndividualLayoutConstraint::Below(wxWindowBase *sibling, int marg)
109 {
110 Set(wxBelow, sibling, wxBottom, 0, marg);
111 }
112
113 //
114 // 'Same edge' alignment
115 //
116 void wxIndividualLayoutConstraint::SameAs(wxWindowBase *otherW, wxEdge edge, int marg)
117 {
118 Set(wxPercentOf, otherW, edge, 100, marg);
119 }
120
121 // The edge is a percentage of the other window's edge
122 void wxIndividualLayoutConstraint::PercentOf(wxWindowBase *otherW, wxEdge wh, int per)
123 {
124 Set(wxPercentOf, otherW, wh, per);
125 }
126
127 //
128 // Edge has absolute value
129 //
130 void wxIndividualLayoutConstraint::Absolute(int val)
131 {
132 value = val;
133 relationship = wxAbsolute;
134 }
135
136 // Reset constraint if it mentions otherWin
137 bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase *otherW)
138 {
139 if (otherW == otherWin)
140 {
141 myEdge = wxTop;
142 relationship = wxAsIs;
143 margin = 0;
144 value = 0;
145 percent = 0;
146 otherEdge = wxTop;
147 otherWin = (wxWindowBase *) NULL;
148 return TRUE;
149 }
150
151 return FALSE;
152 }
153
154 // Try to satisfy constraint
155 bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints *constraints, wxWindowBase *win)
156 {
157 if (relationship == wxAbsolute)
158 {
159 done = TRUE;
160 return TRUE;
161 }
162
163 switch (myEdge)
164 {
165 case wxLeft:
166 {
167 switch (relationship)
168 {
169 case wxLeftOf:
170 {
171 // We can know this edge if: otherWin is win's
172 // parent, or otherWin has a satisfied constraint,
173 // or otherWin has no constraint.
174 int edgePos = GetEdge(otherEdge, win, otherWin);
175 if (edgePos != -1)
176 {
177 value = edgePos - margin;
178 done = TRUE;
179 return TRUE;
180 }
181 else
182 return FALSE;
183 }
184 case wxRightOf:
185 {
186 int edgePos = GetEdge(otherEdge, win, otherWin);
187 if (edgePos != -1)
188 {
189 value = edgePos + margin;
190 done = TRUE;
191 return TRUE;
192 }
193 else
194 return FALSE;
195 }
196 case wxPercentOf:
197 {
198 int edgePos = GetEdge(otherEdge, win, otherWin);
199 if (edgePos != -1)
200 {
201 value = (int)(edgePos*(((float)percent)*0.01) + margin);
202 done = TRUE;
203 return TRUE;
204 }
205 else
206 return FALSE;
207 }
208 case wxUnconstrained:
209 {
210 // We know the left-hand edge position if we know
211 // the right-hand edge and we know the width; OR if
212 // we know the centre and the width.
213 if (constraints->right.GetDone() && constraints->width.GetDone())
214 {
215 value = (constraints->right.GetValue() - constraints->width.GetValue() + margin);
216 done = TRUE;
217 return TRUE;
218 }
219 else if (constraints->centreX.GetDone() && constraints->width.GetDone())
220 {
221 value = (int)(constraints->centreX.GetValue() - (constraints->width.GetValue()/2) + margin);
222 done = TRUE;
223 return TRUE;
224 }
225 else
226 return FALSE;
227 }
228 case wxAsIs:
229 {
230 int y;
231 win->GetPosition(&value, &y);
232 done = TRUE;
233 return TRUE;
234 }
235 default:
236 break;
237 }
238 break;
239 }
240 case wxRight:
241 {
242 switch (relationship)
243 {
244 case wxLeftOf:
245 {
246 // We can know this edge if: otherWin is win's
247 // parent, or otherWin has a satisfied constraint,
248 // or otherWin has no constraint.
249 int edgePos = GetEdge(otherEdge, win, otherWin);
250 if (edgePos != -1)
251 {
252 value = edgePos - margin;
253 done = TRUE;
254 return TRUE;
255 }
256 else
257 return FALSE;
258 }
259 case wxRightOf:
260 {
261 int edgePos = GetEdge(otherEdge, win, otherWin);
262 if (edgePos != -1)
263 {
264 value = edgePos + margin;
265 done = TRUE;
266 return TRUE;
267 }
268 else
269 return FALSE;
270 }
271 case wxPercentOf:
272 {
273 int edgePos = GetEdge(otherEdge, win, otherWin);
274 if (edgePos != -1)
275 {
276 value = (int)(edgePos*(((float)percent)*0.01) - margin);
277 done = TRUE;
278 return TRUE;
279 }
280 else
281 return FALSE;
282 }
283 case wxUnconstrained:
284 {
285 // We know the right-hand edge position if we know the
286 // left-hand edge and we know the width, OR if we know the
287 // centre edge and the width.
288 if (constraints->left.GetDone() && constraints->width.GetDone())
289 {
290 value = (constraints->left.GetValue() + constraints->width.GetValue() - margin);
291 done = TRUE;
292 return TRUE;
293 }
294 else if (constraints->centreX.GetDone() && constraints->width.GetDone())
295 {
296 value = (int)(constraints->centreX.GetValue() + (constraints->width.GetValue()/2) - margin);
297 done = TRUE;
298 return TRUE;
299 }
300 else
301 return FALSE;
302 }
303 case wxAsIs:
304 {
305 int x, y;
306 int w, h;
307 win->GetSize(&w, &h);
308 win->GetPosition(&x, &y);
309 value = x + w;
310 done = TRUE;
311 return TRUE;
312 }
313 default:
314 break;
315 }
316 break;
317 }
318 case wxTop:
319 {
320 switch (relationship)
321 {
322 case wxAbove:
323 {
324 // We can know this edge if: otherWin is win's
325 // parent, or otherWin has a satisfied constraint,
326 // or otherWin has no constraint.
327 int edgePos = GetEdge(otherEdge, win, otherWin);
328 if (edgePos != -1)
329 {
330 value = edgePos - margin;
331 done = TRUE;
332 return TRUE;
333 }
334 else
335 return FALSE;
336 }
337 case wxBelow:
338 {
339 int edgePos = GetEdge(otherEdge, win, otherWin);
340 if (edgePos != -1)
341 {
342 value = edgePos + margin;
343 done = TRUE;
344 return TRUE;
345 }
346 else
347 return FALSE;
348 }
349 case wxPercentOf:
350 {
351 int edgePos = GetEdge(otherEdge, win, otherWin);
352 if (edgePos != -1)
353 {
354 value = (int)(edgePos*(((float)percent)*0.01) + margin);
355 done = TRUE;
356 return TRUE;
357 }
358 else
359 return FALSE;
360 }
361 case wxUnconstrained:
362 {
363 // We know the top edge position if we know the bottom edge
364 // and we know the height; OR if we know the centre edge and
365 // the height.
366 if (constraints->bottom.GetDone() && constraints->height.GetDone())
367 {
368 value = (constraints->bottom.GetValue() - constraints->height.GetValue() + margin);
369 done = TRUE;
370 return TRUE;
371 }
372 else if (constraints->centreY.GetDone() && constraints->height.GetDone())
373 {
374 value = (constraints->centreY.GetValue() - (constraints->height.GetValue()/2) + margin);
375 done = TRUE;
376 return TRUE;
377 }
378 else
379 return FALSE;
380 }
381 case wxAsIs:
382 {
383 int x;
384 win->GetPosition(&x, &value);
385 done = TRUE;
386 return TRUE;
387 }
388 default:
389 break;
390 }
391 break;
392 }
393 case wxBottom:
394 {
395 switch (relationship)
396 {
397 case wxAbove:
398 {
399 // We can know this edge if: otherWin is win's parent,
400 // or otherWin has a satisfied constraint, or
401 // otherWin has no constraint.
402 int edgePos = GetEdge(otherEdge, win, otherWin);
403 if (edgePos != -1)
404 {
405 value = edgePos + margin;
406 done = TRUE;
407 return TRUE;
408 }
409 else
410 return FALSE;
411 }
412 case wxBelow:
413 {
414 int edgePos = GetEdge(otherEdge, win, otherWin);
415 if (edgePos != -1)
416 {
417 value = edgePos - margin;
418 done = TRUE;
419 return TRUE;
420 }
421 else
422 return FALSE;
423 }
424 case wxPercentOf:
425 {
426 int edgePos = GetEdge(otherEdge, win, otherWin);
427 if (edgePos != -1)
428 {
429 value = (int)(edgePos*(((float)percent)*0.01) - margin);
430 done = TRUE;
431 return TRUE;
432 }
433 else
434 return FALSE;
435 }
436 case wxUnconstrained:
437 {
438 // We know the bottom edge position if we know the top edge
439 // and we know the height; OR if we know the centre edge and
440 // the height.
441 if (constraints->top.GetDone() && constraints->height.GetDone())
442 {
443 value = (constraints->top.GetValue() + constraints->height.GetValue() - margin);
444 done = TRUE;
445 return TRUE;
446 }
447 else if (constraints->centreY.GetDone() && constraints->height.GetDone())
448 {
449 value = (constraints->centreY.GetValue() + (constraints->height.GetValue()/2) - margin);
450 done = TRUE;
451 return TRUE;
452 }
453 else
454 return FALSE;
455 }
456 case wxAsIs:
457 {
458 int x, y;
459 int w, h;
460 win->GetSize(&w, &h);
461 win->GetPosition(&x, &y);
462 value = h + y;
463 done = TRUE;
464 return TRUE;
465 }
466 default:
467 break;
468 }
469 break;
470 }
471 case wxCentreX:
472 {
473 switch (relationship)
474 {
475 case wxLeftOf:
476 {
477 // We can know this edge if: otherWin is win's parent, or
478 // otherWin has a satisfied constraint, or otherWin has no
479 // constraint.
480 int edgePos = GetEdge(otherEdge, win, otherWin);
481 if (edgePos != -1)
482 {
483 value = edgePos - margin;
484 done = TRUE;
485 return TRUE;
486 }
487 else
488 return FALSE;
489 }
490 case wxRightOf:
491 {
492 int edgePos = GetEdge(otherEdge, win, otherWin);
493 if (edgePos != -1)
494 {
495 value = edgePos + margin;
496 done = TRUE;
497 return TRUE;
498 }
499 else
500 return FALSE;
501 }
502 case wxPercentOf:
503 {
504 int edgePos = GetEdge(otherEdge, win, otherWin);
505 if (edgePos != -1)
506 {
507 value = (int)(edgePos*(((float)percent)*0.01) + margin);
508 done = TRUE;
509 return TRUE;
510 }
511 else
512 return FALSE;
513 }
514 case wxUnconstrained:
515 {
516 // We know the centre position if we know
517 // the left-hand edge and we know the width, OR
518 // the right-hand edge and the width
519 if (constraints->left.GetDone() && constraints->width.GetDone())
520 {
521 value = (int)(constraints->left.GetValue() + (constraints->width.GetValue()/2) + margin);
522 done = TRUE;
523 return TRUE;
524 }
525 else if (constraints->right.GetDone() && constraints->width.GetDone())
526 {
527 value = (int)(constraints->left.GetValue() - (constraints->width.GetValue()/2) + margin);
528 done = TRUE;
529 return TRUE;
530 }
531 else
532 return FALSE;
533 }
534 default:
535 break;
536 }
537 break;
538 }
539 case wxCentreY:
540 {
541 switch (relationship)
542 {
543 case wxAbove:
544 {
545 // We can know this edge if: otherWin is win's parent,
546 // or otherWin has a satisfied constraint, or otherWin
547 // has no constraint.
548 int edgePos = GetEdge(otherEdge, win, otherWin);
549 if (edgePos != -1)
550 {
551 value = edgePos - margin;
552 done = TRUE;
553 return TRUE;
554 }
555 else
556 return FALSE;
557 }
558 case wxBelow:
559 {
560 int edgePos = GetEdge(otherEdge, win, otherWin);
561 if (edgePos != -1)
562 {
563 value = edgePos + margin;
564 done = TRUE;
565 return TRUE;
566 }
567 else
568 return FALSE;
569 }
570 case wxPercentOf:
571 {
572 int edgePos = GetEdge(otherEdge, win, otherWin);
573 if (edgePos != -1)
574 {
575 value = (int)(edgePos*(((float)percent)*0.01) + margin);
576 done = TRUE;
577 return TRUE;
578 }
579 else
580 return FALSE;
581 }
582 case wxUnconstrained:
583 {
584 // We know the centre position if we know
585 // the top edge and we know the height, OR
586 // the bottom edge and the height.
587 if (constraints->bottom.GetDone() && constraints->height.GetDone())
588 {
589 value = (int)(constraints->bottom.GetValue() - (constraints->height.GetValue()/2) + margin);
590 done = TRUE;
591 return TRUE;
592 }
593 else if (constraints->top.GetDone() && constraints->height.GetDone())
594 {
595 value = (int)(constraints->top.GetValue() + (constraints->height.GetValue()/2) + margin);
596 done = TRUE;
597 return TRUE;
598 }
599 else
600 return FALSE;
601 }
602 default:
603 break;
604 }
605 break;
606 }
607 case wxWidth:
608 {
609 switch (relationship)
610 {
611 case wxPercentOf:
612 {
613 int edgePos = GetEdge(otherEdge, win, otherWin);
614 if (edgePos != -1)
615 {
616 value = (int)(edgePos*(((float)percent)*0.01));
617 done = TRUE;
618 return TRUE;
619 }
620 else
621 return FALSE;
622 }
623 case wxAsIs:
624 {
625 if (win)
626 {
627 int h;
628 win->GetSize(&value, &h);
629 done = TRUE;
630 return TRUE;
631 }
632 else return FALSE;
633 }
634 case wxUnconstrained:
635 {
636 // We know the width if we know the left edge and the right edge, OR
637 // if we know the left edge and the centre, OR
638 // if we know the right edge and the centre
639 if (constraints->left.GetDone() && constraints->right.GetDone())
640 {
641 value = constraints->right.GetValue() - constraints->left.GetValue();
642 done = TRUE;
643 return TRUE;
644 }
645 else if (constraints->centreX.GetDone() && constraints->left.GetDone())
646 {
647 value = (int)(2*(constraints->centreX.GetValue() - constraints->left.GetValue()));
648 done = TRUE;
649 return TRUE;
650 }
651 else if (constraints->centreX.GetDone() && constraints->right.GetDone())
652 {
653 value = (int)(2*(constraints->right.GetValue() - constraints->centreX.GetValue()));
654 done = TRUE;
655 return TRUE;
656 }
657 else
658 return FALSE;
659 }
660 default:
661 break;
662 }
663 break;
664 }
665 case wxHeight:
666 {
667 switch (relationship)
668 {
669 case wxPercentOf:
670 {
671 int edgePos = GetEdge(otherEdge, win, otherWin);
672 if (edgePos != -1)
673 {
674 value = (int)(edgePos*(((float)percent)*0.01));
675 done = TRUE;
676 return TRUE;
677 }
678 else
679 return FALSE;
680 }
681 case wxAsIs:
682 {
683 if (win)
684 {
685 int w;
686 win->GetSize(&w, &value);
687 done = TRUE;
688 return TRUE;
689 }
690 else return FALSE;
691 }
692 case wxUnconstrained:
693 {
694 // We know the height if we know the top edge and the bottom edge, OR
695 // if we know the top edge and the centre, OR
696 // if we know the bottom edge and the centre
697 if (constraints->top.GetDone() && constraints->bottom.GetDone())
698 {
699 value = constraints->bottom.GetValue() - constraints->top.GetValue();
700 done = TRUE;
701 return TRUE;
702 }
703 else if (constraints->top.GetDone() && constraints->centreY.GetDone())
704 {
705 value = (int)(2*(constraints->centreY.GetValue() - constraints->top.GetValue()));
706 done = TRUE;
707 return TRUE;
708 }
709 else if (constraints->bottom.GetDone() && constraints->centreY.GetDone())
710 {
711 value = (int)(2*(constraints->bottom.GetValue() - constraints->centreY.GetValue()));
712 done = TRUE;
713 return TRUE;
714 }
715 else
716 return FALSE;
717 }
718 default:
719 break;
720 }
721 break;
722 }
723 default:
724 break;
725 }
726 return FALSE;
727 }
728
729 // Get the value of this edge or dimension, or if this is not determinable, -1.
730 int wxIndividualLayoutConstraint::GetEdge(wxEdge which,
731 wxWindowBase *thisWin,
732 wxWindowBase *other) const
733 {
734 // If the edge or dimension belongs to the parent, then we know the
735 // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a
736 // button (but the button's true parent is a panel, not the sizer)
737 if (other->GetChildren().Find((wxWindow*)thisWin))
738 {
739 switch (which)
740 {
741 case wxLeft:
742 {
743 return 0;
744 }
745 case wxTop:
746 {
747 return 0;
748 }
749 case wxRight:
750 {
751 int w, h;
752 other->GetClientSizeConstraint(&w, &h);
753 return w;
754 }
755 case wxBottom:
756 {
757 int w, h;
758 other->GetClientSizeConstraint(&w, &h);
759 return h;
760 }
761 case wxWidth:
762 {
763 int w, h;
764 other->GetClientSizeConstraint(&w, &h);
765 return w;
766 }
767 case wxHeight:
768 {
769 int w, h;
770 other->GetClientSizeConstraint(&w, &h);
771 return h;
772 }
773 case wxCentreX:
774 case wxCentreY:
775 {
776 int w, h;
777 other->GetClientSizeConstraint(&w, &h);
778 if (which == wxCentreX)
779 return (int)(w/2);
780 else
781 return (int)(h/2);
782 }
783 default:
784 return -1;
785 }
786 }
787 switch (which)
788 {
789 case wxLeft:
790 {
791 wxLayoutConstraints *constr = other->GetConstraints();
792 // If no constraints, it means the window is not dependent
793 // on anything, and therefore we know its value immediately
794 if (constr)
795 {
796 if (constr->left.GetDone())
797 return constr->left.GetValue();
798 else
799 return -1;
800 }
801 else
802 {
803 int x, y;
804 other->GetPosition(&x, &y);
805 return x;
806 }
807 }
808 case wxTop:
809 {
810 wxLayoutConstraints *constr = other->GetConstraints();
811 // If no constraints, it means the window is not dependent
812 // on anything, and therefore we know its value immediately
813 if (constr)
814 {
815 if (constr->top.GetDone())
816 return constr->top.GetValue();
817 else
818 return -1;
819 }
820 else
821 {
822 int x, y;
823 other->GetPosition(&x, &y);
824 return y;
825 }
826 }
827 case wxRight:
828 {
829 wxLayoutConstraints *constr = other->GetConstraints();
830 // If no constraints, it means the window is not dependent
831 // on anything, and therefore we know its value immediately
832 if (constr)
833 {
834 if (constr->right.GetDone())
835 return constr->right.GetValue();
836 else
837 return -1;
838 }
839 else
840 {
841 int x, y, w, h;
842 other->GetPosition(&x, &y);
843 other->GetSize(&w, &h);
844 return (int)(x + w);
845 }
846 }
847 case wxBottom:
848 {
849 wxLayoutConstraints *constr = other->GetConstraints();
850 // If no constraints, it means the window is not dependent
851 // on anything, and therefore we know its value immediately
852 if (constr)
853 {
854 if (constr->bottom.GetDone())
855 return constr->bottom.GetValue();
856 else
857 return -1;
858 }
859 else
860 {
861 int x, y, w, h;
862 other->GetPosition(&x, &y);
863 other->GetSize(&w, &h);
864 return (int)(y + h);
865 }
866 }
867 case wxWidth:
868 {
869 wxLayoutConstraints *constr = other->GetConstraints();
870 // If no constraints, it means the window is not dependent
871 // on anything, and therefore we know its value immediately
872 if (constr)
873 {
874 if (constr->width.GetDone())
875 return constr->width.GetValue();
876 else
877 return -1;
878 }
879 else
880 {
881 int w, h;
882 other->GetSize(&w, &h);
883 return w;
884 }
885 }
886 case wxHeight:
887 {
888 wxLayoutConstraints *constr = other->GetConstraints();
889 // If no constraints, it means the window is not dependent
890 // on anything, and therefore we know its value immediately
891 if (constr)
892 {
893 if (constr->height.GetDone())
894 return constr->height.GetValue();
895 else
896 return -1;
897 }
898 else
899 {
900 int w, h;
901 other->GetSize(&w, &h);
902 return h;
903 }
904 }
905 case wxCentreX:
906 {
907 wxLayoutConstraints *constr = other->GetConstraints();
908 // If no constraints, it means the window is not dependent
909 // on anything, and therefore we know its value immediately
910 if (constr)
911 {
912 if (constr->centreX.GetDone())
913 return constr->centreX.GetValue();
914 else
915 return -1;
916 }
917 else
918 {
919 int x, y, w, h;
920 other->GetPosition(&x, &y);
921 other->GetSize(&w, &h);
922 return (int)(x + (w/2));
923 }
924 }
925 case wxCentreY:
926 {
927 wxLayoutConstraints *constr = other->GetConstraints();
928 // If no constraints, it means the window is not dependent
929 // on anything, and therefore we know its value immediately
930 if (constr)
931 {
932 if (constr->centreY.GetDone())
933 return constr->centreY.GetValue();
934 else
935 return -1;
936 }
937 else
938 {
939 int x, y, w, h;
940 other->GetPosition(&x, &y);
941 other->GetSize(&w, &h);
942 return (int)(y + (h/2));
943 }
944 }
945 default:
946 break;
947 }
948 return -1;
949 }
950
951 wxLayoutConstraints::wxLayoutConstraints()
952 {
953 left.SetEdge(wxLeft);
954 top.SetEdge(wxTop);
955 right.SetEdge(wxRight);
956 bottom.SetEdge(wxBottom);
957 centreX.SetEdge(wxCentreX);
958 centreY.SetEdge(wxCentreY);
959 width.SetEdge(wxWidth);
960 height.SetEdge(wxHeight);
961 }
962
963 wxLayoutConstraints::~wxLayoutConstraints()
964 {
965 }
966
967 bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase *win, int *nChanges)
968 {
969 int noChanges = 0;
970
971 bool done = width.GetDone();
972 bool newDone = (done ? TRUE : width.SatisfyConstraint(this, win));
973 if (newDone != done)
974 noChanges ++;
975
976 done = height.GetDone();
977 newDone = (done ? TRUE : height.SatisfyConstraint(this, win));
978 if (newDone != done)
979 noChanges ++;
980
981 done = left.GetDone();
982 newDone = (done ? TRUE : left.SatisfyConstraint(this, win));
983 if (newDone != done)
984 noChanges ++;
985
986 done = top.GetDone();
987 newDone = (done ? TRUE : top.SatisfyConstraint(this, win));
988 if (newDone != done)
989 noChanges ++;
990
991 done = right.GetDone();
992 newDone = (done ? TRUE : right.SatisfyConstraint(this, win));
993 if (newDone != done)
994 noChanges ++;
995
996 done = bottom.GetDone();
997 newDone = (done ? TRUE : bottom.SatisfyConstraint(this, win));
998 if (newDone != done)
999 noChanges ++;
1000
1001 done = centreX.GetDone();
1002 newDone = (done ? TRUE : centreX.SatisfyConstraint(this, win));
1003 if (newDone != done)
1004 noChanges ++;
1005
1006 done = centreY.GetDone();
1007 newDone = (done ? TRUE : centreY.SatisfyConstraint(this, win));
1008 if (newDone != done)
1009 noChanges ++;
1010
1011 *nChanges = noChanges;
1012
1013 return AreSatisfied();
1014 }
1015
1016 /*
1017 * Main constrained layout algorithm. Look at all the child
1018 * windows, and their constraints (if any).
1019 * The idea is to keep iterating through the constraints
1020 * until all left, right, bottom and top edges, and widths and heights,
1021 * are known (or no change occurs and we've failed to resolve all
1022 * constraints).
1023 *
1024 * If the user has not specified a dimension or edge, it will be
1025 * be calculated from the other known values. E.g. If we know
1026 * the right hand edge and the left hand edge, we now know the width.
1027 * The snag here is that this means we must specify absolute dimensions
1028 * twice (in constructor and in constraint), if we wish to use the
1029 * constraint notation to just set the position, for example.
1030 * Otherwise, if we only set ONE edge and no dimension, it would never
1031 * find the other edge.
1032 *
1033 * Algorithm:
1034
1035 Mark all constraints as not done.
1036
1037 iterations = 0;
1038 until no change or iterations >= max iterations
1039 For each child:
1040 {
1041 Calculate all constraints
1042 }
1043 iterations ++;
1044
1045 For each child
1046 Set each calculated position and size
1047
1048 */
1049
1050 #if WXWIN_COMPATIBILITY
1051 bool wxOldDoLayout(wxWindowBase *win)
1052 {
1053 // Make sure this isn't called recursively from below
1054 static wxList doneSoFar;
1055
1056 if (doneSoFar.Member(win))
1057 return TRUE;
1058
1059 doneSoFar.Append(win);
1060
1061 wxNode *node = win->GetChildren().First();
1062 while (node)
1063 {
1064 wxWindowBase *child = (wxWindowBase *)node->Data();
1065 wxLayoutConstraints *constr = child->GetConstraints();
1066 if (constr)
1067 {
1068 constr->left.SetDone(FALSE);
1069 constr->top.SetDone(FALSE);
1070 constr->right.SetDone(FALSE);
1071 constr->bottom.SetDone(FALSE);
1072 constr->width.SetDone(FALSE);
1073 constr->height.SetDone(FALSE);
1074 constr->centreX.SetDone(FALSE);
1075 constr->centreY.SetDone(FALSE);
1076 }
1077 node = node->Next();
1078 }
1079 int noIterations = 0;
1080 int maxIterations = 500;
1081 int noChanges = 1;
1082
1083 while ((noChanges > 0) && (noIterations < maxIterations))
1084 {
1085 noChanges = 0;
1086 wxNode *node = win->GetChildren().First();
1087 while (node)
1088 {
1089 wxWindowBase *child = (wxWindowBase *)node->Data();
1090 wxLayoutConstraints *constr = child->GetConstraints();
1091 if (constr)
1092 {
1093 int tempNoChanges = 0;
1094 (void)constr->SatisfyConstraints(child, &tempNoChanges);
1095 noChanges += tempNoChanges;
1096 }
1097 node = node->Next();
1098 }
1099 noIterations ++;
1100 }
1101 /*
1102 // Would be nice to have a test here to see _which_ constraint(s)
1103 // failed, so we can print a specific diagnostic message.
1104 if (noFailures > 0)
1105 {
1106 wxDebugMsg(_("wxWindowBase::Layout() failed.\n"));
1107 }
1108 */
1109 // Now set the sizes and positions of the children, and
1110 // recursively call Layout().
1111 node = win->GetChildren().First();
1112 while (node)
1113 {
1114 wxWindowBase *child = (wxWindowBase *)node->Data();
1115 wxLayoutConstraints *constr = child->GetConstraints();
1116 if (constr && constr->left.GetDone() && constr->right.GetDone() &&
1117 constr->width.GetDone() && constr->height.GetDone())
1118 {
1119 int x = constr->left.GetValue();
1120 int y = constr->top.GetValue();
1121 int w = constr->width.GetValue();
1122 int h = constr->height.GetValue();
1123
1124 // If we don't want to resize this window, just move it...
1125 if ((constr->width.GetRelationship() != wxAsIs) ||
1126 (constr->height.GetRelationship() != wxAsIs))
1127 {
1128 // _Should_ call Layout() recursively.
1129 child->SetSize(x, y, w, h);
1130 }
1131 else
1132 {
1133 child->Move(x, y);
1134 }
1135 }
1136 else
1137 child->Layout();
1138 node = node->Next();
1139 }
1140 doneSoFar.DeleteObject(win);
1141
1142 return TRUE;
1143 }
1144 #endif // WXWIN_COMPATIBILITY
1145
1146 #endif // wxUSE_CONSTRAINTS