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