]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/sizer.cpp
SourceForge patch #654210 to fix naming/numbering shared libs under OS X
[wxWidgets.git] / src / common / sizer.cpp
index 125f342b327d6d9775a568ec0c1d02987d24229a..79da84f99d2f007e597eadd76b7050ecc4b2fe8c 100644 (file)
@@ -44,58 +44,47 @@ IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer)
 //---------------------------------------------------------------------------
 
 wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
+    : m_window( 0 )
+    , m_sizer( 0 )
+    , m_size( wxSize( width, height ) ) // size is set directly
+    , m_minSize( m_size )               // minimal size is the initial size
+    , m_option( option )
+    , m_border( border )
+    , m_flag( flag )
+    , m_show( TRUE )                    // Cannot be changed
+    , m_userData( userData )
 {
-    m_window = (wxWindow *) NULL;
-    m_sizer = (wxSizer *) NULL;
-    m_option = option;
-    m_border = border;
-    m_flag = flag;
-    m_userData = userData;
-
-    // minimal size is the initial size
-    m_minSize.x = width;
-    m_minSize.y = height;
-
-    SetRatio(width, height);
-
-    // size is set directly
-    m_size = m_minSize;
+    SetRatio( m_size );
 }
 
 wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
+    : m_window( window )
+    , m_sizer( 0 )
+    , m_minSize( window->GetSize() )    // minimal size is the initial size
+    , m_option( option )
+    , m_border( border )
+    , m_flag( flag )
+    , m_show( TRUE )
+    , m_userData( userData )
 {
-    m_window = window;
-    m_sizer = (wxSizer *) NULL;
-    m_option = option;
-    m_border = border;
-    m_flag = flag;
-    m_userData = userData;
-
-    // minimal size is the initial size
-    m_minSize = window->GetSize();
-
     // aspect ratio calculated from initial size
-    SetRatio(m_minSize);
+    SetRatio( m_minSize );
 
-    // size is calculated later
-    // m_size = ...
+    // m_size is calculated later
 }
 
 wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
+    : m_window( 0 )
+    , m_sizer( sizer )
+    , m_option( option )
+    , m_border( border )
+    , m_flag( flag )
+    , m_show( TRUE )
+    , m_ratio( 0 )
+    , m_userData( userData )
 {
-    m_window = (wxWindow *) NULL;
-    m_sizer = sizer;
-    m_option = option;
-    m_border = border;
-    m_flag = flag;
-    m_userData = userData;
-
-    // minimal size is calculated later
-    // m_minSize = ...
-    m_ratio = 0;
-
-    // size is calculated later
-    // m_size = ...
+    // m_minSize is calculated later
+    // m_size is calculated later
 }
 
 wxSizerItem::~wxSizerItem()
@@ -145,14 +134,11 @@ wxSize wxSizerItem::CalcMin()
     {
         if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
         {
-            // check if the best (minimal, in fact) window size hadn't changed
-            // by chance: this may happen for, e.g. static text if its label
-            // changed
-            wxSize size = m_window->GetBestSize();
-            if ( size.x > m_minSize.x )
-                m_minSize.x = size.x;
-            if ( size.y > m_minSize.y )
-                m_minSize.y = size.y;
+            // By user request, keep the minimal size for this item
+            // in sync with the largest of BestSize and any user supplied
+            // minimum size hint.  Useful in cases where the item is
+            // changeable -- static text labels, etc.
+            m_minSize = m_window->GetAdjustedBestSize();
         }
 
         ret = m_minSize;
@@ -361,9 +347,44 @@ bool wxSizer::Remove( wxSizer *sizer )
 
 bool wxSizer::Remove( int pos )
 {
+    if ((size_t)pos >= m_children.GetCount())
+        return FALSE;
+    wxNode *node = m_children.Nth( pos );
+    if (!node) return FALSE;
+
+    m_children.DeleteNode( node );
+
+    return TRUE;
+}
+
+bool wxSizer::Detach( wxSizer *sizer )
+{
+    wxASSERT( sizer );
+
+    wxNode *node = m_children.First();
+    while (node)
+    {
+        wxSizerItem *item = (wxSizerItem*)node->Data();
+        if (item->GetSizer() == sizer)
+        {
+            item->DetachSizer();
+            m_children.DeleteNode( node );
+            return TRUE;
+        }
+        node = node->Next();
+    }
+
+    return FALSE;
+}
+
+bool wxSizer::Detach( int pos )
+{
+    if ((size_t)pos >= m_children.GetCount())
+        return FALSE;
     wxNode *node = m_children.Nth( pos );
     if (!node) return FALSE;
 
+    ( (wxSizerItem*)node->Data() )->DetachSizer();
     m_children.DeleteNode( node );
 
     return TRUE;
@@ -528,8 +549,7 @@ void wxSizer::SetDimension( int x, int y, int width, int height )
     m_position.y = y;
     m_size.x = width;
     m_size.y = height;
-    CalcMin();
-    RecalcSizes();
+    Layout();
 }
 
 wxSize wxSizer::GetMinSize()
@@ -568,10 +588,10 @@ bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
         wxSizerItem *item = (wxSizerItem*)node->Data();
         if (item->GetSizer())
         {
-            /* It's a sizer, so lets search recursively. */
+            // It's a sizer, so lets search recursively.
             if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
             {
-                /* A child sizer found the requested windw, exit. */
+                // A child sizer found the requested windw, exit.
                 return TRUE;
             }
         }
@@ -603,10 +623,10 @@ bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
         wxSizerItem *item = (wxSizerItem*)node->Data();
         if (item->GetSizer())
         {
-            /* It's a sizer, so lets search recursively. */
+            // It's a sizer, so lets search recursively.
             if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
             {
-                /* A child sizer found the requested windw, exit. */
+                // A child sizer found the requested windw, exit.
                 return TRUE;
             }
         }
@@ -624,19 +644,102 @@ bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
     wxSizerItem *item = (wxSizerItem*) node->Data();
     if (item->GetSizer())
     {
-        /* Sizers contains the minimal size in them, if not calculated ... */
+        // Sizers contains the minimal size in them, if not calculated ...
         item->GetSizer()->DoSetMinSize( width, height );
     }
     else
     {
-        /* ... whereas the minimal size of spacers and windows in stored
-           in the item */
+        // ... but the minimal size of spacers and windows in stored in them
         item->SetInitSize( width, height );
     }
 
     return TRUE;
 }
 
+void wxSizer::Show(wxWindow *window, bool show)
+{
+    wxNode *node = m_children.GetFirst();
+    while (node)
+    {
+        wxSizerItem *item = (wxSizerItem*) node->Data();
+
+        if (item->IsWindow() && item->GetWindow() == window)
+        {
+            item->Show(show);
+            window->Show(show);
+            return;
+        }
+        node = node->Next();
+    }
+}
+
+void wxSizer::Show(wxSizer *sizer, bool show)
+{
+    wxNode *node = m_children.GetFirst();
+    while (node)
+    {
+        wxSizerItem *item = (wxSizerItem*) node->Data();
+
+        if (item->IsSizer() && item->GetSizer() == sizer)
+        {
+            item->Show(show);
+            sizer->ShowItems(show);
+            return;
+        }
+        node = node->Next();
+    }
+}
+
+void wxSizer::ShowItems (bool show)
+{
+    wxNode *node = m_children.GetFirst();
+    while (node)
+    {
+        wxSizerItem *item = (wxSizerItem*) node->Data();
+
+        if (item->IsWindow())
+            item->GetWindow()->Show (show);
+        else if (item->IsSizer())
+            item->GetSizer()->ShowItems (show);
+
+        node = node->Next();
+    }
+}
+
+bool wxSizer::IsShown (wxWindow *window)
+{
+    wxNode *node = m_children.GetFirst();
+    while (node)
+    {
+        wxSizerItem *item = (wxSizerItem*) node->Data();
+        
+        if (item->IsWindow() && item->GetWindow() == window)
+        {
+            return item->IsShown();
+        }
+        node = node->Next();
+    }
+
+    return FALSE;
+}
+
+bool wxSizer::IsShown (wxSizer *sizer)
+{
+    wxNode *node = m_children.GetFirst();
+    while (node)
+    {
+        wxSizerItem *item = (wxSizerItem*) node->Data();
+
+        if (item->IsSizer() && item->GetSizer() == sizer)
+        {
+            return item->IsShown();
+        }
+        node = node->Next();
+    }
+
+    return FALSE;
+}
+
 //---------------------------------------------------------------------------
 // wxGridSizer
 //---------------------------------------------------------------------------
@@ -657,19 +760,37 @@ wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
     m_hgap = hgap;
 }
 
-void wxGridSizer::RecalcSizes()
+int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
 {
-    if (m_children.GetCount() == 0)
-        return;
-
     int nitems = m_children.GetCount();
-    int nrows = m_rows;
-    int ncols = m_cols;
+    if ( nitems)
+    {
+        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( _T("grid sizer must have either rows or columns fixed") );
 
-    if (ncols > 0)
-        nrows = (nitems + ncols-1) / ncols;
-    else
-        ncols = (nitems + nrows-1) / nrows;
+            nrows = ncols = 0;
+        }
+    }
+
+    return nitems;
+}
+
+void wxGridSizer::RecalcSizes()
+{
+    int nitems, nrows, ncols;
+    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
+        return;
 
     wxSize sz( GetSize() );
     wxPoint pt( GetPosition() );
@@ -699,19 +820,11 @@ void wxGridSizer::RecalcSizes()
 
 wxSize wxGridSizer::CalcMin()
 {
-    if (m_children.GetCount() == 0)
-        return wxSize(10,10);
-
-    int nitems = m_children.GetCount();
-    int nrows = m_rows;
-    int ncols = m_cols;
-
-    if (ncols > 0)
-        nrows = (nitems + ncols-1) / ncols;
-    else
-        ncols = (nitems + nrows-1) / nrows;
+    int nitems, nrows, ncols;
+    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
+        return wxSize(10, 10);
 
-    /* Find the max width and height for any component */
+    // Find the max width and height for any component
     int w = 0;
     int h = 0;
 
@@ -797,17 +910,12 @@ void wxFlexGridSizer::CreateArrays()
     if (m_colWidths)
         delete[] m_colWidths;
 
-    if (m_children.GetCount() == 0)
-        return;
-
-    int nitems = m_children.GetCount();
-    int nrows = m_rows;
-    int ncols = m_cols;
-
-    if (ncols > 0)
-        nrows = (nitems + ncols-1) / ncols;
-    else
-        ncols = (nitems + nrows-1) / nrows;
+    int nitems, nrows, ncols;
+    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
+    {
+        m_rowHeights =
+        m_colWidths = NULL;
+    }
 
     m_rowHeights = new int[nrows];
     m_colWidths = new int[ncols];
@@ -820,36 +928,44 @@ void wxFlexGridSizer::CreateArrays()
 
 void wxFlexGridSizer::RecalcSizes()
 {
-    if (m_children.GetCount() == 0)
+    int nitems, nrows, ncols;
+    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
         return;
 
-    int nitems = m_children.GetCount();
-    int nrows = m_rows;
-    int ncols = m_cols;
-
-    if (ncols > 0)
-        nrows = (nitems + ncols-1) / ncols;
-    else
-        ncols = (nitems + nrows-1) / nrows;
-
     wxSize sz( GetSize() );
     wxSize minsz( CalcMin() );
     wxPoint pt( GetPosition() );
     int    delta;
-    size_t idx;
-
-    if ((m_growableRows.GetCount() > 0) && (sz.y > minsz.y))
+    size_t idx,num;
+    wxArrayInt temp;
+
+    // Transfer only those rows into temp which exist in the sizer
+    // ignoring the superflouus ones. This prevents a segfault when
+    // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
+    for (idx = 0; idx < m_growableRows.GetCount(); idx++)
+        if (m_growableRows[idx] < nrows)
+            temp.Add( m_growableRows[idx] );
+    num = temp.GetCount();
+
+    if ((num > 0) && (sz.y > minsz.y))
     {
-        delta = (sz.y - minsz.y) / m_growableRows.GetCount();
-        for (idx = 0; idx < m_growableRows.GetCount(); idx++)
-            m_rowHeights[ m_growableRows[idx] ] += delta;
+        delta = (sz.y - minsz.y) / num;
+        for (idx = 0; idx < num; idx++)
+            m_rowHeights[ temp[idx] ] += delta;
     }
 
-    if ((m_growableCols.GetCount() > 0) && (sz.x > minsz.x))
+    temp.Empty();
+    // See above
+    for (idx = 0; idx < m_growableCols.GetCount(); idx++)
+        if (m_growableCols[idx] < ncols)
+            temp.Add( m_growableCols[idx] );
+    num = temp.GetCount();
+
+    if ((num > 0) && (sz.x > minsz.x))
     {
-        delta = (sz.x - minsz.x) / m_growableCols.GetCount();
-        for (idx = 0; idx < m_growableCols.GetCount(); idx++)
-            m_colWidths[ m_growableCols[idx] ] += delta;
+        delta = (sz.x - minsz.x) / num;
+        for (idx = 0; idx < num; idx++)
+            m_colWidths[ temp[idx] ] += delta;
     }
 
     sz = wxSize( pt.x + sz.x, pt.y + sz.y );
@@ -879,31 +995,20 @@ void wxFlexGridSizer::RecalcSizes()
 
 wxSize wxFlexGridSizer::CalcMin()
 {
-    if (m_children.GetCount() == 0)
+    int nitems, nrows, ncols;
+    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
         return wxSize(10,10);
 
-    int nitems = m_children.GetCount();
-    int nrows = m_rows;
-    int ncols = m_cols;
-
-    if (ncols > 0)
-        nrows = (nitems + ncols-1) / ncols;
-    else
-        ncols = (nitems + nrows-1) / nrows;
-
     CreateArrays();
 
-    int col;
-    int row;
-
     int i = 0;
     wxNode *node = m_children.First();
     while (node)
     {
         wxSizerItem *item = (wxSizerItem*)node->Data();
         wxSize sz( item->CalcMin() );
-        row = i / ncols;
-        col = i % ncols;
+        int row = i / ncols;
+        int col = i % ncols;
         m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
         m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
 
@@ -912,11 +1017,11 @@ wxSize wxFlexGridSizer::CalcMin()
     }
 
     int width = 0;
-    for (col = 0; col < ncols; col++)
+    for (int col = 0; col < ncols; col++)
         width += m_colWidths[ col ];
 
     int height = 0;
-    for (row = 0; row < nrows; row++)
+    for (int row = 0; row < nrows; row++)
         height += m_rowHeights[ row ];
 
     return wxSize( width +  (ncols-1) * m_hgap,
@@ -977,62 +1082,64 @@ void wxBoxSizer::RecalcSizes()
     while (node)
     {
         wxSizerItem *item = (wxSizerItem*) node->Data();
-
-        int weight = 1;
-        if (item->GetOption())
-            weight = item->GetOption();
-
-        wxSize size( item->CalcMin() );
-
-        if (m_orient == wxVERTICAL)
+        if (item->IsShown())
         {
-            wxCoord height = size.y;
+            int weight = 1;
             if (item->GetOption())
-            {
-                height = (delta * weight) + extra;
-                extra = 0; // only the first item will get the remainder as extra size
-            }
-
-            wxPoint child_pos( pt );
-            wxSize  child_size( wxSize( size.x, height) );
+                weight = item->GetOption();
 
-            if (item->GetFlag() & (wxEXPAND | wxSHAPED))
-                child_size.x = m_size.x;
-            else if (item->GetFlag() & wxALIGN_RIGHT)
-                child_pos.x += m_size.x - size.x;
-            else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
-            // XXX wxCENTER is added for backward compatibility;
-            //     wxALIGN_CENTER should be used in new code
-                child_pos.x += (m_size.x - size.x) / 2;
-
-            item->SetDimension( child_pos, child_size );
+            wxSize size( item->CalcMin() );
 
-            pt.y += height;
-        }
-        else
-        {
-            wxCoord width = size.x;
-            if (item->GetOption())
+            if (m_orient == wxVERTICAL)
             {
-                width = (delta * weight) + extra;
-                extra = 0; // only the first item will get the remainder as extra size
+                wxCoord height = size.y;
+                if (item->GetOption())
+                {
+                    height = (delta * weight) + extra;
+                    extra = 0; // only the first item will get the remainder as extra size
+                }
+
+                wxPoint child_pos( pt );
+                wxSize  child_size( wxSize( size.x, height) );
+
+                if (item->GetFlag() & (wxEXPAND | wxSHAPED))
+                    child_size.x = m_size.x;
+                else if (item->GetFlag() & wxALIGN_RIGHT)
+                    child_pos.x += m_size.x - size.x;
+                else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
+                // XXX wxCENTER is added for backward compatibility;
+                //     wxALIGN_CENTER should be used in new code
+                    child_pos.x += (m_size.x - size.x) / 2;
+
+                item->SetDimension( child_pos, child_size );
+
+                pt.y += height;
+            }
+            else
+            {
+                wxCoord width = size.x;
+                if (item->GetOption())
+                {
+                    width = (delta * weight) + extra;
+                    extra = 0; // only the first item will get the remainder as extra size
+                }
+
+                wxPoint child_pos( pt );
+                wxSize  child_size( wxSize(width, size.y) );
+
+                if (item->GetFlag() & (wxEXPAND | wxSHAPED))
+                    child_size.y = m_size.y;
+                else if (item->GetFlag() & wxALIGN_BOTTOM)
+                    child_pos.y += m_size.y - size.y;
+                else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
+                // XXX wxCENTER is added for backward compatibility;
+                //     wxALIGN_CENTER should be used in new code
+                    child_pos.y += (m_size.y - size.y) / 2;
+
+                item->SetDimension( child_pos, child_size );
+
+                pt.x += width;
             }
-
-            wxPoint child_pos( pt );
-            wxSize  child_size( wxSize(width, size.y) );
-
-            if (item->GetFlag() & (wxEXPAND | wxSHAPED))
-                child_size.y = m_size.y;
-            else if (item->GetFlag() & wxALIGN_BOTTOM)
-                child_pos.y += m_size.y - size.y;
-            else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
-            // XXX wxCENTER is added for backward compatibility;
-            //     wxALIGN_CENTER should be used in new code
-                child_pos.y += (m_size.y - size.y) / 2;
-
-            item->SetDimension( child_pos, child_size );
-
-            pt.x += width;
         }
 
         node = node->Next();
@@ -1056,7 +1163,7 @@ wxSize wxBoxSizer::CalcMin()
     while (node)
     {
         wxSizerItem *item = (wxSizerItem*) node->Data();
-        if (item->GetOption() != 0)
+        if (item->IsShown() && item->GetOption() != 0)
         {
             int stretch = item->GetOption();
             wxSize size( item->CalcMin() );
@@ -1071,48 +1178,49 @@ wxSize wxBoxSizer::CalcMin()
         }
         node = node->Next();
     }
-       // Calculate overall minimum size
-       node = m_children.GetFirst();
+    // Calculate overall minimum size
+    node = m_children.GetFirst();
     while (node)
     {
         wxSizerItem *item = (wxSizerItem*) node->Data();
-
-        m_stretchable += item->GetOption();
-
-        wxSize size( item->CalcMin() );
-        if (item->GetOption() != 0)
+        if (item->IsShown())
         {
-            if (m_orient == wxHORIZONTAL)
-                size.x = stretchSize * item->GetOption();
-            else
-                size.y = stretchSize * item->GetOption();
-        }
+            m_stretchable += item->GetOption();
 
-        if (m_orient == wxHORIZONTAL)
-        {
-            m_minWidth += size.x;
-            m_minHeight = wxMax( m_minHeight, size.y );
-        }
-        else
-        {
-            m_minHeight += size.y;
-            m_minWidth = wxMax( m_minWidth, size.x );
-        }
+            wxSize size( item->CalcMin() );
+            if (item->GetOption() != 0)
+            {
+                if (m_orient == wxHORIZONTAL)
+                    size.x = stretchSize * item->GetOption();
+                else
+                    size.y = stretchSize * item->GetOption();
+            }
 
-        if (item->GetOption() == 0)
-        {
-            if (m_orient == wxVERTICAL)
+            if (m_orient == wxHORIZONTAL)
             {
-                m_fixedHeight += size.y;
-                m_fixedWidth = wxMax( m_fixedWidth, size.x );
+                m_minWidth += size.x;
+                m_minHeight = wxMax( m_minHeight, size.y );
             }
             else
             {
-                m_fixedWidth += size.x;
-                m_fixedHeight = wxMax( m_fixedHeight, size.y );
+                m_minHeight += size.y;
+                m_minWidth = wxMax( m_minWidth, size.x );
             }
-        }
 
+            if (item->GetOption() == 0)
+            {
+                if (m_orient == wxVERTICAL)
+                {
+                    m_fixedHeight += size.y;
+                    m_fixedWidth = wxMax( m_fixedWidth, size.x );
+                }
+                else
+                {
+                    m_fixedWidth += size.x;
+                    m_fixedHeight = wxMax( m_fixedHeight, size.y );
+                }
+            }
+        }
         node = node->Next();
     }
 
@@ -1144,7 +1252,7 @@ static void GetStaticBoxBorders(wxStaticBox *box,
     else
 #endif // __WXGTK__
         *borderTop = 15;
-       (void)box;
+    (void)box;
     *borderOther = 5;
 }