]> git.saurik.com Git - wxWidgets.git/commitdiff
distribute only the extra, free, space according to the items proportions in wxBoxSiz...
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 22 Apr 2007 12:50:01 +0000 (12:50 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 22 Apr 2007 12:50:01 +0000 (12:50 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45577 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/sizer.h
src/common/sizer.cpp

index f03013b0c68329d92ad7811e0dce3d080802b33f..64f032246e42ae30a3f0d5ced59c4be083510e7c 100644 (file)
@@ -19,6 +19,13 @@ Changes in behaviour not resulting in compilation errors, please read this!
   other platforms in the future), use wxWindow::Navigate() or NavigateIn()
   instead.
 
   other platforms in the future), use wxWindow::Navigate() or NavigateIn()
   instead.
 
+- Sizers distribute only the extra space between the stretchable items
+  according to their proportions and not all available space. We believe the
+  new behaviour corresponds better to user expectations but if you did rely
+  on the old behaviour you will have to update your code to set the minimal
+  sizes of the sizer items to be in the same proportion as the items
+  proportions to return to the old behaviour.
+
 Changes in behaviour which may result in compilation errors
 -----------------------------------------------------------
 
 Changes in behaviour which may result in compilation errors
 -----------------------------------------------------------
 
index ce2341c36fd3d97416ddbe78befcb58f74ba265d..cb1bf054394765f0eeb6c388bd59d5c31e4b8490 100644 (file)
@@ -73,7 +73,7 @@ public:
     }
 
     // some shortcuts for Align()
     }
 
     // some shortcuts for Align()
-    wxSizerFlags& Centre() { return Align(wxCENTRE); }
+    wxSizerFlags& Centre() { return Align(wxALIGN_CENTRE); }
     wxSizerFlags& Center() { return Centre(); }
     wxSizerFlags& Top() { return Align(wxALIGN_TOP); }
     wxSizerFlags& Left() { return Align(wxALIGN_LEFT); }
     wxSizerFlags& Center() { return Centre(); }
     wxSizerFlags& Top() { return Align(wxALIGN_TOP); }
     wxSizerFlags& Left() { return Align(wxALIGN_LEFT); }
@@ -569,8 +569,12 @@ public:
     // Calculate the minimal size or return m_minSize if bigger.
     wxSize GetMinSize();
 
     // Calculate the minimal size or return m_minSize if bigger.
     wxSize GetMinSize();
 
-    virtual void RecalcSizes() = 0;
+    // These virtual functions are used by the layout algorithm: first
+    // CalcMin() is called to calculate the minimal size of the sizer and
+    // prepare for laying it out and then RecalcSizes() is called to really
+    // update all the sizer items
     virtual wxSize CalcMin() = 0;
     virtual wxSize CalcMin() = 0;
+    virtual void RecalcSizes() = 0;
 
     virtual void Layout();
 
 
     virtual void Layout();
 
@@ -765,24 +769,80 @@ private:
 class WXDLLEXPORT wxBoxSizer: public wxSizer
 {
 public:
 class WXDLLEXPORT wxBoxSizer: public wxSizer
 {
 public:
-    wxBoxSizer( int orient );
+    wxBoxSizer(int orient)
+    {
+        m_orient = orient;
 
 
-    void RecalcSizes();
-    wxSize CalcMin();
+        wxASSERT_MSG( m_orient == wxHORIZONTAL || m_orient == wxVERTICAL,
+                      _T("invalid value for wxBoxSizer orientation") );
+    }
+
+    int GetOrientation() const { return m_orient; }
 
 
-    int GetOrientation() const
-        { return m_orient; }
+    bool IsVertical() const { return m_orient == wxVERTICAL; }
 
 
-    void SetOrientation(int orient)
-        { m_orient = orient; }
+    void SetOrientation(int orient) { m_orient = orient; }
+
+    // implementation of our resizing logic
+    virtual wxSize CalcMin();
+    virtual void RecalcSizes();
 
 protected:
 
 protected:
+    // helpers for our code: this returns the component of the given wxSize in
+    // the direction of the sizer and in the other direction, respectively
+    int SizeInMajorDir(const wxSize& sz) const
+    {
+        return m_orient == wxHORIZONTAL ? sz.x : sz.y;
+    }
+
+    int& SizeInMajorDir(wxSize& sz)
+    {
+        return m_orient == wxHORIZONTAL ? sz.x : sz.y;
+    }
+
+    int& PosInMajorDir(wxPoint& pt)
+    {
+        return m_orient == wxHORIZONTAL ? pt.x : pt.y;
+    }
+
+    int SizeInMinorDir(const wxSize& sz) const
+    {
+        return m_orient == wxHORIZONTAL ? sz.y : sz.x;
+    }
+
+    int& SizeInMinorDir(wxSize& sz)
+    {
+        return m_orient == wxHORIZONTAL ? sz.y : sz.x;
+    }
+
+    int& PosInMinorDir(wxPoint& pt)
+    {
+        return m_orient == wxHORIZONTAL ? pt.y : pt.x;
+    }
+
+    // another helper: creates wxSize from major and minor components
+    wxSize SizeFromMajorMinor(int major, int minor) const
+    {
+        if ( m_orient == wxHORIZONTAL )
+        {
+            return wxSize(major, minor);
+        }
+        else // wxVERTICAL
+        {
+            return wxSize(minor, major);
+        }
+    }
+
+
+    // either wxHORIZONTAL or wxVERTICAL
     int m_orient;
     int m_orient;
-    int m_stretchable;
-    int m_minWidth;
-    int m_minHeight;
-    int m_fixedWidth;
-    int m_fixedHeight;
+
+    // the sum of proportion of all of our elements
+    int m_totalProportion;
+
+    // the minimal size needed for this sizer as calculated by the last call to
+    // our CalcMin()
+    wxSize m_minSize;
 
 private:
     DECLARE_CLASS(wxBoxSizer)
 
 private:
     DECLARE_CLASS(wxBoxSizer)
index 5f3c324720f396a19abe40cfdcb75d529eb3603f..af09c05b3e34a2c57ccd35813e951f4ceaa0bdbc 100644 (file)
@@ -1628,204 +1628,106 @@ void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
 // wxBoxSizer
 //---------------------------------------------------------------------------
 
 // wxBoxSizer
 //---------------------------------------------------------------------------
 
-wxBoxSizer::wxBoxSizer( int orient )
-    : m_orient( orient )
-{
-}
-
 void wxBoxSizer::RecalcSizes()
 {
 void wxBoxSizer::RecalcSizes()
 {
-    if (m_children.GetCount() == 0)
+    if ( m_children.empty() )
         return;
 
         return;
 
-    int delta = 0;
-    if (m_stretchable)
-    {
-        if (m_orient == wxHORIZONTAL)
-            delta = m_size.x - m_fixedWidth;
-        else
-            delta = m_size.y - m_fixedHeight;
-    }
-
-    wxPoint pt( m_position );
+    // the amount of free space which we should redistribute among the
+    // stretchable items (i.e. those with non zero proportion)
+    const int delta = SizeInMajorDir(m_size) - SizeInMajorDir(m_minSize);
 
 
-    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
-    while (node)
-    {
-        wxSizerItem     *item = node->GetData();
+    // the position at which we put the next child
+    wxPoint pt(m_position);
 
 
-        if (item->IsShown())
-        {
-            wxSize size( item->GetMinSizeWithBorder() );
+    const wxCoord totalMinorSize = SizeInMinorDir(m_size);
 
 
-            if (m_orient == wxVERTICAL)
-            {
-                wxCoord height = size.y;
-                if (item->GetProportion())
-                {
-                    // Because of at least one visible item has non-zero
-                    // proportion then m_stretchable is not zero
-                    height = (delta * item->GetProportion()) / m_stretchable;
-                }
+    for ( wxSizerItemList::const_iterator i = m_children.begin();
+          i != m_children.end();
+          ++i )
+    {
+        wxSizerItem * const item = *i;
 
 
-                wxPoint child_pos( pt );
-                wxSize  child_size( size.x, height );
+        if ( !item->IsShown() )
+            continue;
 
 
-                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;
+        const wxSize sizeThis(item->GetMinSizeWithBorder());
 
 
-                item->SetDimension( child_pos, child_size );
 
 
-                pt.y += height;
-            }
-            else
-            {
-                wxCoord width = size.x;
-                if (item->GetProportion())
-                {
-                    // Because of at least one visible item has non-zero
-                    // proportion then m_stretchable is not zero
-                    width = (delta * item->GetProportion()) / m_stretchable;
-                }
+        // adjust the size in the major direction using the proportion
+        wxCoord majorSize = SizeInMajorDir(sizeThis);
+        if ( item->GetProportion() )
+        {
+            // as at least one visible item has non-zero proportion the total
+            // proportion must be non zero
+            majorSize += (delta * item->GetProportion()) / m_totalProportion;
+        }
 
 
-                wxPoint child_pos( pt );
-                wxSize  child_size( 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;
+        // apply the alignment in the minor direction
+        wxPoint posChild(pt);
 
 
-                if ( m_containingWindow )
-                {
-                    child_pos.x = m_containingWindow->AdjustForLayoutDirection
-                                                      (
-                                                        child_pos.x,
-                                                        width,
-                                                        m_size.x
-                                                      );
-                }
+        wxCoord minorSize = SizeInMinorDir(sizeThis);
+        const int flag = item->GetFlag();
+        if ( flag & (wxEXPAND | wxSHAPED) )
+        {
+            minorSize = totalMinorSize;
+        }
+        else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
+        {
+            PosInMinorDir(posChild) += totalMinorSize - minorSize;
+        }
+        // NB: wxCENTRE is used here only for backwards compatibility,
+        //     wxALIGN_CENTRE should be used in new code
+        else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
+        {
+            PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
+        }
 
 
-                item->SetDimension( child_pos, child_size );
 
 
-                pt.x += width;
-            }
+        // apply RTL adjustment for horizontal sizers:
+        if ( !IsVertical() && m_containingWindow )
+        {
+            posChild.x = m_containingWindow->AdjustForLayoutDirection
+                                             (
+                                                posChild.x,
+                                                majorSize,
+                                                m_size.x
+                                             );
         }
 
         }
 
-        node = node->GetNext();
+        // finally set size of this child and advance to the next one
+        item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
+
+        PosInMajorDir(pt) += majorSize;
     }
 }
 
 wxSize wxBoxSizer::CalcMin()
 {
     }
 }
 
 wxSize wxBoxSizer::CalcMin()
 {
-    if (m_children.GetCount() == 0)
-        return wxSize();
-
-    m_stretchable = 0;
-    m_minWidth = 0;
-    m_minHeight = 0;
-    m_fixedWidth = 0;
-    m_fixedHeight = 0;
+    m_totalProportion = 0;
+    m_minSize = wxSize(0, 0);
 
 
-    // precalc item minsizes and count proportions
-    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
-    while (node)
+    // calculate the minimal sizes for all items and count sum of proportions
+    for ( wxSizerItemList::const_iterator i = m_children.begin();
+          i != m_children.end();
+          ++i )
     {
     {
-        wxSizerItem *item = node->GetData();
+        wxSizerItem * const item = *i;
 
 
-        if ( item->IsShown() )
-        {
-            item->CalcMin();  // result is stored in the item
-
-            m_stretchable += item->GetProportion();
-        }
-
-        node = node->GetNext();
-    }
-
-    // Total minimum size (width or height) of sizer
-    int maxMinSize = 0;
+        if ( !item->IsShown() )
+            continue;
 
 
-    node = m_children.GetFirst();
-    while (node)
-    {
-        wxSizerItem *item = node->GetData();
-
-        if (item->IsShown() && item->GetProportion() != 0)
-        {
-            int stretch = item->GetProportion();
-            wxSize size( item->GetMinSizeWithBorder() );
-            int minSize;
-
-            // Integer division rounded up is (a + b - 1) / b
-            // Round up needed in order to guarantee that all
-            // all items will have size not less then their min size
-            if (m_orient == wxHORIZONTAL)
-                minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
-            else
-                minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
-
-            if (minSize > maxMinSize)
-                maxMinSize = minSize;
-        }
-        node = node->GetNext();
-    }
-
-    // Calculate overall minimum size
-    node = m_children.GetFirst();
-    while (node)
-    {
-        wxSizerItem *item = node->GetData();
+        const wxSize sizeMinThis = item->CalcMin();
 
 
-        if (item->IsShown())
-        {
-            wxSize size( item->GetMinSizeWithBorder() );
-            if (item->GetProportion() != 0)
-            {
-                if (m_orient == wxHORIZONTAL)
-                    size.x = (maxMinSize*item->GetProportion())/m_stretchable;
-                else
-                    size.y = (maxMinSize*item->GetProportion())/m_stretchable;
-            }
-            else
-            {
-                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 );
-                }
-            }
+        SizeInMajorDir(m_minSize) += SizeInMajorDir(sizeMinThis);
+        if ( SizeInMinorDir(sizeMinThis) > SizeInMinorDir(m_minSize) )
+            SizeInMinorDir(m_minSize) = SizeInMinorDir(sizeMinThis);
 
 
-            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 );
-            }
-        }
-        node = node->GetNext();
+        m_totalProportion += item->GetProportion();
     }
 
     }
 
-    return wxSize( m_minWidth, m_minHeight );
+    return m_minSize;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------