From 5d76f4628261a5d80ca18e45b311efa2e79f3d57 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 26 Jan 2003 00:04:24 +0000
Subject: [PATCH] added support for non flexible (in one direction only)
 flexible sizers

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@18931 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt           |   2 +
 docs/latex/wx/flexsizr.tex |  89 ++++++++++++++++++++++
 include/wx/sizer.h         |  61 ++++++++++++---
 src/common/sizer.cpp       | 147 ++++++++++++++++++++++---------------
 4 files changed, 229 insertions(+), 70 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index fa5ab9811c..ddc9309b7a 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -17,6 +17,7 @@ All:
 - use true/false throughout the library instead of TRUE/FALSE
 - wxStopWatch::Start() resumes the stop watch if paused, as per the docs
 - added wxDirTraverser::OnOpenError() to customize the error handling
+- added wxArray::SetCount()
 
 wxBase:
 
@@ -24,6 +25,7 @@ wxBase:
 
 All GUI ports:
 
+- added wxFlexGridSizer::SetFlexibleDirection() (Szczepan Holyszewski)
 - implemented GetEditControl for wxGenericTreeCtrl (Peter Stieber)
 - improved contrib/utils/convertrc parsing (David J. Cooke)
 - fixed handling of URLs and filenames in wxFileSystem
diff --git a/docs/latex/wx/flexsizr.tex b/docs/latex/wx/flexsizr.tex
index d7456bbc21..0ce1e99fe4 100644
--- a/docs/latex/wx/flexsizr.tex
+++ b/docs/latex/wx/flexsizr.tex
@@ -6,6 +6,15 @@ height and all fields in one column having the same width, but all
 rows or all columns are not necessarily the same height or width as in
 the \helpref{wxGridSizer}{wxgridsizer}.
 
+Since wxWindows 2.5.0, wxFlexGridSizer can also size items equally in one
+direction but unequally ("flexibly") in the other. If the sizer is only
+flexible in one direction (this can be changed using 
+\helpref{SetFlexibleDrection}{wxflexgridsizersetflexibledrection}),
+it needs to be decided how the sizer should grow in the other ("non flexible")
+direction in order to fill the available space. The 
+\helpref{SetNonFlexibleGrowMode}{wxflexgridsizersetnonflexiblegrowmode} method
+serves this purpose.
+
 \wxheading{Derived from}
 
 \helpref{wxGridSizer}{wxgridsizer}\\
@@ -16,6 +25,7 @@ the \helpref{wxGridSizer}{wxgridsizer}.
 
 \helpref{wxSizer}{wxsizer}, \helpref{Sizer overview}{sizeroverview}
 
+
 \membersection{wxFlexGridSizer::wxFlexGridSizer}\label{wxflexgridsizerwxflexgridsizer}
 
 \func{}{wxFlexGridSizer}{\param{int }{rows}, \param{int }{cols}, \param{int }{vgap}, \param{int }{hgap}}
@@ -43,15 +53,94 @@ there is extra space available to the sizer.
 Specifies that row idx (starting from zero) should be grown if there
 is extra space available to the sizer.
 
+\membersection{wxFlexGridSizer::GetFlexibleDirection}\label{wxflexgridsizergetflexibledrection}
+
+\constfunc{int}{GetFlexibleDirections}{\void}
+
+Returns a wxOrientation value that specifies whether the sizer flexibly
+resizes its columns, rows, or both (default).
+
+\wxheading{Return value}
+
+One of the following values:
+
+\begin{twocollist}
+\twocolitem{wxVERTICAL}{Rows are flexibly sized.}
+\twocolitem{wxHORIZONTAL}{Columns are flexibly sized.}
+\twocolitem{wxBOTH}{Both rows and columns are flexibly sized (this is the default value).}
+\end{twocollist}
+
+\wxheading{See also}
+
+\helpref{SetFlexibleDrection}{wxflexgridsizersetflexibledrection}
+
+
+\membersection{wxFlexGridSizer::GetNonFlexibleGrowMode}\label{wxflexgridsizergetnonflexiblegrowmode}
+
+\constfunc{int}{GetNonFlexibleGrowMode}{\void}
+
+Returns the value that specifies how the sizer grows in the "non flexible"
+direction if there is one.
+
+\wxheading{Return value}
+
+One of the following values:
+
+\begin{twocollist}
+\twocolitem{wxFLEX\_GROWMODE\_NONE}{Sizer doesn't grow in the non flexible direction.}
+\twocolitem{wxFLEX\_GROWMODE\_SPECIFIED}{Sizer honors growable columns/rows set with
+\helpref{AddGrowableCol}{wxflexgridsizeraddgrowablecol} and 
+\helpref{AddGrowableRow}{wxflexgridsizeraddgrowablerow}.
+In this case equal sizing applies to minimum sizes of columns or
+rows (this is the default value).}
+\twocolitem{wxFLEX\_GROWMODE\_ALL}{Sizer equally stretches all columns or rows
+in the non flexible direction, whether they are growable or not in the flexbile
+direction.}
+\end{twocollist}
+
+\wxheading{See also}
+
+\helpref{SetFlexibleDrection}{wxflexgridsizersetflexibledrection}, 
+\helpref{SetNonFlexibleGrowMode}{wxflexgridsizersetnonflexiblegrowmode}
+
+
 \membersection{wxFlexGridSizer::RemoveGrowableCol}\label{wxflexgridsizerremovegrowablecol}
 
 \func{void}{RemoveGrowableCol}{\param{size\_t }{idx}}
 
 Specifies that column idx is no longer growable.
 
+
 \membersection{wxFlexGridSizer::RemoveGrowableRow}\label{wxflexgridsizerremovegrowablerow}
 
 \func{void}{RemoveGrowableRow}{\param{size\_t }{idx}}
 
 Specifies that row idx is no longer growable.
 
+
+\membersection{wxFlexGridSizer::SetFlexibleDirection}{wxflexgridsizersetflexibledrection}
+
+\func{void}{SetFlexibleDirections}{\param{int }{direction}}
+
+Specifies whether the sizer should flexibly resize its columns, rows, or
+both. Argument {\t direction} can be {\tt wxVERTICAL}, {\tt wxHORIZONTAL} 
+or {\tt wxBOTH} (which is the default value). Any other value is ignored. See
+\helpref{GetFlexibleDirection()}{wxflexgridsizergetflexibledrection} for the
+explanation of these values.
+
+Note that this method does not trigger relayout.
+
+
+\membersection{wxFlexGridSizer::SetNonFlexibleGrowMode}{wxflexgridsizersetnonflexiblegrowmode}
+
+\func{void}{SetNonFlexibleGrowMode}{\param{int }{mode}}
+
+Specifies how the sizer should grow in the non flexible direction if
+there is one (so
+\helpref{SetFlexibleDirections()}{wxflexgridsizersetflexibledrection} must have
+been called previously). Argument {\it mode} can be one of those documented in
+\helpref{GetNonFlexibleGrowMode}{wxflexgridsizergetnonflexiblegrowmode}, please
+see there for their explanation.
+
+Note that this method does not trigger relayout.
+
diff --git a/include/wx/sizer.h b/include/wx/sizer.h
index 913d9131a2..b5f0665955 100644
--- a/include/wx/sizer.h
+++ b/include/wx/sizer.h
@@ -339,8 +339,8 @@ public:
     wxGridSizer( int rows, int cols, int vgap, int hgap );
     wxGridSizer( int cols, int vgap = 0, int hgap = 0 );
 
-    void RecalcSizes();
-    wxSize CalcMin();
+    virtual void RecalcSizes();
+    virtual wxSize CalcMin();
 
     void SetCols( int cols )    { m_cols = cols; }
     void SetRows( int rows )    { m_rows = rows; }
@@ -370,28 +370,67 @@ private:
 // wxFlexGridSizer
 //---------------------------------------------------------------------------
 
+// the bevaiour for resizing wxFlexGridSizer cells in the "non-flexible"
+// direction
+enum wxFlexSizerGrowMode
+{
+    // don't resize the cells in non-flexible direction at all
+    wxFLEX_GROWMODE_NONE,
+
+    // uniformly resize only the specified ones (default)
+    wxFLEX_GROWMODE_SPECIFIED,
+
+    // uniformly resize all cells
+    wxFLEX_GROWMODE_ALL
+};
+
 class WXDLLEXPORT wxFlexGridSizer: public wxGridSizer
 {
 public:
+    // ctors/dtor
     wxFlexGridSizer( int rows, int cols, int vgap, int hgap );
     wxFlexGridSizer( int cols, int vgap = 0, int hgap = 0 );
-    ~wxFlexGridSizer();
+    virtual ~wxFlexGridSizer();
 
-    void RecalcSizes();
-    wxSize CalcMin();
 
+    // set the rows/columns which will grow (the others will remain of the
+    // constant initial size)
     void AddGrowableRow( size_t idx );
     void RemoveGrowableRow( size_t idx );
     void AddGrowableCol( size_t idx );
     void RemoveGrowableCol( size_t idx );
 
-protected:
-    int         *m_rowHeights;
-    int         *m_colWidths;
-    wxArrayInt  m_growableRows;
-    wxArrayInt  m_growableCols;
 
-    void CreateArrays();
+    // the sizer cells may grow in both directions, not grow at all or only
+    // grow in one direction but not the other
+
+    // the direction may be wxVERTICAL, wxHORIZONTAL or wxBOTH (default)
+    void SetFlexibleDirection(int direction) { m_flexDirection = direction; }
+    int GetFlexibleDirection() const { return m_flexDirection; }
+
+    // note that the grow mode only applies to the direction which is not
+    // flexible
+    void SetNonFlexibleGrowMode(wxFlexSizerGrowMode mode) { m_growMode = mode; }
+    wxFlexSizerGrowMode GetNonFlexibleGrowMode() const { return m_growMode; }
+
+
+    // implementation
+    virtual void RecalcSizes();
+    virtual wxSize CalcMin();
+
+protected:
+    // the heights/widths of all rows/columns
+    wxArrayInt  m_rowHeights,
+                m_colWidths;
+
+    // indices of the growable columns and rows
+    wxArrayInt  m_growableRows,
+                m_growableCols;
+
+    // parameters describing whether the growable cells should be resized in
+    // both directions or only one
+    int m_flexDirection;
+    wxFlexSizerGrowMode m_growMode;
 
 private:
     DECLARE_CLASS(wxFlexGridSizer);
diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp
index 1d7ed91c2c..a0ee65773c 100644
--- a/src/common/sizer.cpp
+++ b/src/common/sizer.cpp
@@ -1000,48 +1000,21 @@ void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
 //---------------------------------------------------------------------------
 
 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
-   : wxGridSizer( rows, cols, vgap, hgap )
-   , m_rowHeights( NULL )
-   , m_colWidths( NULL )
+               : wxGridSizer( rows, cols, vgap, hgap ),
+                 m_flexDirection(wxBOTH),
+                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
 {
 }
 
 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
-   : wxGridSizer( cols, vgap, hgap )
-   , m_rowHeights( NULL )
-   , m_colWidths( NULL )
+               : wxGridSizer( cols, vgap, hgap ),
+                 m_flexDirection(wxBOTH),
+                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
 {
 }
 
 wxFlexGridSizer::~wxFlexGridSizer()
 {
-    if (m_rowHeights)
-        delete[] m_rowHeights;
-    if (m_colWidths)
-        delete[] m_colWidths;
-}
-
-void wxFlexGridSizer::CreateArrays()
-{
-    if (m_rowHeights)
-        delete[] m_rowHeights;
-    if (m_colWidths)
-        delete[] m_colWidths;
-
-    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];
-
-    for (int col = 0; col < ncols; col++)
-        m_colWidths[ col ] = 0;
-    for (int row = 0; row < nrows; row++)
-        m_rowHeights[ row ] = 0;
 }
 
 void wxFlexGridSizer::RecalcSizes()
@@ -1054,36 +1027,63 @@ void wxFlexGridSizer::RecalcSizes()
     wxSize minsz( CalcMin() );
     wxPoint pt( GetPosition() );
     int    delta;
-    size_t idx,num;
+    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();
+    // what to do with the rows? by default, resize them proportionally
+    if ( (m_flexDirection & wxVERTICAL) ||
+            (m_growMode == wxFLEX_GROWMODE_SPECIFIED) )
+    {
+        // Transfer only those rows into temp which exist in the sizer
+        // ignoring the superfluous 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))
+        if ((num > 0) && (sz.y > minsz.y))
+        {
+            delta = (sz.y - minsz.y) / num;
+            for (idx = 0; idx < num; idx++)
+                m_rowHeights[ temp[idx] ] += delta;
+        }
+        temp.Empty();
+    }
+    else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
     {
-        delta = (sz.y - minsz.y) / num;
-        for (idx = 0; idx < num; idx++)
-            m_rowHeights[ temp[idx] ] += delta;
+        // rounding problem?
+        for ( int row = 0; row < nrows; ++row )
+            m_rowHeights[ row ] = sz.y / nrows;
     }
 
-    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();
+    // the same logic as above but for the columns
+    if ( (m_flexDirection & wxHORIZONTAL) ||
+            (m_growMode == wxFLEX_GROWMODE_SPECIFIED) )
+    {
+        // 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))
+        if ((num > 0) && (sz.x > minsz.x))
+        {
+            delta = (sz.x - minsz.x) / num;
+            for (idx = 0; idx < num; idx++)
+                m_colWidths[ temp[idx] ] += delta;
+        }
+    }
+    else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
     {
-        delta = (sz.x - minsz.x) / num;
-        for (idx = 0; idx < num; idx++)
-            m_colWidths[ temp[idx] ] += delta;
+        for ( int col=0; col < ncols; ++col )
+            m_colWidths[ col ] = sz.x / ncols;
     }
 
     sz = wxSize( pt.x + sz.x, pt.y + sz.y );
@@ -1114,11 +1114,12 @@ void wxFlexGridSizer::RecalcSizes()
 
 wxSize wxFlexGridSizer::CalcMin()
 {
-    int nitems, nrows, ncols;
-    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
-        return wxSize(10,10);
+    int nrows, ncols;
+    if ( !CalcRowsCols(nrows, ncols) )
+        return wxSize(10, 10);
 
-    CreateArrays();
+    m_rowHeights.SetCount(nrows);
+    m_colWidths.SetCount(ncols);
 
     int                      i = 0;
     wxSizerItemList::Node   *node = m_children.GetFirst();
@@ -1137,6 +1138,34 @@ wxSize wxFlexGridSizer::CalcMin()
         i++;
     }
 
+    // the logic above works when we resize flexibly in both directions but
+    // maybe this is not the case
+    if ( m_flexDirection != wxBOTH )
+    {
+        // select the array corresponding to the direction in which we do *not*
+        // resize flexibly
+        wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
+                                                          : m_rowHeights;
+
+        const int count = array.GetCount();
+
+        // find the largest value in this array
+        int n,
+            largest = 0;
+        for ( n = 0; n < count; ++n )
+        {
+            if ( array[n] > largest )
+                largest = array[n];
+        }
+
+        // and now fill it with the largest value
+        for ( n = 0; n < count; ++n )
+        {
+            array[n] = largest;
+        }
+    }
+
+
     int width = 0;
     for (int col = 0; col < ncols; col++)
         width += m_colWidths[ col ];
-- 
2.50.0

