]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
wx{V,H}SCROLL code is needed on all platforms
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/sizer.cpp
3 // Purpose: provide new wxSizer class for layout
4 // Author: Robert Roebling and Robin Dunn, contributions by
5 // Dirk Holtwick, Ron Lee
6 // Modified by: Ron Lee
7 // Created:
8 // RCS-ID: $Id$
9 // Copyright: (c) Robin Dunn, Robert Roebling
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #include "wx/sizer.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/string.h"
24 #include "wx/intl.h"
25 #include "wx/math.h"
26 #include "wx/utils.h"
27 #include "wx/settings.h"
28 #include "wx/button.h"
29 #include "wx/statbox.h"
30 #include "wx/toplevel.h"
31 #endif // WX_PRECOMP
32
33 #include "wx/listimpl.cpp"
34
35 #if WXWIN_COMPATIBILITY_2_4
36 #include "wx/notebook.h"
37 #endif
38
39 //---------------------------------------------------------------------------
40
41 IMPLEMENT_CLASS(wxSizerItem, wxObject)
42 IMPLEMENT_CLASS(wxSizer, wxObject)
43 IMPLEMENT_CLASS(wxGridSizer, wxSizer)
44 IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
45 IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
46 #if wxUSE_STATBOX
47 IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
48 #endif
49 #if wxUSE_BUTTON
50 IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
51 #endif
52
53 WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
54
55 /*
56 TODO PROPERTIES
57 sizeritem
58 object
59 object_ref
60 minsize
61 option
62 flag
63 border
64 spacer
65 option
66 flag
67 borfder
68 boxsizer
69 orient
70 staticboxsizer
71 orient
72 label
73 gridsizer
74 rows
75 cols
76 vgap
77 hgap
78 flexgridsizer
79 rows
80 cols
81 vgap
82 hgap
83 growablerows
84 growablecols
85 minsize
86 */
87
88 // ----------------------------------------------------------------------------
89 // wxSizerItem
90 // ----------------------------------------------------------------------------
91
92 void wxSizerItem::Init(const wxSizerFlags& flags)
93 {
94 Init();
95
96 m_proportion = flags.GetProportion();
97 m_flag = flags.GetFlags();
98 m_border = flags.GetBorderInPixels();
99 }
100
101 wxSizerItem::wxSizerItem()
102 {
103 Init();
104
105 m_proportion = 0;
106 m_border = 0;
107 m_flag = 0;
108
109 m_kind = Item_None;
110 }
111
112 // window item
113 void wxSizerItem::SetWindow(wxWindow *window)
114 {
115 wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") );
116
117 m_kind = Item_Window;
118 m_window = window;
119
120 // window doesn't become smaller than its initial size, whatever happens
121 m_minSize = window->GetSize();
122
123 if ( m_flag & wxFIXED_MINSIZE )
124 window->SetMinSize(m_minSize);
125
126 // aspect ratio calculated from initial size
127 SetRatio(m_minSize);
128 }
129
130 wxSizerItem::wxSizerItem(wxWindow *window,
131 int proportion,
132 int flag,
133 int border,
134 wxObject* userData)
135 : m_proportion(proportion),
136 m_border(border),
137 m_flag(flag),
138 m_userData(userData)
139 {
140 SetWindow(window);
141 }
142
143 // sizer item
144 void wxSizerItem::SetSizer(wxSizer *sizer)
145 {
146 m_kind = Item_Sizer;
147 m_sizer = sizer;
148 }
149
150 wxSizerItem::wxSizerItem(wxSizer *sizer,
151 int proportion,
152 int flag,
153 int border,
154 wxObject* userData)
155 : m_proportion(proportion),
156 m_border(border),
157 m_flag(flag),
158 m_ratio(0.0),
159 m_userData(userData)
160 {
161 SetSizer(sizer);
162
163 // m_minSize is set later
164 }
165
166 // spacer item
167 void wxSizerItem::SetSpacer(const wxSize& size)
168 {
169 m_kind = Item_Spacer;
170 m_spacer = new wxSizerSpacer(size);
171 m_minSize = size;
172 SetRatio(size);
173 }
174
175 wxSizerItem::wxSizerItem(int width,
176 int height,
177 int proportion,
178 int flag,
179 int border,
180 wxObject* userData)
181 : m_minSize(width, height), // minimal size is the initial size
182 m_proportion(proportion),
183 m_border(border),
184 m_flag(flag),
185 m_userData(userData)
186 {
187 SetSpacer(width, height);
188 }
189
190 wxSizerItem::~wxSizerItem()
191 {
192 delete m_userData;
193
194 switch ( m_kind )
195 {
196 case Item_None:
197 break;
198
199 case Item_Window:
200 m_window->SetContainingSizer(NULL);
201 break;
202
203 case Item_Sizer:
204 delete m_sizer;
205 break;
206
207 case Item_Spacer:
208 delete m_spacer;
209 break;
210
211 case Item_Max:
212 default:
213 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
214 }
215 }
216
217 wxSize wxSizerItem::GetSpacer() const
218 {
219 wxSize size;
220 if ( m_kind == Item_Spacer )
221 size = m_spacer->GetSize();
222
223 return size;
224 }
225
226
227 wxSize wxSizerItem::GetSize() const
228 {
229 wxSize ret;
230 switch ( m_kind )
231 {
232 case Item_None:
233 break;
234
235 case Item_Window:
236 ret = m_window->GetSize();
237 break;
238
239 case Item_Sizer:
240 ret = m_sizer->GetSize();
241 break;
242
243 case Item_Spacer:
244 ret = m_spacer->GetSize();
245 break;
246
247 case Item_Max:
248 default:
249 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
250 }
251
252 if (m_flag & wxWEST)
253 ret.x += m_border;
254 if (m_flag & wxEAST)
255 ret.x += m_border;
256 if (m_flag & wxNORTH)
257 ret.y += m_border;
258 if (m_flag & wxSOUTH)
259 ret.y += m_border;
260
261 return ret;
262 }
263
264 wxSize wxSizerItem::CalcMin()
265 {
266 if (IsSizer())
267 {
268 m_minSize = m_sizer->GetMinSize();
269
270 // if we have to preserve aspect ratio _AND_ this is
271 // the first-time calculation, consider ret to be initial size
272 if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) )
273 SetRatio(m_minSize);
274 }
275 else if ( IsWindow() )
276 {
277 // Since the size of the window may change during runtime, we
278 // should use the current minimal/best size.
279 m_minSize = m_window->GetBestFittingSize();
280 }
281
282 return GetMinSizeWithBorder();
283 }
284
285 wxSize wxSizerItem::GetMinSizeWithBorder() const
286 {
287 wxSize ret = m_minSize;
288
289 if (m_flag & wxWEST)
290 ret.x += m_border;
291 if (m_flag & wxEAST)
292 ret.x += m_border;
293 if (m_flag & wxNORTH)
294 ret.y += m_border;
295 if (m_flag & wxSOUTH)
296 ret.y += m_border;
297
298 return ret;
299 }
300
301
302 void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ )
303 {
304 wxPoint pos = pos_;
305 wxSize size = size_;
306 if (m_flag & wxSHAPED)
307 {
308 // adjust aspect ratio
309 int rwidth = (int) (size.y * m_ratio);
310 if (rwidth > size.x)
311 {
312 // fit horizontally
313 int rheight = (int) (size.x / m_ratio);
314 // add vertical space
315 if (m_flag & wxALIGN_CENTER_VERTICAL)
316 pos.y += (size.y - rheight) / 2;
317 else if (m_flag & wxALIGN_BOTTOM)
318 pos.y += (size.y - rheight);
319 // use reduced dimensions
320 size.y =rheight;
321 }
322 else if (rwidth < size.x)
323 {
324 // add horizontal space
325 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
326 pos.x += (size.x - rwidth) / 2;
327 else if (m_flag & wxALIGN_RIGHT)
328 pos.x += (size.x - rwidth);
329 size.x = rwidth;
330 }
331 }
332
333 // This is what GetPosition() returns. Since we calculate
334 // borders afterwards, GetPosition() will be the left/top
335 // corner of the surrounding border.
336 m_pos = pos;
337
338 if (m_flag & wxWEST)
339 {
340 pos.x += m_border;
341 size.x -= m_border;
342 }
343 if (m_flag & wxEAST)
344 {
345 size.x -= m_border;
346 }
347 if (m_flag & wxNORTH)
348 {
349 pos.y += m_border;
350 size.y -= m_border;
351 }
352 if (m_flag & wxSOUTH)
353 {
354 size.y -= m_border;
355 }
356
357 if (size.x < 0)
358 size.x = 0;
359 if (size.y < 0)
360 size.y = 0;
361
362 m_rect = wxRect(pos, size);
363
364 switch ( m_kind )
365 {
366 case Item_None:
367 wxFAIL_MSG( _T("can't set size of uninitialized sizer item") );
368 break;
369
370 case Item_Window:
371 m_window->SetSize(pos.x, pos.y, size.x, size.y,
372 wxSIZE_ALLOW_MINUS_ONE);
373 break;
374
375 case Item_Sizer:
376 m_sizer->SetDimension(pos.x, pos.y, size.x, size.y);
377 break;
378
379 case Item_Spacer:
380 m_spacer->SetSize(size);
381 break;
382
383 case Item_Max:
384 default:
385 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
386 }
387 }
388
389 void wxSizerItem::DeleteWindows()
390 {
391 switch ( m_kind )
392 {
393 case Item_None:
394 case Item_Spacer:
395 break;
396
397 case Item_Window:
398 //We are deleting the window from this sizer - normally
399 //the window destroys the sizer associated with it,
400 //which might destroy this, which we don't want
401 m_window->SetContainingSizer(NULL);
402 m_window->Destroy();
403 //Putting this after the switch will result in a spacer
404 //not being deleted properly on destruction
405 m_kind = Item_None;
406 break;
407
408 case Item_Sizer:
409 m_sizer->DeleteWindows();
410 break;
411
412 case Item_Max:
413 default:
414 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
415 }
416
417 }
418
419 void wxSizerItem::Show( bool show )
420 {
421 switch ( m_kind )
422 {
423 case Item_None:
424 wxFAIL_MSG( _T("can't show uninitialized sizer item") );
425 break;
426
427 case Item_Window:
428 m_window->Show(show);
429 break;
430
431 case Item_Sizer:
432 m_sizer->Show(show);
433 break;
434
435 case Item_Spacer:
436 m_spacer->Show(show);
437 break;
438
439 case Item_Max:
440 default:
441 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
442 }
443 }
444
445 bool wxSizerItem::IsShown() const
446 {
447 switch ( m_kind )
448 {
449 case Item_None:
450 // we may be called from CalcMin(), just return false so that we're
451 // not used
452 break;
453
454 case Item_Window:
455 return m_window->IsShown();
456
457 case Item_Sizer:
458 // arbitrarily decide that if at least one of our elements is
459 // shown, so are we (this arbitrariness is the reason for
460 // deprecating this function)
461 {
462 for ( wxSizerItemList::compatibility_iterator
463 node = m_sizer->GetChildren().GetFirst();
464 node;
465 node = node->GetNext() )
466 {
467 if ( node->GetData()->IsShown() )
468 return true;
469 }
470 }
471 return false;
472
473 case Item_Spacer:
474 return m_spacer->IsShown();
475
476 case Item_Max:
477 default:
478 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
479 }
480
481 return false;
482 }
483
484 #if WXWIN_COMPATIBILITY_2_6
485 void wxSizerItem::SetOption( int option )
486 {
487 SetProportion( option );
488 }
489
490 int wxSizerItem::GetOption() const
491 {
492 return GetProportion();
493 }
494 #endif // WXWIN_COMPATIBILITY_2_6
495
496
497 //---------------------------------------------------------------------------
498 // wxSizer
499 //---------------------------------------------------------------------------
500
501 wxSizer::~wxSizer()
502 {
503 WX_CLEAR_LIST(wxSizerItemList, m_children);
504 }
505
506 wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
507 {
508 m_children.Insert( index, item );
509
510 if ( item->GetWindow() )
511 item->GetWindow()->SetContainingSizer( this );
512
513 return item;
514 }
515
516 void wxSizer::SetContainingWindow(wxWindow *win)
517 {
518 if ( win == m_containingWindow )
519 return;
520
521 m_containingWindow = win;
522
523 // set the same window for all nested sizers as well, they also are in the
524 // same window
525 for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
526 node;
527 node = node->GetNext() )
528 {
529 wxSizerItem *const item = node->GetData();
530 wxSizer *const sizer = item->GetSizer();
531
532 if ( sizer )
533 {
534 sizer->SetContainingWindow(win);
535 }
536 }
537 }
538
539 #if WXWIN_COMPATIBILITY_2_6
540 bool wxSizer::Remove( wxWindow *window )
541 {
542 return Detach( window );
543 }
544 #endif // WXWIN_COMPATIBILITY_2_6
545
546 bool wxSizer::Remove( wxSizer *sizer )
547 {
548 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
549
550 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
551 while (node)
552 {
553 wxSizerItem *item = node->GetData();
554
555 if (item->GetSizer() == sizer)
556 {
557 delete item;
558 m_children.Erase( node );
559 return true;
560 }
561
562 node = node->GetNext();
563 }
564
565 return false;
566 }
567
568 bool wxSizer::Remove( int index )
569 {
570 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
571 false,
572 _T("Remove index is out of range") );
573
574 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
575
576 wxCHECK_MSG( node, false, _T("Failed to find child node") );
577
578 wxSizerItem *item = node->GetData();
579
580 if ( item->IsWindow() )
581 item->GetWindow()->SetContainingSizer( NULL );
582
583 delete item;
584 m_children.Erase( node );
585 return true;
586 }
587
588 bool wxSizer::Detach( wxSizer *sizer )
589 {
590 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
591
592 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
593 while (node)
594 {
595 wxSizerItem *item = node->GetData();
596
597 if (item->GetSizer() == sizer)
598 {
599 item->DetachSizer();
600 delete item;
601 m_children.Erase( node );
602 return true;
603 }
604 node = node->GetNext();
605 }
606
607 return false;
608 }
609
610 bool wxSizer::Detach( wxWindow *window )
611 {
612 wxASSERT_MSG( window, _T("Detaching NULL window") );
613
614 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
615 while (node)
616 {
617 wxSizerItem *item = node->GetData();
618
619 if (item->GetWindow() == window)
620 {
621 item->GetWindow()->SetContainingSizer( NULL );
622 delete item;
623 m_children.Erase( node );
624 return true;
625 }
626 node = node->GetNext();
627 }
628
629 return false;
630 }
631
632 bool wxSizer::Detach( int index )
633 {
634 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
635 false,
636 _T("Detach index is out of range") );
637
638 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
639
640 wxCHECK_MSG( node, false, _T("Failed to find child node") );
641
642 wxSizerItem *item = node->GetData();
643
644 if ( item->IsSizer() )
645 item->DetachSizer();
646 else if ( item->IsWindow() )
647 item->GetWindow()->SetContainingSizer( NULL );
648
649 delete item;
650 m_children.Erase( node );
651 return true;
652 }
653
654 bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive )
655 {
656 wxASSERT_MSG( oldwin, _T("Replacing NULL window") );
657 wxASSERT_MSG( newwin, _T("Replacing with NULL window") );
658
659 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
660 while (node)
661 {
662 wxSizerItem *item = node->GetData();
663
664 if (item->GetWindow() == oldwin)
665 {
666 item->GetWindow()->SetContainingSizer( NULL );
667 item->SetWindow(newwin);
668 newwin->SetContainingSizer( this );
669 return true;
670 }
671 else if (recursive && item->IsSizer())
672 {
673 if (item->GetSizer()->Replace( oldwin, newwin, true ))
674 return true;
675 }
676
677 node = node->GetNext();
678 }
679
680 return false;
681 }
682
683 bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive )
684 {
685 wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") );
686 wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") );
687
688 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
689 while (node)
690 {
691 wxSizerItem *item = node->GetData();
692
693 if (item->GetSizer() == oldsz)
694 {
695 wxSizer *old = item->GetSizer();
696 item->SetSizer(newsz);
697 delete old;
698 return true;
699 }
700 else if (recursive && item->IsSizer())
701 {
702 if (item->GetSizer()->Replace( oldsz, newsz, true ))
703 return true;
704 }
705
706 node = node->GetNext();
707 }
708
709 return false;
710 }
711
712 bool wxSizer::Replace( size_t old, wxSizerItem *newitem )
713 {
714 wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") );
715 wxASSERT_MSG( newitem, _T("Replacing with NULL item") );
716
717 wxSizerItemList::compatibility_iterator node = m_children.Item( old );
718
719 wxCHECK_MSG( node, false, _T("Failed to find child node") );
720
721 wxSizerItem *item = node->GetData();
722 node->SetData(newitem);
723 delete item;
724
725 return true;
726 }
727
728 void wxSizer::Clear( bool delete_windows )
729 {
730 // First clear the ContainingSizer pointers
731 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
732 while (node)
733 {
734 wxSizerItem *item = node->GetData();
735
736 if (item->IsWindow())
737 item->GetWindow()->SetContainingSizer( NULL );
738 node = node->GetNext();
739 }
740
741 // Destroy the windows if needed
742 if (delete_windows)
743 DeleteWindows();
744
745 // Now empty the list
746 WX_CLEAR_LIST(wxSizerItemList, m_children);
747 }
748
749 void wxSizer::DeleteWindows()
750 {
751 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
752 while (node)
753 {
754 wxSizerItem *item = node->GetData();
755
756 item->DeleteWindows();
757 node = node->GetNext();
758 }
759 }
760
761 wxSize wxSizer::Fit( wxWindow *window )
762 {
763 wxSize size(window->IsTopLevel() ? FitSize(window)
764 : GetMinWindowSize(window));
765
766 window->SetSize( size );
767
768 return size;
769 }
770
771 void wxSizer::FitInside( wxWindow *window )
772 {
773 wxSize size;
774 if (window->IsTopLevel())
775 size = VirtualFitSize( window );
776 else
777 size = GetMinClientSize( window );
778
779 window->SetVirtualSize( size );
780 }
781
782 void wxSizer::Layout()
783 {
784 // (re)calculates minimums needed for each item and other preparations
785 // for layout
786 CalcMin();
787
788 // Applies the layout and repositions/resizes the items
789 RecalcSizes();
790 }
791
792 void wxSizer::SetSizeHints( wxWindow *window )
793 {
794 // Preserve the window's max size hints, but set the
795 // lower bound according to the sizer calculations.
796
797 wxSize size = Fit( window );
798
799 window->SetSizeHints( size.x,
800 size.y,
801 window->GetMaxWidth(),
802 window->GetMaxHeight() );
803 }
804
805 void wxSizer::SetVirtualSizeHints( wxWindow *window )
806 {
807 // Preserve the window's max size hints, but set the
808 // lower bound according to the sizer calculations.
809
810 FitInside( window );
811 wxSize size( window->GetVirtualSize() );
812 window->SetVirtualSizeHints( size.x,
813 size.y,
814 window->GetMaxWidth(),
815 window->GetMaxHeight() );
816 }
817
818 wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
819 {
820 return window->GetMaxSize();
821 }
822
823 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
824 {
825 wxSize minSize( GetMinSize() );
826 wxSize size( window->GetSize() );
827 wxSize client_size( window->GetClientSize() );
828
829 return wxSize( minSize.x+size.x-client_size.x,
830 minSize.y+size.y-client_size.y );
831 }
832
833 // TODO on mac we need a function that determines how much free space this
834 // min size contains, in order to make sure that we have 20 pixels of free
835 // space around the controls
836
837 // Return a window size that will fit within the screens dimensions
838 wxSize wxSizer::FitSize( wxWindow *window )
839 {
840 if ( window->IsTopLevel() )
841 {
842 wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
843 if ( tlw && tlw->IsAlwaysMaximized() )
844 {
845 return tlw->GetClientSize();
846 }
847 }
848
849 wxSize size = GetMinWindowSize( window );
850 wxSize sizeMax = GetMaxWindowSize( window );
851
852 // Limit the size if sizeMax != wxDefaultSize
853
854 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
855 size.x = sizeMax.x;
856 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
857 size.y = sizeMax.y;
858
859 return size;
860 }
861
862 wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
863 {
864 wxSize maxSize( window->GetMaxSize() );
865
866 if ( maxSize != wxDefaultSize )
867 {
868 wxSize size( window->GetSize() );
869 wxSize client_size( window->GetClientSize() );
870
871 return wxSize( maxSize.x + client_size.x - size.x,
872 maxSize.y + client_size.y - size.y );
873 }
874 else
875 return wxDefaultSize;
876 }
877
878 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
879 {
880 return GetMinSize(); // Already returns client size.
881 }
882
883 wxSize wxSizer::VirtualFitSize( wxWindow *window )
884 {
885 wxSize size = GetMinClientSize( window );
886 wxSize sizeMax = GetMaxClientSize( window );
887
888 // Limit the size if sizeMax != wxDefaultSize
889
890 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
891 size.x = sizeMax.x;
892 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
893 size.y = sizeMax.y;
894
895 return size;
896 }
897
898 void wxSizer::SetDimension( int x, int y, int width, int height )
899 {
900 m_position.x = x;
901 m_position.y = y;
902 m_size.x = width;
903 m_size.y = height;
904 Layout();
905 }
906
907 wxSize wxSizer::GetMinSize()
908 {
909 wxSize ret( CalcMin() );
910 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
911 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
912 return ret;
913 }
914
915 void wxSizer::DoSetMinSize( int width, int height )
916 {
917 m_minSize.x = width;
918 m_minSize.y = height;
919 }
920
921 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
922 {
923 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
924
925 // Is it our immediate child?
926
927 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
928 while (node)
929 {
930 wxSizerItem *item = node->GetData();
931
932 if (item->GetWindow() == window)
933 {
934 item->SetMinSize( width, height );
935 return true;
936 }
937 node = node->GetNext();
938 }
939
940 // No? Search any subsizers we own then
941
942 node = m_children.GetFirst();
943 while (node)
944 {
945 wxSizerItem *item = node->GetData();
946
947 if ( item->GetSizer() &&
948 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
949 {
950 // A child sizer found the requested windw, exit.
951 return true;
952 }
953 node = node->GetNext();
954 }
955
956 return false;
957 }
958
959 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
960 {
961 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
962
963 // Is it our immediate child?
964
965 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
966 while (node)
967 {
968 wxSizerItem *item = node->GetData();
969
970 if (item->GetSizer() == sizer)
971 {
972 item->GetSizer()->DoSetMinSize( width, height );
973 return true;
974 }
975 node = node->GetNext();
976 }
977
978 // No? Search any subsizers we own then
979
980 node = m_children.GetFirst();
981 while (node)
982 {
983 wxSizerItem *item = node->GetData();
984
985 if ( item->GetSizer() &&
986 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
987 {
988 // A child found the requested sizer, exit.
989 return true;
990 }
991 node = node->GetNext();
992 }
993
994 return false;
995 }
996
997 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
998 {
999 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
1000
1001 wxCHECK_MSG( node, false, _T("Failed to find child node") );
1002
1003 wxSizerItem *item = node->GetData();
1004
1005 if (item->GetSizer())
1006 {
1007 // Sizers contains the minimal size in them, if not calculated ...
1008 item->GetSizer()->DoSetMinSize( width, height );
1009 }
1010 else
1011 {
1012 // ... but the minimal size of spacers and windows is stored via the item
1013 item->SetMinSize( width, height );
1014 }
1015
1016 return true;
1017 }
1018
1019 wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
1020 {
1021 wxASSERT_MSG( window, _T("GetItem for NULL window") );
1022
1023 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1024 while (node)
1025 {
1026 wxSizerItem *item = node->GetData();
1027
1028 if (item->GetWindow() == window)
1029 {
1030 return item;
1031 }
1032 else if (recursive && item->IsSizer())
1033 {
1034 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
1035 if (subitem)
1036 return subitem;
1037 }
1038
1039 node = node->GetNext();
1040 }
1041
1042 return NULL;
1043 }
1044
1045 wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
1046 {
1047 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
1048
1049 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1050 while (node)
1051 {
1052 wxSizerItem *item = node->GetData();
1053
1054 if (item->GetSizer() == sizer)
1055 {
1056 return item;
1057 }
1058 else if (recursive && item->IsSizer())
1059 {
1060 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
1061 if (subitem)
1062 return subitem;
1063 }
1064
1065 node = node->GetNext();
1066 }
1067
1068 return NULL;
1069 }
1070
1071 wxSizerItem* wxSizer::GetItem( size_t index )
1072 {
1073 wxCHECK_MSG( index < m_children.GetCount(),
1074 NULL,
1075 _T("GetItem index is out of range") );
1076
1077 return m_children.Item( index )->GetData();
1078 }
1079
1080 bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
1081 {
1082 wxSizerItem *item = GetItem( window, recursive );
1083
1084 if ( item )
1085 {
1086 item->Show( show );
1087 return true;
1088 }
1089
1090 return false;
1091 }
1092
1093 bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
1094 {
1095 wxSizerItem *item = GetItem( sizer, recursive );
1096
1097 if ( item )
1098 {
1099 item->Show( show );
1100 return true;
1101 }
1102
1103 return false;
1104 }
1105
1106 bool wxSizer::Show( size_t index, bool show)
1107 {
1108 wxSizerItem *item = GetItem( index );
1109
1110 if ( item )
1111 {
1112 item->Show( show );
1113 return true;
1114 }
1115
1116 return false;
1117 }
1118
1119 void wxSizer::ShowItems( bool show )
1120 {
1121 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1122 while (node)
1123 {
1124 node->GetData()->Show( show );
1125 node = node->GetNext();
1126 }
1127 }
1128
1129 bool wxSizer::IsShown( wxWindow *window ) const
1130 {
1131 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1132 while (node)
1133 {
1134 wxSizerItem *item = node->GetData();
1135
1136 if (item->GetWindow() == window)
1137 {
1138 return item->IsShown();
1139 }
1140 node = node->GetNext();
1141 }
1142
1143 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1144
1145 return false;
1146 }
1147
1148 bool wxSizer::IsShown( wxSizer *sizer ) const
1149 {
1150 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1151 while (node)
1152 {
1153 wxSizerItem *item = node->GetData();
1154
1155 if (item->GetSizer() == sizer)
1156 {
1157 return item->IsShown();
1158 }
1159 node = node->GetNext();
1160 }
1161
1162 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1163
1164 return false;
1165 }
1166
1167 bool wxSizer::IsShown( size_t index ) const
1168 {
1169 wxCHECK_MSG( index < m_children.GetCount(),
1170 false,
1171 _T("IsShown index is out of range") );
1172
1173 return m_children.Item( index )->GetData()->IsShown();
1174 }
1175
1176
1177 //---------------------------------------------------------------------------
1178 // wxGridSizer
1179 //---------------------------------------------------------------------------
1180
1181 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
1182 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
1183 , m_cols( cols )
1184 , m_vgap( vgap )
1185 , m_hgap( hgap )
1186 {
1187 }
1188
1189 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
1190 : m_rows( cols == 0 ? 1 : 0 )
1191 , m_cols( cols )
1192 , m_vgap( vgap )
1193 , m_hgap( hgap )
1194 {
1195 }
1196
1197 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
1198 {
1199 int nitems = m_children.GetCount();
1200 if ( nitems)
1201 {
1202 if ( m_cols )
1203 {
1204 ncols = m_cols;
1205 nrows = (nitems + m_cols - 1) / m_cols;
1206 }
1207 else if ( m_rows )
1208 {
1209 ncols = (nitems + m_rows - 1) / m_rows;
1210 nrows = m_rows;
1211 }
1212 else // 0 columns, 0 rows?
1213 {
1214 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
1215
1216 nrows = ncols = 0;
1217 }
1218 }
1219
1220 return nitems;
1221 }
1222
1223 void wxGridSizer::RecalcSizes()
1224 {
1225 int nitems, nrows, ncols;
1226 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1227 return;
1228
1229 wxSize sz( GetSize() );
1230 wxPoint pt( GetPosition() );
1231
1232 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1233 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
1234
1235 int x = pt.x;
1236 for (int c = 0; c < ncols; c++)
1237 {
1238 int y = pt.y;
1239 for (int r = 0; r < nrows; r++)
1240 {
1241 int i = r * ncols + c;
1242 if (i < nitems)
1243 {
1244 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1245
1246 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
1247
1248 SetItemBounds( node->GetData(), x, y, w, h);
1249 }
1250 y = y + h + m_vgap;
1251 }
1252 x = x + w + m_hgap;
1253 }
1254 }
1255
1256 wxSize wxGridSizer::CalcMin()
1257 {
1258 int nrows, ncols;
1259 if ( CalcRowsCols(nrows, ncols) == 0 )
1260 return wxSize();
1261
1262 // Find the max width and height for any component
1263 int w = 0;
1264 int h = 0;
1265
1266 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1267 while (node)
1268 {
1269 wxSizerItem *item = node->GetData();
1270 wxSize sz( item->CalcMin() );
1271
1272 w = wxMax( w, sz.x );
1273 h = wxMax( h, sz.y );
1274
1275 node = node->GetNext();
1276 }
1277
1278 return wxSize( ncols * w + (ncols-1) * m_hgap,
1279 nrows * h + (nrows-1) * m_vgap );
1280 }
1281
1282 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1283 {
1284 wxPoint pt( x,y );
1285 wxSize sz( item->GetMinSizeWithBorder() );
1286 int flag = item->GetFlag();
1287
1288 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1289 {
1290 sz = wxSize(w, h);
1291 }
1292 else
1293 {
1294 if (flag & wxALIGN_CENTER_HORIZONTAL)
1295 {
1296 pt.x = x + (w - sz.x) / 2;
1297 }
1298 else if (flag & wxALIGN_RIGHT)
1299 {
1300 pt.x = x + (w - sz.x);
1301 }
1302
1303 if (flag & wxALIGN_CENTER_VERTICAL)
1304 {
1305 pt.y = y + (h - sz.y) / 2;
1306 }
1307 else if (flag & wxALIGN_BOTTOM)
1308 {
1309 pt.y = y + (h - sz.y);
1310 }
1311 }
1312
1313 item->SetDimension(pt, sz);
1314 }
1315
1316 //---------------------------------------------------------------------------
1317 // wxFlexGridSizer
1318 //---------------------------------------------------------------------------
1319
1320 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
1321 : wxGridSizer( rows, cols, vgap, hgap ),
1322 m_flexDirection(wxBOTH),
1323 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1324 {
1325 }
1326
1327 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1328 : wxGridSizer( cols, vgap, hgap ),
1329 m_flexDirection(wxBOTH),
1330 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1331 {
1332 }
1333
1334 wxFlexGridSizer::~wxFlexGridSizer()
1335 {
1336 }
1337
1338 void wxFlexGridSizer::RecalcSizes()
1339 {
1340 int nitems, nrows, ncols;
1341 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1342 return;
1343
1344 wxPoint pt( GetPosition() );
1345 wxSize sz( GetSize() );
1346
1347 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols);
1348
1349 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1350
1351 int x = pt.x;
1352 for (int c = 0; c < ncols; c++)
1353 {
1354 int y = pt.y;
1355 for (int r = 0; r < nrows; r++)
1356 {
1357 int i = r * ncols + c;
1358 if (i < nitems)
1359 {
1360 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1361
1362 wxASSERT_MSG( node, _T("Failed to find node") );
1363
1364 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1365 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1366
1367 SetItemBounds( node->GetData(), x, y, w, h);
1368 }
1369 if (m_rowHeights[r] != -1)
1370 y = y + m_rowHeights[r] + m_vgap;
1371 }
1372 if (m_colWidths[c] != -1)
1373 x = x + m_colWidths[c] + m_hgap;
1374 }
1375 }
1376
1377 wxSize wxFlexGridSizer::CalcMin()
1378 {
1379 int nrows,
1380 ncols;
1381 size_t i, s;
1382
1383 // Number of rows/columns can change as items are added or removed.
1384 if ( !CalcRowsCols(nrows, ncols) )
1385 return wxSize();
1386
1387 m_rowHeights.SetCount(nrows);
1388 m_colWidths.SetCount(ncols);
1389
1390 // We have to recalcuate the sizes in case the item minimum size has
1391 // changed since the previous layout, or the item has been hidden using
1392 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1393 // dimension of the row/column will be -1, indicating that the column
1394 // itself is hidden.
1395 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1396 m_rowHeights[ i ] = -1;
1397 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1398 m_colWidths[ i ] = -1;
1399
1400 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1401
1402 i = 0;
1403 while (node)
1404 {
1405 wxSizerItem *item = node->GetData();
1406 if ( item->IsShown() )
1407 {
1408 wxSize sz( item->CalcMin() );
1409 int row = i / ncols;
1410 int col = i % ncols;
1411
1412 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1413 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1414 }
1415
1416 node = node->GetNext();
1417 i++;
1418 }
1419
1420 AdjustForFlexDirection();
1421
1422 // Sum total minimum size, including gaps between rows/columns.
1423 // -1 is used as a magic number meaning empty column.
1424 int width = 0;
1425 for (int col = 0; col < ncols; col++)
1426 if ( m_colWidths[ col ] != -1 )
1427 width += m_colWidths[ col ] + m_hgap;
1428 if (width > 0)
1429 width -= m_hgap;
1430
1431 int height = 0;
1432 for (int row = 0; row < nrows; row++)
1433 if ( m_rowHeights[ row ] != -1 )
1434 height += m_rowHeights[ row ] + m_vgap;
1435 if (height > 0)
1436 height -= m_vgap;
1437
1438 m_calculatedMinSize = wxSize( width, height );
1439 return m_calculatedMinSize;
1440 }
1441
1442 void wxFlexGridSizer::AdjustForFlexDirection()
1443 {
1444 // the logic in CalcMin works when we resize flexibly in both directions
1445 // but maybe this is not the case
1446 if ( m_flexDirection != wxBOTH )
1447 {
1448 // select the array corresponding to the direction in which we do *not*
1449 // resize flexibly
1450 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1451 : m_rowHeights;
1452
1453 const size_t count = array.GetCount();
1454
1455 // find the largest value in this array
1456 size_t n;
1457 int largest = 0;
1458
1459 for ( n = 0; n < count; ++n )
1460 {
1461 if ( array[n] > largest )
1462 largest = array[n];
1463 }
1464
1465 // and now fill it with the largest value
1466 for ( n = 0; n < count; ++n )
1467 {
1468 array[n] = largest;
1469 }
1470 }
1471 }
1472
1473
1474 void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1475 int nrows, int ncols)
1476 {
1477 // what to do with the rows? by default, resize them proportionally
1478 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1479 {
1480 int sum_proportions = 0;
1481 int growable_space = 0;
1482 int num = 0;
1483 size_t idx;
1484 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1485 {
1486 // Since the number of rows/columns can change as items are
1487 // inserted/deleted, we need to verify at runtime that the
1488 // requested growable rows/columns are still valid.
1489 if (m_growableRows[idx] >= nrows)
1490 continue;
1491
1492 // If all items in a row/column are hidden, that row/column will
1493 // have a dimension of -1. This causes the row/column to be
1494 // hidden completely.
1495 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1496 continue;
1497 sum_proportions += m_growableRowsProportions[idx];
1498 growable_space += m_rowHeights[ m_growableRows[idx] ];
1499 num++;
1500 }
1501
1502 if (num > 0)
1503 {
1504 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1505 {
1506 if (m_growableRows[idx] >= nrows )
1507 continue;
1508 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1509 m_rowHeights[ m_growableRows[idx] ] = 0;
1510 else
1511 {
1512 int delta = (sz.y - minsz.y);
1513 if (sum_proportions == 0)
1514 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1515 else
1516 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1517 m_rowHeights[ m_growableRows[idx] ] = delta;
1518 }
1519 }
1520 }
1521 }
1522 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1523 {
1524 // rounding problem?
1525 for ( int row = 0; row < nrows; ++row )
1526 m_rowHeights[ row ] = sz.y / nrows;
1527 }
1528
1529 // the same logic as above but for the columns
1530 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1531 {
1532 int sum_proportions = 0;
1533 int growable_space = 0;
1534 int num = 0;
1535 size_t idx;
1536 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1537 {
1538 // Since the number of rows/columns can change as items are
1539 // inserted/deleted, we need to verify at runtime that the
1540 // requested growable rows/columns are still valid.
1541 if (m_growableCols[idx] >= ncols)
1542 continue;
1543
1544 // If all items in a row/column are hidden, that row/column will
1545 // have a dimension of -1. This causes the column to be hidden
1546 // completely.
1547 if (m_colWidths[ m_growableCols[idx] ] == -1)
1548 continue;
1549 sum_proportions += m_growableColsProportions[idx];
1550 growable_space += m_colWidths[ m_growableCols[idx] ];
1551 num++;
1552 }
1553
1554 if (num > 0)
1555 {
1556 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1557 {
1558 if (m_growableCols[idx] >= ncols )
1559 continue;
1560 if (m_colWidths[ m_growableCols[idx] ] == -1)
1561 m_colWidths[ m_growableCols[idx] ] = 0;
1562 else
1563 {
1564 int delta = (sz.x - minsz.x);
1565 if (sum_proportions == 0)
1566 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1567 else
1568 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1569 m_colWidths[ m_growableCols[idx] ] = delta;
1570 }
1571 }
1572 }
1573 }
1574 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1575 {
1576 for ( int col=0; col < ncols; ++col )
1577 m_colWidths[ col ] = sz.x / ncols;
1578 }
1579 }
1580
1581
1582 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1583 {
1584 m_growableRows.Add( idx );
1585 m_growableRowsProportions.Add( proportion );
1586 }
1587
1588 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1589 {
1590 m_growableCols.Add( idx );
1591 m_growableColsProportions.Add( proportion );
1592 }
1593
1594 // helper function for RemoveGrowableCol/Row()
1595 static void
1596 DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1597 {
1598 const size_t count = items.size();
1599 for ( size_t n = 0; n < count; n++ )
1600 {
1601 if ( (size_t)items[n] == idx )
1602 {
1603 items.RemoveAt(n);
1604 proportions.RemoveAt(n);
1605 return;
1606 }
1607 }
1608
1609 wxFAIL_MSG( _T("column/row is already not growable") );
1610 }
1611
1612 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1613 {
1614 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1615 }
1616
1617 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1618 {
1619 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
1620 }
1621
1622 //---------------------------------------------------------------------------
1623 // wxBoxSizer
1624 //---------------------------------------------------------------------------
1625
1626 wxBoxSizer::wxBoxSizer( int orient )
1627 : m_orient( orient )
1628 {
1629 }
1630
1631 void wxBoxSizer::RecalcSizes()
1632 {
1633 if (m_children.GetCount() == 0)
1634 return;
1635
1636 int delta = 0;
1637 if (m_stretchable)
1638 {
1639 if (m_orient == wxHORIZONTAL)
1640 delta = m_size.x - m_fixedWidth;
1641 else
1642 delta = m_size.y - m_fixedHeight;
1643 }
1644
1645 wxPoint pt( m_position );
1646
1647 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1648 while (node)
1649 {
1650 wxSizerItem *item = node->GetData();
1651
1652 if (item->IsShown())
1653 {
1654 wxSize size( item->GetMinSizeWithBorder() );
1655
1656 if (m_orient == wxVERTICAL)
1657 {
1658 wxCoord height = size.y;
1659 if (item->GetProportion())
1660 {
1661 // Because of at least one visible item has non-zero
1662 // proportion then m_stretchable is not zero
1663 height = (delta * item->GetProportion()) / m_stretchable;
1664 }
1665
1666 wxPoint child_pos( pt );
1667 wxSize child_size( size.x, height );
1668
1669 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1670 child_size.x = m_size.x;
1671 else if (item->GetFlag() & wxALIGN_RIGHT)
1672 child_pos.x += m_size.x - size.x;
1673 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1674 // XXX wxCENTER is added for backward compatibility;
1675 // wxALIGN_CENTER should be used in new code
1676 child_pos.x += (m_size.x - size.x) / 2;
1677
1678 item->SetDimension( child_pos, child_size );
1679
1680 pt.y += height;
1681 }
1682 else
1683 {
1684 wxCoord width = size.x;
1685 if (item->GetProportion())
1686 {
1687 // Because of at least one visible item has non-zero
1688 // proportion then m_stretchable is not zero
1689 width = (delta * item->GetProportion()) / m_stretchable;
1690 }
1691
1692 wxPoint child_pos( pt );
1693 wxSize child_size( width, size.y );
1694
1695 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1696 child_size.y = m_size.y;
1697 else if (item->GetFlag() & wxALIGN_BOTTOM)
1698 child_pos.y += m_size.y - size.y;
1699 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1700 // XXX wxCENTER is added for backward compatibility;
1701 // wxALIGN_CENTER should be used in new code
1702 child_pos.y += (m_size.y - size.y) / 2;
1703
1704 if ( m_containingWindow )
1705 {
1706 child_pos.x = m_containingWindow->AdjustForLayoutDirection
1707 (
1708 child_pos.x,
1709 width,
1710 m_size.x
1711 );
1712 }
1713
1714 item->SetDimension( child_pos, child_size );
1715
1716 pt.x += width;
1717 }
1718 }
1719
1720 node = node->GetNext();
1721 }
1722 }
1723
1724 wxSize wxBoxSizer::CalcMin()
1725 {
1726 if (m_children.GetCount() == 0)
1727 return wxSize();
1728
1729 m_stretchable = 0;
1730 m_minWidth = 0;
1731 m_minHeight = 0;
1732 m_fixedWidth = 0;
1733 m_fixedHeight = 0;
1734
1735 // precalc item minsizes and count proportions
1736 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1737 while (node)
1738 {
1739 wxSizerItem *item = node->GetData();
1740
1741 if ( item->IsShown() )
1742 {
1743 item->CalcMin(); // result is stored in the item
1744
1745 m_stretchable += item->GetProportion();
1746 }
1747
1748 node = node->GetNext();
1749 }
1750
1751 // Total minimum size (width or height) of sizer
1752 int maxMinSize = 0;
1753
1754 node = m_children.GetFirst();
1755 while (node)
1756 {
1757 wxSizerItem *item = node->GetData();
1758
1759 if (item->IsShown() && item->GetProportion() != 0)
1760 {
1761 int stretch = item->GetProportion();
1762 wxSize size( item->GetMinSizeWithBorder() );
1763 int minSize;
1764
1765 // Integer division rounded up is (a + b - 1) / b
1766 // Round up needed in order to guarantee that all
1767 // all items will have size not less then their min size
1768 if (m_orient == wxHORIZONTAL)
1769 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
1770 else
1771 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
1772
1773 if (minSize > maxMinSize)
1774 maxMinSize = minSize;
1775 }
1776 node = node->GetNext();
1777 }
1778
1779 // Calculate overall minimum size
1780 node = m_children.GetFirst();
1781 while (node)
1782 {
1783 wxSizerItem *item = node->GetData();
1784
1785 if (item->IsShown())
1786 {
1787 wxSize size( item->GetMinSizeWithBorder() );
1788 if (item->GetProportion() != 0)
1789 {
1790 if (m_orient == wxHORIZONTAL)
1791 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
1792 else
1793 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
1794 }
1795 else
1796 {
1797 if (m_orient == wxVERTICAL)
1798 {
1799 m_fixedHeight += size.y;
1800 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1801 }
1802 else
1803 {
1804 m_fixedWidth += size.x;
1805 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1806 }
1807 }
1808
1809 if (m_orient == wxHORIZONTAL)
1810 {
1811 m_minWidth += size.x;
1812 m_minHeight = wxMax( m_minHeight, size.y );
1813 }
1814 else
1815 {
1816 m_minHeight += size.y;
1817 m_minWidth = wxMax( m_minWidth, size.x );
1818 }
1819 }
1820 node = node->GetNext();
1821 }
1822
1823 return wxSize( m_minWidth, m_minHeight );
1824 }
1825
1826 //---------------------------------------------------------------------------
1827 // wxStaticBoxSizer
1828 //---------------------------------------------------------------------------
1829
1830 #if wxUSE_STATBOX
1831
1832 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1833 : wxBoxSizer( orient ),
1834 m_staticBox( box )
1835 {
1836 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1837
1838 // do this so that our Detach() is called if the static box is destroyed
1839 // before we are
1840 m_staticBox->SetContainingSizer(this);
1841 }
1842
1843 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1844 : wxBoxSizer(orient),
1845 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1846 {
1847 // same as above
1848 m_staticBox->SetContainingSizer(this);
1849 }
1850
1851 wxStaticBoxSizer::~wxStaticBoxSizer()
1852 {
1853 delete m_staticBox;
1854 }
1855
1856 static void GetStaticBoxBorders( wxStaticBox *box,
1857 int *borderTop,
1858 int *borderOther)
1859 {
1860 // this has to be done platform by platform as there is no way to
1861 // guess the thickness of a wxStaticBox border
1862 box->GetBordersForSizer(borderTop, borderOther);
1863 }
1864
1865 void wxStaticBoxSizer::RecalcSizes()
1866 {
1867 int top_border, other_border;
1868 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1869
1870 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1871
1872 wxPoint old_pos( m_position );
1873 m_position.x += other_border;
1874 m_position.y += top_border;
1875 wxSize old_size( m_size );
1876 m_size.x -= 2*other_border;
1877 m_size.y -= top_border + other_border;
1878
1879 wxBoxSizer::RecalcSizes();
1880
1881 m_position = old_pos;
1882 m_size = old_size;
1883 }
1884
1885 wxSize wxStaticBoxSizer::CalcMin()
1886 {
1887 int top_border, other_border;
1888 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1889
1890 wxSize ret( wxBoxSizer::CalcMin() );
1891 ret.x += 2*other_border;
1892 ret.y += other_border + top_border;
1893
1894 return ret;
1895 }
1896
1897 void wxStaticBoxSizer::ShowItems( bool show )
1898 {
1899 m_staticBox->Show( show );
1900 wxBoxSizer::ShowItems( show );
1901 }
1902
1903 bool wxStaticBoxSizer::Detach( wxWindow *window )
1904 {
1905 // avoid deleting m_staticBox in our dtor if it's being detached from the
1906 // sizer (which can happen because it's being already destroyed for
1907 // example)
1908 if ( window == m_staticBox )
1909 {
1910 m_staticBox = NULL;
1911 return true;
1912 }
1913
1914 return wxSizer::Detach( window );
1915 }
1916
1917 #endif // wxUSE_STATBOX
1918
1919 #if wxUSE_BUTTON
1920
1921 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1922 : wxBoxSizer(wxHORIZONTAL)
1923 {
1924 // Vertical buttons with lots of space on either side
1925 // looks rubbish on WinCE, so let's not do this for now.
1926 // If we are going to use vertical buttons, we should
1927 // put the sizer to the right of other controls in the dialog,
1928 // and that's beyond the scope of this sizer.
1929 #ifndef __WXWINCE__
1930 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1931 // If we have a PDA screen, put yes/no button over
1932 // all other buttons, otherwise on the left side.
1933 if (is_pda)
1934 m_orient = wxVERTICAL;
1935 #endif
1936
1937 m_buttonAffirmative = NULL;
1938 m_buttonApply = NULL;
1939 m_buttonNegative = NULL;
1940 m_buttonCancel = NULL;
1941 m_buttonHelp = NULL;
1942 }
1943
1944 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1945 {
1946 switch (mybutton->GetId())
1947 {
1948 case wxID_OK:
1949 case wxID_YES:
1950 case wxID_SAVE:
1951 m_buttonAffirmative = mybutton;
1952 break;
1953 case wxID_APPLY:
1954 m_buttonApply = mybutton;
1955 break;
1956 case wxID_NO:
1957 m_buttonNegative = mybutton;
1958 break;
1959 case wxID_CANCEL:
1960 m_buttonCancel = mybutton;
1961 break;
1962 case wxID_HELP:
1963 case wxID_CONTEXT_HELP:
1964 m_buttonHelp = mybutton;
1965 break;
1966 default:
1967 break;
1968 }
1969 }
1970
1971 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1972 {
1973 m_buttonAffirmative = button;
1974 }
1975
1976 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1977 {
1978 m_buttonNegative = button;
1979 }
1980
1981 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1982 {
1983 m_buttonCancel = button;
1984 }
1985
1986 void wxStdDialogButtonSizer::Realize()
1987 {
1988 #ifdef __WXMAC__
1989 Add(0, 0, 0, wxLEFT, 6);
1990 if (m_buttonHelp)
1991 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1992
1993 if (m_buttonNegative){
1994 // HIG POLICE BULLETIN - destructive buttons need extra padding
1995 // 24 pixels on either side
1996 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1997 }
1998
1999 // extra whitespace between help/negative and cancel/ok buttons
2000 Add(0, 0, 1, wxEXPAND, 0);
2001
2002 if (m_buttonCancel){
2003 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2004 // Cancel or help should be default
2005 // m_buttonCancel->SetDefaultButton();
2006 }
2007
2008 // Ugh, Mac doesn't really have apply dialogs, so I'll just
2009 // figure the best place is between Cancel and OK
2010 if (m_buttonApply)
2011 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2012
2013 if (m_buttonAffirmative){
2014 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
2015
2016 if (m_buttonAffirmative->GetId() == wxID_SAVE){
2017 // these buttons have set labels under Mac so we should use them
2018 m_buttonAffirmative->SetLabel(_("Save"));
2019 m_buttonNegative->SetLabel(_("Don't Save"));
2020 }
2021 }
2022
2023 // Extra space around and at the right
2024 Add(12, 24);
2025 #elif defined(__WXGTK20__)
2026 Add(0, 0, 0, wxLEFT, 9);
2027 if (m_buttonHelp)
2028 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2029
2030 // extra whitespace between help and cancel/ok buttons
2031 Add(0, 0, 1, wxEXPAND, 0);
2032
2033 if (m_buttonNegative){
2034 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2035 }
2036
2037 if (m_buttonCancel){
2038 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2039 // Cancel or help should be default
2040 // m_buttonCancel->SetDefaultButton();
2041 }
2042
2043 if (m_buttonApply)
2044 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2045
2046 if (m_buttonAffirmative)
2047 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
2048 #elif defined(__WXMSW__)
2049 // Windows
2050
2051 // right-justify buttons
2052 Add(0, 0, 1, wxEXPAND, 0);
2053
2054 if (m_buttonAffirmative){
2055 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
2056 }
2057
2058 if (m_buttonNegative){
2059 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
2060 }
2061
2062 if (m_buttonCancel){
2063 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
2064 }
2065 if (m_buttonApply)
2066 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
2067
2068 if (m_buttonHelp)
2069 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
2070 #else
2071 // GTK+1 and any other platform
2072
2073 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
2074 if (m_buttonHelp)
2075 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
2076
2077 // extra whitespace between help and cancel/ok buttons
2078 Add(0, 0, 1, wxEXPAND, 0);
2079
2080 if (m_buttonApply)
2081 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
2082
2083 if (m_buttonAffirmative){
2084 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
2085 }
2086
2087 if (m_buttonNegative){
2088 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2089 }
2090
2091 if (m_buttonCancel){
2092 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
2093 // Cancel or help should be default
2094 // m_buttonCancel->SetDefaultButton();
2095 }
2096
2097 #endif
2098 }
2099
2100 #endif // wxUSE_BUTTON
2101
2102 #if WXWIN_COMPATIBILITY_2_4
2103
2104 // ----------------------------------------------------------------------------
2105 // wxNotebookSizer
2106 // ----------------------------------------------------------------------------
2107
2108 #if wxUSE_BOOKCTRL
2109 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
2110 #if wxUSE_NOTEBOOK
2111 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
2112 #endif // wxUSE_NOTEBOOK
2113 #endif // wxUSE_BOOKCTRL
2114
2115 #if wxUSE_BOOKCTRL
2116
2117 #if WXWIN_COMPATIBILITY_2_6
2118
2119 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
2120 : m_bookctrl(bookctrl)
2121 {
2122 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
2123 }
2124
2125 #endif // WXWIN_COMPATIBILITY_2_6
2126
2127 void wxBookCtrlSizer::RecalcSizes()
2128 {
2129 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
2130 }
2131
2132 wxSize wxBookCtrlSizer::CalcMin()
2133 {
2134 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0));
2135
2136 sizeBorder.x += 5;
2137 sizeBorder.y += 5;
2138
2139 if ( m_bookctrl->GetPageCount() == 0 )
2140 {
2141 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
2142 }
2143
2144 int maxX = 0;
2145 int maxY = 0;
2146
2147 wxWindowList::compatibility_iterator
2148 node = m_bookctrl->GetChildren().GetFirst();
2149 while (node)
2150 {
2151 wxWindow *item = node->GetData();
2152 wxSizer *itemsizer = item->GetSizer();
2153
2154 if (itemsizer)
2155 {
2156 wxSize subsize( itemsizer->CalcMin() );
2157
2158 if (subsize.x > maxX)
2159 maxX = subsize.x;
2160 if (subsize.y > maxY)
2161 maxY = subsize.y;
2162 }
2163
2164 node = node->GetNext();
2165 }
2166
2167 return wxSize( maxX, maxY ) + sizeBorder;
2168 }
2169
2170 #if wxUSE_NOTEBOOK
2171
2172 #if WXWIN_COMPATIBILITY_2_6
2173
2174 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
2175 {
2176 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
2177 m_bookctrl = nb;
2178 }
2179
2180 #endif // WXWIN_COMPATIBILITY_2_6
2181
2182 #endif // wxUSE_NOTEBOOOK
2183 #endif // wxUSE_BOOKCTRL
2184
2185 #endif // WXWIN_COMPATIBILITY_2_4