1 ///////////////////////////////////////////////////////////////////////////// 
   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 
   9 // Copyright:   (c) Robin Dunn, Robert Roebling 
  10 // Licence:     wxWindows licence 
  11 ///////////////////////////////////////////////////////////////////////////// 
  13 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  14 #pragma implementation "sizer.h" 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  26 #include "wx/statbox.h" 
  27 #include "wx/notebook.h" 
  28 #include "wx/listimpl.cpp" 
  31 #   include "wx/mac/uma.h" 
  34 //--------------------------------------------------------------------------- 
  36 IMPLEMENT_CLASS(wxSizerItem
, wxObject
) 
  37 IMPLEMENT_CLASS(wxSizer
, wxObject
) 
  38 IMPLEMENT_CLASS(wxGridSizer
, wxSizer
) 
  39 IMPLEMENT_CLASS(wxFlexGridSizer
, wxGridSizer
) 
  40 IMPLEMENT_CLASS(wxBoxSizer
, wxSizer
) 
  42 IMPLEMENT_CLASS(wxStaticBoxSizer
, wxBoxSizer
) 
  45 IMPLEMENT_CLASS(wxBookCtrlSizer
, wxSizer
) 
  47 IMPLEMENT_CLASS(wxNotebookSizer
, wxBookCtrlSizer
) 
  48 #endif // wxUSE_NOTEBOOK 
  49 #endif // wxUSE_BOOKCTRL 
  51 WX_DEFINE_EXPORTED_LIST( wxSizerItemList 
); 
  85 //--------------------------------------------------------------------------- 
  87 //--------------------------------------------------------------------------- 
  89 wxSizerItem::wxSizerItem( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
  92     , m_size( wxSize( width
, height 
) ) // size is set directly 
  93     , m_minSize( m_size 
)               // minimal size is the initial size 
  94     , m_proportion( proportion 
) 
  98     , m_userData( userData 
) 
 103 wxSizerItem::wxSizerItem( wxWindow 
*window
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 106     , m_minSize( window
->GetSize() )    // minimal size is the initial size 
 107     , m_proportion( proportion 
) 
 111     , m_userData( userData 
) 
 113     // aspect ratio calculated from initial size 
 114     SetRatio( m_minSize 
); 
 116     // m_size is calculated later 
 119 wxSizerItem::wxSizerItem( wxSizer 
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 122     , m_proportion( proportion 
) 
 127     , m_userData( userData 
) 
 129     // m_minSize is calculated later 
 130     // m_size is calculated later 
 133 wxSizerItem::wxSizerItem() 
 145 wxSizerItem::~wxSizerItem() 
 151         m_window
->SetContainingSizer(NULL
); 
 153     else // we must be a sizer 
 160 wxSize 
wxSizerItem::GetSize() const 
 164         ret 
= m_sizer
->GetSize(); 
 167         ret 
= m_window
->GetSize(); 
 174     if (m_flag 
& wxNORTH
) 
 176     if (m_flag 
& wxSOUTH
) 
 182 wxSize 
wxSizerItem::CalcMin() 
 187         ret 
= m_sizer
->GetMinSize(); 
 189         // if we have to preserve aspect ratio _AND_ this is 
 190         // the first-time calculation, consider ret to be initial size 
 191         if ((m_flag 
& wxSHAPED
) && !m_ratio
) 
 196         if ( IsWindow() && !(m_flag 
& wxFIXED_MINSIZE
) ) 
 198             // the size of the window may change during run-time, we should 
 199             // use the current minimal size 
 200             m_minSize 
= m_window
->GetAdjustedBestSize(); 
 210     if (m_flag 
& wxNORTH
) 
 212     if (m_flag 
& wxSOUTH
) 
 218 void wxSizerItem::SetDimension( wxPoint pos
, wxSize size 
) 
 220     if (m_flag 
& wxSHAPED
) 
 222         // adjust aspect ratio 
 223         int rwidth 
= (int) (size
.y 
* m_ratio
); 
 227             int rheight 
= (int) (size
.x 
/ m_ratio
); 
 228             // add vertical space 
 229             if (m_flag 
& wxALIGN_CENTER_VERTICAL
) 
 230                 pos
.y 
+= (size
.y 
- rheight
) / 2; 
 231             else if (m_flag 
& wxALIGN_BOTTOM
) 
 232                 pos
.y 
+= (size
.y 
- rheight
); 
 233             // use reduced dimensions 
 236         else if (rwidth 
< size
.x
) 
 238             // add horizontal space 
 239             if (m_flag 
& wxALIGN_CENTER_HORIZONTAL
) 
 240                 pos
.x 
+= (size
.x 
- rwidth
) / 2; 
 241             else if (m_flag 
& wxALIGN_RIGHT
) 
 242                 pos
.x 
+= (size
.x 
- rwidth
); 
 247     // This is what GetPosition() returns. Since we calculate 
 248     // borders afterwards, GetPosition() will be the left/top 
 249     // corner of the surrounding border. 
 261     if (m_flag 
& wxNORTH
) 
 266     if (m_flag 
& wxSOUTH
) 
 272         m_sizer
->SetDimension( pos
.x
, pos
.y
, size
.x
, size
.y 
); 
 275         m_window
->SetSize( pos
.x
, pos
.y
, size
.x
, size
.y
, wxSIZE_ALLOW_MINUS_ONE 
); 
 280 void wxSizerItem::DeleteWindows() 
 286         m_sizer
->DeleteWindows(); 
 289 bool wxSizerItem::IsWindow() const 
 291     return (m_window 
!= NULL
); 
 294 bool wxSizerItem::IsSizer() const 
 296     return (m_sizer 
!= NULL
); 
 299 bool wxSizerItem::IsSpacer() const 
 301     return (m_window 
== NULL
) && (m_sizer 
== NULL
); 
 304 void wxSizerItem::Show( bool show 
) 
 309         m_window
->Show( show 
); 
 311         m_sizer
->ShowItems( show 
); 
 313     // ... nothing else to do to hide/show spacers 
 316 void wxSizerItem::SetOption( int option 
) 
 318     SetProportion( option 
); 
 321 int wxSizerItem::GetOption() const 
 323     return GetProportion(); 
 327 //--------------------------------------------------------------------------- 
 329 //--------------------------------------------------------------------------- 
 332     : m_minSize( wxSize( 0, 0 ) ) 
 338     WX_CLEAR_LIST(wxSizerItemList
, m_children
); 
 341 void wxSizer::Add( wxWindow 
*window
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 343     m_children
.Append( new wxSizerItem( window
, proportion
, flag
, border
, userData 
) ); 
 344     window
->SetContainingSizer( this ); 
 347 void wxSizer::Add( wxSizer 
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 349     m_children
.Append( new wxSizerItem( sizer
, proportion
, flag
, border
, userData 
) ); 
 352 void wxSizer::Add( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 354     m_children
.Append( new wxSizerItem( width
, height
, proportion
, flag
, border
, userData 
) ); 
 357 void wxSizer::Add( wxSizerItem 
*item 
) 
 359     m_children
.Append( item 
); 
 361     if( item
->GetWindow() ) 
 362         item
->GetWindow()->SetContainingSizer( this ); 
 365 void wxSizer::Prepend( wxWindow 
*window
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 367     m_children
.Insert( new wxSizerItem( window
, proportion
, flag
, border
, userData 
) ); 
 368     window
->SetContainingSizer( this ); 
 371 void wxSizer::Prepend( wxSizer 
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 373     m_children
.Insert( new wxSizerItem( sizer
, proportion
, flag
, border
, userData 
) ); 
 376 void wxSizer::Prepend( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 378     m_children
.Insert( new wxSizerItem( width
, height
, proportion
, flag
, border
, userData 
) ); 
 381 void wxSizer::Prepend( wxSizerItem 
*item 
) 
 383     m_children
.Insert( item 
); 
 385     if( item
->GetWindow() ) 
 386         item
->GetWindow()->SetContainingSizer( this ); 
 389 void wxSizer::Insert( size_t index
, 
 396     m_children
.Insert( index
, 
 397                        new wxSizerItem( window
, proportion
, flag
, border
, userData 
) ); 
 398     window
->SetContainingSizer( this ); 
 401 void wxSizer::Insert( size_t index
, 
 408     m_children
.Insert( index
, 
 409                        new wxSizerItem( sizer
, proportion
, flag
, border
, userData 
) ); 
 412 void wxSizer::Insert( size_t index
, 
 420     m_children
.Insert( index
, 
 421                        new wxSizerItem( width
, height
, proportion
, flag
, border
, userData 
) ); 
 424 void wxSizer::Insert( size_t index
, wxSizerItem 
*item 
) 
 426     m_children
.Insert( index
, item 
); 
 428     if( item
->GetWindow() ) 
 429         item
->GetWindow()->SetContainingSizer( this ); 
 432 bool wxSizer::Remove( wxWindow 
*window 
) 
 434     return Detach( window 
); 
 437 bool wxSizer::Remove( wxSizer 
*sizer 
) 
 439     wxASSERT_MSG( sizer
, _T("Removing NULL sizer") ); 
 441     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 444         wxSizerItem     
*item 
= node
->GetData(); 
 446         if (item
->GetSizer() == sizer
) 
 449             m_children
.Erase( node 
); 
 453         node 
= node
->GetNext(); 
 459 bool wxSizer::Remove( int index 
) 
 461     wxCHECK_MSG( index 
>= 0 && (size_t)index 
< m_children
.GetCount(), 
 463                  _T("Remove index is out of range") ); 
 465     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 467     wxCHECK_MSG( node
, false, _T("Failed to find child node") ); 
 469     wxSizerItem 
*item 
= node
->GetData(); 
 471     if( item
->IsWindow() ) 
 472         item
->GetWindow()->SetContainingSizer( NULL 
); 
 475     m_children
.Erase( node 
); 
 479 bool wxSizer::Detach( wxSizer 
*sizer 
) 
 481     wxASSERT_MSG( sizer
, _T("Detaching NULL sizer") ); 
 483     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 486         wxSizerItem     
*item 
= node
->GetData(); 
 488         if (item
->GetSizer() == sizer
) 
 492             m_children
.Erase( node 
); 
 495         node 
= node
->GetNext(); 
 501 bool wxSizer::Detach( wxWindow 
*window 
) 
 503     wxASSERT_MSG( window
, _T("Detaching NULL window") ); 
 505     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 508         wxSizerItem     
*item 
= node
->GetData(); 
 510         if (item
->GetWindow() == window
) 
 512             item
->GetWindow()->SetContainingSizer( NULL 
); 
 514             m_children
.Erase( node 
); 
 517         node 
= node
->GetNext(); 
 523 bool wxSizer::Detach( int index 
) 
 525     wxCHECK_MSG( index 
>= 0 && (size_t)index 
< m_children
.GetCount(), 
 527                  _T("Detach index is out of range") ); 
 529     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 531     wxCHECK_MSG( node
, false, _T("Failed to find child node") ); 
 533     wxSizerItem 
*item 
= node
->GetData(); 
 535     if( item
->IsSizer() ) 
 537     else if( item
->IsWindow() ) 
 538         item
->GetWindow()->SetContainingSizer( NULL 
); 
 541     m_children
.Erase( node 
); 
 545 void wxSizer::Clear( bool delete_windows 
) 
 547     // First clear the ContainingSizer pointers 
 548     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 551         wxSizerItem     
*item 
= node
->GetData(); 
 553         if (item
->IsWindow()) 
 554             item
->GetWindow()->SetContainingSizer( NULL 
); 
 555         node 
= node
->GetNext(); 
 558     // Destroy the windows if needed 
 562     // Now empty the list 
 563     WX_CLEAR_LIST(wxSizerItemList
, m_children
); 
 566 void wxSizer::DeleteWindows() 
 568     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 571         wxSizerItem     
*item 
= node
->GetData(); 
 573         item
->DeleteWindows(); 
 574         node 
= node
->GetNext(); 
 578 wxSize 
wxSizer::Fit( wxWindow 
*window 
) 
 580     wxSize 
size(window
->IsTopLevel() ? FitSize(window
) 
 581                                      : GetMinWindowSize(window
)); 
 583     window
->SetSize( size 
); 
 588 void wxSizer::FitInside( wxWindow 
*window 
) 
 591     if (window
->IsTopLevel()) 
 592         size 
= VirtualFitSize( window 
); 
 594         size 
= GetMinClientSize( window 
); 
 596     window
->SetVirtualSize( size 
); 
 599 void wxSizer::Layout() 
 605 void wxSizer::SetSizeHints( wxWindow 
*window 
) 
 607     // Preserve the window's max size hints, but set the 
 608     // lower bound according to the sizer calculations. 
 610     wxSize size 
= Fit( window 
); 
 612     window
->SetSizeHints( size
.x
, 
 614                           window
->GetMaxWidth(), 
 615                           window
->GetMaxHeight() ); 
 618 void wxSizer::SetVirtualSizeHints( wxWindow 
*window 
) 
 620     // Preserve the window's max size hints, but set the 
 621     // lower bound according to the sizer calculations. 
 624     wxSize 
size( window
->GetVirtualSize() ); 
 625     window
->SetVirtualSizeHints( size
.x
, 
 627                                  window
->GetMaxWidth(), 
 628                                  window
->GetMaxHeight() ); 
 631 wxSize 
wxSizer::GetMaxWindowSize( wxWindow 
*window 
) const 
 633     return window
->GetMaxSize(); 
 636 wxSize 
wxSizer::GetMinWindowSize( wxWindow 
*window 
) 
 638     wxSize      
minSize( GetMinSize() ); 
 639     wxSize      
size( window
->GetSize() ); 
 640     wxSize      
client_size( window
->GetClientSize() ); 
 642     return wxSize( minSize
.x
+size
.x
-client_size
.x
, 
 643                    minSize
.y
+size
.y
-client_size
.y 
); 
 646 // TODO on mac we need a function that determines how much free space this 
 647 // min size contains, in order to make sure that we have 20 pixels of free 
 648 // space around the controls 
 650 // Return a window size that will fit within the screens dimensions 
 651 wxSize 
wxSizer::FitSize( wxWindow 
*window 
) 
 653     wxSize size     
= GetMinWindowSize( window 
); 
 654     wxSize sizeMax  
= GetMaxWindowSize( window 
); 
 656     // Limit the size if sizeMax != wxDefaultSize 
 658     if ( size
.x 
> sizeMax
.x 
&& sizeMax
.x 
!= -1 ) 
 660     if ( size
.y 
> sizeMax
.y 
&& sizeMax
.y 
!= -1 ) 
 666 wxSize 
wxSizer::GetMaxClientSize( wxWindow 
*window 
) const 
 668     wxSize 
maxSize( window
->GetMaxSize() ); 
 670     if( maxSize 
!= wxDefaultSize 
) 
 672         wxSize 
size( window
->GetSize() ); 
 673         wxSize 
client_size( window
->GetClientSize() ); 
 675         return wxSize( maxSize
.x 
+ client_size
.x 
- size
.x
, 
 676                        maxSize
.y 
+ client_size
.y 
- size
.y 
); 
 679         return wxDefaultSize
; 
 682 wxSize 
wxSizer::GetMinClientSize( wxWindow 
*WXUNUSED(window
) ) 
 684     return GetMinSize();  // Already returns client size. 
 687 wxSize 
wxSizer::VirtualFitSize( wxWindow 
*window 
) 
 689     wxSize size     
= GetMinClientSize( window 
); 
 690     wxSize sizeMax  
= GetMaxClientSize( window 
); 
 692     // Limit the size if sizeMax != wxDefaultSize 
 694     if ( size
.x 
> sizeMax
.x 
&& sizeMax
.x 
!= -1 ) 
 696     if ( size
.y 
> sizeMax
.y 
&& sizeMax
.y 
!= -1 ) 
 702 void wxSizer::SetDimension( int x
, int y
, int width
, int height 
) 
 711 wxSize 
wxSizer::GetMinSize() 
 713     wxSize 
ret( CalcMin() ); 
 714     if (ret
.x 
< m_minSize
.x
) ret
.x 
= m_minSize
.x
; 
 715     if (ret
.y 
< m_minSize
.y
) ret
.y 
= m_minSize
.y
; 
 719 void wxSizer::DoSetMinSize( int width
, int height 
) 
 722     m_minSize
.y 
= height
; 
 725 bool wxSizer::DoSetItemMinSize( wxWindow 
*window
, int width
, int height 
) 
 727     wxASSERT_MSG( window
, _T("SetMinSize for NULL window") ); 
 729     // Is it our immediate child? 
 731     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 734         wxSizerItem     
*item 
= node
->GetData(); 
 736         if (item
->GetWindow() == window
) 
 738             item
->SetMinSize( width
, height 
); 
 741         node 
= node
->GetNext(); 
 744     // No?  Search any subsizers we own then 
 746     node 
= m_children
.GetFirst(); 
 749         wxSizerItem     
*item 
= node
->GetData(); 
 751         if ( item
->GetSizer() && 
 752              item
->GetSizer()->DoSetItemMinSize( window
, width
, height 
) ) 
 754             // A child sizer found the requested windw, exit. 
 757         node 
= node
->GetNext(); 
 763 bool wxSizer::DoSetItemMinSize( wxSizer 
*sizer
, int width
, int height 
) 
 765     wxASSERT_MSG( sizer
, _T("SetMinSize for NULL sizer") ); 
 767     // Is it our immediate child? 
 769     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 772         wxSizerItem     
*item 
= node
->GetData(); 
 774         if (item
->GetSizer() == sizer
) 
 776             item
->GetSizer()->DoSetMinSize( width
, height 
); 
 779         node 
= node
->GetNext(); 
 782     // No?  Search any subsizers we own then 
 784     node 
= m_children
.GetFirst(); 
 787         wxSizerItem     
*item 
= node
->GetData(); 
 789         if ( item
->GetSizer() && 
 790              item
->GetSizer()->DoSetItemMinSize( sizer
, width
, height 
) ) 
 792             // A child found the requested sizer, exit. 
 795         node 
= node
->GetNext(); 
 801 bool wxSizer::DoSetItemMinSize( size_t index
, int width
, int height 
) 
 803     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 805     wxCHECK_MSG( node
, false, _T("Failed to find child node") ); 
 807     wxSizerItem     
*item 
= node
->GetData(); 
 809     if (item
->GetSizer()) 
 811         // Sizers contains the minimal size in them, if not calculated ... 
 812         item
->GetSizer()->DoSetMinSize( width
, height 
); 
 816         // ... but the minimal size of spacers and windows in stored in them 
 817         item
->SetMinSize( width
, height 
); 
 823 void wxSizer::Show( wxWindow 
*window
, bool show 
) 
 825     wxASSERT_MSG( window
, _T("Show for NULL window") ); 
 827     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 830         wxSizerItem     
*item 
= node
->GetData(); 
 832         if (item
->GetWindow() == window
) 
 837         node 
= node
->GetNext(); 
 841 void wxSizer::Show( wxSizer 
*sizer
, bool show 
) 
 843     wxASSERT_MSG( sizer
, _T("Show for NULL sizer") ); 
 845     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 848         wxSizerItem     
*item 
= node
->GetData(); 
 850         if (item
->GetSizer() == sizer
) 
 855         node 
= node
->GetNext(); 
 859 void wxSizer::Show( size_t index
, bool show 
) 
 861     wxCHECK_RET( index 
< m_children
.GetCount(), 
 862                  _T("Show index is out of range") ); 
 864     m_children
.Item( index 
)->GetData()->Show( show 
); 
 867 void wxSizer::ShowItems( bool show 
) 
 869     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 872         node
->GetData()->Show( show 
); 
 873         node 
= node
->GetNext(); 
 877 bool wxSizer::IsShown( wxWindow 
*window 
) const 
 879     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 882         wxSizerItem     
*item 
= node
->GetData(); 
 884         if (item
->GetWindow() == window
) 
 886             return item
->IsShown(); 
 888         node 
= node
->GetNext(); 
 891     wxFAIL_MSG( _T("IsShown failed to find sizer item") ); 
 896 bool wxSizer::IsShown( wxSizer 
*sizer 
) const 
 898     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 901         wxSizerItem     
*item 
= node
->GetData(); 
 903         if (item
->GetSizer() == sizer
) 
 905             return item
->IsShown(); 
 907         node 
= node
->GetNext(); 
 910     wxFAIL_MSG( _T("IsShown failed to find sizer item") ); 
 915 bool wxSizer::IsShown( size_t index 
) const 
 917     wxCHECK_MSG( index 
< m_children
.GetCount(), 
 919                  _T("IsShown index is out of range") ); 
 921     return m_children
.Item( index 
)->GetData()->IsShown(); 
 925 //--------------------------------------------------------------------------- 
 927 //--------------------------------------------------------------------------- 
 929 wxGridSizer::wxGridSizer( int rows
, int cols
, int vgap
, int hgap 
) 
 935     if (m_rows 
== 0 && m_cols 
== 0) 
 939 wxGridSizer::wxGridSizer( int cols
, int vgap
, int hgap 
) 
 945     if (m_rows 
== 0 && m_cols 
== 0) 
 949 int wxGridSizer::CalcRowsCols(int& nrows
, int& ncols
) const 
 951     int nitems 
= m_children
.GetCount(); 
 957             nrows 
= (nitems 
+ m_cols 
- 1) / m_cols
; 
 961             ncols 
= (nitems 
+ m_rows 
- 1) / m_rows
; 
 964         else // 0 columns, 0 rows? 
 966             wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); 
 975 void wxGridSizer::RecalcSizes() 
 977     int nitems
, nrows
, ncols
; 
 978     if ( (nitems 
= CalcRowsCols(nrows
, ncols
)) == 0 ) 
 981     wxSize 
sz( GetSize() ); 
 982     wxPoint 
pt( GetPosition() ); 
 984     int w 
= (sz
.x 
- (ncols 
- 1) * m_hgap
) / ncols
; 
 985     int h 
= (sz
.y 
- (nrows 
- 1) * m_vgap
) / nrows
; 
 988     for (int c 
= 0; c 
< ncols
; c
++) 
 991         for (int r 
= 0; r 
< nrows
; r
++) 
 993             int i 
= r 
* ncols 
+ c
; 
 996                 wxSizerItemList::compatibility_iterator node 
= m_children
.Item( i 
); 
 998                 wxASSERT_MSG( node
, _T("Failed to find SizerItemList node") ); 
1000                 SetItemBounds( node
->GetData(), x
, y
, w
, h
); 
1008 wxSize 
wxGridSizer::CalcMin() 
1011     if ( CalcRowsCols(nrows
, ncols
) == 0 ) 
1012         return wxSize(10, 10); 
1014     // Find the max width and height for any component 
1018     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1021         wxSizerItem     
*item 
= node
->GetData(); 
1022         wxSize           
sz( item
->CalcMin() ); 
1024         w 
= wxMax( w
, sz
.x 
); 
1025         h 
= wxMax( h
, sz
.y 
); 
1027         node 
= node
->GetNext(); 
1030     return wxSize( ncols 
* w 
+ (ncols
-1) * m_hgap
, 
1031                    nrows 
* h 
+ (nrows
-1) * m_vgap 
); 
1034 void wxGridSizer::SetItemBounds( wxSizerItem 
*item
, int x
, int y
, int w
, int h 
) 
1037     wxSize 
sz( item
->CalcMin() ); 
1038     int flag 
= item
->GetFlag(); 
1040     if ((flag 
& wxEXPAND
) || (flag 
& wxSHAPED
)) 
1046         if (flag 
& wxALIGN_CENTER_HORIZONTAL
) 
1048             pt
.x 
= x 
+ (w 
- sz
.x
) / 2; 
1050         else if (flag 
& wxALIGN_RIGHT
) 
1052             pt
.x 
= x 
+ (w 
- sz
.x
); 
1055         if (flag 
& wxALIGN_CENTER_VERTICAL
) 
1057             pt
.y 
= y 
+ (h 
- sz
.y
) / 2; 
1059         else if (flag 
& wxALIGN_BOTTOM
) 
1061             pt
.y 
= y 
+ (h 
- sz
.y
); 
1065     item
->SetDimension(pt
, sz
); 
1068 //--------------------------------------------------------------------------- 
1070 //--------------------------------------------------------------------------- 
1072 wxFlexGridSizer::wxFlexGridSizer( int rows
, int cols
, int vgap
, int hgap 
) 
1073                : wxGridSizer( rows
, cols
, vgap
, hgap 
), 
1074                  m_flexDirection(wxBOTH
), 
1075                  m_growMode(wxFLEX_GROWMODE_SPECIFIED
) 
1079 wxFlexGridSizer::wxFlexGridSizer( int cols
, int vgap
, int hgap 
) 
1080                : wxGridSizer( cols
, vgap
, hgap 
), 
1081                  m_flexDirection(wxBOTH
), 
1082                  m_growMode(wxFLEX_GROWMODE_SPECIFIED
) 
1086 wxFlexGridSizer::~wxFlexGridSizer() 
1090 void wxFlexGridSizer::RecalcSizes() 
1092     int nitems
, nrows
, ncols
; 
1093     if ( (nitems 
= CalcRowsCols(nrows
, ncols
)) == 0 ) 
1096     wxPoint 
pt( GetPosition() ); 
1097     wxSize 
sz( GetSize() ); 
1098     wxSize 
minsz( CalcMin() ); 
1100     AdjustForGrowables(sz
, minsz
, nrows
, ncols
); 
1102     sz 
= wxSize( pt
.x 
+ sz
.x
, pt
.y 
+ sz
.y 
); 
1105     for (int c 
= 0; c 
< ncols
; c
++) 
1108         for (int r 
= 0; r 
< nrows
; r
++) 
1110             int i 
= r 
* ncols 
+ c
; 
1113                 wxSizerItemList::compatibility_iterator node 
= m_children
.Item( i 
); 
1115                 wxASSERT_MSG( node
, _T("Failed to find node") ); 
1117                 int w 
= wxMax( 0, wxMin( m_colWidths
[c
], sz
.x 
- x 
) ); 
1118                 int h 
= wxMax( 0, wxMin( m_rowHeights
[r
], sz
.y 
- y 
) ); 
1120                 SetItemBounds( node
->GetData(), x
, y
, w
, h
); 
1122             y 
= y 
+ m_rowHeights
[r
] + m_vgap
; 
1124         x 
= x 
+ m_colWidths
[c
] + m_hgap
; 
1128 wxSize 
wxFlexGridSizer::CalcMin() 
1134     // Number of rows/columns can change as items are added or removed. 
1135     if ( !CalcRowsCols(nrows
, ncols
) ) 
1136         return wxSize(10, 10); 
1138     m_rowHeights
.SetCount(nrows
); 
1139     m_colWidths
.SetCount(ncols
); 
1141     // We have to recalcuate the sizes in case the item minimum size has 
1142     // changed since the previous layout, or the item has been hidden using 
1143     // wxSizer::Show(). If all the items in a row/column are hidden, the final 
1144     // dimension of the row/column will be -1, indicating that the column 
1145     // itself is hidden. 
1146     for( s 
= m_rowHeights
.GetCount(), i 
= 0; i 
< s
; ++i 
) 
1147         m_rowHeights
[ i 
] = -1; 
1148     for( s 
= m_colWidths
.GetCount(), i 
= 0; i 
< s
; ++i 
) 
1149         m_colWidths
[ i 
] = -1; 
1151     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1156         wxSizerItem    
*item 
= node
->GetData(); 
1157         if ( item
->IsShown() ) 
1159             wxSize 
sz( item
->CalcMin() ); 
1160             int row 
= i 
/ ncols
; 
1161             int col 
= i 
% ncols
; 
1163             m_rowHeights
[ row 
] = wxMax( wxMax( 0, sz
.y 
), m_rowHeights
[ row 
] ); 
1164             m_colWidths
[ col 
] = wxMax( wxMax( 0, sz
.x 
), m_colWidths
[ col 
] ); 
1167         node 
= node
->GetNext(); 
1171     AdjustForFlexDirection(); 
1173     // Sum total minimum size, including gaps between rows/columns. 
1174     // -1 is used as a magic number meaning empty column. 
1176     for (int col 
= 0; col 
< ncols
; col
++) 
1177         if ( m_colWidths
[ col 
] != -1 ) 
1178             width 
+= m_colWidths
[ col 
] + ( col 
== ncols
-1 ? 0 : m_hgap 
); 
1181     for (int row 
= 0; row 
< nrows
; row
++) 
1182         if ( m_rowHeights
[ row 
] != -1 ) 
1183             height 
+= m_rowHeights
[ row 
] + ( row 
== nrows
-1 ? 0 : m_vgap 
); 
1185     return wxSize( width
, height 
); 
1188 void wxFlexGridSizer::AdjustForFlexDirection() 
1190     // the logic in CalcMin works when we resize flexibly in both directions 
1191     // but maybe this is not the case 
1192     if ( m_flexDirection 
!= wxBOTH 
) 
1194         // select the array corresponding to the direction in which we do *not* 
1196         wxArrayInt
& array 
= m_flexDirection 
== wxVERTICAL 
? m_colWidths
 
1199         const int count 
= array
.GetCount(); 
1201         // find the largest value in this array 
1203         for ( n 
= 0; n 
< count
; ++n 
) 
1205             if ( array
[n
] > largest 
) 
1209         // and now fill it with the largest value 
1210         for ( n 
= 0; n 
< count
; ++n 
) 
1218 void wxFlexGridSizer::AdjustForGrowables(const wxSize
& sz
, const wxSize
& minsz
, 
1219                                          int nrows
, int ncols
) 
1221     // what to do with the rows? by default, resize them proportionally 
1222     if ( sz
.y 
> minsz
.y 
&& ( (m_flexDirection 
& wxVERTICAL
) || (m_growMode 
== wxFLEX_GROWMODE_SPECIFIED
) ) ) 
1224         int sum_proportions 
= 0; 
1225         int growable_space 
= 0; 
1228         for (idx 
= 0; idx 
< m_growableRows
.GetCount(); idx
++) 
1230             // Since the number of rows/columns can change as items are 
1231             // inserted/deleted, we need to verify at runtime that the 
1232             // requested growable rows/columns are still valid. 
1233             if (m_growableRows
[idx
] >= nrows
) 
1236             // If all items in a row/column are hidden, that row/column will 
1237             // have a dimension of -1.  This causes the row/column to be 
1238             // hidden completely. 
1239             if (m_rowHeights
[ m_growableRows
[idx
] ] == -1) 
1241             sum_proportions 
+= m_growableRowsProportions
[idx
]; 
1242             growable_space 
+= m_rowHeights
[ m_growableRows
[idx
] ]; 
1248             for (idx 
= 0; idx 
< m_growableRows
.GetCount(); idx
++) 
1250                 if (m_growableRows
[idx
] >= nrows 
) 
1252                 if (m_rowHeights
[ m_growableRows
[idx
] ] == -1) 
1253                     m_rowHeights
[ m_growableRows
[idx
] ] = 0; 
1256                     int delta 
= (sz
.y 
- minsz
.y
); 
1257                     if (sum_proportions 
== 0) 
1258                         delta 
= (delta
/num
) + m_rowHeights
[ m_growableRows
[idx
] ]; 
1260                         delta 
= ((delta
+growable_space
)*m_growableRowsProportions
[idx
]) / sum_proportions
; 
1261                     m_rowHeights
[ m_growableRows
[idx
] ] = delta
; 
1266     else if ( (m_growMode 
== wxFLEX_GROWMODE_ALL
) && (sz
.y 
> minsz
.y
) ) 
1268         // rounding problem? 
1269         for ( int row 
= 0; row 
< nrows
; ++row 
) 
1270             m_rowHeights
[ row 
] = sz
.y 
/ nrows
; 
1273     // the same logic as above but for the columns 
1274     if ( sz
.x 
> minsz
.x 
&& ( (m_flexDirection 
& wxHORIZONTAL
) || (m_growMode 
== wxFLEX_GROWMODE_SPECIFIED
) ) ) 
1276         int sum_proportions 
= 0; 
1277         int growable_space 
= 0; 
1280         for (idx 
= 0; idx 
< m_growableCols
.GetCount(); idx
++) 
1282             // Since the number of rows/columns can change as items are 
1283             // inserted/deleted, we need to verify at runtime that the 
1284             // requested growable rows/columns are still valid. 
1285             if (m_growableCols
[idx
] >= ncols
) 
1288             // If all items in a row/column are hidden, that row/column will 
1289             // have a dimension of -1.  This causes the column to be hidden 
1291             if (m_colWidths
[ m_growableCols
[idx
] ] == -1) 
1293             sum_proportions 
+= m_growableColsProportions
[idx
]; 
1294             growable_space 
+= m_colWidths
[ m_growableCols
[idx
] ]; 
1300             for (idx 
= 0; idx 
< m_growableCols
.GetCount(); idx
++) 
1302                 if (m_growableCols
[idx
] >= ncols 
) 
1304                 if (m_colWidths
[ m_growableCols
[idx
] ] == -1) 
1305                     m_colWidths
[ m_growableCols
[idx
] ] = 0; 
1308                     int delta 
= (sz
.x 
- minsz
.x
); 
1309                     if (sum_proportions 
== 0) 
1310                         delta 
= (delta
/num
) + m_colWidths
[ m_growableCols
[idx
] ]; 
1312                         delta 
= ((delta
+growable_space
)*m_growableColsProportions
[idx
])/sum_proportions
; 
1313                     m_colWidths
[ m_growableCols
[idx
] ] = delta
; 
1318     else if ( (m_growMode 
== wxFLEX_GROWMODE_ALL
) && (sz
.x 
> minsz
.x
) ) 
1320         for ( int col
=0; col 
< ncols
; ++col 
) 
1321             m_colWidths
[ col 
] = sz
.x 
/ ncols
; 
1326 void wxFlexGridSizer::AddGrowableRow( size_t idx
, int proportion 
) 
1328     m_growableRows
.Add( idx 
); 
1329     m_growableRowsProportions
.Add( proportion 
); 
1332 void wxFlexGridSizer::RemoveGrowableRow( size_t idx 
) 
1334     m_growableRows
.Remove( idx 
); 
1337 void wxFlexGridSizer::AddGrowableCol( size_t idx
, int proportion 
) 
1339     m_growableCols
.Add( idx 
); 
1340     m_growableColsProportions
.Add( proportion 
); 
1343 void wxFlexGridSizer::RemoveGrowableCol( size_t idx 
) 
1345     m_growableCols
.Remove( idx 
); 
1348 //--------------------------------------------------------------------------- 
1350 //--------------------------------------------------------------------------- 
1352 wxBoxSizer::wxBoxSizer( int orient 
) 
1353     : m_orient( orient 
) 
1357 void wxBoxSizer::RecalcSizes() 
1359     if (m_children
.GetCount() == 0) 
1365         if (m_orient 
== wxHORIZONTAL
) 
1366             delta 
= m_size
.x 
- m_fixedWidth
; 
1368             delta 
= m_size
.y 
- m_fixedHeight
; 
1371     wxPoint 
pt( m_position 
); 
1373     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1376         wxSizerItem     
*item 
= node
->GetData(); 
1378         if (item
->IsShown()) 
1380             wxSize 
size( item
->CalcMin() ); 
1382             if (m_orient 
== wxVERTICAL
) 
1384                 wxCoord height 
= size
.y
; 
1385                 if (item
->GetProportion()) 
1387                     // Because of at least one visible item has non-zero 
1388                     // proportion then m_stretchable is not zero 
1389                     height 
= (delta 
* item
->GetProportion()) / m_stretchable
; 
1392                 wxPoint 
child_pos( pt 
); 
1393                 wxSize  
child_size( wxSize( size
.x
, height
) ); 
1395                 if (item
->GetFlag() & (wxEXPAND 
| wxSHAPED
)) 
1396                     child_size
.x 
= m_size
.x
; 
1397                 else if (item
->GetFlag() & wxALIGN_RIGHT
) 
1398                     child_pos
.x 
+= m_size
.x 
- size
.x
; 
1399                 else if (item
->GetFlag() & (wxCENTER 
| wxALIGN_CENTER_HORIZONTAL
)) 
1400                 // XXX wxCENTER is added for backward compatibility; 
1401                 //     wxALIGN_CENTER should be used in new code 
1402                     child_pos
.x 
+= (m_size
.x 
- size
.x
) / 2; 
1404                 item
->SetDimension( child_pos
, child_size 
); 
1410                 wxCoord width 
= size
.x
; 
1411                 if (item
->GetProportion()) 
1413                     // Because of at least one visible item has non-zero 
1414                     // proportion then m_stretchable is not zero 
1415                     width 
= (delta 
* item
->GetProportion()) / m_stretchable
; 
1418                 wxPoint 
child_pos( pt 
); 
1419                 wxSize  
child_size( wxSize(width
, size
.y
) ); 
1421                 if (item
->GetFlag() & (wxEXPAND 
| wxSHAPED
)) 
1422                     child_size
.y 
= m_size
.y
; 
1423                 else if (item
->GetFlag() & wxALIGN_BOTTOM
) 
1424                     child_pos
.y 
+= m_size
.y 
- size
.y
; 
1425                 else if (item
->GetFlag() & (wxCENTER 
| wxALIGN_CENTER_VERTICAL
)) 
1426                 // XXX wxCENTER is added for backward compatibility; 
1427                 //     wxALIGN_CENTER should be used in new code 
1428                     child_pos
.y 
+= (m_size
.y 
- size
.y
) / 2; 
1430                 item
->SetDimension( child_pos
, child_size 
); 
1436         node 
= node
->GetNext(); 
1440 wxSize 
wxBoxSizer::CalcMin() 
1442     if (m_children
.GetCount() == 0) 
1443         return wxSize(10,10); 
1451     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1454         wxSizerItem 
*item 
= node
->GetData(); 
1456         if (item
->IsShown() && item
->GetProportion() != 0) 
1457             m_stretchable 
+= item
->GetProportion(); 
1459         node 
= node
->GetNext(); 
1462     // Total minimum size (width or height) of sizer 
1465     node 
= m_children
.GetFirst(); 
1468         wxSizerItem 
*item 
= node
->GetData(); 
1470         if (item
->IsShown() && item
->GetProportion() != 0) 
1472             int stretch 
= item
->GetProportion(); 
1473             wxSize 
size( item
->CalcMin() ); 
1476             // Integer division rounded up is (a + b - 1) / b 
1477             // Round up needed in order to guarantee that all 
1478             // all items will have size not less then their min size 
1479             if (m_orient 
== wxHORIZONTAL
) 
1480                 minSize 
= ( size
.x
*m_stretchable 
+ stretch 
- 1)/stretch
; 
1482                 minSize 
= ( size
.y
*m_stretchable 
+ stretch 
- 1)/stretch
; 
1484             if (minSize 
> maxMinSize
) 
1485                 maxMinSize 
= minSize
; 
1487         node 
= node
->GetNext(); 
1490     // Calculate overall minimum size 
1491     node 
= m_children
.GetFirst(); 
1494         wxSizerItem 
*item 
= node
->GetData(); 
1496         if (item
->IsShown()) 
1498             wxSize 
size( item
->CalcMin() ); 
1499             if (item
->GetProportion() != 0) 
1501                 if (m_orient 
== wxHORIZONTAL
) 
1502                     size
.x 
= (maxMinSize
*item
->GetProportion())/m_stretchable
; 
1504                     size
.y 
= (maxMinSize
*item
->GetProportion())/m_stretchable
; 
1508                 if (m_orient 
== wxVERTICAL
) 
1510                     m_fixedHeight 
+= size
.y
; 
1511                     m_fixedWidth 
= wxMax( m_fixedWidth
, size
.x 
); 
1515                     m_fixedWidth 
+= size
.x
; 
1516                     m_fixedHeight 
= wxMax( m_fixedHeight
, size
.y 
); 
1520             if (m_orient 
== wxHORIZONTAL
) 
1522                 m_minWidth 
+= size
.x
; 
1523                 m_minHeight 
= wxMax( m_minHeight
, size
.y 
); 
1527                 m_minHeight 
+= size
.y
; 
1528                 m_minWidth 
= wxMax( m_minWidth
, size
.x 
); 
1531         node 
= node
->GetNext(); 
1534     return wxSize( m_minWidth
, m_minHeight 
); 
1537 //--------------------------------------------------------------------------- 
1539 //--------------------------------------------------------------------------- 
1543 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox 
*box
, int orient 
) 
1544     : wxBoxSizer( orient 
) 
1545     , m_staticBox( box 
) 
1547     wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") ); 
1550 static void GetStaticBoxBorders( wxStaticBox 
*box
, 
1554     // this has to be done platform by platform as there is no way to 
1555     // guess the thickness of a wxStaticBox border 
1557     box
->GetBordersForSizer(borderTop
,borderOther
); 
1558 #elif defined(__WXMAC__) 
1560     static int extraTop 
= -1; // Uninitted 
1561     static int other 
= 5; 
1563     if ( extraTop 
== -1 ) 
1565         // The minimal border used for the top. Later on the staticbox' 
1566         // font height is added to this. 
1569         if ( UMAGetSystemVersion() >= 0x1030 /*Panther*/ ) 
1571             // As indicated by the HIG, Panther needs an extra border of 11 
1572             // pixels (otherwise overlapping occurs at the top). The "other" 
1573             // border has to be 11. 
1580     *borderTop 
= extraTop 
+ box
->GetCharHeight(); 
1581     *borderOther 
= other
; 
1585     if ( box
->GetLabel().IsEmpty() ) 
1589         *borderTop 
= box
->GetCharHeight(); 
1592 #endif // __WXCOCOA__ 
1595 void wxStaticBoxSizer::RecalcSizes() 
1597     int top_border
, other_border
; 
1598     GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
); 
1600     m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y 
); 
1602     wxPoint 
old_pos( m_position 
); 
1603     m_position
.x 
+= other_border
; 
1604     m_position
.y 
+= top_border
; 
1605     wxSize 
old_size( m_size 
); 
1606     m_size
.x 
-= 2*other_border
; 
1607     m_size
.y 
-= top_border 
+ other_border
; 
1609     wxBoxSizer::RecalcSizes(); 
1611     m_position 
= old_pos
; 
1615 wxSize 
wxStaticBoxSizer::CalcMin() 
1617     int top_border
, other_border
; 
1618     GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
); 
1620     wxSize 
ret( wxBoxSizer::CalcMin() ); 
1621     ret
.x 
+= 2*other_border
; 
1622     ret
.y 
+= other_border 
+ top_border
; 
1627 #endif // wxUSE_STATBOX 
1629 // ---------------------------------------------------------------------------- 
1631 // ---------------------------------------------------------------------------- 
1635 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrl 
*bookctrl
) 
1636                : m_bookctrl(bookctrl
) 
1638     wxASSERT_MSG( bookctrl
, wxT("wxBookCtrlSizer needs a control") ); 
1641 void wxBookCtrlSizer::RecalcSizes() 
1643     m_bookctrl
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y 
); 
1646 wxSize 
wxBookCtrlSizer::CalcMin() 
1648     wxSize sizeBorder 
= m_bookctrl
->CalcSizeFromPage(wxSize(0, 0)); 
1653     if ( m_bookctrl
->GetPageCount() == 0 ) 
1655         return wxSize(sizeBorder
.x 
+ 10, sizeBorder
.y 
+ 10); 
1661     wxWindowList::compatibility_iterator
 
1662         node 
= m_bookctrl
->GetChildren().GetFirst(); 
1665         wxWindow 
*item 
= node
->GetData(); 
1666         wxSizer 
*itemsizer 
= item
->GetSizer(); 
1670             wxSize 
subsize( itemsizer
->CalcMin() ); 
1672             if (subsize
.x 
> maxX
) 
1674             if (subsize
.y 
> maxY
) 
1678         node 
= node
->GetNext(); 
1681     return wxSize( maxX
, maxY 
) + sizeBorder
; 
1687 wxNotebookSizer::wxNotebookSizer(wxNotebook 
*nb
) 
1688     : wxBookCtrlSizer(nb
) 
1692 #endif // wxUSE_NOTEBOOOK 
1693 #endif // wxUSE_BOOKCTRL