]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
turning on old quit apple event handling
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
14 #pragma implementation "sizer.h"
15 #endif
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21     #pragma hdrstop
22 #endif
23
24 #include "wx/sizer.h"
25 #include "wx/utils.h"
26 #include "wx/statbox.h"
27 #include "wx/notebook.h"
28 #include <wx/listimpl.cpp>
29
30 //---------------------------------------------------------------------------
31
32 IMPLEMENT_CLASS(wxSizerItem, wxObject)
33 IMPLEMENT_CLASS(wxSizer, wxObject)
34 IMPLEMENT_CLASS(wxGridSizer, wxSizer)
35 IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
36 IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
37 #if wxUSE_STATBOX
38 IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
39 #endif
40 #if wxUSE_BOOKCTRL
41 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
42 #if wxUSE_NOTEBOOK
43 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
44 #endif // wxUSE_NOTEBOOK
45 #endif // wxUSE_BOOKCTRL
46
47 WX_DEFINE_EXPORTED_LIST( wxSizerItemList );
48
49 /*
50         TODO PROPERTIES
51           sizeritem
52             object
53                 object_ref
54                   minsize
55                   option
56                   flag
57                   border
58      spacer
59                 option
60                 flag
61                 borfder
62         boxsizer
63            orient
64     staticboxsizer
65            orient
66            label
67         gridsizer
68            rows
69            cols
70            vgap
71            hgap
72         flexgridsizer
73            rows
74            cols
75            vgap
76            hgap
77            growablerows
78            growablecols
79     minsize
80 */
81 //---------------------------------------------------------------------------
82 // wxSizerItem
83 //---------------------------------------------------------------------------
84
85 wxSizerItem::wxSizerItem( int width, int height, int proportion, int flag, int border, wxObject* userData )
86     : m_window( NULL )
87     , m_sizer( NULL )
88     , m_size( wxSize( width, height ) ) // size is set directly
89     , m_minSize( m_size )               // minimal size is the initial size
90     , m_proportion( proportion )
91     , m_border( border )
92     , m_flag( flag )
93     , m_show( true )
94     , m_userData( userData )
95 {
96     SetRatio( m_size );
97 }
98
99 wxSizerItem::wxSizerItem( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
100     : m_window( window )
101     , m_sizer( NULL )
102     , m_minSize( window->GetSize() )    // minimal size is the initial size
103     , m_proportion( proportion )
104     , m_border( border )
105     , m_flag( flag )
106     , m_show( true )
107     , m_userData( userData )
108 {
109     // aspect ratio calculated from initial size
110     SetRatio( m_minSize );
111
112     // m_size is calculated later
113 }
114
115 wxSizerItem::wxSizerItem( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
116     : m_window( NULL )
117     , m_sizer( sizer )
118     , m_proportion( proportion )
119     , m_border( border )
120     , m_flag( flag )
121     , m_show( true )
122     , m_ratio( 0.0 )
123     , m_userData( userData )
124 {
125     // m_minSize is calculated later
126     // m_size is calculated later
127 }
128
129 wxSizerItem::~wxSizerItem()
130 {
131     delete m_userData;
132
133     if ( m_window )
134     {
135         m_window->SetContainingSizer(NULL);
136     }
137     else // we must be a sizer
138     {
139         delete m_sizer;
140     }
141 }
142
143
144 wxSize wxSizerItem::GetSize() const
145 {
146     wxSize ret;
147     if (IsSizer())
148         ret = m_sizer->GetSize();
149     else
150     if (IsWindow())
151         ret = m_window->GetSize();
152     else ret = m_size;
153
154     if (m_flag & wxWEST)
155         ret.x += m_border;
156     if (m_flag & wxEAST)
157         ret.x += m_border;
158     if (m_flag & wxNORTH)
159         ret.y += m_border;
160     if (m_flag & wxSOUTH)
161         ret.y += m_border;
162
163     return ret;
164 }
165
166 wxSize wxSizerItem::CalcMin()
167 {
168     wxSize ret;
169     if (IsSizer())
170     {
171         ret = m_sizer->GetMinSize();
172
173         // if we have to preserve aspect ratio _AND_ this is
174         // the first-time calculation, consider ret to be initial size
175         if ((m_flag & wxSHAPED) && !m_ratio)
176             SetRatio(ret);
177     }
178     else
179     {
180         if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
181         {
182             // By user request, keep the minimal size for this item
183             // in sync with the largest of BestSize and any user supplied
184             // minimum size hint.  Useful in cases where the item is
185             // changeable -- static text labels, etc.
186             m_minSize = m_window->GetAdjustedBestSize();
187         }
188
189         ret = m_minSize;
190     }
191
192     if (m_flag & wxWEST)
193         ret.x += m_border;
194     if (m_flag & wxEAST)
195         ret.x += m_border;
196     if (m_flag & wxNORTH)
197         ret.y += m_border;
198     if (m_flag & wxSOUTH)
199         ret.y += m_border;
200
201     return ret;
202 }
203
204 void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
205 {
206     if (m_flag & wxSHAPED)
207     {
208         // adjust aspect ratio
209         int rwidth = (int) (size.y * m_ratio);
210         if (rwidth > size.x)
211         {
212             // fit horizontally
213             int rheight = (int) (size.x / m_ratio);
214             // add vertical space
215             if (m_flag & wxALIGN_CENTER_VERTICAL)
216                 pos.y += (size.y - rheight) / 2;
217             else if (m_flag & wxALIGN_BOTTOM)
218                 pos.y += (size.y - rheight);
219             // use reduced dimensions
220             size.y =rheight;
221         }
222         else if (rwidth < size.x)
223         {
224             // add horizontal space
225             if (m_flag & wxALIGN_CENTER_HORIZONTAL)
226                 pos.x += (size.x - rwidth) / 2;
227             else if (m_flag & wxALIGN_RIGHT)
228                 pos.x += (size.x - rwidth);
229             size.x = rwidth;
230         }
231     }
232
233     // This is what GetPosition() returns. Since we calculate
234     // borders afterwards, GetPosition() will be the left/top
235     // corner of the surrounding border.
236     m_pos = pos;
237
238     if (m_flag & wxWEST)
239     {
240         pos.x += m_border;
241         size.x -= m_border;
242     }
243     if (m_flag & wxEAST)
244     {
245         size.x -= m_border;
246     }
247     if (m_flag & wxNORTH)
248     {
249         pos.y += m_border;
250         size.y -= m_border;
251     }
252     if (m_flag & wxSOUTH)
253     {
254         size.y -= m_border;
255     }
256
257     if (IsSizer())
258         m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
259
260     if (IsWindow())
261         m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
262
263     m_size = size;
264 }
265
266 void wxSizerItem::DeleteWindows()
267 {
268     if (m_window)
269          m_window->Destroy();
270
271     if (m_sizer)
272         m_sizer->DeleteWindows();
273 }
274
275 bool wxSizerItem::IsWindow() const
276 {
277     return (m_window != NULL);
278 }
279
280 bool wxSizerItem::IsSizer() const
281 {
282     return (m_sizer != NULL);
283 }
284
285 bool wxSizerItem::IsSpacer() const
286 {
287     return (m_window == NULL) && (m_sizer == NULL);
288 }
289
290 void wxSizerItem::Show( bool show )
291 {
292     m_show = show;
293
294     if( IsWindow() )
295         m_window->Show( show );
296     else if( IsSizer() )
297         m_sizer->ShowItems( show );
298
299     // ... nothing else to do to hide/show spacers
300 }
301
302 void wxSizerItem::SetOption( int option )
303 {
304     SetProportion( option );
305 }
306
307 int wxSizerItem::GetOption() const
308 {
309     return GetProportion();
310 }
311
312
313 //---------------------------------------------------------------------------
314 // wxSizer
315 //---------------------------------------------------------------------------
316
317 wxSizer::wxSizer()
318     : m_minSize( wxSize( 0, 0 ) )
319 {
320 }
321
322 wxSizer::~wxSizer()
323 {
324     WX_CLEAR_LIST(wxSizerItemList, m_children);
325 }
326
327 void wxSizer::Add( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
328 {
329     m_children.Append( new wxSizerItem( window, proportion, flag, border, userData ) );
330     window->SetContainingSizer( this );
331 }
332
333 void wxSizer::Add( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
334 {
335     m_children.Append( new wxSizerItem( sizer, proportion, flag, border, userData ) );
336 }
337
338 void wxSizer::Add( int width, int height, int proportion, int flag, int border, wxObject* userData )
339 {
340     m_children.Append( new wxSizerItem( width, height, proportion, flag, border, userData ) );
341 }
342
343 void wxSizer::Add( wxSizerItem *item )
344 {
345     m_children.Append( item );
346
347     if( item->GetWindow() )
348         item->GetWindow()->SetContainingSizer( this );
349 }
350
351 void wxSizer::Prepend( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
352 {
353     m_children.Insert( new wxSizerItem( window, proportion, flag, border, userData ) );
354     window->SetContainingSizer( this );
355 }
356
357 void wxSizer::Prepend( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
358 {
359     m_children.Insert( new wxSizerItem( sizer, proportion, flag, border, userData ) );
360 }
361
362 void wxSizer::Prepend( int width, int height, int proportion, int flag, int border, wxObject* userData )
363 {
364     m_children.Insert( new wxSizerItem( width, height, proportion, flag, border, userData ) );
365 }
366
367 void wxSizer::Prepend( wxSizerItem *item )
368 {
369     m_children.Insert( item );
370
371     if( item->GetWindow() )
372         item->GetWindow()->SetContainingSizer( this );
373 }
374
375 void wxSizer::Insert( size_t index,
376                       wxWindow *window,
377                       int proportion,
378                       int flag,
379                       int border,
380                       wxObject* userData )
381 {
382     m_children.Insert( index,
383                        new wxSizerItem( window, proportion, flag, border, userData ) );
384     window->SetContainingSizer( this );
385 }
386
387 void wxSizer::Insert( size_t index,
388                       wxSizer *sizer,
389                       int proportion,
390                       int flag,
391                       int border,
392                       wxObject* userData )
393 {
394     m_children.Insert( index,
395                        new wxSizerItem( sizer, proportion, flag, border, userData ) );
396 }
397
398 void wxSizer::Insert( size_t index,
399                       int width,
400                       int height,
401                       int proportion,
402                       int flag,
403                       int border,
404                       wxObject* userData )
405 {
406     m_children.Insert( index,
407                        new wxSizerItem( width, height, proportion, flag, border, userData ) );
408 }
409
410 void wxSizer::Insert( size_t index, wxSizerItem *item )
411 {
412     m_children.Insert( index, item );
413
414     if( item->GetWindow() )
415         item->GetWindow()->SetContainingSizer( this );
416 }
417
418 bool wxSizer::Remove( wxWindow *window )
419 {
420     return Detach( window );
421 }
422
423 bool wxSizer::Remove( wxSizer *sizer )
424 {
425     wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
426
427     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
428     while (node)
429     {
430         wxSizerItem     *item = node->GetData();
431
432         if (item->GetSizer() == sizer)
433         {
434             delete item;
435             m_children.Erase( node );
436             return true;
437         }
438
439         node = node->GetNext();
440     }
441
442     return false;
443 }
444
445 bool wxSizer::Remove( int index )
446 {
447     wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
448                  false,
449                  _T("Remove index is out of range") );
450
451     wxSizerItemList::compatibility_iterator node = m_children.Item( index );
452
453     wxCHECK_MSG( node, false, _T("Failed to find child node") );
454
455     wxSizerItem *item = node->GetData();
456
457     if( item->IsWindow() )
458         item->GetWindow()->SetContainingSizer( NULL );
459
460     delete item;
461     m_children.Erase( node );
462     return true;
463 }
464
465 bool wxSizer::Detach( wxSizer *sizer )
466 {
467     wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
468
469     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
470     while (node)
471     {
472         wxSizerItem     *item = node->GetData();
473
474         if (item->GetSizer() == sizer)
475         {
476             item->DetachSizer();
477             delete item;
478             m_children.Erase( node );
479             return true;
480         }
481         node = node->GetNext();
482     }
483
484     return false;
485 }
486
487 bool wxSizer::Detach( wxWindow *window )
488 {
489     wxASSERT_MSG( window, _T("Detaching NULL window") );
490
491     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
492     while (node)
493     {
494         wxSizerItem     *item = node->GetData();
495
496         if (item->GetWindow() == window)
497         {
498             item->GetWindow()->SetContainingSizer( NULL );
499             delete item;
500             m_children.Erase( node );
501             return true;
502         }
503         node = node->GetNext();
504     }
505
506     return false;
507 }
508
509 bool wxSizer::Detach( int index )
510 {
511     wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
512                  false,
513                  _T("Detach index is out of range") );
514
515     wxSizerItemList::compatibility_iterator node = m_children.Item( index );
516
517     wxCHECK_MSG( node, false, _T("Failed to find child node") );
518
519     wxSizerItem *item = node->GetData();
520
521     if( item->IsSizer() )
522         item->DetachSizer();
523     else if( item->IsWindow() )
524         item->GetWindow()->SetContainingSizer( NULL );
525
526     delete item;
527     m_children.Erase( node );
528     return true;
529 }
530
531 void wxSizer::Clear( bool delete_windows )
532 {
533     // First clear the ContainingSizer pointers
534     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
535     while (node)
536     {
537         wxSizerItem     *item = node->GetData();
538
539         if (item->IsWindow())
540             item->GetWindow()->SetContainingSizer( NULL );
541         node = node->GetNext();
542     }
543
544     // Destroy the windows if needed
545     if (delete_windows)
546         DeleteWindows();
547
548     // Now empty the list
549     WX_CLEAR_LIST(wxSizerItemList, m_children);
550 }
551
552 void wxSizer::DeleteWindows()
553 {
554     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
555     while (node)
556     {
557         wxSizerItem     *item = node->GetData();
558
559         item->DeleteWindows();
560         node = node->GetNext();
561     }
562 }
563
564 wxSize wxSizer::Fit( wxWindow *window )
565 {
566     wxSize size(window->IsTopLevel() ? FitSize(window)
567                                      : GetMinWindowSize(window));
568
569     window->SetSize( size );
570
571     return size;
572 }
573
574 void wxSizer::FitInside( wxWindow *window )
575 {
576     wxSize size;
577     if (window->IsTopLevel())
578         size = VirtualFitSize( window );
579     else
580         size = GetMinClientSize( window );
581
582     window->SetVirtualSize( size );
583 }
584
585 void wxSizer::Layout()
586 {
587     CalcMin();
588     RecalcSizes();
589 }
590
591 void wxSizer::SetSizeHints( wxWindow *window )
592 {
593     // Preserve the window's max size hints, but set the
594     // lower bound according to the sizer calculations.
595
596     wxSize size = Fit( window );
597
598     window->SetSizeHints( size.x,
599                           size.y,
600                           window->GetMaxWidth(),
601                           window->GetMaxHeight() );
602 }
603
604 void wxSizer::SetVirtualSizeHints( wxWindow *window )
605 {
606     // Preserve the window's max size hints, but set the
607     // lower bound according to the sizer calculations.
608
609     FitInside( window );
610     wxSize size( window->GetVirtualSize() );
611     window->SetVirtualSizeHints( size.x,
612                                  size.y,
613                                  window->GetMaxWidth(),
614                                  window->GetMaxHeight() );
615 }
616
617 wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
618 {
619     return window->GetMaxSize();
620 }
621
622 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
623 {
624     wxSize      minSize( GetMinSize() );
625     wxSize      size( window->GetSize() );
626     wxSize      client_size( window->GetClientSize() );
627
628     return wxSize( minSize.x+size.x-client_size.x,
629                    minSize.y+size.y-client_size.y );
630 }
631
632 // Return a window size that will fit within the screens dimensions
633 wxSize wxSizer::FitSize( wxWindow *window )
634 {
635     wxSize size     = GetMinWindowSize( window );
636     wxSize sizeMax  = GetMaxWindowSize( window );
637
638     // Limit the size if sizeMax != wxDefaultSize
639
640     if ( size.x > sizeMax.x && sizeMax.x != -1 )
641         size.x = sizeMax.x;
642     if ( size.y > sizeMax.y && sizeMax.y != -1 )
643         size.y = sizeMax.y;
644
645     return size;
646 }
647
648 wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
649 {
650     wxSize maxSize( window->GetMaxSize() );
651
652     if( maxSize != wxDefaultSize )
653     {
654         wxSize size( window->GetSize() );
655         wxSize client_size( window->GetClientSize() );
656
657         return wxSize( maxSize.x + client_size.x - size.x,
658                        maxSize.y + client_size.y - size.y );
659     }
660     else
661         return wxDefaultSize;
662 }
663
664 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
665 {
666     return GetMinSize();  // Already returns client size.
667 }
668
669 wxSize wxSizer::VirtualFitSize( wxWindow *window )
670 {
671     wxSize size     = GetMinClientSize( window );
672     wxSize sizeMax  = GetMaxClientSize( window );
673
674     // Limit the size if sizeMax != wxDefaultSize
675
676     if ( size.x > sizeMax.x && sizeMax.x != -1 )
677         size.x = sizeMax.x;
678     if ( size.y > sizeMax.y && sizeMax.y != -1 )
679         size.y = sizeMax.y;
680
681     return size;
682 }
683
684 void wxSizer::SetDimension( int x, int y, int width, int height )
685 {
686     m_position.x = x;
687     m_position.y = y;
688     m_size.x = width;
689     m_size.y = height;
690     Layout();
691 }
692
693 wxSize wxSizer::GetMinSize()
694 {
695     wxSize ret( CalcMin() );
696     if (ret.x < m_minSize.x) ret.x = m_minSize.x;
697     if (ret.y < m_minSize.y) ret.y = m_minSize.y;
698     return ret;
699 }
700
701 void wxSizer::DoSetMinSize( int width, int height )
702 {
703     m_minSize.x = width;
704     m_minSize.y = height;
705 }
706
707 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
708 {
709     wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
710
711     // Is it our immediate child?
712
713     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
714     while (node)
715     {
716         wxSizerItem     *item = node->GetData();
717
718         if (item->GetWindow() == window)
719         {
720             item->SetInitSize( width, height );
721             return true;
722         }
723         node = node->GetNext();
724     }
725
726     // No?  Search any subsizers we own then
727
728     node = m_children.GetFirst();
729     while (node)
730     {
731         wxSizerItem     *item = node->GetData();
732
733         if ( item->GetSizer() &&
734              item->GetSizer()->DoSetItemMinSize( window, width, height ) )
735         {
736             // A child sizer found the requested windw, exit.
737             return true;
738         }
739         node = node->GetNext();
740     }
741
742     return false;
743 }
744
745 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
746 {
747     wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
748
749     // Is it our immediate child?
750
751     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
752     while (node)
753     {
754         wxSizerItem     *item = node->GetData();
755
756         if (item->GetSizer() == sizer)
757         {
758             item->GetSizer()->DoSetMinSize( width, height );
759             return true;
760         }
761         node = node->GetNext();
762     }
763
764     // No?  Search any subsizers we own then
765
766     node = m_children.GetFirst();
767     while (node)
768     {
769         wxSizerItem     *item = node->GetData();
770
771         if ( item->GetSizer() &&
772              item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
773         {
774             // A child found the requested sizer, exit.
775             return true;
776         }
777         node = node->GetNext();
778     }
779
780     return false;
781 }
782
783 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
784 {
785     wxSizerItemList::compatibility_iterator node = m_children.Item( index );
786
787     wxCHECK_MSG( node, false, _T("Failed to find child node") );
788
789     wxSizerItem     *item = node->GetData();
790
791     if (item->GetSizer())
792     {
793         // Sizers contains the minimal size in them, if not calculated ...
794         item->GetSizer()->DoSetMinSize( width, height );
795     }
796     else
797     {
798         // ... but the minimal size of spacers and windows in stored in them
799         item->SetInitSize( width, height );
800     }
801
802     return true;
803 }
804
805 void wxSizer::Show( wxWindow *window, bool show )
806 {
807     wxASSERT_MSG( window, _T("Show for NULL window") );
808
809     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
810     while (node)
811     {
812         wxSizerItem     *item = node->GetData();
813
814         if (item->GetWindow() == window)
815         {
816             item->Show( show );
817             break;
818         }
819         node = node->GetNext();
820     }
821 }
822
823 void wxSizer::Show( wxSizer *sizer, bool show )
824 {
825     wxASSERT_MSG( sizer, _T("Show for NULL sizer") );
826
827     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
828     while (node)
829     {
830         wxSizerItem     *item = node->GetData();
831
832         if (item->GetSizer() == sizer)
833         {
834             item->Show( show );
835             break;
836         }
837         node = node->GetNext();
838     }
839 }
840
841 void wxSizer::Show( size_t index, bool show )
842 {
843     wxCHECK_RET( index < m_children.GetCount(),
844                  _T("Show index is out of range") );
845
846     m_children.Item( index )->GetData()->Show( show );
847 }
848
849 void wxSizer::ShowItems( bool show )
850 {
851     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
852     while (node)
853     {
854         node->GetData()->Show( show );
855         node = node->GetNext();
856     }
857 }
858
859 bool wxSizer::IsShown( wxWindow *window ) const
860 {
861     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
862     while (node)
863     {
864         wxSizerItem     *item = node->GetData();
865
866         if (item->GetWindow() == window)
867         {
868             return item->IsShown();
869         }
870         node = node->GetNext();
871     }
872
873     wxFAIL_MSG( _T("IsShown failed to find sizer item") );
874
875     return false;
876 }
877
878 bool wxSizer::IsShown( wxSizer *sizer ) const
879 {
880     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
881     while (node)
882     {
883         wxSizerItem     *item = node->GetData();
884
885         if (item->GetSizer() == sizer)
886         {
887             return item->IsShown();
888         }
889         node = node->GetNext();
890     }
891
892     wxFAIL_MSG( _T("IsShown failed to find sizer item") );
893
894     return false;
895 }
896
897 bool wxSizer::IsShown( size_t index ) const
898 {
899     wxCHECK_MSG( index < m_children.GetCount(),
900                  false,
901                  _T("IsShown index is out of range") );
902
903     return m_children.Item( index )->GetData()->IsShown();
904 }
905
906
907 //---------------------------------------------------------------------------
908 // wxGridSizer
909 //---------------------------------------------------------------------------
910
911 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
912     : m_rows( rows )
913     , m_cols( cols )
914     , m_vgap( vgap )
915     , m_hgap( hgap )
916 {
917 }
918
919 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
920     : m_rows( 0 )
921     , m_cols( cols )
922     , m_vgap( vgap )
923     , m_hgap( hgap )
924 {
925 }
926
927 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
928 {
929     int nitems = m_children.GetCount();
930     if ( nitems)
931     {
932         if ( m_cols )
933         {
934             ncols = m_cols;
935             nrows = (nitems + m_cols - 1) / m_cols;
936         }
937         else if ( m_rows )
938         {
939             ncols = (nitems + m_rows - 1) / m_rows;
940             nrows = m_rows;
941         }
942         else // 0 columns, 0 rows?
943         {
944             wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
945
946             nrows = ncols = 0;
947         }
948     }
949
950     return nitems;
951 }
952
953 void wxGridSizer::RecalcSizes()
954 {
955     int nitems, nrows, ncols;
956     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
957         return;
958
959     wxSize sz( GetSize() );
960     wxPoint pt( GetPosition() );
961
962     int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
963     int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
964
965     int x = pt.x;
966     for (int c = 0; c < ncols; c++)
967     {
968         int y = pt.y;
969         for (int r = 0; r < nrows; r++)
970         {
971             int i = r * ncols + c;
972             if (i < nitems)
973             {
974                 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
975
976                 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
977
978                 SetItemBounds( node->GetData(), x, y, w, h);
979             }
980             y = y + h + m_vgap;
981         }
982         x = x + w + m_hgap;
983     }
984 }
985
986 wxSize wxGridSizer::CalcMin()
987 {
988     int nrows, ncols;
989     if ( CalcRowsCols(nrows, ncols) == 0 )
990         return wxSize(10, 10);
991
992     // Find the max width and height for any component
993     int w = 0;
994     int h = 0;
995
996     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
997     while (node)
998     {
999         wxSizerItem     *item = node->GetData();
1000         wxSize           sz( item->CalcMin() );
1001
1002         w = wxMax( w, sz.x );
1003         h = wxMax( h, sz.y );
1004
1005         node = node->GetNext();
1006     }
1007
1008     return wxSize( ncols * w + (ncols-1) * m_hgap,
1009                    nrows * h + (nrows-1) * m_vgap );
1010 }
1011
1012 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1013 {
1014     wxPoint pt( x,y );
1015     wxSize sz( item->CalcMin() );
1016     int flag = item->GetFlag();
1017
1018     if ((flag & wxEXPAND) || (flag & wxSHAPED))
1019     {
1020        sz = wxSize(w, h);
1021     }
1022     else
1023     {
1024         if (flag & wxALIGN_CENTER_HORIZONTAL)
1025         {
1026             pt.x = x + (w - sz.x) / 2;
1027         }
1028         else if (flag & wxALIGN_RIGHT)
1029         {
1030             pt.x = x + (w - sz.x);
1031         }
1032
1033         if (flag & wxALIGN_CENTER_VERTICAL)
1034         {
1035             pt.y = y + (h - sz.y) / 2;
1036         }
1037         else if (flag & wxALIGN_BOTTOM)
1038         {
1039             pt.y = y + (h - sz.y);
1040         }
1041     }
1042
1043     item->SetDimension(pt, sz);
1044 }
1045
1046 //---------------------------------------------------------------------------
1047 // wxFlexGridSizer
1048 //---------------------------------------------------------------------------
1049
1050 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
1051                : wxGridSizer( rows, cols, vgap, hgap ),
1052                  m_flexDirection(wxBOTH),
1053                  m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1054 {
1055 }
1056
1057 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1058                : wxGridSizer( cols, vgap, hgap ),
1059                  m_flexDirection(wxBOTH),
1060                  m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1061 {
1062 }
1063
1064 wxFlexGridSizer::~wxFlexGridSizer()
1065 {
1066 }
1067
1068 void wxFlexGridSizer::RecalcSizes()
1069 {
1070     int nitems, nrows, ncols;
1071     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1072         return;
1073
1074     wxSize sz( GetSize() );
1075     wxSize minsz( CalcMin() );
1076     wxPoint pt( GetPosition() );
1077
1078     // what to do with the rows? by default, resize them proportionally
1079     if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1080     {
1081         int sum_proportions = 0;
1082         int growable_space = 0;
1083         int num = 0;
1084         size_t idx;
1085         for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1086         {
1087             // Since the number of rows/columns can change as items are inserted/deleted, we need
1088             // to verify at runtime that the requested growable rows/columns are still valid.
1089             if (m_growableRows[idx] >= nrows)
1090                 continue;
1091             // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1092             // This causes the row/column to be hidden completely.
1093             if (m_rowHeights[ m_growableRows[idx] ] == -1)
1094                 continue;
1095             sum_proportions += m_growableRowsProportions[idx];
1096             growable_space += m_rowHeights[ m_growableRows[idx] ];
1097             num++;
1098         }
1099
1100         if (num > 0)
1101         {
1102             for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1103             {
1104                 if (m_growableRows[idx] >= nrows )
1105                     continue;
1106                 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1107                     m_rowHeights[ m_growableRows[idx] ] = 0;
1108                 else
1109                 {
1110                     int delta = (sz.y - minsz.y);
1111                     if (sum_proportions == 0)
1112                         delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1113                     else
1114                         delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1115                     m_rowHeights[ m_growableRows[idx] ] = delta;
1116                 }
1117             }
1118         }
1119     }
1120     else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1121     {
1122         // rounding problem?
1123         for ( int row = 0; row < nrows; ++row )
1124             m_rowHeights[ row ] = sz.y / nrows;
1125     }
1126
1127     // the same logic as above but for the columns
1128     if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1129     {
1130         int sum_proportions = 0;
1131         int growable_space = 0;
1132         int num = 0;
1133         size_t idx;
1134         for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1135         {
1136             // Since the number of rows/columns can change as items are inserted/deleted, we need
1137             // to verify at runtime that the requested growable rows/columns are still valid.
1138             if (m_growableCols[idx] >= ncols)
1139                 continue;
1140             // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1141             // This causes the column to be hidden completely.
1142             if (m_colWidths[ m_growableCols[idx] ] == -1)
1143                 continue;
1144             sum_proportions += m_growableColsProportions[idx];
1145             // wtb 5/12/02 bugfix - was m_ColWidths[idx]!!
1146             growable_space += m_colWidths[ m_growableCols[idx] ];
1147             num++;
1148         }
1149
1150         if (num > 0)
1151         {
1152             for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1153             {
1154                 if (m_growableCols[idx] >= ncols )
1155                     continue;
1156                 if (m_colWidths[ m_growableCols[idx] ] == -1)
1157                     m_colWidths[ m_growableCols[idx] ] = 0;
1158                 else
1159                 {
1160                     int delta = (sz.x - minsz.x);
1161                     if (sum_proportions == 0)
1162                         delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1163                     else
1164                         delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1165                     m_colWidths[ m_growableCols[idx] ] = delta;
1166                 }
1167             }
1168         }
1169     }
1170     else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1171     {
1172         for ( int col=0; col < ncols; ++col )
1173             m_colWidths[ col ] = sz.x / ncols;
1174     }
1175
1176     sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1177
1178     int x = pt.x;
1179     for (int c = 0; c < ncols; c++)
1180     {
1181         int y = pt.y;
1182         for (int r = 0; r < nrows; r++)
1183         {
1184             int i = r * ncols + c;
1185             if (i < nitems)
1186             {
1187                 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1188
1189                 wxASSERT_MSG( node, _T("Failed to find node") );
1190
1191                 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1192                 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1193
1194                 SetItemBounds( node->GetData(), x, y, w, h);
1195             }
1196             y = y + m_rowHeights[r] + m_vgap;
1197         }
1198         x = x + m_colWidths[c] + m_hgap;
1199     }
1200 }
1201
1202 wxSize wxFlexGridSizer::CalcMin()
1203 {
1204     int     nrows,
1205             ncols;
1206     size_t  i, s;
1207
1208     // Number of rows/columns can change as items are added or removed.
1209     if ( !CalcRowsCols(nrows, ncols) )
1210         return wxSize(10, 10);
1211
1212     m_rowHeights.SetCount(nrows);
1213     m_colWidths.SetCount(ncols);
1214
1215     // We have to recalcuate the sizes in case an item has wxADJUST_MINSIZE, has changed
1216     // minimum size since the previous layout, or has been hidden using wxSizer::Show().
1217     // If all the items in a row/column are hidden, the final dimension of the row/column
1218     // will be -1, indicating that the column itself is hidden.
1219     for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1220         m_rowHeights[ i ] = -1;
1221     for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1222         m_colWidths[ i ] = -1;
1223
1224     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1225
1226     i = 0;
1227     while (node)
1228     {
1229         wxSizerItem    *item = node->GetData();
1230         if ( item->IsShown() )
1231         {
1232             wxSize sz( item->CalcMin() );
1233             int row = i / ncols;
1234             int col = i % ncols;
1235
1236             m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1237             m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1238         }
1239
1240         node = node->GetNext();
1241         i++;
1242     }
1243
1244     // the logic above works when we resize flexibly in both directions but
1245     // maybe this is not the case
1246     if ( m_flexDirection != wxBOTH )
1247     {
1248         // select the array corresponding to the direction in which we do *not*
1249         // resize flexibly
1250         wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1251                                                           : m_rowHeights;
1252
1253         const int count = array.GetCount();
1254
1255         // find the largest value in this array
1256         int n, largest = 0;
1257         for ( n = 0; n < count; ++n )
1258         {
1259             if ( array[n] > largest )
1260                 largest = array[n];
1261         }
1262
1263         // and now fill it with the largest value
1264         for ( n = 0; n < count; ++n )
1265         {
1266             array[n] = largest;
1267         }
1268     }
1269
1270     // Sum total minimum size, including gaps between rows/columns.
1271     // -1 is used as a magic number meaning empty column.
1272     int width = 0;
1273     for (int col = 0; col < ncols; col++)
1274         if ( m_colWidths[ col ] != -1 )
1275             width += m_colWidths[ col ] + ( col == ncols-1 ? 0 : m_hgap );
1276
1277     int height = 0;
1278     for (int row = 0; row < nrows; row++)
1279         if ( m_rowHeights[ row ] != -1 )
1280             height += m_rowHeights[ row ] + ( row == nrows-1 ? 0 : m_vgap );
1281
1282     return wxSize( width, height );
1283 }
1284
1285 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1286 {
1287     m_growableRows.Add( idx );
1288     m_growableRowsProportions.Add( proportion );
1289 }
1290
1291 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1292 {
1293     m_growableRows.Remove( idx );
1294 }
1295
1296 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1297 {
1298     m_growableCols.Add( idx );
1299     m_growableColsProportions.Add( proportion );
1300 }
1301
1302 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1303 {
1304     m_growableCols.Remove( idx );
1305 }
1306
1307 //---------------------------------------------------------------------------
1308 // wxBoxSizer
1309 //---------------------------------------------------------------------------
1310
1311 wxBoxSizer::wxBoxSizer( int orient )
1312     : m_orient( orient )
1313 {
1314 }
1315
1316 void wxBoxSizer::RecalcSizes()
1317 {
1318     if (m_children.GetCount() == 0)
1319         return;
1320
1321     int delta = 0;
1322     if (m_stretchable)
1323     {
1324         if (m_orient == wxHORIZONTAL)
1325             delta = m_size.x - m_fixedWidth;
1326         else
1327             delta = m_size.y - m_fixedHeight;
1328     }
1329
1330     wxPoint pt( m_position );
1331
1332     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1333     while (node)
1334     {
1335         wxSizerItem     *item = node->GetData();
1336
1337         if (item->IsShown())
1338         {
1339             wxSize size( item->CalcMin() );
1340
1341             if (m_orient == wxVERTICAL)
1342             {
1343                 wxCoord height = size.y;
1344                 if (item->GetProportion())
1345                 {
1346                     // Because of at least one visible item has non-zero
1347                     // proportion then m_stretchable is not zero
1348                     height = (delta * item->GetProportion()) / m_stretchable;
1349                 }
1350
1351                 wxPoint child_pos( pt );
1352                 wxSize  child_size( wxSize( size.x, height) );
1353
1354                 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1355                     child_size.x = m_size.x;
1356                 else if (item->GetFlag() & wxALIGN_RIGHT)
1357                     child_pos.x += m_size.x - size.x;
1358                 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1359                 // XXX wxCENTER is added for backward compatibility;
1360                 //     wxALIGN_CENTER should be used in new code
1361                     child_pos.x += (m_size.x - size.x) / 2;
1362
1363                 item->SetDimension( child_pos, child_size );
1364
1365                 pt.y += height;
1366             }
1367             else
1368             {
1369                 wxCoord width = size.x;
1370                 if (item->GetProportion())
1371                 {
1372                     // Because of at least one visible item has non-zero
1373                     // proportion then m_stretchable is not zero
1374                     width = (delta * item->GetProportion()) / m_stretchable;
1375                 }
1376
1377                 wxPoint child_pos( pt );
1378                 wxSize  child_size( wxSize(width, size.y) );
1379
1380                 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1381                     child_size.y = m_size.y;
1382                 else if (item->GetFlag() & wxALIGN_BOTTOM)
1383                     child_pos.y += m_size.y - size.y;
1384                 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1385                 // XXX wxCENTER is added for backward compatibility;
1386                 //     wxALIGN_CENTER should be used in new code
1387                     child_pos.y += (m_size.y - size.y) / 2;
1388
1389                 item->SetDimension( child_pos, child_size );
1390
1391                 pt.x += width;
1392             }
1393         }
1394
1395         node = node->GetNext();
1396     }
1397 }
1398
1399 wxSize wxBoxSizer::CalcMin()
1400 {
1401     if (m_children.GetCount() == 0)
1402         return wxSize(10,10);
1403
1404     m_stretchable = 0;
1405     m_minWidth = 0;
1406     m_minHeight = 0;
1407     m_fixedWidth = 0;
1408     m_fixedHeight = 0;
1409
1410     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1411     while (node)
1412     {
1413         wxSizerItem *item = node->GetData();
1414
1415         if (item->IsShown() && item->GetProportion() != 0)
1416             m_stretchable += item->GetProportion();
1417
1418         node = node->GetNext();
1419     }
1420
1421     // Total minimum size (width or height) of sizer
1422     int maxMinSize = 0;
1423
1424     node = m_children.GetFirst();
1425     while (node)
1426     {
1427         wxSizerItem *item = node->GetData();
1428
1429         if (item->IsShown() && item->GetProportion() != 0)
1430         {
1431             int stretch = item->GetProportion();
1432             wxSize size( item->CalcMin() );
1433             int minSize;
1434             
1435             // Integer division rounded up is (a + b - 1) / b
1436             // Round up needed in order to guarantee that all
1437             // all items will have size not less then their min size
1438             if (m_orient == wxHORIZONTAL)
1439                 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
1440             else
1441                 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
1442             
1443             if (minSize > maxMinSize)
1444                 maxMinSize = minSize;
1445         }
1446         node = node->GetNext();
1447     }
1448
1449     // Calculate overall minimum size
1450     node = m_children.GetFirst();
1451     while (node)
1452     {
1453         wxSizerItem *item = node->GetData();
1454
1455         if (item->IsShown())
1456         {
1457             wxSize size( item->CalcMin() );
1458             if (item->GetProportion() != 0)
1459             {
1460                 if (m_orient == wxHORIZONTAL)
1461                     size.x = (maxMinSize*item->GetProportion())/m_stretchable;
1462                 else
1463                     size.y = (maxMinSize*item->GetProportion())/m_stretchable;
1464             }
1465             else
1466             {
1467                 if (m_orient == wxVERTICAL)
1468                 {
1469                     m_fixedHeight += size.y;
1470                     m_fixedWidth = wxMax( m_fixedWidth, size.x );
1471                 }
1472                 else
1473                 {
1474                     m_fixedWidth += size.x;
1475                     m_fixedHeight = wxMax( m_fixedHeight, size.y );
1476                 }
1477             }
1478
1479             if (m_orient == wxHORIZONTAL)
1480             {
1481                 m_minWidth += size.x;
1482                 m_minHeight = wxMax( m_minHeight, size.y );
1483             }
1484             else
1485             {
1486                 m_minHeight += size.y;
1487                 m_minWidth = wxMax( m_minWidth, size.x );
1488             }
1489         }
1490         node = node->GetNext();
1491     }
1492
1493     return wxSize( m_minWidth, m_minHeight );
1494 }
1495
1496 //---------------------------------------------------------------------------
1497 // wxStaticBoxSizer
1498 //---------------------------------------------------------------------------
1499
1500 #if wxUSE_STATBOX
1501
1502 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1503     : wxBoxSizer( orient )
1504     , m_staticBox( box )
1505 {
1506     wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1507 }
1508
1509 static void GetStaticBoxBorders( wxStaticBox *box,
1510                                  int *borderTop,
1511                                  int *borderOther)
1512 {
1513     // this has to be done platform by platform as there is no way to
1514     // guess the thickness of a wxStaticBox border
1515 #ifdef __WXCOCOA__
1516     box->GetBordersForSizer(borderTop,borderOther);
1517 #else // __WXCOCOA__
1518 #ifdef __WXGTK__
1519     if ( box->GetLabel().IsEmpty() )
1520         *borderTop = 5;
1521     else
1522 #endif // __WXGTK__
1523         *borderTop = box->GetCharHeight();
1524
1525     *borderOther = 5;
1526 #endif // __WXCOCOA__
1527 }
1528
1529 void wxStaticBoxSizer::RecalcSizes()
1530 {
1531     int top_border, other_border;
1532     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1533
1534     m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1535
1536     wxPoint old_pos( m_position );
1537     m_position.x += other_border;
1538     m_position.y += top_border;
1539     wxSize old_size( m_size );
1540     m_size.x -= 2*other_border;
1541     m_size.y -= top_border + other_border;
1542
1543     wxBoxSizer::RecalcSizes();
1544
1545     m_position = old_pos;
1546     m_size = old_size;
1547 }
1548
1549 wxSize wxStaticBoxSizer::CalcMin()
1550 {
1551     int top_border, other_border;
1552     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1553
1554     wxSize ret( wxBoxSizer::CalcMin() );
1555     ret.x += 2*other_border;
1556     ret.y += other_border + top_border;
1557
1558     return ret;
1559 }
1560
1561 #endif // wxUSE_STATBOX
1562
1563 // ----------------------------------------------------------------------------
1564 // wxNotebookSizer
1565 // ----------------------------------------------------------------------------
1566
1567 #if wxUSE_BOOKCTRL
1568
1569 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrl *bookctrl)
1570                : m_bookctrl(bookctrl)
1571 {
1572     wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
1573 }
1574
1575 void wxBookCtrlSizer::RecalcSizes()
1576 {
1577     m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1578 }
1579
1580 wxSize wxBookCtrlSizer::CalcMin()
1581 {
1582     wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0, 0));
1583
1584     sizeBorder.x += 5;
1585     sizeBorder.y += 5;
1586
1587     if ( m_bookctrl->GetPageCount() == 0 )
1588     {
1589         return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1590     }
1591
1592     int maxX = 0;
1593     int maxY = 0;
1594
1595     wxWindowList::compatibility_iterator
1596         node = m_bookctrl->GetChildren().GetFirst();
1597     while (node)
1598     {
1599         wxWindow *item = node->GetData();
1600         wxSizer *itemsizer = item->GetSizer();
1601
1602         if (itemsizer)
1603         {
1604             wxSize subsize( itemsizer->CalcMin() );
1605
1606             if (subsize.x > maxX)
1607                 maxX = subsize.x;
1608             if (subsize.y > maxY)
1609                 maxY = subsize.y;
1610         }
1611
1612         node = node->GetNext();
1613     }
1614
1615     return wxSize( maxX, maxY ) + sizeBorder;
1616 }
1617
1618
1619 #if wxUSE_NOTEBOOK
1620
1621 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
1622     : wxBookCtrlSizer(nb)
1623 {
1624 }
1625
1626 #endif // wxUSE_NOTEBOOOK
1627 #endif // wxUSE_BOOKCTRL
1628