]> git.saurik.com Git - wxWidgets.git/commitdiff
Add optional columns autosizing to wxDataViewCtrl.
authorVáclav Slavík <vslavik@fastmail.fm>
Sat, 30 Oct 2010 15:57:41 +0000 (15:57 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Sat, 30 Oct 2010 15:57:41 +0000 (15:57 +0000)
Only implemented in the generic and GTK+ versions at the moment, OS X
support will be added later.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65948 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/generic/dataview.h
include/wx/headercol.h
interface/wx/headercol.h
samples/dataview/dataview.cpp
src/generic/datavgen.cpp
src/gtk/dataview.cpp

index f06776ea0b2b882f2da405239a25991fc23c69c4..d47b028b04db9d0c8656442ca4d4375bb3ffd2c9 100644 (file)
@@ -17,6 +17,7 @@
 #include "wx/control.h"
 #include "wx/scrolwin.h"
 #include "wx/icon.h"
+#include "wx/vector.h"
 
 class WXDLLIMPEXP_FWD_ADV wxDataViewMainWindow;
 class WXDLLIMPEXP_FWD_ADV wxDataViewHeaderWindow;
@@ -56,7 +57,7 @@ public:
     virtual wxString GetTitle() const { return m_title; }
 
     virtual void SetWidth(int width) { m_width = width; UpdateDisplay(); }
-    virtual int GetWidth() const { return m_width; }
+    virtual int GetWidth() const;
 
     virtual void SetMinWidth(int minWidth) { m_minWidth = minWidth; UpdateDisplay(); }
     virtual int GetMinWidth() const { return m_minWidth; }
@@ -206,10 +207,7 @@ protected:
 public:     // utility functions not part of the API
 
     // returns the "best" width for the idx-th column
-    unsigned int GetBestColumnWidth(int WXUNUSED(idx)) const
-    {
-        return GetClientSize().GetWidth() / GetColumnCount();
-    }
+    unsigned int GetBestColumnWidth(int idx) const;
 
     // called by header window after reorder
     void ColumnMoved( wxDataViewColumn* col, unsigned int new_pos );
@@ -232,7 +230,13 @@ private:
     virtual wxDataViewItem DoGetCurrentItem() const;
     virtual void DoSetCurrentItem(const wxDataViewItem& item);
 
+    void InvalidateColBestWidths();
+    void InvalidateColBestWidth(int idx);
+
     wxDataViewColumnList      m_cols;
+    // cached column best widths or 0 if not computed, values are for
+    // respective columns from m_cols and the arrays have same size
+    wxVector<int>             m_colsBestWidths;
     wxDataViewModelNotifier  *m_notifier;
     wxDataViewMainWindow     *m_clientArea;
     wxDataViewHeaderWindow   *m_headerArea;
index a52713d2285f7d343d06287c0309c811effd95ce..051ebbf14efcee9d477632eb6fad6d0b3e65498d 100644 (file)
 enum
 {
     // special value for column width meaning unspecified/default
-    wxCOL_WIDTH_DEFAULT = -1
+    wxCOL_WIDTH_DEFAULT = -1,
+
+    // size the column automatically to fit all values
+    wxCOL_WIDTH_AUTOSIZE = -2
 };
 
 // bit masks for the various column attributes
index 5142326892c708857b30c659601b782ef1c5e6b9..e0a65b9e62815faf7d109eb1813fdd9ac6af6e5d 100644 (file)
@@ -9,9 +9,16 @@
 /////////////////////////////////////////////////////////////////////////////
 
 /**
-    Special value used for column width meaning unspecified or default.
+    Column width special values.
  */
-enum { wxCOL_WIDTH_DEFAULT = -1 };
+enum
+{
+    /// Special value used for column width meaning unspecified or default.
+    wxCOL_WIDTH_DEFAULT = -1,
+
+    /// Size the column automatically to fit all values.
+    wxCOL_WIDTH_AUTOSIZE = -2
+};
 
 /**
     Bit flags used as wxHeaderColumn flags.
@@ -77,7 +84,8 @@ public:
         Returns the current width of the column.
 
         @return
-            Width of the column in pixels, never wxCOL_WIDTH_DEFAULT.
+            Width of the column in pixels, never wxCOL_WIDTH_DEFAULT or
+            wxCOL_WIDTH_AUTOSIZE.
     */
     virtual int GetWidth() const = 0;
 
@@ -199,8 +207,9 @@ public:
         Set the column width.
 
         @param width
-            The column width in pixels or the special wxCOL_WIDTH_DEFAULT value
-            meaning to use default width.
+            The column width in pixels or the special wxCOL_WIDTH_DEFAULT
+            (meaning to use default width) or wxCOL_WIDTH_AUTOSIZE (size to
+            fit the content) value.
      */
     virtual void SetWidth(int width) = 0;
 
index 7dc4ea6a7a94f13a87d04b04ad386e831495ef2a..9c67b7e60bfe757a87ea251b7865aaf787bf448e 100644 (file)
@@ -622,16 +622,18 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
             // the various columns
             m_ctrl[1]->AppendTextColumn("editable string",
                                         MyListModel::Col_EditableText,
-                                        wxDATAVIEW_CELL_EDITABLE);
+                                        wxDATAVIEW_CELL_EDITABLE,
+                                        wxCOL_WIDTH_AUTOSIZE);
             m_ctrl[1]->AppendIconTextColumn("icon",
                                             MyListModel::Col_IconText,
-                                            wxDATAVIEW_CELL_EDITABLE);
+                                            wxDATAVIEW_CELL_EDITABLE,
+                                            wxCOL_WIDTH_AUTOSIZE);
 
             m_attributes =
                 new wxDataViewColumn("attributes",
                                      new wxDataViewTextRenderer,
                                      MyListModel::Col_TextWithAttr,
-                                     80,
+                                     wxCOL_WIDTH_AUTOSIZE,
                                      wxALIGN_RIGHT,
                                      wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE );
             m_ctrl[1]->AppendColumn( m_attributes );
index 6df48842d202f708d8905282d0216a8cc831dd86..ec68fc76a991a0184737473a2a484ac65109de4e 100644 (file)
@@ -88,7 +88,7 @@ static bool g_asending = true;
 
 void wxDataViewColumn::Init(int width, wxAlignment align, int flags)
 {
-    m_width = width == wxCOL_WIDTH_DEFAULT ? wxDVC_DEFAULT_WIDTH : width;
+    m_width = width;
     m_minWidth = 0;
     m_align = align;
     m_flags = flags;
@@ -96,6 +96,22 @@ void wxDataViewColumn::Init(int width, wxAlignment align, int flags)
     m_sortAscending = true;
 }
 
+int wxDataViewColumn::GetWidth() const
+{
+    switch ( m_width )
+    {
+        case wxCOL_WIDTH_DEFAULT:
+            return wxDVC_DEFAULT_WIDTH;
+
+        case wxCOL_WIDTH_AUTOSIZE:
+            wxCHECK_MSG( m_owner, wxDVC_DEFAULT_WIDTH, "no owner control" );
+            return m_owner->GetBestColumnWidth(m_owner->GetColumnIndex(this));
+
+        default:
+            return m_width;
+    }
+}
+
 void wxDataViewColumn::UpdateDisplay()
 {
     if (m_owner)
@@ -1930,6 +1946,8 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func )
 
 bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
 {
+    GetOwner()->InvalidateColBestWidths();
+
     if (IsVirtualList())
     {
         wxDataViewVirtualListModel *list_model =
@@ -1972,6 +1990,8 @@ static void DestroyTreeHelper( wxDataViewTreeNode * node);
 bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
                                        const wxDataViewItem& item)
 {
+    GetOwner()->InvalidateColBestWidths();
+
     if (IsVirtualList())
     {
         wxDataViewVirtualListModel *list_model =
@@ -2050,6 +2070,8 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
 
 bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
 {
+    GetOwner()->InvalidateColBestWidths();
+
     SortPrepare();
     g_model->Resort();
 
@@ -2066,6 +2088,8 @@ bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
 
 bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int col )
 {
+    GetOwner()->InvalidateColBestWidth(col);
+
     // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
 /*#define MAX_VIRTUAL_WIDTH       100000
 
@@ -2093,6 +2117,8 @@ bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned i
 
 bool wxDataViewMainWindow::Cleared()
 {
+    GetOwner()->InvalidateColBestWidths();
+
     DestroyTree();
     m_selection.Clear();
 
@@ -3879,6 +3905,7 @@ wxDataViewCtrl::~wxDataViewCtrl()
         GetModel()->RemoveNotifier( m_notifier );
 
     m_cols.Clear();
+    m_colsBestWidths.clear();
 }
 
 void wxDataViewCtrl::Init()
@@ -4029,6 +4056,7 @@ bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
         return false;
 
     m_cols.Append( col );
+    m_colsBestWidths.push_back(0);
     OnColumnsCountChanged();
     return true;
 }
@@ -4039,6 +4067,7 @@ bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
         return false;
 
     m_cols.Insert( col );
+    m_colsBestWidths.insert(m_colsBestWidths.begin(), 0);
     OnColumnsCountChanged();
     return true;
 }
@@ -4049,6 +4078,7 @@ bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
         return false;
 
     m_cols.Insert( pos, col );
+    m_colsBestWidths.insert(m_colsBestWidths.begin() + pos, 0);
     OnColumnsCountChanged();
     return true;
 }
@@ -4111,6 +4141,44 @@ int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn *column) const
     return wxNOT_FOUND;
 }
 
+unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const
+{
+    if ( m_colsBestWidths[idx] != 0 )
+        return m_colsBestWidths[idx];
+
+    const unsigned count = m_clientArea->GetRowCount();
+    wxDataViewColumn *column = GetColumn(idx);
+    wxDataViewRenderer *renderer =
+        const_cast<wxDataViewRenderer*>(column->GetRenderer());
+
+    int max_width = 0;
+
+    if ( m_headerArea )
+    {
+        max_width = m_headerArea->GetTextExtent(column->GetTitle()).x;
+
+        // Labels on native MSW header are indented on both sides
+        max_width += wxRendererNative::Get().GetHeaderButtonMargin(m_headerArea);
+    }
+
+    for ( unsigned row = 0; row < count; row++ )
+    {
+        wxDataViewItem item = m_clientArea->GetItemByRow(row);
+
+        wxVariant value;
+        GetModel()->GetValue(value, item, column->GetModelColumn());
+        renderer->SetValue(value);
+
+        max_width = (unsigned)wxMax((int)max_width, renderer->GetSize().x);
+    }
+
+    if ( max_width > 0 )
+        max_width += 2 * PADDING_RIGHTLEFT;
+
+    const_cast<wxDataViewCtrl*>(this)->m_colsBestWidths[idx] = max_width;
+    return max_width;
+}
+
 void wxDataViewCtrl::ColumnMoved(wxDataViewColumn * WXUNUSED(col),
                                 unsigned int WXUNUSED(new_pos))
 {
@@ -4126,6 +4194,7 @@ bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
     if (!ret)
         return false;
 
+    m_colsBestWidths.erase(m_colsBestWidths.begin() + GetColumnIndex(column));
     m_cols.Erase(ret);
     OnColumnsCountChanged();
 
@@ -4135,10 +4204,31 @@ bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
 bool wxDataViewCtrl::ClearColumns()
 {
     m_cols.Clear();
+    m_colsBestWidths.clear();
     OnColumnsCountChanged();
     return true;
 }
 
+void wxDataViewCtrl::InvalidateColBestWidth(int idx)
+{
+    m_colsBestWidths[idx] = 0;
+
+    if ( m_headerArea )
+        m_headerArea->UpdateColumn(idx);
+}
+
+void wxDataViewCtrl::InvalidateColBestWidths()
+{
+    m_colsBestWidths.clear();
+    m_colsBestWidths.resize(m_cols.size());
+
+    if ( m_headerArea )
+    {
+        // this updates visual appearance of columns 0 and up, not just 0
+        m_headerArea->UpdateColumn(0);
+    }
+}
+
 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
 {
 #if 1
index 3290b2ad0f7aeb8ee6cc54a2362da9f356c8b212..f0e0d60b72fe58f9bfefe596e3d49d5b87f299a7 100644 (file)
@@ -3205,23 +3205,20 @@ int wxDataViewColumn::GetWidth() const
 
 void wxDataViewColumn::SetWidth( int width )
 {
-    if (width < 0)
+    if ( width == wxCOL_WIDTH_AUTOSIZE )
     {
-#if 1
-        gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
-
-        // TODO find a better calculation
-        gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), wxDVC_DEFAULT_WIDTH );
-#else
-        // this is unpractical for large numbers of items and disables
-        // user resizing, which is totally unexpected
+        // NB: this disables user resizing
         gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE );
-#endif
     }
     else
     {
-        gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
+        if ( width == wxCOL_WIDTH_DEFAULT )
+        {
+            // TODO find a better calculation
+            width = wxDVC_DEFAULT_WIDTH;
+        }
 
+        gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
         gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
     }
 }