From d0154e3a5a3353bc9f26f8ef1ca7db44ac4835e4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Sat, 30 Oct 2010 15:57:41 +0000 Subject: [PATCH] Add optional columns autosizing to wxDataViewCtrl. 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 | 14 ++++-- include/wx/headercol.h | 5 +- interface/wx/headercol.h | 19 ++++++-- samples/dataview/dataview.cpp | 8 +-- src/generic/datavgen.cpp | 92 ++++++++++++++++++++++++++++++++++- src/gtk/dataview.cpp | 19 +++----- 6 files changed, 131 insertions(+), 26 deletions(-) diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index f06776ea0b..d47b028b04 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -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 m_colsBestWidths; wxDataViewModelNotifier *m_notifier; wxDataViewMainWindow *m_clientArea; wxDataViewHeaderWindow *m_headerArea; diff --git a/include/wx/headercol.h b/include/wx/headercol.h index a52713d228..051ebbf14e 100644 --- a/include/wx/headercol.h +++ b/include/wx/headercol.h @@ -22,7 +22,10 @@ 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 diff --git a/interface/wx/headercol.h b/interface/wx/headercol.h index 5142326892..e0a65b9e62 100644 --- a/interface/wx/headercol.h +++ b/interface/wx/headercol.h @@ -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; diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 7dc4ea6a7a..9c67b7e60b 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -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 ); diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 6df48842d2..ec68fc76a9 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -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(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(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 diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 3290b2ad0f..f0e0d60b72 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -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 ); } } -- 2.45.2