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>
30 //---------------------------------------------------------------------------
32 IMPLEMENT_CLASS(wxSizerItem, wxObject)
33 IMPLEMENT_CLASS(wxSizer, wxObject)
34 IMPLEMENT_CLASS(wxGridSizer, wxSizer)
35 IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
36 IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
38 IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
41 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
43 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
44 #endif // wxUSE_NOTEBOOK
45 #endif // wxUSE_BOOKCTRL
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_minSize( window->GetSize() ) // minimal size is the initial size
103 , m_proportion( proportion )
107 , m_userData( userData )
109 // aspect ratio calculated from initial size
110 SetRatio( m_minSize );
112 // m_size is calculated later
115 wxSizerItem::wxSizerItem( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
118 , m_proportion( proportion )
123 , m_userData( userData )
125 // m_minSize is calculated later
126 // m_size is calculated later
129 wxSizerItem::~wxSizerItem()
135 m_window->SetContainingSizer(NULL);
137 else // we must be a sizer
144 wxSize wxSizerItem::GetSize() const
148 ret = m_sizer->GetSize();
151 ret = m_window->GetSize();
158 if (m_flag & wxNORTH)
160 if (m_flag & wxSOUTH)
166 wxSize wxSizerItem::CalcMin()
171 ret = m_sizer->GetMinSize();
173 // if we have to preserve aspect ratio _AND_ this is
174 // the first-time calculation, consider ret to be initial size
175 if ((m_flag & wxSHAPED) && !m_ratio)
180 if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
182 // By user request, keep the minimal size for this item
183 // in sync with the largest of BestSize and any user supplied
184 // minimum size hint. Useful in cases where the item is
185 // changeable -- static text labels, etc.
186 m_minSize = m_window->GetAdjustedBestSize();
196 if (m_flag & wxNORTH)
198 if (m_flag & wxSOUTH)
204 void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
206 if (m_flag & wxSHAPED)
208 // adjust aspect ratio
209 int rwidth = (int) (size.y * m_ratio);
213 int rheight = (int) (size.x / m_ratio);
214 // add vertical space
215 if (m_flag & wxALIGN_CENTER_VERTICAL)
216 pos.y += (size.y - rheight) / 2;
217 else if (m_flag & wxALIGN_BOTTOM)
218 pos.y += (size.y - rheight);
219 // use reduced dimensions
222 else if (rwidth < size.x)
224 // add horizontal space
225 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
226 pos.x += (size.x - rwidth) / 2;
227 else if (m_flag & wxALIGN_RIGHT)
228 pos.x += (size.x - rwidth);
233 // This is what GetPosition() returns. Since we calculate
234 // borders afterwards, GetPosition() will be the left/top
235 // corner of the surrounding border.
247 if (m_flag & wxNORTH)
252 if (m_flag & wxSOUTH)
258 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
261 m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
266 void wxSizerItem::DeleteWindows()
272 m_sizer->DeleteWindows();
275 bool wxSizerItem::IsWindow() const
277 return (m_window != NULL);
280 bool wxSizerItem::IsSizer() const
282 return (m_sizer != NULL);
285 bool wxSizerItem::IsSpacer() const
287 return (m_window == NULL) && (m_sizer == NULL);
290 void wxSizerItem::Show( bool show )
295 m_window->Show( show );
297 m_sizer->ShowItems( show );
299 // ... nothing else to do to hide/show spacers
302 void wxSizerItem::SetOption( int option )
304 SetProportion( option );
307 int wxSizerItem::GetOption() const
309 return GetProportion();
313 //---------------------------------------------------------------------------
315 //---------------------------------------------------------------------------
318 : m_minSize( wxSize( 0, 0 ) )
324 WX_CLEAR_LIST(wxSizerItemList, m_children);
327 void wxSizer::Add( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
329 m_children.Append( new wxSizerItem( window, proportion, flag, border, userData ) );
330 window->SetContainingSizer( this );
333 void wxSizer::Add( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
335 m_children.Append( new wxSizerItem( sizer, proportion, flag, border, userData ) );
338 void wxSizer::Add( int width, int height, int proportion, int flag, int border, wxObject* userData )
340 m_children.Append( new wxSizerItem( width, height, proportion, flag, border, userData ) );
343 void wxSizer::Add( wxSizerItem *item )
345 m_children.Append( item );
347 if( item->GetWindow() )
348 item->GetWindow()->SetContainingSizer( this );
351 void wxSizer::Prepend( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
353 m_children.Insert( new wxSizerItem( window, proportion, flag, border, userData ) );
354 window->SetContainingSizer( this );
357 void wxSizer::Prepend( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
359 m_children.Insert( new wxSizerItem( sizer, proportion, flag, border, userData ) );
362 void wxSizer::Prepend( int width, int height, int proportion, int flag, int border, wxObject* userData )
364 m_children.Insert( new wxSizerItem( width, height, proportion, flag, border, userData ) );
367 void wxSizer::Prepend( wxSizerItem *item )
369 m_children.Insert( item );
371 if( item->GetWindow() )
372 item->GetWindow()->SetContainingSizer( this );
375 void wxSizer::Insert( size_t index,
382 m_children.Insert( index,
383 new wxSizerItem( window, proportion, flag, border, userData ) );
384 window->SetContainingSizer( this );
387 void wxSizer::Insert( size_t index,
394 m_children.Insert( index,
395 new wxSizerItem( sizer, proportion, flag, border, userData ) );
398 void wxSizer::Insert( size_t index,
406 m_children.Insert( index,
407 new wxSizerItem( width, height, proportion, flag, border, userData ) );
410 void wxSizer::Insert( size_t index, wxSizerItem *item )
412 m_children.Insert( index, item );
414 if( item->GetWindow() )
415 item->GetWindow()->SetContainingSizer( this );
418 bool wxSizer::Remove( wxWindow *window )
420 return Detach( window );
423 bool wxSizer::Remove( wxSizer *sizer )
425 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
427 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
430 wxSizerItem *item = node->GetData();
432 if (item->GetSizer() == sizer)
435 m_children.Erase( node );
439 node = node->GetNext();
445 bool wxSizer::Remove( int index )
447 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
449 _T("Remove index is out of range") );
451 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
453 wxCHECK_MSG( node, false, _T("Failed to find child node") );
455 wxSizerItem *item = node->GetData();
457 if( item->IsWindow() )
458 item->GetWindow()->SetContainingSizer( NULL );
461 m_children.Erase( node );
465 bool wxSizer::Detach( wxSizer *sizer )
467 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
469 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
472 wxSizerItem *item = node->GetData();
474 if (item->GetSizer() == sizer)
478 m_children.Erase( node );
481 node = node->GetNext();
487 bool wxSizer::Detach( wxWindow *window )
489 wxASSERT_MSG( window, _T("Detaching NULL window") );
491 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
494 wxSizerItem *item = node->GetData();
496 if (item->GetWindow() == window)
498 item->GetWindow()->SetContainingSizer( NULL );
500 m_children.Erase( node );
503 node = node->GetNext();
509 bool wxSizer::Detach( int index )
511 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
513 _T("Detach index is out of range") );
515 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
517 wxCHECK_MSG( node, false, _T("Failed to find child node") );
519 wxSizerItem *item = node->GetData();
521 if( item->IsSizer() )
523 else if( item->IsWindow() )
524 item->GetWindow()->SetContainingSizer( NULL );
527 m_children.Erase( node );
531 void wxSizer::Clear( bool delete_windows )
533 // First clear the ContainingSizer pointers
534 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
537 wxSizerItem *item = node->GetData();
539 if (item->IsWindow())
540 item->GetWindow()->SetContainingSizer( NULL );
541 node = node->GetNext();
544 // Destroy the windows if needed
548 // Now empty the list
549 WX_CLEAR_LIST(wxSizerItemList, m_children);
552 void wxSizer::DeleteWindows()
554 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
557 wxSizerItem *item = node->GetData();
559 item->DeleteWindows();
560 node = node->GetNext();
564 wxSize wxSizer::Fit( wxWindow *window )
566 wxSize size(window->IsTopLevel() ? FitSize(window)
567 : GetMinWindowSize(window));
569 window->SetSize( size );
574 void wxSizer::FitInside( wxWindow *window )
577 if (window->IsTopLevel())
578 size = VirtualFitSize( window );
580 size = GetMinClientSize( window );
582 window->SetVirtualSize( size );
585 void wxSizer::Layout()
591 void wxSizer::SetSizeHints( wxWindow *window )
593 // Preserve the window's max size hints, but set the
594 // lower bound according to the sizer calculations.
596 wxSize size = Fit( window );
598 window->SetSizeHints( size.x,
600 window->GetMaxWidth(),
601 window->GetMaxHeight() );
604 void wxSizer::SetVirtualSizeHints( wxWindow *window )
606 // Preserve the window's max size hints, but set the
607 // lower bound according to the sizer calculations.
610 wxSize size( window->GetVirtualSize() );
611 window->SetVirtualSizeHints( size.x,
613 window->GetMaxWidth(),
614 window->GetMaxHeight() );
617 wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
619 return window->GetMaxSize();
622 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
624 wxSize minSize( GetMinSize() );
625 wxSize size( window->GetSize() );
626 wxSize client_size( window->GetClientSize() );
628 return wxSize( minSize.x+size.x-client_size.x,
629 minSize.y+size.y-client_size.y );
632 // Return a window size that will fit within the screens dimensions
633 wxSize wxSizer::FitSize( wxWindow *window )
635 wxSize size = GetMinWindowSize( window );
636 wxSize sizeMax = GetMaxWindowSize( window );
638 // Limit the size if sizeMax != wxDefaultSize
640 if ( size.x > sizeMax.x && sizeMax.x != -1 )
642 if ( size.y > sizeMax.y && sizeMax.y != -1 )
648 wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
650 wxSize maxSize( window->GetMaxSize() );
652 if( maxSize != wxDefaultSize )
654 wxSize size( window->GetSize() );
655 wxSize client_size( window->GetClientSize() );
657 return wxSize( maxSize.x + client_size.x - size.x,
658 maxSize.y + client_size.y - size.y );
661 return wxDefaultSize;
664 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
666 return GetMinSize(); // Already returns client size.
669 wxSize wxSizer::VirtualFitSize( wxWindow *window )
671 wxSize size = GetMinClientSize( window );
672 wxSize sizeMax = GetMaxClientSize( window );
674 // Limit the size if sizeMax != wxDefaultSize
676 if ( size.x > sizeMax.x && sizeMax.x != -1 )
678 if ( size.y > sizeMax.y && sizeMax.y != -1 )
684 void wxSizer::SetDimension( int x, int y, int width, int height )
693 wxSize wxSizer::GetMinSize()
695 wxSize ret( CalcMin() );
696 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
697 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
701 void wxSizer::DoSetMinSize( int width, int height )
704 m_minSize.y = height;
707 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
709 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
711 // Is it our immediate child?
713 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
716 wxSizerItem *item = node->GetData();
718 if (item->GetWindow() == window)
720 item->SetInitSize( width, height );
723 node = node->GetNext();
726 // No? Search any subsizers we own then
728 node = m_children.GetFirst();
731 wxSizerItem *item = node->GetData();
733 if ( item->GetSizer() &&
734 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
736 // A child sizer found the requested windw, exit.
739 node = node->GetNext();
745 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
747 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
749 // Is it our immediate child?
751 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
754 wxSizerItem *item = node->GetData();
756 if (item->GetSizer() == sizer)
758 item->GetSizer()->DoSetMinSize( width, height );
761 node = node->GetNext();
764 // No? Search any subsizers we own then
766 node = m_children.GetFirst();
769 wxSizerItem *item = node->GetData();
771 if ( item->GetSizer() &&
772 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
774 // A child found the requested sizer, exit.
777 node = node->GetNext();
783 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
785 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
787 wxCHECK_MSG( node, false, _T("Failed to find child node") );
789 wxSizerItem *item = node->GetData();
791 if (item->GetSizer())
793 // Sizers contains the minimal size in them, if not calculated ...
794 item->GetSizer()->DoSetMinSize( width, height );
798 // ... but the minimal size of spacers and windows in stored in them
799 item->SetInitSize( width, height );
805 void wxSizer::Show( wxWindow *window, bool show )
807 wxASSERT_MSG( window, _T("Show for NULL window") );
809 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
812 wxSizerItem *item = node->GetData();
814 if (item->GetWindow() == window)
819 node = node->GetNext();
823 void wxSizer::Show( wxSizer *sizer, bool show )
825 wxASSERT_MSG( sizer, _T("Show for NULL sizer") );
827 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
830 wxSizerItem *item = node->GetData();
832 if (item->GetSizer() == sizer)
837 node = node->GetNext();
841 void wxSizer::Show( size_t index, bool show )
843 wxCHECK_RET( index < m_children.GetCount(),
844 _T("Show index is out of range") );
846 m_children.Item( index )->GetData()->Show( show );
849 void wxSizer::ShowItems( bool show )
851 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
854 node->GetData()->Show( show );
855 node = node->GetNext();
859 bool wxSizer::IsShown( wxWindow *window ) const
861 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
864 wxSizerItem *item = node->GetData();
866 if (item->GetWindow() == window)
868 return item->IsShown();
870 node = node->GetNext();
873 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
878 bool wxSizer::IsShown( wxSizer *sizer ) const
880 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
883 wxSizerItem *item = node->GetData();
885 if (item->GetSizer() == sizer)
887 return item->IsShown();
889 node = node->GetNext();
892 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
897 bool wxSizer::IsShown( size_t index ) const
899 wxCHECK_MSG( index < m_children.GetCount(),
901 _T("IsShown index is out of range") );
903 return m_children.Item( index )->GetData()->IsShown();
907 //---------------------------------------------------------------------------
909 //---------------------------------------------------------------------------
911 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
919 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
927 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
929 int nitems = m_children.GetCount();
935 nrows = (nitems + m_cols - 1) / m_cols;
939 ncols = (nitems + m_rows - 1) / m_rows;
942 else // 0 columns, 0 rows?
944 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
953 void wxGridSizer::RecalcSizes()
955 int nitems, nrows, ncols;
956 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
959 wxSize sz( GetSize() );
960 wxPoint pt( GetPosition() );
962 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
963 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
966 for (int c = 0; c < ncols; c++)
969 for (int r = 0; r < nrows; r++)
971 int i = r * ncols + c;
974 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
976 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
978 SetItemBounds( node->GetData(), x, y, w, h);
986 wxSize wxGridSizer::CalcMin()
989 if ( CalcRowsCols(nrows, ncols) == 0 )
990 return wxSize(10, 10);
992 // Find the max width and height for any component
996 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
999 wxSizerItem *item = node->GetData();
1000 wxSize sz( item->CalcMin() );
1002 w = wxMax( w, sz.x );
1003 h = wxMax( h, sz.y );
1005 node = node->GetNext();
1008 return wxSize( ncols * w + (ncols-1) * m_hgap,
1009 nrows * h + (nrows-1) * m_vgap );
1012 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1015 wxSize sz( item->CalcMin() );
1016 int flag = item->GetFlag();
1018 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1024 if (flag & wxALIGN_CENTER_HORIZONTAL)
1026 pt.x = x + (w - sz.x) / 2;
1028 else if (flag & wxALIGN_RIGHT)
1030 pt.x = x + (w - sz.x);
1033 if (flag & wxALIGN_CENTER_VERTICAL)
1035 pt.y = y + (h - sz.y) / 2;
1037 else if (flag & wxALIGN_BOTTOM)
1039 pt.y = y + (h - sz.y);
1043 item->SetDimension(pt, sz);
1046 //---------------------------------------------------------------------------
1048 //---------------------------------------------------------------------------
1050 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
1051 : wxGridSizer( rows, cols, vgap, hgap ),
1052 m_flexDirection(wxBOTH),
1053 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1057 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1058 : wxGridSizer( cols, vgap, hgap ),
1059 m_flexDirection(wxBOTH),
1060 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1064 wxFlexGridSizer::~wxFlexGridSizer()
1068 void wxFlexGridSizer::RecalcSizes()
1070 int nitems, nrows, ncols;
1071 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1074 wxSize sz( GetSize() );
1075 wxSize minsz( CalcMin() );
1076 wxPoint pt( GetPosition() );
1078 // what to do with the rows? by default, resize them proportionally
1079 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1081 int sum_proportions = 0;
1082 int growable_space = 0;
1085 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1087 // Since the number of rows/columns can change as items are inserted/deleted, we need
1088 // to verify at runtime that the requested growable rows/columns are still valid.
1089 if (m_growableRows[idx] >= nrows)
1091 // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1092 // This causes the row/column to be hidden completely.
1093 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1095 sum_proportions += m_growableRowsProportions[idx];
1096 growable_space += m_rowHeights[ m_growableRows[idx] ];
1102 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1104 if (m_growableRows[idx] >= nrows )
1106 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1107 m_rowHeights[ m_growableRows[idx] ] = 0;
1110 int delta = (sz.y - minsz.y);
1111 if (sum_proportions == 0)
1112 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1114 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1115 m_rowHeights[ m_growableRows[idx] ] = delta;
1120 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1122 // rounding problem?
1123 for ( int row = 0; row < nrows; ++row )
1124 m_rowHeights[ row ] = sz.y / nrows;
1127 // the same logic as above but for the columns
1128 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1130 int sum_proportions = 0;
1131 int growable_space = 0;
1134 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1136 // Since the number of rows/columns can change as items are inserted/deleted, we need
1137 // to verify at runtime that the requested growable rows/columns are still valid.
1138 if (m_growableCols[idx] >= ncols)
1140 // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1141 // This causes the column to be hidden completely.
1142 if (m_colWidths[ m_growableCols[idx] ] == -1)
1144 sum_proportions += m_growableColsProportions[idx];
1145 // wtb 5/12/02 bugfix - was m_ColWidths[idx]!!
1146 growable_space += m_colWidths[ m_growableCols[idx] ];
1152 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1154 if (m_growableCols[idx] >= ncols )
1156 if (m_colWidths[ m_growableCols[idx] ] == -1)
1157 m_colWidths[ m_growableCols[idx] ] = 0;
1160 int delta = (sz.x - minsz.x);
1161 if (sum_proportions == 0)
1162 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1164 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1165 m_colWidths[ m_growableCols[idx] ] = delta;
1170 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1172 for ( int col=0; col < ncols; ++col )
1173 m_colWidths[ col ] = sz.x / ncols;
1176 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1179 for (int c = 0; c < ncols; c++)
1182 for (int r = 0; r < nrows; r++)
1184 int i = r * ncols + c;
1187 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1189 wxASSERT_MSG( node, _T("Failed to find node") );
1191 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1192 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1194 SetItemBounds( node->GetData(), x, y, w, h);
1196 y = y + m_rowHeights[r] + m_vgap;
1198 x = x + m_colWidths[c] + m_hgap;
1202 wxSize wxFlexGridSizer::CalcMin()
1208 // Number of rows/columns can change as items are added or removed.
1209 if ( !CalcRowsCols(nrows, ncols) )
1210 return wxSize(10, 10);
1212 m_rowHeights.SetCount(nrows);
1213 m_colWidths.SetCount(ncols);
1215 // We have to recalcuate the sizes in case an item has wxADJUST_MINSIZE, has changed
1216 // minimum size since the previous layout, or has been hidden using wxSizer::Show().
1217 // If all the items in a row/column are hidden, the final dimension of the row/column
1218 // will be -1, indicating that the column itself is hidden.
1219 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1220 m_rowHeights[ i ] = -1;
1221 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1222 m_colWidths[ i ] = -1;
1224 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1229 wxSizerItem *item = node->GetData();
1230 if ( item->IsShown() )
1232 wxSize sz( item->CalcMin() );
1233 int row = i / ncols;
1234 int col = i % ncols;
1236 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1237 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1240 node = node->GetNext();
1244 // the logic above works when we resize flexibly in both directions but
1245 // maybe this is not the case
1246 if ( m_flexDirection != wxBOTH )
1248 // select the array corresponding to the direction in which we do *not*
1250 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1253 const int count = array.GetCount();
1255 // find the largest value in this array
1257 for ( n = 0; n < count; ++n )
1259 if ( array[n] > largest )
1263 // and now fill it with the largest value
1264 for ( n = 0; n < count; ++n )
1270 // Sum total minimum size, including gaps between rows/columns.
1271 // -1 is used as a magic number meaning empty column.
1273 for (int col = 0; col < ncols; col++)
1274 if ( m_colWidths[ col ] != -1 )
1275 width += m_colWidths[ col ] + ( col == ncols-1 ? 0 : m_hgap );
1278 for (int row = 0; row < nrows; row++)
1279 if ( m_rowHeights[ row ] != -1 )
1280 height += m_rowHeights[ row ] + ( row == nrows-1 ? 0 : m_vgap );
1282 return wxSize( width, height );
1285 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1287 m_growableRows.Add( idx );
1288 m_growableRowsProportions.Add( proportion );
1291 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
1295 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1297 m_growableCols.Add( idx );
1298 m_growableColsProportions.Add( proportion );
1301 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
1305 //---------------------------------------------------------------------------
1307 //---------------------------------------------------------------------------
1309 wxBoxSizer::wxBoxSizer( int orient )
1310 : m_orient( orient )
1314 void wxBoxSizer::RecalcSizes()
1316 if (m_children.GetCount() == 0)
1322 if (m_orient == wxHORIZONTAL)
1323 delta = m_size.x - m_fixedWidth;
1325 delta = m_size.y - m_fixedHeight;
1328 wxPoint pt( m_position );
1330 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1333 wxSizerItem *item = node->GetData();
1335 if (item->IsShown())
1337 wxSize size( item->CalcMin() );
1339 if (m_orient == wxVERTICAL)
1341 wxCoord height = size.y;
1342 if (item->GetProportion())
1344 // Because of at least one visible item has non-zero
1345 // proportion then m_stretchable is not zero
1346 height = (delta * item->GetProportion()) / m_stretchable;
1349 wxPoint child_pos( pt );
1350 wxSize child_size( wxSize( size.x, height) );
1352 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1353 child_size.x = m_size.x;
1354 else if (item->GetFlag() & wxALIGN_RIGHT)
1355 child_pos.x += m_size.x - size.x;
1356 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1357 // XXX wxCENTER is added for backward compatibility;
1358 // wxALIGN_CENTER should be used in new code
1359 child_pos.x += (m_size.x - size.x) / 2;
1361 item->SetDimension( child_pos, child_size );
1367 wxCoord width = size.x;
1368 if (item->GetProportion())
1370 // Because of at least one visible item has non-zero
1371 // proportion then m_stretchable is not zero
1372 width = (delta * item->GetProportion()) / m_stretchable;
1375 wxPoint child_pos( pt );
1376 wxSize child_size( wxSize(width, size.y) );
1378 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1379 child_size.y = m_size.y;
1380 else if (item->GetFlag() & wxALIGN_BOTTOM)
1381 child_pos.y += m_size.y - size.y;
1382 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1383 // XXX wxCENTER is added for backward compatibility;
1384 // wxALIGN_CENTER should be used in new code
1385 child_pos.y += (m_size.y - size.y) / 2;
1387 item->SetDimension( child_pos, child_size );
1393 node = node->GetNext();
1397 wxSize wxBoxSizer::CalcMin()
1399 if (m_children.GetCount() == 0)
1400 return wxSize(10,10);
1408 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1411 wxSizerItem *item = node->GetData();
1413 if (item->IsShown() && item->GetProportion() != 0)
1414 m_stretchable += item->GetProportion();
1416 node = node->GetNext();
1419 // Total minimum size (width or height) of sizer
1422 node = m_children.GetFirst();
1425 wxSizerItem *item = node->GetData();
1427 if (item->IsShown() && item->GetProportion() != 0)
1429 int stretch = item->GetProportion();
1430 wxSize size( item->CalcMin() );
1433 // Integer division rounded up is (a + b - 1) / b
1434 // Round up needed in order to guarantee that all
1435 // all items will have size not less then their min size
1436 if (m_orient == wxHORIZONTAL)
1437 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
1439 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
1441 if (minSize > maxMinSize)
1442 maxMinSize = minSize;
1444 node = node->GetNext();
1447 // Calculate overall minimum size
1448 node = m_children.GetFirst();
1451 wxSizerItem *item = node->GetData();
1453 if (item->IsShown())
1455 wxSize size( item->CalcMin() );
1456 if (item->GetProportion() != 0)
1458 if (m_orient == wxHORIZONTAL)
1459 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
1461 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
1465 if (m_orient == wxVERTICAL)
1467 m_fixedHeight += size.y;
1468 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1472 m_fixedWidth += size.x;
1473 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1477 if (m_orient == wxHORIZONTAL)
1479 m_minWidth += size.x;
1480 m_minHeight = wxMax( m_minHeight, size.y );
1484 m_minHeight += size.y;
1485 m_minWidth = wxMax( m_minWidth, size.x );
1488 node = node->GetNext();
1491 return wxSize( m_minWidth, m_minHeight );
1494 //---------------------------------------------------------------------------
1496 //---------------------------------------------------------------------------
1500 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1501 : wxBoxSizer( orient )
1502 , m_staticBox( box )
1504 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1507 static void GetStaticBoxBorders( wxStaticBox *box,
1511 // this has to be done platform by platform as there is no way to
1512 // guess the thickness of a wxStaticBox border
1514 box->GetBordersForSizer(borderTop,borderOther);
1515 #else // __WXCOCOA__
1517 if ( box->GetLabel().IsEmpty() )
1521 *borderTop = box->GetCharHeight();
1524 #endif // __WXCOCOA__
1527 void wxStaticBoxSizer::RecalcSizes()
1529 int top_border, other_border;
1530 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1532 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1534 wxPoint old_pos( m_position );
1535 m_position.x += other_border;
1536 m_position.y += top_border;
1537 wxSize old_size( m_size );
1538 m_size.x -= 2*other_border;
1539 m_size.y -= top_border + other_border;
1541 wxBoxSizer::RecalcSizes();
1543 m_position = old_pos;
1547 wxSize wxStaticBoxSizer::CalcMin()
1549 int top_border, other_border;
1550 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1552 wxSize ret( wxBoxSizer::CalcMin() );
1553 ret.x += 2*other_border;
1554 ret.y += other_border + top_border;
1559 #endif // wxUSE_STATBOX
1561 // ----------------------------------------------------------------------------
1563 // ----------------------------------------------------------------------------
1567 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrl *bookctrl)
1568 : m_bookctrl(bookctrl)
1570 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
1573 void wxBookCtrlSizer::RecalcSizes()
1575 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1578 wxSize wxBookCtrlSizer::CalcMin()
1580 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0, 0));
1585 if ( m_bookctrl->GetPageCount() == 0 )
1587 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1593 wxWindowList::compatibility_iterator
1594 node = m_bookctrl->GetChildren().GetFirst();
1597 wxWindow *item = node->GetData();
1598 wxSizer *itemsizer = item->GetSizer();
1602 wxSize subsize( itemsizer->CalcMin() );
1604 if (subsize.x > maxX)
1606 if (subsize.y > maxY)
1610 node = node->GetNext();
1613 return wxSize( maxX, maxY ) + sizeBorder;
1619 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
1620 : wxBookCtrlSizer(nb)
1624 #endif // wxUSE_NOTEBOOOK
1625 #endif // wxUSE_BOOKCTRL