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:
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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 );
|
||||||
|
@@ -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
|
||||||
|
@@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user