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/listimpl.cpp" 
  28 #if WXWIN_COMPATIBILITY_2_4 
  29     #include "wx/notebook.h" 
  33 #   include "wx/mac/uma.h" 
  36 //--------------------------------------------------------------------------- 
  38 IMPLEMENT_CLASS(wxSizerItem
, wxObject
) 
  39 IMPLEMENT_CLASS(wxSizer
, wxObject
) 
  40 IMPLEMENT_CLASS(wxGridSizer
, wxSizer
) 
  41 IMPLEMENT_CLASS(wxFlexGridSizer
, wxGridSizer
) 
  42 IMPLEMENT_CLASS(wxBoxSizer
, wxSizer
) 
  44 IMPLEMENT_CLASS(wxStaticBoxSizer
, wxBoxSizer
) 
  47 WX_DEFINE_EXPORTED_LIST( wxSizerItemList 
); 
  81 //--------------------------------------------------------------------------- 
  83 //--------------------------------------------------------------------------- 
  85 wxSizerItem::wxSizerItem( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
  88     , m_size( wxSize( width
, height 
) ) // size is set directly 
  89     , m_minSize( m_size 
)               // minimal size is the initial size 
  90     , m_proportion( proportion 
) 
  94     , m_userData( userData 
) 
  99 wxSizerItem::wxSizerItem( wxWindow 
*window
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 102     , m_proportion( proportion 
) 
 106     , m_userData( userData 
) 
 108     if (flag 
& wxFIXED_MINSIZE
) 
 109         window
->SetMinSize(window
->GetSize()); 
 110     m_minSize 
= window
->GetSize(); 
 112     // aspect ratio calculated from initial size 
 113     SetRatio( m_minSize 
); 
 115     // m_size is calculated later 
 118 wxSizerItem::wxSizerItem( wxSizer 
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 121     , m_proportion( proportion 
) 
 126     , m_userData( userData 
) 
 128     // m_minSize is calculated later 
 129     // m_size is calculated later 
 132 wxSizerItem::wxSizerItem() 
 144 wxSizerItem::~wxSizerItem() 
 150         m_window
->SetContainingSizer(NULL
); 
 152     else // we must be a sizer 
 159 wxSize 
wxSizerItem::GetSize() const 
 163         ret 
= m_sizer
->GetSize(); 
 166         ret 
= m_window
->GetSize(); 
 173     if (m_flag 
& wxNORTH
) 
 175     if (m_flag 
& wxSOUTH
) 
 181 wxSize 
wxSizerItem::CalcMin() 
 185         m_minSize 
= m_sizer
->GetMinSize(); 
 187         // if we have to preserve aspect ratio _AND_ this is 
 188         // the first-time calculation, consider ret to be initial size 
 189         if ((m_flag 
& wxSHAPED
) && !m_ratio
) 
 192     else if ( IsWindow() ) 
 194         // Since the size of the window may change during runtime, we 
 195         // should use the current minimal/best size. 
 196         m_minSize 
= m_window
->GetBestFittingSize(); 
 199     return GetMinSizeWithBorder(); 
 202 wxSize 
wxSizerItem::GetMinSizeWithBorder() const 
 204     wxSize ret 
= m_minSize
; 
 210     if (m_flag 
& wxNORTH
) 
 212     if (m_flag 
& wxSOUTH
) 
 219 void wxSizerItem::SetDimension( wxPoint pos
, wxSize size 
) 
 221     if (m_flag 
& wxSHAPED
) 
 223         // adjust aspect ratio 
 224         int rwidth 
= (int) (size
.y 
* m_ratio
); 
 228             int rheight 
= (int) (size
.x 
/ m_ratio
); 
 229             // add vertical space 
 230             if (m_flag 
& wxALIGN_CENTER_VERTICAL
) 
 231                 pos
.y 
+= (size
.y 
- rheight
) / 2; 
 232             else if (m_flag 
& wxALIGN_BOTTOM
) 
 233                 pos
.y 
+= (size
.y 
- rheight
); 
 234             // use reduced dimensions 
 237         else if (rwidth 
< size
.x
) 
 239             // add horizontal space 
 240             if (m_flag 
& wxALIGN_CENTER_HORIZONTAL
) 
 241                 pos
.x 
+= (size
.x 
- rwidth
) / 2; 
 242             else if (m_flag 
& wxALIGN_RIGHT
) 
 243                 pos
.x 
+= (size
.x 
- rwidth
); 
 248     // This is what GetPosition() returns. Since we calculate 
 249     // borders afterwards, GetPosition() will be the left/top 
 250     // corner of the surrounding border. 
 262     if (m_flag 
& wxNORTH
) 
 267     if (m_flag 
& wxSOUTH
) 
 273         m_sizer
->SetDimension( pos
.x
, pos
.y
, size
.x
, size
.y 
); 
 276         m_window
->SetSize( pos
.x
, pos
.y
, size
.x
, size
.y
, wxSIZE_ALLOW_MINUS_ONE 
); 
 281 void wxSizerItem::DeleteWindows() 
 290         m_sizer
->DeleteWindows(); 
 293 bool wxSizerItem::IsWindow() const 
 295     return (m_window 
!= NULL
); 
 298 bool wxSizerItem::IsSizer() const 
 300     return (m_sizer 
!= NULL
); 
 303 bool wxSizerItem::IsSpacer() const 
 305     return (m_window 
== NULL
) && (m_sizer 
== NULL
); 
 308 void wxSizerItem::Show( bool show 
) 
 313         m_window
->Show( show 
); 
 315         m_sizer
->ShowItems( show 
); 
 317     // ... nothing else to do to hide/show spacers 
 320 void wxSizerItem::SetOption( int option 
) 
 322     SetProportion( option 
); 
 325 int wxSizerItem::GetOption() const 
 327     return GetProportion(); 
 331 //--------------------------------------------------------------------------- 
 333 //--------------------------------------------------------------------------- 
 336     : m_minSize( wxSize( 0, 0 ) ) 
 342     WX_CLEAR_LIST(wxSizerItemList
, m_children
); 
 345 void wxSizer::Add( wxWindow 
*window
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 347     m_children
.Append( new wxSizerItem( window
, proportion
, flag
, border
, userData 
) ); 
 348     window
->SetContainingSizer( this ); 
 351 void wxSizer::Add( wxSizer 
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 353     m_children
.Append( new wxSizerItem( sizer
, proportion
, flag
, border
, userData 
) ); 
 356 void wxSizer::Add( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 358     m_children
.Append( new wxSizerItem( width
, height
, proportion
, flag
, border
, userData 
) ); 
 361 void wxSizer::Add( wxSizerItem 
*item 
) 
 363     m_children
.Append( item 
); 
 365     if( item
->GetWindow() ) 
 366         item
->GetWindow()->SetContainingSizer( this ); 
 369 void wxSizer::AddSpacer(int size
) 
 374 void wxSizer::AddStretchSpacer(int prop
) 
 379 void wxSizer::Prepend( wxWindow 
*window
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 381     m_children
.Insert( new wxSizerItem( window
, proportion
, flag
, border
, userData 
) ); 
 382     window
->SetContainingSizer( this ); 
 385 void wxSizer::Prepend( wxSizer 
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 387     m_children
.Insert( new wxSizerItem( sizer
, proportion
, flag
, border
, userData 
) ); 
 390 void wxSizer::Prepend( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData 
) 
 392     m_children
.Insert( new wxSizerItem( width
, height
, proportion
, flag
, border
, userData 
) ); 
 395 void wxSizer::Prepend( wxSizerItem 
*item 
) 
 397     m_children
.Insert( item 
); 
 399     if( item
->GetWindow() ) 
 400         item
->GetWindow()->SetContainingSizer( this ); 
 403 void wxSizer::PrependSpacer(int size
) 
 408 void wxSizer::PrependStretchSpacer(int prop
) 
 413 void wxSizer::Insert( size_t index
, 
 420     m_children
.Insert( index
, 
 421                        new wxSizerItem( window
, proportion
, flag
, border
, userData 
) ); 
 422     window
->SetContainingSizer( this ); 
 425 void wxSizer::Insert( size_t index
, 
 432     m_children
.Insert( index
, 
 433                        new wxSizerItem( sizer
, proportion
, flag
, border
, userData 
) ); 
 436 void wxSizer::Insert( size_t index
, 
 444     m_children
.Insert( index
, 
 445                        new wxSizerItem( width
, height
, proportion
, flag
, border
, userData 
) ); 
 448 void wxSizer::Insert( size_t index
, wxSizerItem 
*item 
) 
 450     m_children
.Insert( index
, item 
); 
 452     if( item
->GetWindow() ) 
 453         item
->GetWindow()->SetContainingSizer( this ); 
 456 void wxSizer::InsertSpacer(size_t index
, int size
) 
 458     Insert(index
, size
, size
); 
 461 void wxSizer::InsertStretchSpacer(size_t index
, int prop
) 
 463     Insert(index
, 0, 0, prop
); 
 466 bool wxSizer::Remove( wxWindow 
*window 
) 
 468     return Detach( window 
); 
 471 bool wxSizer::Remove( wxSizer 
*sizer 
) 
 473     wxASSERT_MSG( sizer
, _T("Removing NULL sizer") ); 
 475     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 478         wxSizerItem     
*item 
= node
->GetData(); 
 480         if (item
->GetSizer() == sizer
) 
 483             m_children
.Erase( node 
); 
 487         node 
= node
->GetNext(); 
 493 bool wxSizer::Remove( int index 
) 
 495     wxCHECK_MSG( index 
>= 0 && (size_t)index 
< m_children
.GetCount(), 
 497                  _T("Remove index is out of range") ); 
 499     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 501     wxCHECK_MSG( node
, false, _T("Failed to find child node") ); 
 503     wxSizerItem 
*item 
= node
->GetData(); 
 505     if( item
->IsWindow() ) 
 506         item
->GetWindow()->SetContainingSizer( NULL 
); 
 509     m_children
.Erase( node 
); 
 513 bool wxSizer::Detach( wxSizer 
*sizer 
) 
 515     wxASSERT_MSG( sizer
, _T("Detaching NULL sizer") ); 
 517     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 520         wxSizerItem     
*item 
= node
->GetData(); 
 522         if (item
->GetSizer() == sizer
) 
 526             m_children
.Erase( node 
); 
 529         node 
= node
->GetNext(); 
 535 bool wxSizer::Detach( wxWindow 
*window 
) 
 537     wxASSERT_MSG( window
, _T("Detaching NULL window") ); 
 539     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 542         wxSizerItem     
*item 
= node
->GetData(); 
 544         if (item
->GetWindow() == window
) 
 546             item
->GetWindow()->SetContainingSizer( NULL 
); 
 548             m_children
.Erase( node 
); 
 551         node 
= node
->GetNext(); 
 557 bool wxSizer::Detach( int index 
) 
 559     wxCHECK_MSG( index 
>= 0 && (size_t)index 
< m_children
.GetCount(), 
 561                  _T("Detach index is out of range") ); 
 563     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 565     wxCHECK_MSG( node
, false, _T("Failed to find child node") ); 
 567     wxSizerItem 
*item 
= node
->GetData(); 
 569     if( item
->IsSizer() ) 
 571     else if( item
->IsWindow() ) 
 572         item
->GetWindow()->SetContainingSizer( NULL 
); 
 575     m_children
.Erase( node 
); 
 579 void wxSizer::Clear( bool delete_windows 
) 
 581     // First clear the ContainingSizer pointers 
 582     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 585         wxSizerItem     
*item 
= node
->GetData(); 
 587         if (item
->IsWindow()) 
 588             item
->GetWindow()->SetContainingSizer( NULL 
); 
 589         node 
= node
->GetNext(); 
 592     // Destroy the windows if needed 
 596     // Now empty the list 
 597     WX_CLEAR_LIST(wxSizerItemList
, m_children
); 
 600 void wxSizer::DeleteWindows() 
 602     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 605         wxSizerItem     
*item 
= node
->GetData(); 
 607         item
->DeleteWindows(); 
 608         node 
= node
->GetNext(); 
 612 wxSize 
wxSizer::Fit( wxWindow 
*window 
) 
 614     wxSize 
size(window
->IsTopLevel() ? FitSize(window
) 
 615                                      : GetMinWindowSize(window
)); 
 617     window
->SetSize( size 
); 
 622 void wxSizer::FitInside( wxWindow 
*window 
) 
 625     if (window
->IsTopLevel()) 
 626         size 
= VirtualFitSize( window 
); 
 628         size 
= GetMinClientSize( window 
); 
 630     window
->SetVirtualSize( size 
); 
 633 void wxSizer::Layout() 
 635     // (re)calculates minimums needed for each item and other preparations 
 639     // Applies the layout and repositions/resizes the items 
 643 void wxSizer::SetSizeHints( wxWindow 
*window 
) 
 645     // Preserve the window's max size hints, but set the 
 646     // lower bound according to the sizer calculations. 
 648     wxSize size 
= Fit( window 
); 
 650     window
->SetSizeHints( size
.x
, 
 652                           window
->GetMaxWidth(), 
 653                           window
->GetMaxHeight() ); 
 656 void wxSizer::SetVirtualSizeHints( wxWindow 
*window 
) 
 658     // Preserve the window's max size hints, but set the 
 659     // lower bound according to the sizer calculations. 
 662     wxSize 
size( window
->GetVirtualSize() ); 
 663     window
->SetVirtualSizeHints( size
.x
, 
 665                                  window
->GetMaxWidth(), 
 666                                  window
->GetMaxHeight() ); 
 669 wxSize 
wxSizer::GetMaxWindowSize( wxWindow 
*window 
) const 
 671     return window
->GetMaxSize(); 
 674 wxSize 
wxSizer::GetMinWindowSize( wxWindow 
*window 
) 
 676     wxSize      
minSize( GetMinSize() ); 
 677     wxSize      
size( window
->GetSize() ); 
 678     wxSize      
client_size( window
->GetClientSize() ); 
 680     return wxSize( minSize
.x
+size
.x
-client_size
.x
, 
 681                    minSize
.y
+size
.y
-client_size
.y 
); 
 684 // TODO on mac we need a function that determines how much free space this 
 685 // min size contains, in order to make sure that we have 20 pixels of free 
 686 // space around the controls 
 688 // Return a window size that will fit within the screens dimensions 
 689 wxSize 
wxSizer::FitSize( wxWindow 
*window 
) 
 691     wxSize size     
= GetMinWindowSize( window 
); 
 692     wxSize sizeMax  
= GetMaxWindowSize( window 
); 
 694     // Limit the size if sizeMax != wxDefaultSize 
 696     if ( size
.x 
> sizeMax
.x 
&& sizeMax
.x 
!= -1 ) 
 698     if ( size
.y 
> sizeMax
.y 
&& sizeMax
.y 
!= -1 ) 
 704 wxSize 
wxSizer::GetMaxClientSize( wxWindow 
*window 
) const 
 706     wxSize 
maxSize( window
->GetMaxSize() ); 
 708     if( maxSize 
!= wxDefaultSize 
) 
 710         wxSize 
size( window
->GetSize() ); 
 711         wxSize 
client_size( window
->GetClientSize() ); 
 713         return wxSize( maxSize
.x 
+ client_size
.x 
- size
.x
, 
 714                        maxSize
.y 
+ client_size
.y 
- size
.y 
); 
 717         return wxDefaultSize
; 
 720 wxSize 
wxSizer::GetMinClientSize( wxWindow 
*WXUNUSED(window
) ) 
 722     return GetMinSize();  // Already returns client size. 
 725 wxSize 
wxSizer::VirtualFitSize( wxWindow 
*window 
) 
 727     wxSize size     
= GetMinClientSize( window 
); 
 728     wxSize sizeMax  
= GetMaxClientSize( window 
); 
 730     // Limit the size if sizeMax != wxDefaultSize 
 732     if ( size
.x 
> sizeMax
.x 
&& sizeMax
.x 
!= -1 ) 
 734     if ( size
.y 
> sizeMax
.y 
&& sizeMax
.y 
!= -1 ) 
 740 void wxSizer::SetDimension( int x
, int y
, int width
, int height 
) 
 749 wxSize 
wxSizer::GetMinSize() 
 751     wxSize 
ret( CalcMin() ); 
 752     if (ret
.x 
< m_minSize
.x
) ret
.x 
= m_minSize
.x
; 
 753     if (ret
.y 
< m_minSize
.y
) ret
.y 
= m_minSize
.y
; 
 757 void wxSizer::DoSetMinSize( int width
, int height 
) 
 760     m_minSize
.y 
= height
; 
 763 bool wxSizer::DoSetItemMinSize( wxWindow 
*window
, int width
, int height 
) 
 765     wxASSERT_MSG( window
, _T("SetMinSize for NULL window") ); 
 767     // Is it our immediate child? 
 769     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 772         wxSizerItem     
*item 
= node
->GetData(); 
 774         if (item
->GetWindow() == window
) 
 776             item
->SetMinSize( 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( window
, width
, height 
) ) 
 792             // A child sizer found the requested windw, exit. 
 795         node 
= node
->GetNext(); 
 801 bool wxSizer::DoSetItemMinSize( wxSizer 
*sizer
, int width
, int height 
) 
 803     wxASSERT_MSG( sizer
, _T("SetMinSize for NULL sizer") ); 
 805     // Is it our immediate child? 
 807     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 810         wxSizerItem     
*item 
= node
->GetData(); 
 812         if (item
->GetSizer() == sizer
) 
 814             item
->GetSizer()->DoSetMinSize( width
, height 
); 
 817         node 
= node
->GetNext(); 
 820     // No?  Search any subsizers we own then 
 822     node 
= m_children
.GetFirst(); 
 825         wxSizerItem     
*item 
= node
->GetData(); 
 827         if ( item
->GetSizer() && 
 828              item
->GetSizer()->DoSetItemMinSize( sizer
, width
, height 
) ) 
 830             // A child found the requested sizer, exit. 
 833         node 
= node
->GetNext(); 
 839 bool wxSizer::DoSetItemMinSize( size_t index
, int width
, int height 
) 
 841     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 843     wxCHECK_MSG( node
, false, _T("Failed to find child node") ); 
 845     wxSizerItem     
*item 
= node
->GetData(); 
 847     if (item
->GetSizer()) 
 849         // Sizers contains the minimal size in them, if not calculated ... 
 850         item
->GetSizer()->DoSetMinSize( width
, height 
); 
 854         // ... but the minimal size of spacers and windows is stored via the item 
 855         item
->SetMinSize( width
, height 
); 
 861 void wxSizer::Show( wxWindow 
*window
, bool show 
) 
 863     wxASSERT_MSG( window
, _T("Show for NULL window") ); 
 865     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 868         wxSizerItem     
*item 
= node
->GetData(); 
 870         if (item
->GetWindow() == window
) 
 875         node 
= node
->GetNext(); 
 879 void wxSizer::Show( wxSizer 
*sizer
, bool show 
) 
 881     wxASSERT_MSG( sizer
, _T("Show for NULL sizer") ); 
 883     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 886         wxSizerItem     
*item 
= node
->GetData(); 
 888         if (item
->GetSizer() == sizer
) 
 893         node 
= node
->GetNext(); 
 897 void wxSizer::Show( size_t index
, bool show 
) 
 899     wxCHECK_RET( index 
< m_children
.GetCount(), 
 900                  _T("Show index is out of range") ); 
 902     m_children
.Item( index 
)->GetData()->Show( show 
); 
 905 void wxSizer::ShowItems( bool show 
) 
 907     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 910         node
->GetData()->Show( show 
); 
 911         node 
= node
->GetNext(); 
 915 bool wxSizer::IsShown( wxWindow 
*window 
) const 
 917     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 920         wxSizerItem     
*item 
= node
->GetData(); 
 922         if (item
->GetWindow() == window
) 
 924             return item
->IsShown(); 
 926         node 
= node
->GetNext(); 
 929     wxFAIL_MSG( _T("IsShown failed to find sizer item") ); 
 934 bool wxSizer::IsShown( wxSizer 
*sizer 
) const 
 936     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 939         wxSizerItem     
*item 
= node
->GetData(); 
 941         if (item
->GetSizer() == sizer
) 
 943             return item
->IsShown(); 
 945         node 
= node
->GetNext(); 
 948     wxFAIL_MSG( _T("IsShown failed to find sizer item") ); 
 953 bool wxSizer::IsShown( size_t index 
) const 
 955     wxCHECK_MSG( index 
< m_children
.GetCount(), 
 957                  _T("IsShown index is out of range") ); 
 959     return m_children
.Item( index 
)->GetData()->IsShown(); 
 963 //--------------------------------------------------------------------------- 
 965 //--------------------------------------------------------------------------- 
 967 wxGridSizer::wxGridSizer( int rows
, int cols
, int vgap
, int hgap 
) 
 973     if (m_rows 
== 0 && m_cols 
== 0) 
 977 wxGridSizer::wxGridSizer( int cols
, int vgap
, int hgap 
) 
 983     if (m_rows 
== 0 && m_cols 
== 0) 
 987 int wxGridSizer::CalcRowsCols(int& nrows
, int& ncols
) const 
 989     int nitems 
= m_children
.GetCount(); 
 995             nrows 
= (nitems 
+ m_cols 
- 1) / m_cols
; 
 999             ncols 
= (nitems 
+ m_rows 
- 1) / m_rows
; 
1002         else // 0 columns, 0 rows? 
1004             wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); 
1013 void wxGridSizer::RecalcSizes() 
1015     int nitems
, nrows
, ncols
; 
1016     if ( (nitems 
= CalcRowsCols(nrows
, ncols
)) == 0 ) 
1019     wxSize 
sz( GetSize() ); 
1020     wxPoint 
pt( GetPosition() ); 
1022     int w 
= (sz
.x 
- (ncols 
- 1) * m_hgap
) / ncols
; 
1023     int h 
= (sz
.y 
- (nrows 
- 1) * m_vgap
) / nrows
; 
1026     for (int c 
= 0; c 
< ncols
; c
++) 
1029         for (int r 
= 0; r 
< nrows
; r
++) 
1031             int i 
= r 
* ncols 
+ c
; 
1034                 wxSizerItemList::compatibility_iterator node 
= m_children
.Item( i 
); 
1036                 wxASSERT_MSG( node
, _T("Failed to find SizerItemList node") ); 
1038                 SetItemBounds( node
->GetData(), x
, y
, w
, h
); 
1046 wxSize 
wxGridSizer::CalcMin() 
1049     if ( CalcRowsCols(nrows
, ncols
) == 0 ) 
1050         return wxSize(10, 10); 
1052     // Find the max width and height for any component 
1056     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1059         wxSizerItem     
*item 
= node
->GetData(); 
1060         wxSize           
sz( item
->CalcMin() ); 
1062         w 
= wxMax( w
, sz
.x 
); 
1063         h 
= wxMax( h
, sz
.y 
); 
1065         node 
= node
->GetNext(); 
1068     return wxSize( ncols 
* w 
+ (ncols
-1) * m_hgap
, 
1069                    nrows 
* h 
+ (nrows
-1) * m_vgap 
); 
1072 void wxGridSizer::SetItemBounds( wxSizerItem 
*item
, int x
, int y
, int w
, int h 
) 
1075     wxSize 
sz( item
->GetMinSizeWithBorder() );  
1076     int flag 
= item
->GetFlag(); 
1078     if ((flag 
& wxEXPAND
) || (flag 
& wxSHAPED
)) 
1084         if (flag 
& wxALIGN_CENTER_HORIZONTAL
) 
1086             pt
.x 
= x 
+ (w 
- sz
.x
) / 2; 
1088         else if (flag 
& wxALIGN_RIGHT
) 
1090             pt
.x 
= x 
+ (w 
- sz
.x
); 
1093         if (flag 
& wxALIGN_CENTER_VERTICAL
) 
1095             pt
.y 
= y 
+ (h 
- sz
.y
) / 2; 
1097         else if (flag 
& wxALIGN_BOTTOM
) 
1099             pt
.y 
= y 
+ (h 
- sz
.y
); 
1103     item
->SetDimension(pt
, sz
); 
1106 //--------------------------------------------------------------------------- 
1108 //--------------------------------------------------------------------------- 
1110 wxFlexGridSizer::wxFlexGridSizer( int rows
, int cols
, int vgap
, int hgap 
) 
1111                : wxGridSizer( rows
, cols
, vgap
, hgap 
), 
1112                  m_flexDirection(wxBOTH
), 
1113                  m_growMode(wxFLEX_GROWMODE_SPECIFIED
) 
1117 wxFlexGridSizer::wxFlexGridSizer( int cols
, int vgap
, int hgap 
) 
1118                : wxGridSizer( cols
, vgap
, hgap 
), 
1119                  m_flexDirection(wxBOTH
), 
1120                  m_growMode(wxFLEX_GROWMODE_SPECIFIED
) 
1124 wxFlexGridSizer::~wxFlexGridSizer() 
1128 void wxFlexGridSizer::RecalcSizes() 
1130     int nitems
, nrows
, ncols
; 
1131     if ( (nitems 
= CalcRowsCols(nrows
, ncols
)) == 0 ) 
1134     wxPoint 
pt( GetPosition() ); 
1135     wxSize 
sz( GetSize() ); 
1137     AdjustForGrowables(sz
, m_calculatedMinSize
, nrows
, ncols
); 
1139     sz 
= wxSize( pt
.x 
+ sz
.x
, pt
.y 
+ sz
.y 
); 
1142     for (int c 
= 0; c 
< ncols
; c
++) 
1145         for (int r 
= 0; r 
< nrows
; r
++) 
1147             int i 
= r 
* ncols 
+ c
; 
1150                 wxSizerItemList::compatibility_iterator node 
= m_children
.Item( i 
); 
1152                 wxASSERT_MSG( node
, _T("Failed to find node") ); 
1154                 int w 
= wxMax( 0, wxMin( m_colWidths
[c
], sz
.x 
- x 
) ); 
1155                 int h 
= wxMax( 0, wxMin( m_rowHeights
[r
], sz
.y 
- y 
) ); 
1157                 SetItemBounds( node
->GetData(), x
, y
, w
, h
); 
1159             y 
= y 
+ m_rowHeights
[r
] + m_vgap
; 
1161         x 
= x 
+ m_colWidths
[c
] + m_hgap
; 
1165 wxSize 
wxFlexGridSizer::CalcMin() 
1171     // Number of rows/columns can change as items are added or removed. 
1172     if ( !CalcRowsCols(nrows
, ncols
) ) 
1173         return wxSize(10, 10); 
1175     m_rowHeights
.SetCount(nrows
); 
1176     m_colWidths
.SetCount(ncols
); 
1178     // We have to recalcuate the sizes in case the item minimum size has 
1179     // changed since the previous layout, or the item has been hidden using 
1180     // wxSizer::Show(). If all the items in a row/column are hidden, the final 
1181     // dimension of the row/column will be -1, indicating that the column 
1182     // itself is hidden. 
1183     for( s 
= m_rowHeights
.GetCount(), i 
= 0; i 
< s
; ++i 
) 
1184         m_rowHeights
[ i 
] = -1; 
1185     for( s 
= m_colWidths
.GetCount(), i 
= 0; i 
< s
; ++i 
) 
1186         m_colWidths
[ i 
] = -1; 
1188     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1193         wxSizerItem    
*item 
= node
->GetData(); 
1194         if ( item
->IsShown() ) 
1196             wxSize 
sz( item
->CalcMin() ); 
1197             int row 
= i 
/ ncols
; 
1198             int col 
= i 
% ncols
; 
1200             m_rowHeights
[ row 
] = wxMax( wxMax( 0, sz
.y 
), m_rowHeights
[ row 
] ); 
1201             m_colWidths
[ col 
] = wxMax( wxMax( 0, sz
.x 
), m_colWidths
[ col 
] ); 
1204         node 
= node
->GetNext(); 
1208     AdjustForFlexDirection(); 
1210     // Sum total minimum size, including gaps between rows/columns. 
1211     // -1 is used as a magic number meaning empty column. 
1213     for (int col 
= 0; col 
< ncols
; col
++) 
1214         if ( m_colWidths
[ col 
] != -1 ) 
1215             width 
+= m_colWidths
[ col 
] + ( col 
== ncols
-1 ? 0 : m_hgap 
); 
1218     for (int row 
= 0; row 
< nrows
; row
++) 
1219         if ( m_rowHeights
[ row 
] != -1 ) 
1220             height 
+= m_rowHeights
[ row 
] + ( row 
== nrows
-1 ? 0 : m_vgap 
); 
1222     m_calculatedMinSize 
= wxSize( width
, height 
); 
1223     return m_calculatedMinSize
; 
1226 void wxFlexGridSizer::AdjustForFlexDirection() 
1228     // the logic in CalcMin works when we resize flexibly in both directions 
1229     // but maybe this is not the case 
1230     if ( m_flexDirection 
!= wxBOTH 
) 
1232         // select the array corresponding to the direction in which we do *not* 
1234         wxArrayInt
& array 
= m_flexDirection 
== wxVERTICAL 
? m_colWidths
 
1237         const int count 
= array
.GetCount(); 
1239         // find the largest value in this array 
1241         for ( n 
= 0; n 
< count
; ++n 
) 
1243             if ( array
[n
] > largest 
) 
1247         // and now fill it with the largest value 
1248         for ( n 
= 0; n 
< count
; ++n 
) 
1256 void wxFlexGridSizer::AdjustForGrowables(const wxSize
& sz
, const wxSize
& minsz
, 
1257                                          int nrows
, int ncols
) 
1259     // what to do with the rows? by default, resize them proportionally 
1260     if ( sz
.y 
> minsz
.y 
&& ( (m_flexDirection 
& wxVERTICAL
) || (m_growMode 
== wxFLEX_GROWMODE_SPECIFIED
) ) ) 
1262         int sum_proportions 
= 0; 
1263         int growable_space 
= 0; 
1266         for (idx 
= 0; idx 
< m_growableRows
.GetCount(); idx
++) 
1268             // Since the number of rows/columns can change as items are 
1269             // inserted/deleted, we need to verify at runtime that the 
1270             // requested growable rows/columns are still valid. 
1271             if (m_growableRows
[idx
] >= nrows
) 
1274             // If all items in a row/column are hidden, that row/column will 
1275             // have a dimension of -1.  This causes the row/column to be 
1276             // hidden completely. 
1277             if (m_rowHeights
[ m_growableRows
[idx
] ] == -1) 
1279             sum_proportions 
+= m_growableRowsProportions
[idx
]; 
1280             growable_space 
+= m_rowHeights
[ m_growableRows
[idx
] ]; 
1286             for (idx 
= 0; idx 
< m_growableRows
.GetCount(); idx
++) 
1288                 if (m_growableRows
[idx
] >= nrows 
) 
1290                 if (m_rowHeights
[ m_growableRows
[idx
] ] == -1) 
1291                     m_rowHeights
[ m_growableRows
[idx
] ] = 0; 
1294                     int delta 
= (sz
.y 
- minsz
.y
); 
1295                     if (sum_proportions 
== 0) 
1296                         delta 
= (delta
/num
) + m_rowHeights
[ m_growableRows
[idx
] ]; 
1298                         delta 
= ((delta
+growable_space
)*m_growableRowsProportions
[idx
]) / sum_proportions
; 
1299                     m_rowHeights
[ m_growableRows
[idx
] ] = delta
; 
1304     else if ( (m_growMode 
== wxFLEX_GROWMODE_ALL
) && (sz
.y 
> minsz
.y
) ) 
1306         // rounding problem? 
1307         for ( int row 
= 0; row 
< nrows
; ++row 
) 
1308             m_rowHeights
[ row 
] = sz
.y 
/ nrows
; 
1311     // the same logic as above but for the columns 
1312     if ( sz
.x 
> minsz
.x 
&& ( (m_flexDirection 
& wxHORIZONTAL
) || (m_growMode 
== wxFLEX_GROWMODE_SPECIFIED
) ) ) 
1314         int sum_proportions 
= 0; 
1315         int growable_space 
= 0; 
1318         for (idx 
= 0; idx 
< m_growableCols
.GetCount(); idx
++) 
1320             // Since the number of rows/columns can change as items are 
1321             // inserted/deleted, we need to verify at runtime that the 
1322             // requested growable rows/columns are still valid. 
1323             if (m_growableCols
[idx
] >= ncols
) 
1326             // If all items in a row/column are hidden, that row/column will 
1327             // have a dimension of -1.  This causes the column to be hidden 
1329             if (m_colWidths
[ m_growableCols
[idx
] ] == -1) 
1331             sum_proportions 
+= m_growableColsProportions
[idx
]; 
1332             growable_space 
+= m_colWidths
[ m_growableCols
[idx
] ]; 
1338             for (idx 
= 0; idx 
< m_growableCols
.GetCount(); idx
++) 
1340                 if (m_growableCols
[idx
] >= ncols 
) 
1342                 if (m_colWidths
[ m_growableCols
[idx
] ] == -1) 
1343                     m_colWidths
[ m_growableCols
[idx
] ] = 0; 
1346                     int delta 
= (sz
.x 
- minsz
.x
); 
1347                     if (sum_proportions 
== 0) 
1348                         delta 
= (delta
/num
) + m_colWidths
[ m_growableCols
[idx
] ]; 
1350                         delta 
= ((delta
+growable_space
)*m_growableColsProportions
[idx
])/sum_proportions
; 
1351                     m_colWidths
[ m_growableCols
[idx
] ] = delta
; 
1356     else if ( (m_growMode 
== wxFLEX_GROWMODE_ALL
) && (sz
.x 
> minsz
.x
) ) 
1358         for ( int col
=0; col 
< ncols
; ++col 
) 
1359             m_colWidths
[ col 
] = sz
.x 
/ ncols
; 
1364 void wxFlexGridSizer::AddGrowableRow( size_t idx
, int proportion 
) 
1366     m_growableRows
.Add( idx 
); 
1367     m_growableRowsProportions
.Add( proportion 
); 
1370 void wxFlexGridSizer::RemoveGrowableRow( size_t idx 
) 
1372     m_growableRows
.Remove( idx 
); 
1375 void wxFlexGridSizer::AddGrowableCol( size_t idx
, int proportion 
) 
1377     m_growableCols
.Add( idx 
); 
1378     m_growableColsProportions
.Add( proportion 
); 
1381 void wxFlexGridSizer::RemoveGrowableCol( size_t idx 
) 
1383     m_growableCols
.Remove( idx 
); 
1386 //--------------------------------------------------------------------------- 
1388 //--------------------------------------------------------------------------- 
1390 wxBoxSizer::wxBoxSizer( int orient 
) 
1391     : m_orient( orient 
) 
1395 void wxBoxSizer::RecalcSizes() 
1397     if (m_children
.GetCount() == 0) 
1403         if (m_orient 
== wxHORIZONTAL
) 
1404             delta 
= m_size
.x 
- m_fixedWidth
; 
1406             delta 
= m_size
.y 
- m_fixedHeight
; 
1409     wxPoint 
pt( m_position 
); 
1411     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1414         wxSizerItem     
*item 
= node
->GetData(); 
1416         if (item
->IsShown()) 
1418             wxSize 
size( item
->GetMinSizeWithBorder() ); 
1420             if (m_orient 
== wxVERTICAL
) 
1422                 wxCoord height 
= size
.y
; 
1423                 if (item
->GetProportion()) 
1425                     // Because of at least one visible item has non-zero 
1426                     // proportion then m_stretchable is not zero 
1427                     height 
= (delta 
* item
->GetProportion()) / m_stretchable
; 
1430                 wxPoint 
child_pos( pt 
); 
1431                 wxSize  
child_size( wxSize( size
.x
, height
) ); 
1433                 if (item
->GetFlag() & (wxEXPAND 
| wxSHAPED
)) 
1434                     child_size
.x 
= m_size
.x
; 
1435                 else if (item
->GetFlag() & wxALIGN_RIGHT
) 
1436                     child_pos
.x 
+= m_size
.x 
- size
.x
; 
1437                 else if (item
->GetFlag() & (wxCENTER 
| wxALIGN_CENTER_HORIZONTAL
)) 
1438                 // XXX wxCENTER is added for backward compatibility; 
1439                 //     wxALIGN_CENTER should be used in new code 
1440                     child_pos
.x 
+= (m_size
.x 
- size
.x
) / 2; 
1442                 item
->SetDimension( child_pos
, child_size 
); 
1448                 wxCoord width 
= size
.x
; 
1449                 if (item
->GetProportion()) 
1451                     // Because of at least one visible item has non-zero 
1452                     // proportion then m_stretchable is not zero 
1453                     width 
= (delta 
* item
->GetProportion()) / m_stretchable
; 
1456                 wxPoint 
child_pos( pt 
); 
1457                 wxSize  
child_size( wxSize(width
, size
.y
) ); 
1459                 if (item
->GetFlag() & (wxEXPAND 
| wxSHAPED
)) 
1460                     child_size
.y 
= m_size
.y
; 
1461                 else if (item
->GetFlag() & wxALIGN_BOTTOM
) 
1462                     child_pos
.y 
+= m_size
.y 
- size
.y
; 
1463                 else if (item
->GetFlag() & (wxCENTER 
| wxALIGN_CENTER_VERTICAL
)) 
1464                 // XXX wxCENTER is added for backward compatibility; 
1465                 //     wxALIGN_CENTER should be used in new code 
1466                     child_pos
.y 
+= (m_size
.y 
- size
.y
) / 2; 
1468                 item
->SetDimension( child_pos
, child_size 
); 
1474         node 
= node
->GetNext(); 
1478 wxSize 
wxBoxSizer::CalcMin() 
1480     if (m_children
.GetCount() == 0) 
1481         return wxSize(10,10); 
1489     // precalc item minsizes and count proportions 
1490     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
1493         wxSizerItem 
*item 
= node
->GetData(); 
1495         if (item
->IsShown()) 
1496             item
->CalcMin();  // result is stored in the item 
1498         if (item
->IsShown() && item
->GetProportion() != 0) 
1499             m_stretchable 
+= item
->GetProportion(); 
1501         node 
= node
->GetNext(); 
1504     // Total minimum size (width or height) of sizer 
1507     node 
= m_children
.GetFirst(); 
1510         wxSizerItem 
*item 
= node
->GetData(); 
1512         if (item
->IsShown() && item
->GetProportion() != 0) 
1514             int stretch 
= item
->GetProportion(); 
1515             wxSize 
size( item
->GetMinSizeWithBorder() ); 
1518             // Integer division rounded up is (a + b - 1) / b 
1519             // Round up needed in order to guarantee that all 
1520             // all items will have size not less then their min size 
1521             if (m_orient 
== wxHORIZONTAL
) 
1522                 minSize 
= ( size
.x
*m_stretchable 
+ stretch 
- 1)/stretch
; 
1524                 minSize 
= ( size
.y
*m_stretchable 
+ stretch 
- 1)/stretch
; 
1526             if (minSize 
> maxMinSize
) 
1527                 maxMinSize 
= minSize
; 
1529         node 
= node
->GetNext(); 
1532     // Calculate overall minimum size 
1533     node 
= m_children
.GetFirst(); 
1536         wxSizerItem 
*item 
= node
->GetData(); 
1538         if (item
->IsShown()) 
1540             wxSize 
size( item
->GetMinSizeWithBorder() ); 
1541             if (item
->GetProportion() != 0) 
1543                 if (m_orient 
== wxHORIZONTAL
) 
1544                     size
.x 
= (maxMinSize
*item
->GetProportion())/m_stretchable
; 
1546                     size
.y 
= (maxMinSize
*item
->GetProportion())/m_stretchable
; 
1550                 if (m_orient 
== wxVERTICAL
) 
1552                     m_fixedHeight 
+= size
.y
; 
1553                     m_fixedWidth 
= wxMax( m_fixedWidth
, size
.x 
); 
1557                     m_fixedWidth 
+= size
.x
; 
1558                     m_fixedHeight 
= wxMax( m_fixedHeight
, size
.y 
); 
1562             if (m_orient 
== wxHORIZONTAL
) 
1564                 m_minWidth 
+= size
.x
; 
1565                 m_minHeight 
= wxMax( m_minHeight
, size
.y 
); 
1569                 m_minHeight 
+= size
.y
; 
1570                 m_minWidth 
= wxMax( m_minWidth
, size
.x 
); 
1573         node 
= node
->GetNext(); 
1576     return wxSize( m_minWidth
, m_minHeight 
); 
1579 //--------------------------------------------------------------------------- 
1581 //--------------------------------------------------------------------------- 
1585 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox 
*box
, int orient 
) 
1586     : wxBoxSizer( orient 
) 
1587     , m_staticBox( box 
) 
1589     wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") ); 
1592 static void GetStaticBoxBorders( wxStaticBox 
*box
, 
1596     // this has to be done platform by platform as there is no way to 
1597     // guess the thickness of a wxStaticBox border 
1599     box
->GetBordersForSizer(borderTop
,borderOther
); 
1600 #elif defined(__WXMAC__) 
1602     static int extraTop 
= -1; // Uninitted 
1603     static int other 
= 5; 
1605     if ( extraTop 
== -1 ) 
1607         // The minimal border used for the top. Later on the staticbox' 
1608         // font height is added to this. 
1611         if ( UMAGetSystemVersion() >= 0x1030 /*Panther*/ ) 
1613             // As indicated by the HIG, Panther needs an extra border of 11 
1614             // pixels (otherwise overlapping occurs at the top). The "other" 
1615             // border has to be 11. 
1622     *borderTop 
= extraTop 
+ box
->GetCharHeight(); 
1623     *borderOther 
= other
; 
1627     if ( box
->GetLabel().IsEmpty() ) 
1631         *borderTop 
= box
->GetCharHeight(); 
1634 #endif // __WXCOCOA__ 
1637 void wxStaticBoxSizer::RecalcSizes() 
1639     int top_border
, other_border
; 
1640     GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
); 
1642     m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y 
); 
1644     wxPoint 
old_pos( m_position 
); 
1645     m_position
.x 
+= other_border
; 
1646     m_position
.y 
+= top_border
; 
1647     wxSize 
old_size( m_size 
); 
1648     m_size
.x 
-= 2*other_border
; 
1649     m_size
.y 
-= top_border 
+ other_border
; 
1651     wxBoxSizer::RecalcSizes(); 
1653     m_position 
= old_pos
; 
1657 wxSize 
wxStaticBoxSizer::CalcMin() 
1659     int top_border
, other_border
; 
1660     GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
); 
1662     wxSize 
ret( wxBoxSizer::CalcMin() ); 
1663     ret
.x 
+= 2*other_border
; 
1664     ret
.y 
+= other_border 
+ top_border
; 
1669 void wxStaticBoxSizer::ShowItems( bool show 
) 
1671     m_staticBox
->Show( show 
); 
1672     wxBoxSizer::ShowItems( show 
); 
1675 #endif // wxUSE_STATBOX 
1678 #if WXWIN_COMPATIBILITY_2_4 
1680 // ---------------------------------------------------------------------------- 
1682 // ---------------------------------------------------------------------------- 
1685 IMPLEMENT_CLASS(wxBookCtrlSizer
, wxSizer
) 
1687 IMPLEMENT_CLASS(wxNotebookSizer
, wxBookCtrlSizer
) 
1688 #endif // wxUSE_NOTEBOOK 
1689 #endif // wxUSE_BOOKCTRL 
1693 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrl 
*bookctrl
) 
1694                : m_bookctrl(bookctrl
) 
1696     wxASSERT_MSG( bookctrl
, wxT("wxBookCtrlSizer needs a control") ); 
1699 void wxBookCtrlSizer::RecalcSizes() 
1701     m_bookctrl
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y 
); 
1704 wxSize 
wxBookCtrlSizer::CalcMin() 
1706     wxSize sizeBorder 
= m_bookctrl
->CalcSizeFromPage(wxSize(0, 0)); 
1711     if ( m_bookctrl
->GetPageCount() == 0 ) 
1713         return wxSize(sizeBorder
.x 
+ 10, sizeBorder
.y 
+ 10); 
1719     wxWindowList::compatibility_iterator
 
1720         node 
= m_bookctrl
->GetChildren().GetFirst(); 
1723         wxWindow 
*item 
= node
->GetData(); 
1724         wxSizer 
*itemsizer 
= item
->GetSizer(); 
1728             wxSize 
subsize( itemsizer
->CalcMin() ); 
1730             if (subsize
.x 
> maxX
) 
1732             if (subsize
.y 
> maxY
) 
1736         node 
= node
->GetNext(); 
1739     return wxSize( maxX
, maxY 
) + sizeBorder
; 
1744 wxNotebookSizer::wxNotebookSizer(wxNotebook 
*nb
) 
1746     wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a control") ); 
1750 #endif // wxUSE_NOTEBOOOK 
1751 #endif // wxUSE_BOOKCTRL 
1753 #endif // WXWIN_COMPATIBILITY_2_4