]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
fix static box label drawing in RTL locale (patch 1552545)
[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