]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/sizer.cpp
Ensure that size in the major direction of box sizer doesn't exceed the total.
[wxWidgets.git] / src / common / sizer.cpp
index e9e7ad1193674e6d5d33b999618923441b7ce649..ad0abd60edaa85ea3f8e3c965b531194cfd0ec6b 100644 (file)
@@ -634,7 +634,7 @@ wxSizer::~wxSizer()
     WX_CLEAR_LIST(wxSizerItemList, m_children);
 }
 
-wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
+wxSizerItem* wxSizer::DoInsert( size_t index, wxSizerItem *item )
 {
     m_children.Insert( index, item );
 
@@ -1317,39 +1317,39 @@ bool wxSizer::IsShown( size_t index ) const
 // wxGridSizer
 //---------------------------------------------------------------------------
 
-wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
-    : m_rows( rows || cols ? rows : 1 ),
+wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
+    : m_rows( cols == 0 ? 1 : 0 ),
       m_cols( cols ),
       m_vgap( vgap ),
       m_hgap( hgap )
 {
 }
 
-wxGridSizer::wxGridSizer( int rows, int cols, const wxSize& gap )
-    : m_rows( rows || cols ? rows : 1 ),
+wxGridSizer::wxGridSizer( int cols, const wxSize& gap )
+    : m_rows( cols == 0 ? 1 : 0 ),
       m_cols( cols ),
       m_vgap( gap.GetHeight() ),
       m_hgap( gap.GetWidth() )
 {
 }
 
-wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
-    : m_rows( cols == 0 ? 1 : 0 ),
+wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
+    : m_rows( rows || cols ? rows : 1 ),
       m_cols( cols ),
       m_vgap( vgap ),
       m_hgap( hgap )
 {
 }
 
-wxGridSizer::wxGridSizer( int cols, const wxSize& gap )
-    : m_rows( cols == 0 ? 1 : 0 ),
+wxGridSizer::wxGridSizer( int rows, int cols, const wxSize& gap )
+    : m_rows( rows || cols ? rows : 1 ),
       m_cols( cols ),
       m_vgap( gap.GetHeight() ),
       m_hgap( gap.GetWidth() )
 {
 }
 
-wxSizerItem *wxGridSizer::Insert(size_t index, wxSizerItem *item)
+wxSizerItem *wxGridSizer::DoInsert(size_t index, wxSizerItem *item)
 {
     // if only the number of columns or the number of rows is specified for a
     // sizer, arbitrarily many items can be added to it but if both of them are
@@ -1369,7 +1369,7 @@ wxSizerItem *wxGridSizer::Insert(size_t index, wxSizerItem *item)
 
             // additionally, continuing to use the specified number of columns
             // and rows is not a good idea as callers of CalcRowsCols() expect
-            // that all sizer items can fit into m_cols/m_rows-sized arrays
+            // that all sizer items can fit into m_cols-/m_rows-sized arrays
             // which is not the case if there are too many items and results in
             // crashes, so let it compute the number of rows automatically by
             // forgetting the (wrong) number of rows specified (this also has a
@@ -1379,38 +1379,19 @@ wxSizerItem *wxGridSizer::Insert(size_t index, wxSizerItem *item)
         }
     }
 
-    return wxSizer::Insert(index, item);
+    return wxSizer::DoInsert(index, item);
 }
 
 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
 {
     const int nitems = m_children.GetCount();
-    if ( m_cols && m_rows )
-    {
-        ncols = m_cols;
-        nrows = m_rows;
 
-        // this should be impossible because the too high number of items
-        // should have been detected by Insert() above
-        wxASSERT_MSG( nitems <= ncols*nrows, "logic error in wxGridSizer" );
-    }
-    else if ( m_cols )
-    {
-        ncols = m_cols;
-        nrows = (nitems + m_cols - 1) / m_cols;
-    }
-    else if ( m_rows )
-    {
-        ncols = (nitems + m_rows - 1) / m_rows;
-        nrows = m_rows;
-    }
-    else // 0 columns, 0 rows?
-    {
-        wxFAIL_MSG( wxT("grid sizer must have either rows or columns fixed") );
+    ncols = GetEffectiveColsCount();
+    nrows = GetEffectiveRowsCount();
 
-        nrows =
-        ncols = 0;
-    }
+    // Since Insert() checks for overpopulation, the following
+    // should only assert if the grid was shrunk via SetRows() / SetCols()
+    wxASSERT_MSG( nitems <= ncols*nrows, "logic error in wxGridSizer" );
 
     return nitems;
 }
@@ -1541,6 +1522,20 @@ void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
 // wxFlexGridSizer
 //---------------------------------------------------------------------------
 
+wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
+               : wxGridSizer( cols, vgap, hgap ),
+                 m_flexDirection(wxBOTH),
+                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
+{
+}
+
+wxFlexGridSizer::wxFlexGridSizer( int cols, const wxSize& gap )
+               : wxGridSizer( cols, gap ),
+                 m_flexDirection(wxBOTH),
+                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
+{
+}
+
 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
                : wxGridSizer( rows, cols, vgap, hgap ),
                  m_flexDirection(wxBOTH),
@@ -1548,8 +1543,8 @@ wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
 {
 }
 
-wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
-               : wxGridSizer( cols, vgap, hgap ),
+wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, const wxSize& gap )
+               : wxGridSizer( rows, cols, gap ),
                  m_flexDirection(wxBOTH),
                  m_growMode(wxFLEX_GROWMODE_SPECIFIED)
 {
@@ -1836,11 +1831,10 @@ void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
     // comments in AddGrowableCol/Row())
     if ( !m_rows || !m_cols )
     {
-        int nrows, ncols;
-        CalcRowsCols(nrows, ncols);
-
         if ( !m_rows )
         {
+            int nrows = CalcRows();
+
             for ( size_t n = 0; n < m_growableRows.size(); n++ )
             {
                 wxASSERT_MSG( m_growableRows[n] < nrows,
@@ -1850,6 +1844,8 @@ void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
 
         if ( !m_cols )
         {
+            int ncols = CalcCols();
+
             for ( size_t n = 0; n < m_growableCols.size(); n++ )
             {
                 wxASSERT_MSG( m_growableCols[n] < ncols,
@@ -1874,17 +1870,17 @@ void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
         // This gives nested objects that benefit from knowing one size
         // component in advance the chance to use that.
         bool didAdjustMinSize = false;
-        int nrows, ncols;
-        CalcRowsCols(nrows, ncols);
 
         // Iterate over all items and inform about column width
-        size_t n = 0;
+        const int ncols = GetEffectiveColsCount();
+        int col = 0;
         for ( wxSizerItemList::iterator i = m_children.begin();
               i != m_children.end();
-              ++i, ++n )
+              ++i )
         {
-            const int col = n % ncols;
             didAdjustMinSize |= (*i)->InformFirstDirection(wxHORIZONTAL, m_colWidths[col], sz.y - m_calculatedMinSize.y);
+            if ( ++col == ncols )
+                col = 0;
         }
 
         // Only redo if info was actually used
@@ -1928,9 +1924,6 @@ bool wxFlexGridSizer::IsColGrowable( size_t idx )
 
 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
 {
-    int nrows, ncols;
-    CalcRowsCols(nrows, ncols);
-
     wxASSERT_MSG( !IsRowGrowable( idx ),
                   "AddGrowableRow() called for growable row" );
 
@@ -1946,15 +1939,12 @@ void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
 
 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
 {
-    int nrows, ncols;
-    CalcRowsCols(nrows, ncols);
-
     wxASSERT_MSG( !IsColGrowable( idx ),
                   "AddGrowableCol() called for growable column" );
 
     // see comment in AddGrowableRow(): although it's less common to omit the
     // specification of the number of columns, it still can also happen
-    wxCHECK_RET( !m_cols || idx < (size_t)ncols, "invalid column index" );
+    wxCHECK_RET( !m_cols || idx < (size_t)m_cols, "invalid column index" );
 
     m_growableCols.Add( idx );
     m_growableColsProportions.Add( proportion );
@@ -1992,16 +1982,22 @@ void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
 // wxBoxSizer
 //---------------------------------------------------------------------------
 
+wxSizerItem *wxBoxSizer::AddSpacer(int size)
+{
+    return IsVertical() ? Add(0, size) : Add(size, 0);
+}
+
 void wxBoxSizer::RecalcSizes()
 {
     if ( m_children.empty() )
         return;
 
     const wxCoord totalMinorSize = GetSizeInMinorDir(m_size);
+    const wxCoord totalMajorSize = GetSizeInMajorDir(m_size);
 
     // the amount of free space which we should redistribute among the
     // stretchable items (i.e. those with non zero proportion)
-    int delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
+    int delta = totalMajorSize - GetSizeInMajorDir(m_minSize);
 
 
     // Inform child items about the size in minor direction, that can
@@ -2034,11 +2030,14 @@ void wxBoxSizer::RecalcSizes()
 
 
     // might have a new delta now
-    delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
+    delta = totalMajorSize - GetSizeInMajorDir(m_minSize);
 
     // the position at which we put the next child
     wxPoint pt(m_position);
 
+    // space remaining for the items
+    wxCoord majorRemaining = totalMajorSize;
+
     int totalProportion = m_totalProportion;
     for ( i = m_children.begin();
           i != m_children.end();
@@ -2054,11 +2053,10 @@ void wxBoxSizer::RecalcSizes()
         // adjust the size in the major direction using the proportion
         wxCoord majorSize = GetSizeInMajorDir(sizeThis);
 
-        // if there is not enough space, don't try to distribute negative space
-        // among the children, this would result in overlapping windows which
-        // we don't want
         if ( delta > 0 )
         {
+            // distribute extra space among the items respecting their
+            // proportions
             const int propItem = item->GetProportion();
             if ( propItem )
             {
@@ -2070,6 +2068,18 @@ void wxBoxSizer::RecalcSizes()
                 totalProportion -= propItem;
             }
         }
+        else // delta < 0
+        {
+            // we're not going to have enough space for making all items even
+            // of their minimal size, check if this item still fits at all and
+            // truncate it if it doesn't -- even if it means giving it 0 size
+            // and thus making it invisible because we just can't do anything
+            // else
+            if ( majorSize > majorRemaining )
+                majorSize = majorRemaining;
+
+            majorRemaining -= majorSize;
+        }
 
 
         // apply the alignment in the minor direction
@@ -2184,12 +2194,12 @@ void wxStaticBoxSizer::RecalcSizes()
 #if defined( __WXGTK20__ )
         // if the wxStaticBox has created a wxPizza to contain its children
         // (see wxStaticBox::AddChild) then we need to place the items it contains
-        // in the wxBoxSizer::RecalcSizes() call below using coordinates relative 
+        // in the wxBoxSizer::RecalcSizes() call below using coordinates relative
         // to the top-left corner of the staticbox:
         m_position.x = m_position.y = 0;
 #else
         // if the wxStaticBox has childrens, then these windows must be placed
-        // by the wxBoxSizer::RecalcSizes() call below using coordinates relative 
+        // by the wxBoxSizer::RecalcSizes() call below using coordinates relative
         // to the top-left corner of the staticbox (but unlike wxGTK, we need
         // to keep in count the static borders here!):
         m_position.x = other_border;