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
This commit is contained in:
Václav Slavík
2010-10-30 15:57:41 +00:00
parent 9aebcb5e44
commit d0154e3a5a
6 changed files with 131 additions and 26 deletions

View File

@@ -17,6 +17,7 @@
#include "wx/control.h" #include "wx/control.h"
#include "wx/scrolwin.h" #include "wx/scrolwin.h"
#include "wx/icon.h" #include "wx/icon.h"
#include "wx/vector.h"
class WXDLLIMPEXP_FWD_ADV wxDataViewMainWindow; class WXDLLIMPEXP_FWD_ADV wxDataViewMainWindow;
class WXDLLIMPEXP_FWD_ADV wxDataViewHeaderWindow; class WXDLLIMPEXP_FWD_ADV wxDataViewHeaderWindow;
@@ -56,7 +57,7 @@ public:
virtual wxString GetTitle() const { return m_title; } virtual wxString GetTitle() const { return m_title; }
virtual void SetWidth(int width) { m_width = width; UpdateDisplay(); } 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 void SetMinWidth(int minWidth) { m_minWidth = minWidth; UpdateDisplay(); }
virtual int GetMinWidth() const { return m_minWidth; } virtual int GetMinWidth() const { return m_minWidth; }
@@ -206,10 +207,7 @@ protected:
public: // utility functions not part of the API public: // utility functions not part of the API
// returns the "best" width for the idx-th column // returns the "best" width for the idx-th column
unsigned int GetBestColumnWidth(int WXUNUSED(idx)) const unsigned int GetBestColumnWidth(int idx) const;
{
return GetClientSize().GetWidth() / GetColumnCount();
}
// called by header window after reorder // called by header window after reorder
void ColumnMoved( wxDataViewColumn* col, unsigned int new_pos ); void ColumnMoved( wxDataViewColumn* col, unsigned int new_pos );
@@ -232,7 +230,13 @@ private:
virtual wxDataViewItem DoGetCurrentItem() const; virtual wxDataViewItem DoGetCurrentItem() const;
virtual void DoSetCurrentItem(const wxDataViewItem& item); virtual void DoSetCurrentItem(const wxDataViewItem& item);
void InvalidateColBestWidths();
void InvalidateColBestWidth(int idx);
wxDataViewColumnList m_cols; 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; wxDataViewModelNotifier *m_notifier;
wxDataViewMainWindow *m_clientArea; wxDataViewMainWindow *m_clientArea;
wxDataViewHeaderWindow *m_headerArea; wxDataViewHeaderWindow *m_headerArea;

View File

@@ -22,7 +22,10 @@
enum enum
{ {
// special value for column width meaning unspecified/default // 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 // bit masks for the various column attributes

View 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. Bit flags used as wxHeaderColumn flags.
@@ -77,7 +84,8 @@ public:
Returns the current width of the column. Returns the current width of the column.
@return @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; virtual int GetWidth() const = 0;
@@ -199,8 +207,9 @@ public:
Set the column width. Set the column width.
@param width @param width
The column width in pixels or the special wxCOL_WIDTH_DEFAULT value The column width in pixels or the special wxCOL_WIDTH_DEFAULT
meaning to use default width. (meaning to use default width) or wxCOL_WIDTH_AUTOSIZE (size to
fit the content) value.
*/ */
virtual void SetWidth(int width) = 0; virtual void SetWidth(int width) = 0;

View File

@@ -622,16 +622,18 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l
// the various columns // the various columns
m_ctrl[1]->AppendTextColumn("editable string", m_ctrl[1]->AppendTextColumn("editable string",
MyListModel::Col_EditableText, MyListModel::Col_EditableText,
wxDATAVIEW_CELL_EDITABLE); wxDATAVIEW_CELL_EDITABLE,
wxCOL_WIDTH_AUTOSIZE);
m_ctrl[1]->AppendIconTextColumn("icon", m_ctrl[1]->AppendIconTextColumn("icon",
MyListModel::Col_IconText, MyListModel::Col_IconText,
wxDATAVIEW_CELL_EDITABLE); wxDATAVIEW_CELL_EDITABLE,
wxCOL_WIDTH_AUTOSIZE);
m_attributes = m_attributes =
new wxDataViewColumn("attributes", new wxDataViewColumn("attributes",
new wxDataViewTextRenderer, new wxDataViewTextRenderer,
MyListModel::Col_TextWithAttr, MyListModel::Col_TextWithAttr,
80, wxCOL_WIDTH_AUTOSIZE,
wxALIGN_RIGHT, wxALIGN_RIGHT,
wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE ); wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE );
m_ctrl[1]->AppendColumn( m_attributes ); m_ctrl[1]->AppendColumn( m_attributes );

View File

@@ -88,7 +88,7 @@ static bool g_asending = true;
void wxDataViewColumn::Init(int width, wxAlignment align, int flags) 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_minWidth = 0;
m_align = align; m_align = align;
m_flags = flags; m_flags = flags;
@@ -96,6 +96,22 @@ void wxDataViewColumn::Init(int width, wxAlignment align, int flags)
m_sortAscending = true; 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() void wxDataViewColumn::UpdateDisplay()
{ {
if (m_owner) if (m_owner)
@@ -1930,6 +1946,8 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func )
bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item) bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
{ {
GetOwner()->InvalidateColBestWidths();
if (IsVirtualList()) if (IsVirtualList())
{ {
wxDataViewVirtualListModel *list_model = wxDataViewVirtualListModel *list_model =
@@ -1972,6 +1990,8 @@ static void DestroyTreeHelper( wxDataViewTreeNode * node);
bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent, bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
const wxDataViewItem& item) const wxDataViewItem& item)
{ {
GetOwner()->InvalidateColBestWidths();
if (IsVirtualList()) if (IsVirtualList())
{ {
wxDataViewVirtualListModel *list_model = wxDataViewVirtualListModel *list_model =
@@ -2050,6 +2070,8 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item) bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
{ {
GetOwner()->InvalidateColBestWidths();
SortPrepare(); SortPrepare();
g_model->Resort(); g_model->Resort();
@@ -2066,6 +2088,8 @@ bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int col ) bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int col )
{ {
GetOwner()->InvalidateColBestWidth(col);
// NOTE: to be valid, we cannot use e.g. INT_MAX - 1 // NOTE: to be valid, we cannot use e.g. INT_MAX - 1
/*#define MAX_VIRTUAL_WIDTH 100000 /*#define MAX_VIRTUAL_WIDTH 100000
@@ -2093,6 +2117,8 @@ bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned i
bool wxDataViewMainWindow::Cleared() bool wxDataViewMainWindow::Cleared()
{ {
GetOwner()->InvalidateColBestWidths();
DestroyTree(); DestroyTree();
m_selection.Clear(); m_selection.Clear();
@@ -3879,6 +3905,7 @@ wxDataViewCtrl::~wxDataViewCtrl()
GetModel()->RemoveNotifier( m_notifier ); GetModel()->RemoveNotifier( m_notifier );
m_cols.Clear(); m_cols.Clear();
m_colsBestWidths.clear();
} }
void wxDataViewCtrl::Init() void wxDataViewCtrl::Init()
@@ -4029,6 +4056,7 @@ bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
return false; return false;
m_cols.Append( col ); m_cols.Append( col );
m_colsBestWidths.push_back(0);
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; return true;
} }
@@ -4039,6 +4067,7 @@ bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
return false; return false;
m_cols.Insert( col ); m_cols.Insert( col );
m_colsBestWidths.insert(m_colsBestWidths.begin(), 0);
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; return true;
} }
@@ -4049,6 +4078,7 @@ bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
return false; return false;
m_cols.Insert( pos, col ); m_cols.Insert( pos, col );
m_colsBestWidths.insert(m_colsBestWidths.begin() + pos, 0);
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; return true;
} }
@@ -4111,6 +4141,44 @@ int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn *column) const
return wxNOT_FOUND; 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), void wxDataViewCtrl::ColumnMoved(wxDataViewColumn * WXUNUSED(col),
unsigned int WXUNUSED(new_pos)) unsigned int WXUNUSED(new_pos))
{ {
@@ -4126,6 +4194,7 @@ bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
if (!ret) if (!ret)
return false; return false;
m_colsBestWidths.erase(m_colsBestWidths.begin() + GetColumnIndex(column));
m_cols.Erase(ret); m_cols.Erase(ret);
OnColumnsCountChanged(); OnColumnsCountChanged();
@@ -4135,10 +4204,31 @@ bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column )
bool wxDataViewCtrl::ClearColumns() bool wxDataViewCtrl::ClearColumns()
{ {
m_cols.Clear(); m_cols.Clear();
m_colsBestWidths.clear();
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; 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 int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
{ {
#if 1 #if 1

View File

@@ -3205,23 +3205,20 @@ int wxDataViewColumn::GetWidth() const
void wxDataViewColumn::SetWidth( int width ) void wxDataViewColumn::SetWidth( int width )
{ {
if (width < 0) if ( width == wxCOL_WIDTH_AUTOSIZE )
{ {
#if 1 // NB: this disables user resizing
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
gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE ); gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE );
#endif
} }
else 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 ); gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
} }
} }