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/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;

View File

@ -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

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.
@ -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;

View 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 );

View 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

View 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 );
}
}