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