From 9861f022c31f3f46b694f77cb166b02452a63b6d Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Fri, 23 Feb 2007 07:57:46 +0000 Subject: [PATCH] [ 1665996 ] Fixes/extensions to wxDataViewCtrl git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@44556 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dataview.h | 132 ++++--- include/wx/generic/dataview.h | 113 ++++-- include/wx/gtk/dataview.h | 96 ++++-- samples/dataview/dataview.cpp | 411 ++++++++++++++++------ src/common/datavcmn.cpp | 108 +++--- src/generic/datavgen.cpp | 632 +++++++++++++++++++++++++--------- src/gtk/dataview.cpp | 458 +++++++++++++++++------- src/msw/listctrl.cpp | 2 +- 8 files changed, 1386 insertions(+), 566 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index d255228773..c495318526 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -53,6 +53,12 @@ extern WXDLLIMPEXP_DATA_ADV(const wxChar) wxDataViewCtrlNameStr[]; // the default width of new toggle columns: #define wxDVC_TOGGLE_DEFAULT_WIDTH 30 +// the default minimal width of the columns: +#define wxDVC_DEFAULT_MINWIDTH 30 + +// the default alignment of wxDataViewRenderers: +#define wxDVR_DEFAULT_ALIGNMENT (wxALIGN_LEFT|wxALIGN_TOP) + // --------------------------------------------------------- // wxDataViewModel @@ -124,14 +130,14 @@ class WXDLLIMPEXP_ADV wxDataViewListModel: public wxDataViewModel public: wxDataViewListModel(); - virtual unsigned int GetNumberOfRows() = 0; - virtual unsigned int GetNumberOfCols() = 0; + virtual unsigned int GetRowCount() const = 0; + virtual unsigned int GetColumnCount() const = 0; // return type as reported by wxVariant - virtual wxString GetColType( unsigned int col ) = 0; + virtual wxString GetColumnType( unsigned int col ) const = 0; // get value into a wxVariant - virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) = 0; + virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) const = 0; // set value, call ValueChanged() afterwards! virtual bool SetValue( wxVariant &variant, unsigned int col, unsigned int row ) = 0; @@ -170,7 +176,8 @@ protected: typedef int (wxCALLBACK *wxDataViewListModelCompare) (unsigned int row1, unsigned int row2, unsigned int col, wxDataViewListModel* model ); -WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, wxDataViewSortedIndexArray, WXDLLIMPEXP_ADV); +WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_SIZE_T(unsigned int, + wxDataViewSortedIndexArray, WXDLLIMPEXP_ADV); class WXDLLIMPEXP_ADV wxDataViewSortedListModel: public wxDataViewListModel { @@ -181,14 +188,17 @@ public: virtual ~wxDataViewSortedListModel(); void SetAscending( bool ascending ) { m_ascending = ascending; } - bool GetAscending() { return m_ascending; } + bool IsAscending() const { return m_ascending; } + + virtual unsigned int GetRowCount() const; + virtual unsigned int GetColumnCount() const; - virtual unsigned int GetNumberOfRows(); - virtual unsigned int GetNumberOfCols(); // return type as reported by wxVariant - virtual wxString GetColType( unsigned int col ); + virtual wxString GetColumnType( unsigned int col ) const; + // get value into a wxVariant - virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ); + virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) const; + // set value, call ValueChanged() afterwards! virtual bool SetValue( wxVariant &variant, unsigned int col, unsigned int row ); @@ -245,23 +255,39 @@ enum wxDataViewCellRenderState class WXDLLIMPEXP_ADV wxDataViewRendererBase: public wxObject { public: - wxDataViewRendererBase( const wxString &varianttype, wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewRendererBase( const wxString &varianttype, + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int alignment = wxDVR_DEFAULT_ALIGNMENT ); - virtual bool SetValue( const wxVariant& WXUNUSED(value) ) { return true; } - virtual bool GetValue( wxVariant& WXUNUSED(value) ) { return true; } - virtual bool Validate( wxVariant& WXUNUSED(value) ) { return true; } - - wxString GetVariantType() { return m_variantType; } - wxDataViewCellMode GetMode() { return m_mode; } + virtual bool Validate( wxVariant& WXUNUSED(value) ) + { return true; } void SetOwner( wxDataViewColumn *owner ) { m_owner = owner; } wxDataViewColumn* GetOwner() { return m_owner; } + // renderer properties: + + virtual bool SetValue( const wxVariant& WXUNUSED(value) ) = 0; + virtual bool GetValue( wxVariant& WXUNUSED(value) ) const = 0; + + wxString GetVariantType() const { return m_variantType; } + + virtual void SetMode( wxDataViewCellMode mode ) = 0; + virtual wxDataViewCellMode GetMode() const = 0; + + // NOTE: Set/GetAlignment do not take/return a wxAlignment enum but + // rather an "int"; that's because for rendering cells it's allowed + // to combine alignment flags (e.g. wxALIGN_LEFT|wxALIGN_BOTTOM) + virtual void SetAlignment( int align ) = 0; + virtual int GetAlignment() const = 0; + protected: - wxDataViewCellMode m_mode; wxString m_variantType; wxDataViewColumn *m_owner; + // internal utility: + const wxDataViewCtrl* GetView() const; + protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRendererBase) }; @@ -290,40 +316,47 @@ public: int flags = wxDATAVIEW_COL_RESIZABLE ); virtual ~wxDataViewColumnBase(); - virtual void SetTitle( const wxString &title ); - virtual wxString GetTitle(); + // setters: - virtual void SetBitmap( const wxBitmap &bitmap ); - virtual const wxBitmap &GetBitmap(); - + virtual void SetTitle( const wxString &title ) = 0; virtual void SetAlignment( wxAlignment align ) = 0; - virtual void SetSortable( bool sortable ) = 0; - virtual bool IsSortable() const - { return (m_flags & wxDATAVIEW_COL_SORTABLE) != 0; } - virtual bool IsResizeable() const - { return (m_flags & wxDATAVIEW_COL_RESIZABLE) != 0; } - virtual bool IsHidden() const - { return (m_flags & wxDATAVIEW_COL_HIDDEN) != 0; } - + virtual void SetResizeable( bool resizeable ) = 0; + virtual void SetHidden( bool hidden ) = 0; virtual void SetSortOrder( bool ascending ) = 0; + virtual void SetFlags( int flags ); + virtual void SetOwner( wxDataViewCtrl *owner ) + { m_owner = owner; } + virtual void SetBitmap( const wxBitmap &bitmap ) + { m_bitmap=bitmap; } + + virtual void SetMinWidth( int minWidth ) = 0; + virtual void SetWidth( int width ) = 0; + + + // getters: + + virtual wxString GetTitle() const = 0; + virtual wxAlignment GetAlignment() const = 0; + virtual int GetWidth() const = 0; + virtual int GetMinWidth() const = 0; + + virtual int GetFlags() const; + + virtual bool IsSortable() const = 0; + virtual bool IsResizeable() const = 0; + virtual bool IsHidden() const = 0; virtual bool IsSortOrderAscending() const = 0; + const wxBitmap &GetBitmap() const { return m_bitmap; } + unsigned int GetModelColumn() const { return m_model_column; } + + wxDataViewCtrl *GetOwner() { return m_owner; } wxDataViewRenderer* GetRenderer() { return m_renderer; } - unsigned int GetModelColumn() { return m_model_column; } - - virtual void SetOwner( wxDataViewCtrl *owner ) { m_owner = owner; } - wxDataViewCtrl *GetOwner() { return m_owner; } - - virtual int GetWidth() const = 0; - -private: - wxDataViewCtrl *m_ctrl; +protected: wxDataViewRenderer *m_renderer; int m_model_column; - int m_flags; - wxString m_title; wxBitmap m_bitmap; wxDataViewCtrl *m_owner; @@ -336,7 +369,11 @@ protected: // --------------------------------------------------------- #define wxDV_SINGLE 0x0000 // for convenience -#define wxDV_MULTIPLE 0x0020 // can select multiple items +#define wxDV_MULTIPLE 0x0001 // can select multiple items + +#define wxDV_NO_HEADER 0x0002 // column titles not visible +#define wxDV_HORIZ_RULES 0x0004 // light horizontal rules between rows +#define wxDV_VERT_RULES 0x0008 // light vertical rules between columns class WXDLLIMPEXP_ADV wxDataViewCtrlBase: public wxControl { @@ -390,7 +427,9 @@ public: int flags = wxDATAVIEW_COL_RESIZABLE ); virtual bool AppendColumn( wxDataViewColumn *col ); - virtual unsigned int GetNumberOfColumns(); + + virtual unsigned int GetColumnCount() const; + virtual bool DeleteColumn( unsigned int pos ); virtual bool ClearColumns(); virtual wxDataViewColumn* GetColumn( unsigned int pos ); @@ -443,16 +482,19 @@ public: int GetColumn() const { return m_col; } void SetColumn( int col ) { m_col = col; } + int GetRow() const { return m_row; } void SetRow( int row ) { m_row = row; } + wxDataViewModel* GetModel() const { return m_model; } void SetModel( wxDataViewModel *model ) { m_model = model; } + const wxVariant &GetValue() const { return m_value; } void SetValue( const wxVariant &value ) { m_value = value; } // for wxEVT_DATAVIEW_COLUMN_HEADER_CLICKED only void SetDataViewColumn( wxDataViewColumn *col ) { m_column = col; } - wxDataViewColumn *GetDataViewColumn() { return m_column; } + wxDataViewColumn *GetDataViewColumn() const { return m_column; } // was label editing canceled? (for wxEVT_COMMAND_DATVIEW_END_LABEL_EDIT only) bool IsEditCancelled() const { return m_editCancelled; } diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 0a96c88b3f..9f2d6f009f 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -33,11 +33,22 @@ class WXDLLIMPEXP_ADV wxDataViewRenderer: public wxDataViewRendererBase { public: wxDataViewRenderer( const wxString &varianttype, - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); virtual ~wxDataViewRenderer(); virtual bool Render( wxRect cell, wxDC *dc, int state ) = 0; - virtual wxSize GetSize() = 0; + virtual wxSize GetSize() const = 0; + + virtual void SetAlignment( int align ) + { m_align=align; } + virtual int GetAlignment() const + { return m_align; } + + virtual void SetMode( wxDataViewCellMode mode ) + { m_mode=mode; } + virtual wxDataViewCellMode GetMode() const + { return m_mode; } virtual bool Activate( wxRect WXUNUSED(cell), wxDataViewListModel *WXUNUSED(model), @@ -68,7 +79,9 @@ public: virtual wxDC *GetDC(); private: - wxDC *m_dc; + wxDC *m_dc; + int m_align; + wxDataViewCellMode m_mode; protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRenderer) @@ -82,7 +95,8 @@ class WXDLLIMPEXP_ADV wxDataViewCustomRenderer: public wxDataViewRenderer { public: wxDataViewCustomRenderer( const wxString &varianttype = wxT("string"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewCustomRenderer) @@ -96,13 +110,14 @@ class WXDLLIMPEXP_ADV wxDataViewTextRenderer: public wxDataViewCustomRenderer { public: wxDataViewTextRenderer( const wxString &varianttype = wxT("string"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); - bool GetValue( wxVariant &value ); + bool GetValue( wxVariant &value ) const; bool Render( wxRect cell, wxDC *dc, int state ); - wxSize GetSize(); + wxSize GetSize() const; private: wxString m_text; @@ -119,13 +134,14 @@ class WXDLLIMPEXP_ADV wxDataViewBitmapRenderer: public wxDataViewCustomRenderer { public: wxDataViewBitmapRenderer( const wxString &varianttype = wxT("wxBitmap"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); - bool GetValue( wxVariant &value ); + bool GetValue( wxVariant &value ) const; bool Render( wxRect cell, wxDC *dc, int state ); - wxSize GetSize(); + wxSize GetSize() const; private: wxIcon m_icon; @@ -143,15 +159,16 @@ class WXDLLIMPEXP_ADV wxDataViewToggleRenderer: public wxDataViewCustomRenderer { public: wxDataViewToggleRenderer( const wxString &varianttype = wxT("bool"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); - bool GetValue( wxVariant &value ); + bool GetValue( wxVariant &value ) const; bool Render( wxRect cell, wxDC *dc, int state ); bool Activate( wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row ); - wxSize GetSize(); + wxSize GetSize() const; private: bool m_toggle; @@ -169,13 +186,15 @@ class WXDLLIMPEXP_ADV wxDataViewProgressRenderer: public wxDataViewCustomRendere public: wxDataViewProgressRenderer( const wxString &label = wxEmptyString, const wxString &varianttype = wxT("long"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); virtual ~wxDataViewProgressRenderer(); bool SetValue( const wxVariant &value ); + bool GetValue( wxVariant& value ) const; virtual bool Render( wxRect cell, wxDC *dc, int state ); - virtual wxSize GetSize(); + virtual wxSize GetSize() const; private: wxString m_label; @@ -193,12 +212,14 @@ class WXDLLIMPEXP_ADV wxDataViewDateRenderer: public wxDataViewCustomRenderer { public: wxDataViewDateRenderer( const wxString &varianttype = wxT("datetime"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_ACTIVATABLE ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_ACTIVATABLE, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); + bool GetValue( wxVariant& value ) const; virtual bool Render( wxRect cell, wxDC *dc, int state ); - virtual wxSize GetSize(); + virtual wxSize GetSize() const; virtual bool Activate( wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row ); @@ -230,32 +251,53 @@ public: int flags = wxDATAVIEW_COL_RESIZABLE ); virtual ~wxDataViewColumn(); - virtual void SetTitle( const wxString &title ); - virtual void SetBitmap( const wxBitmap &bitmap ); - + // setters: + + virtual void SetTitle( const wxString &title ) + { m_title=title; } virtual void SetAlignment( wxAlignment align ) { m_align=align; } - wxAlignment GetAlignment() const - { return m_align; } - + virtual void SetMinWidth( int minWidth ) + { m_minWidth=minWidth; } + virtual void SetWidth( int width ); virtual void SetSortable( bool sortable ); + virtual void SetResizeable( bool resizeable ); + virtual void SetHidden( bool hidden ); virtual void SetSortOrder( bool ascending ); + + + // getters: + + virtual wxString GetTitle() const + { return m_title; } + virtual wxAlignment GetAlignment() const + { return m_align; } + virtual int GetWidth() const + { return m_width; } + virtual int GetMinWidth() const + { return m_minWidth; } + virtual bool IsSortable() const + { return (m_flags & wxDATAVIEW_COL_SORTABLE) != 0; } + virtual bool IsResizeable() const + { return (m_flags & wxDATAVIEW_COL_RESIZABLE) != 0; } + virtual bool IsHidden() const + { return (m_flags & wxDATAVIEW_COL_HIDDEN) != 0; } virtual bool IsSortOrderAscending() const; - virtual int GetWidth() const; - -protected: - - void SetWidth(int w) - { m_width=w; } private: int m_width; - int m_fixedWidth; - wxAlignment m_align; + int m_minWidth; + int m_flags; + wxAlignment m_align; + wxString m_title; void Init(int width); + // like SetWidth() but does not ask the header window of the + // wxDataViewCtrl to reflect the width-change. + void SetInternalWidth(int width); + protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewColumn) }; @@ -271,6 +313,7 @@ class WXDLLIMPEXP_ADV wxDataViewCtrl: public wxDataViewCtrlBase, friend class wxDataViewHeaderWindowBase; friend class wxDataViewHeaderWindow; friend class wxDataViewHeaderWindowMSW; + friend class wxDataViewColumn; public: wxDataViewCtrl() : wxScrollHelperNative(this) @@ -308,12 +351,16 @@ public: virtual int GetSelection() const; virtual int GetSelections(wxArrayInt& aSelections) const; +public: // utility functions not part of the API + // returns the "best" width for the idx-th column - unsigned int GetBestColumnWidth(int WXUNUSED(idx)) + unsigned int GetBestColumnWidth(int WXUNUSED(idx)) const { - return GetClientSize().GetWidth() / GetNumberOfColumns(); + return GetClientSize().GetWidth() / GetColumnCount(); } + // updates the header window after a change in a column setting + void OnColumnChange(); private: wxDataViewListModelNotifier *m_notifier; diff --git a/include/wx/gtk/dataview.h b/include/wx/gtk/dataview.h index 78ddb1d55b..cb4043722c 100644 --- a/include/wx/gtk/dataview.h +++ b/include/wx/gtk/dataview.h @@ -30,19 +30,25 @@ class wxDataViewRenderer: public wxDataViewRendererBase { public: wxDataViewRenderer( const wxString &varianttype, - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); // implementation - void* GetGtkHandle() { return m_renderer; } + GtkWidget* GetGtkHandle() { return m_renderer; } + + virtual void SetMode( wxDataViewCellMode mode ); + virtual wxDataViewCellMode GetMode() const; + + virtual void SetAlignment( int align ); + virtual int GetAlignment() const; protected: - // holds the GTK handle - void* m_renderer; + GtkWidget *m_renderer; protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRenderer) }; - + // --------------------------------------------------------- // wxDataViewTextRenderer // --------------------------------------------------------- @@ -51,11 +57,14 @@ class wxDataViewTextRenderer: public wxDataViewRenderer { public: wxDataViewTextRenderer( const wxString &varianttype = wxT("string"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); - bool GetValue( wxVariant &value ); - + bool GetValue( wxVariant &value ) const; + + void SetAlignment( int align ); + protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer) }; @@ -68,10 +77,11 @@ class wxDataViewBitmapRenderer: public wxDataViewRenderer { public: wxDataViewBitmapRenderer( const wxString &varianttype = wxT("wxBitmap"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); - bool GetValue( wxVariant &value ); + bool GetValue( wxVariant &value ) const; protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewBitmapRenderer) @@ -85,10 +95,11 @@ class wxDataViewToggleRenderer: public wxDataViewRenderer { public: wxDataViewToggleRenderer( const wxString &varianttype = wxT("bool"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); - bool GetValue( wxVariant &value ); + bool GetValue( wxVariant &value ) const; protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewToggleRenderer) @@ -103,17 +114,18 @@ class wxDataViewCustomRenderer: public wxDataViewRenderer public: wxDataViewCustomRenderer( const wxString &varianttype = wxT("string"), wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT, bool no_init = false ); virtual ~wxDataViewCustomRenderer(); - bool Init(); - + + virtual bool Render( wxRect cell, wxDC *dc, int state ) = 0; - virtual wxSize GetSize() = 0; - + virtual wxSize GetSize() const = 0; + virtual bool Activate( wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row ) { return false; } - + virtual bool LeftClick( wxPoint cursor, wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row ) { return false; } @@ -127,6 +139,11 @@ public: // Create DC on request virtual wxDC *GetDC(); + +protected: + + bool Init(wxDataViewCellMode mode, int align); + private: wxDC *m_dc; @@ -143,13 +160,15 @@ class wxDataViewProgressRenderer: public wxDataViewCustomRenderer public: wxDataViewProgressRenderer( const wxString &label = wxEmptyString, const wxString &varianttype = wxT("long"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, + int align = wxDVR_DEFAULT_ALIGNMENT ); virtual ~wxDataViewProgressRenderer(); bool SetValue( const wxVariant &value ); + bool GetValue( wxVariant &value ) const; virtual bool Render( wxRect cell, wxDC *dc, int state ); - virtual wxSize GetSize(); + virtual wxSize GetSize() const; private: wxString m_label; @@ -167,12 +186,14 @@ class wxDataViewDateRenderer: public wxDataViewCustomRenderer { public: wxDataViewDateRenderer( const wxString &varianttype = wxT("datetime"), - wxDataViewCellMode mode = wxDATAVIEW_CELL_ACTIVATABLE ); + wxDataViewCellMode mode = wxDATAVIEW_CELL_ACTIVATABLE, + int align = wxDVR_DEFAULT_ALIGNMENT ); bool SetValue( const wxVariant &value ); + bool GetValue( wxVariant &value ) const; virtual bool Render( wxRect cell, wxDC *dc, int state ); - virtual wxSize GetSize(); + virtual wxSize GetSize() const; virtual bool Activate( wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row ); @@ -201,6 +222,9 @@ public: virtual ~wxDataViewColumn(); + + // setters: + virtual void SetTitle( const wxString &title ); virtual void SetBitmap( const wxBitmap &bitmap ); @@ -211,26 +235,40 @@ public: virtual void SetSortable( bool sortable ); virtual void SetSortOrder( bool ascending ); + virtual void SetResizeable( bool resizeable ); + virtual void SetHidden( bool hidden ); + + virtual void SetMinWidth( int minWidth ); + virtual void SetWidth( int width ); + + + // getters: + + virtual wxString GetTitle() const; + virtual wxAlignment GetAlignment() const; + virtual bool IsSortable() const; virtual bool IsSortOrderAscending() const; + virtual bool IsResizeable() const; + virtual bool IsHidden() const; virtual int GetWidth() const; - - virtual void SetFixedWidth( int width ); - virtual int GetFixedWidth() const; - + virtual int GetMinWidth() const; + // implementation - void* GetGtkHandle() { return m_column; } + GtkWidget* GetGtkHandle() { return m_column; } private: // holds the GTK handle - void* m_column; + GtkWidget *m_column; // delayed connection to mouse events friend class wxDataViewCtrl; void OnInternalIdle(); - bool m_isConnected; - + bool m_isConnected; + + void Init(wxAlignment align, int flags, int width); + protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewColumn) }; diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index dd44fadb32..73daada988 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -1,8 +1,8 @@ ///////////////////////////////////////////////////////////////////////////// // Name: dataview.cpp -// Purpose: DataVewCtrl wxWidgets sample +// Purpose: wxDataViewCtrl wxWidgets sample // Author: Robert Roebling -// Modified by: +// Modified by: Francesco Montorsi // Created: 06/01/06 // RCS-ID: $Id$ // Copyright: (c) Robert Roebling @@ -23,6 +23,9 @@ #include "wx/datetime.h" #include "wx/splitter.h" #include "wx/aboutdlg.h" +#include "wx/choicdlg.h" +#include "wx/numdlg.h" +#include "wx/dataview.h" #ifndef __WXMSW__ #include "../sample.xpm" @@ -30,7 +33,11 @@ #include "null.xpm" -#include "wx/dataview.h" + +#define DEFAULT_ALIGN wxALIGN_LEFT +#define DATAVIEW_DEFAULT_STYLE (wxDV_MULTIPLE|wxDV_HORIZ_RULES|wxDV_VERT_RULES) + + // ------------------------------------- // MyTextModel @@ -61,13 +68,13 @@ public: } } - virtual unsigned int GetNumberOfRows() + virtual unsigned int GetRowCount() const { return 1000; } - virtual unsigned int GetNumberOfCols() + virtual unsigned int GetColumnCount() const { return 7; } // as reported by wxVariant - virtual wxString GetColType( unsigned int col ) + virtual wxString GetColumnType( unsigned int col ) const { if (col == 6) return wxT("datetime"); @@ -81,7 +88,7 @@ public: return wxT("string"); } - virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) + virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) const { if (col == 6) { @@ -151,6 +158,13 @@ public: m_colour = value.GetString(); return true; } + + bool GetValue( wxVariant &value ) const + { + value = m_colour; + return true; + } + bool Render( wxRect rect, wxDC *dc, int WXUNUSED(state) ) { dc->SetPen( *wxBLACK_PEN ); @@ -163,7 +177,7 @@ public: dc->DrawRectangle( rect ); return true; } - wxSize GetSize() + wxSize GetSize() const { return wxSize(20,8); } @@ -199,10 +213,22 @@ public: m_bitmap = wxBitmap( null_xpm ); } - virtual unsigned int GetNumberOfRows() { return m_list.GetCount(); } - virtual unsigned int GetNumberOfCols() { return 2; } - virtual wxString GetColType( unsigned int WXUNUSED(col) ) { return wxT("string"); } - virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) + virtual unsigned int GetRowCount() const + { + return m_list.GetCount(); + } + + virtual unsigned int GetColumnCount() const + { + return 2; + } + + virtual wxString GetColumnType( unsigned int WXUNUSED(col) ) const + { + return wxT("string"); + } + + virtual void GetValue( wxVariant &variant, unsigned int col, unsigned int row ) const { if (col == 0) { @@ -218,6 +244,7 @@ public: tmp.Printf( wxT("item(%d;%d)"), (int)row, (int)col ); variant = tmp; } + virtual bool SetValue( wxVariant &variant, unsigned int col, unsigned int row ) { if (col == 0) @@ -282,21 +309,24 @@ public: void OnAbout(wxCommandEvent& event); void OnNewSortingFrame(wxCommandEvent& event); - void OnSingleSelMode(wxCommandEvent& event); - void OnMultipleSelMode(wxCommandEvent& event); - void OnResizeableColumn(wxCommandEvent& event); - void OnSortableColumn(wxCommandEvent& event); - void OnHideColumn(wxCommandEvent& event); - void OnChooseAlign(wxCommandEvent& event); + void OnStyleChange(wxCommandEvent& event); + void OnColumnSetting(wxCommandEvent& event); private: wxDataViewCtrl* dataview_left; wxDataViewCtrl* dataview_right; wxSplitterWindow *m_splitter; + wxPanel *m_panelLeft, *m_panelRight; - wxAlignment m_align; + // utilities: - void CreateControls(); + void CreateDataViewControls(); + + wxArrayInt GetFlaggedColumns(int flag); + wxAlignment ChooseAlign(const wxString &msg, bool onlyHorizontal); + void SetFlag(const wxArrayInt &idx, int flag); + void SetAlignment(const wxArrayInt &idx, bool header, wxAlignment align); + void SetWidth(const wxArrayInt &idx, bool minwidth, int width); private: DECLARE_EVENT_TABLE() @@ -367,8 +397,8 @@ private: wxLog *m_logOld; wxTextCtrl *m_logWindow; - MyUnsortedTextModel *m_unsorted_model; - wxDataViewSortedListModel *m_sorted_model; + wxObjectDataPtr m_unsorted_model; + wxObjectDataPtr m_sorted_model; DECLARE_EVENT_TABLE() }; @@ -407,18 +437,25 @@ enum { // file menu ID_ABOUT = wxID_ABOUT, - ID_NEW_SORT_FRAME, + ID_NEW_SORT_FRAME = wxID_HIGHEST+1, ID_EXIT = wxID_EXIT, // dataviewctrl menu - ID_SINGLE_SEL_MODE, + ID_SINGLE_SEL_MODE = wxID_HIGHEST+2, ID_MULTIPLE_SEL_MODE, + ID_NO_HEADER_MODE, + ID_HORIZ_RULES_MODE, + ID_VERT_RULES_MODE, ID_RESIZEABLE_COLUMNS, ID_SORTABLE_COLUMNS, ID_HIDDEN_COLUMNS, - ID_CHOOSE_ALIGNMENT + ID_CHOOSE_COLUMN_ALIGNMENT, + ID_CHOOSE_CONTENTS_ALIGNMENT, + + ID_SET_MINWIDTH, + ID_SET_WIDTH }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) @@ -429,14 +466,11 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU( ID_EXIT, MyFrame::OnQuit ) // dataviewctrl menu - EVT_MENU( ID_SINGLE_SEL_MODE, MyFrame::OnSingleSelMode ) - EVT_MENU( ID_MULTIPLE_SEL_MODE, MyFrame::OnMultipleSelMode ) + EVT_COMMAND_RANGE( ID_SINGLE_SEL_MODE, ID_VERT_RULES_MODE, + wxEVT_COMMAND_MENU_SELECTED, MyFrame::OnStyleChange ) - EVT_MENU( ID_RESIZEABLE_COLUMNS, MyFrame::OnResizeableColumn ) - EVT_MENU( ID_SORTABLE_COLUMNS, MyFrame::OnSortableColumn ) - EVT_MENU( ID_HIDDEN_COLUMNS, MyFrame::OnHideColumn ) - - EVT_MENU( ID_CHOOSE_ALIGNMENT, MyFrame::OnChooseAlign ) + EVT_COMMAND_RANGE( ID_RESIZEABLE_COLUMNS, ID_SET_WIDTH, + wxEVT_COMMAND_MENU_SELECTED, MyFrame::OnColumnSetting ) END_EVENT_TABLE() @@ -458,11 +492,19 @@ MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): data_menu->AppendRadioItem(ID_SINGLE_SEL_MODE, _T("&Single selection mode")); data_menu->AppendRadioItem(ID_MULTIPLE_SEL_MODE, _T("&Multiple selection mode")); data_menu->AppendSeparator(); - data_menu->AppendCheckItem(ID_RESIZEABLE_COLUMNS, _T("Make columns resizeable")); - data_menu->AppendCheckItem(ID_SORTABLE_COLUMNS, _T("Make columns sortable")); - data_menu->AppendCheckItem(ID_HIDDEN_COLUMNS, _T("Make columns hidden")); + data_menu->AppendCheckItem(ID_NO_HEADER_MODE, _T("No header mode")); + data_menu->AppendCheckItem(ID_HORIZ_RULES_MODE, _T("Horizontal rules")); + data_menu->AppendCheckItem(ID_VERT_RULES_MODE, _T("Vertical rules")); data_menu->AppendSeparator(); - data_menu->Append(ID_CHOOSE_ALIGNMENT, _T("Set alignment...")); + data_menu->Append(ID_RESIZEABLE_COLUMNS, _T("Set column(s) as resizeable...")); + data_menu->Append(ID_SORTABLE_COLUMNS, _T("Set column(s) as sortable...")); + data_menu->Append(ID_HIDDEN_COLUMNS, _T("Set column(s) as hidden...")); + data_menu->AppendSeparator(); + data_menu->Append(ID_CHOOSE_COLUMN_ALIGNMENT, _T("Set column(s) title alignment...")); + data_menu->Append(ID_CHOOSE_CONTENTS_ALIGNMENT, _T("Set column(s) contents alignment...")); + data_menu->AppendSeparator(); + data_menu->Append(ID_SET_MINWIDTH, _T("Set column(s) minimal width...")); + data_menu->Append(ID_SET_WIDTH, _T("Set column(s) width...")); wxMenuBar *menu_bar = new wxMenuBar; menu_bar->Append(file_menu, _T("&File")); @@ -472,19 +514,52 @@ MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): CreateStatusBar(); + // check the menus for the default wxDataViewCtrl style + data_menu->Check(ID_MULTIPLE_SEL_MODE, (DATAVIEW_DEFAULT_STYLE & wxDV_MULTIPLE) != 0); + data_menu->Check(ID_NO_HEADER_MODE, (DATAVIEW_DEFAULT_STYLE & wxDV_NO_HEADER) != 0); + data_menu->Check(ID_HORIZ_RULES_MODE, (DATAVIEW_DEFAULT_STYLE & wxDV_HORIZ_RULES) != 0); + data_menu->Check(ID_VERT_RULES_MODE, (DATAVIEW_DEFAULT_STYLE & wxDV_VERT_RULES) != 0); + + // build the other controls: m_splitter = new wxSplitterWindow( this, wxID_ANY ); m_splitter->SetSashGravity(0.5); - m_align = wxALIGN_CENTER; - dataview_left = dataview_right = NULL; - CreateControls(); + m_panelLeft = new wxPanel( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxNO_BORDER ); + m_panelRight = new wxPanel( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, + wxNO_BORDER ); + wxSizer *szLeft = new wxBoxSizer(wxVERTICAL); + wxSizer *szRight = new wxBoxSizer(wxVERTICAL); - m_splitter->SplitVertically(dataview_left, dataview_right); + dataview_left = NULL; + dataview_right = NULL; + CreateDataViewControls(); + + // left panel + szLeft->Add( dataview_left, 1, wxGROW|wxALL, 5 ); + m_panelLeft->SetSizerAndFit(szLeft); + + // right panel + wxStaticText *stattext = + new wxStaticText(m_panelRight, wxID_ANY, + wxT("This is another wxDataViewCtrl using the same wxDataViewModel ") + wxT("of the wxDataViewCtrl on the left but, unlike it, this window ") + wxT("won't react to the style/column changes done through the ") + wxT("'DataViewCtrl' menu")); + stattext->Wrap(GetClientSize().GetWidth() / 2); + + szRight->Add( stattext, 0, wxALL, 5 ); + szRight->Add( dataview_right, 1, wxGROW|wxALL, 5 ); + m_panelRight->SetSizerAndFit(szRight); + + // split the two panels + m_splitter->SplitVertically(m_panelLeft, m_panelRight); + this->SetMinSize(m_splitter->GetBestSize()); } -void MyFrame::CreateControls() +void MyFrame::CreateDataViewControls() { wxDataViewCtrl *old1 = NULL, *old2 = NULL; @@ -494,58 +569,52 @@ void MyFrame::CreateControls() old2 = dataview_right; // styles: - long style = 0; if (GetMenuBar()->FindItem(ID_MULTIPLE_SEL_MODE)->IsChecked()) style |= wxDV_MULTIPLE; - - int flags = 0; - if (GetMenuBar()->FindItem(ID_RESIZEABLE_COLUMNS)->IsChecked()) - flags |= wxDATAVIEW_COL_RESIZABLE; - if (GetMenuBar()->FindItem(ID_SORTABLE_COLUMNS)->IsChecked()) - flags |= wxDATAVIEW_COL_SORTABLE; - if (GetMenuBar()->FindItem(ID_HIDDEN_COLUMNS)->IsChecked()) - flags |= wxDATAVIEW_COL_HIDDEN; + if (GetMenuBar()->FindItem(ID_NO_HEADER_MODE)->IsChecked()) + style |= wxDV_NO_HEADER; + if (GetMenuBar()->FindItem(ID_HORIZ_RULES_MODE)->IsChecked()) + style |= wxDV_HORIZ_RULES; + if (GetMenuBar()->FindItem(ID_VERT_RULES_MODE)->IsChecked()) + style |= wxDV_VERT_RULES; // Left wxDataViewCtrl - dataview_left = new wxDataViewCtrl( m_splitter, wxID_ANY, wxDefaultPosition, + dataview_left = new wxDataViewCtrl( m_panelLeft, wxID_ANY, wxDefaultPosition, wxDefaultSize, style ); - MyTextModel *model = new MyTextModel; - dataview_left->AssociateModel( model ); - model->DecRef(); // don't leak memory - dataview_left->AppendTextColumn( wxT("first"), 0, wxDATAVIEW_CELL_INERT, -1, - m_align, flags ); - dataview_left->AppendTextColumn( wxT("second"), 1, wxDATAVIEW_CELL_INERT, -1, - m_align, flags ); + wxObjectDataPtr model(new MyTextModel); + dataview_left->AssociateModel( model.get() ); + + dataview_left->AppendTextColumn( wxT("First"), 0, wxDATAVIEW_CELL_INERT, -1, + DEFAULT_ALIGN ); + dataview_left->AppendTextColumn( wxT("Second"), 1, wxDATAVIEW_CELL_INERT, -1, + DEFAULT_ALIGN ); wxDataViewTextRenderer *text_renderer = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); wxDataViewColumn *column = new wxDataViewColumn( wxT("editable"), text_renderer, 2, - -1, m_align, flags ); + -1, DEFAULT_ALIGN ); dataview_left->AppendColumn( column ); - dataview_left->AppendToggleColumn( wxT("fourth"), 3, wxDATAVIEW_CELL_INERT, -1, - m_align, flags ); + dataview_left->AppendToggleColumn( wxT("fourth"), 3, wxDATAVIEW_CELL_INERT, -1, + DEFAULT_ALIGN ); MyCustomRenderer *custom_renderer = new MyCustomRenderer; - column = new wxDataViewColumn( wxT("custom"), custom_renderer, 4, -1, - m_align, flags ); + column = new wxDataViewColumn( wxT("custom"), custom_renderer, 4, -1, DEFAULT_ALIGN ); dataview_left->AppendColumn( column ); - dataview_left->AppendProgressColumn( wxT("progress"), 5, wxDATAVIEW_CELL_INERT, -1, - m_align, flags ); + dataview_left->AppendProgressColumn( wxT("progress"), 5, wxDATAVIEW_CELL_INERT, -1, + DEFAULT_ALIGN ); - dataview_left->AppendDateColumn( wxT("date"), 6, wxDATAVIEW_CELL_INERT, -1, - m_align, flags ); + dataview_left->AppendDateColumn( wxT("date"), 6, wxDATAVIEW_CELL_INERT, -1, DEFAULT_ALIGN ); // Right wxDataViewCtrl using the same model - dataview_right = new wxDataViewCtrl( m_splitter, wxID_ANY, wxDefaultPosition, - wxDefaultSize, style ); - dataview_right->AssociateModel( model ); + dataview_right = new wxDataViewCtrl( m_panelRight, wxID_ANY ); + dataview_right->AssociateModel( model.get() ); text_renderer = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); column = new wxDataViewColumn( wxT("editable"), text_renderer, 2 ); @@ -559,17 +628,22 @@ void MyFrame::CreateControls() dataview_right->AppendDateColumn( wxT("date"), 6 ); - // layout dataview controls + + // layout the new dataview controls if (old1) { - m_splitter->ReplaceWindow(old1, dataview_left); + m_panelLeft->GetSizer()->Replace(old1, dataview_left); delete old1; + + m_panelLeft->Layout(); } if (old2) { - m_splitter->ReplaceWindow(old2, dataview_right); + m_panelRight->GetSizer()->Replace(old2, dataview_right); delete old2; + + m_panelRight->Layout(); } } @@ -595,32 +669,102 @@ void MyFrame::OnNewSortingFrame(wxCommandEvent& WXUNUSED(event) ) frame2->Show(true); } -void MyFrame::OnSingleSelMode(wxCommandEvent& event) +void MyFrame::OnStyleChange(wxCommandEvent& WXUNUSED(event) ) { - CreateControls(); + // recreate the wxDataViewCtrl: + CreateDataViewControls(); } -void MyFrame::OnMultipleSelMode(wxCommandEvent& event) +void MyFrame::OnColumnSetting(wxCommandEvent& event) { - CreateControls(); + wxArrayInt columns; + int flag = 0; + bool header = false, minwidth = false; + wxString msg; + + switch (event.GetId()) + { + case ID_RESIZEABLE_COLUMNS: + flag = wxDATAVIEW_COL_RESIZABLE; + columns = GetFlaggedColumns(flag); + break; + case ID_SORTABLE_COLUMNS: + flag = wxDATAVIEW_COL_SORTABLE; + columns = GetFlaggedColumns(flag); + break; + case ID_HIDDEN_COLUMNS: + flag = wxDATAVIEW_COL_HIDDEN; + columns = GetFlaggedColumns(flag); + break; + + case ID_CHOOSE_COLUMN_ALIGNMENT: + msg = wxT("Select the columns whose headers' alignment will be modified."); + header = true; + break; + case ID_CHOOSE_CONTENTS_ALIGNMENT: + msg = wxT("Select the columns whose contents' alignment will be modified."); + header = false; + break; + + case ID_SET_MINWIDTH: + msg = wxT("Please provide the new minimal width:"); + minwidth = true; + break; + case ID_SET_WIDTH: + msg = wxT("Please provide the new width:"); + minwidth = false; + break; + } + + // get column titles: + + wxArrayString choices; + for (size_t i=0; iGetColumnCount(); i++) + choices.Add(dataview_left->GetColumn(i)->GetTitle()); + + // ask the user + wxGetMultipleChoices( + columns, + wxT("Choose the columns to which apply the change."), + wxT("Choose the column"), + choices, + this); + + switch (event.GetId()) + { + case ID_RESIZEABLE_COLUMNS: + case ID_SORTABLE_COLUMNS: + case ID_HIDDEN_COLUMNS: + SetFlag(columns, flag); + break; + + case ID_CHOOSE_COLUMN_ALIGNMENT: + case ID_CHOOSE_CONTENTS_ALIGNMENT: + SetAlignment(columns, header, ChooseAlign(msg, header)); + break; + + case ID_SET_MINWIDTH: + case ID_SET_WIDTH: + { + int def = minwidth ? wxDVC_DEFAULT_MINWIDTH : wxDVC_DEFAULT_WIDTH; + + msg << wxT("\nNOTE: all non-selected columns will be reset to a width of ") + << def << wxT(" pixels."); + + long ret = + wxGetNumberFromUser(msg, wxT("New value:"), wxT("Modify width"), + def, 0, 300, this); + + if (ret != -1) + SetWidth(columns, minwidth, ret); + } + break; + } + + dataview_left->Refresh(); } -void MyFrame::OnResizeableColumn(wxCommandEvent& event) -{ - CreateControls(); -} - -void MyFrame::OnSortableColumn(wxCommandEvent& event) -{ - CreateControls(); -} - -void MyFrame::OnHideColumn(wxCommandEvent& event) -{ - CreateControls(); -} - -void MyFrame::OnChooseAlign(wxCommandEvent& event) +wxAlignment MyFrame::ChooseAlign(const wxString &msg, bool onlyHorizontal) { const wxString choices[] = { @@ -644,17 +788,78 @@ void MyFrame::OnChooseAlign(wxCommandEvent& event) wxALIGN_CENTER }; + int n = WXSIZEOF(choices); + if (onlyHorizontal) + n = 3; // show only the first three choices + int choice = wxGetSingleChoiceIndex( - wxT("Select the alignment for the cells of the wxDataViewCtrl:"), + msg + wxT("\nNOTE: _all_ non-selected column's alignment will be reset to wxALIGN_LEFT!"), wxT("Alignment"), - WXSIZEOF(choices), choices, + n, choices, this); if (choice == wxNOT_FOUND) - return; + return wxALIGN_LEFT; - m_align = flags[choice]; - CreateControls(); + return flags[choice]; +} + +void MyFrame::SetFlag(const wxArrayInt &idx, int toadd) +{ + for (size_t i=0; iGetColumnCount(); i++) + { + int current = dataview_left->GetColumn(i)->GetFlags(); + + if (idx.Index(i) != wxNOT_FOUND) + dataview_left->GetColumn(i)->SetFlags(current | toadd); + else + dataview_left->GetColumn(i)->SetFlags(current & ~toadd); + } +} + +wxArrayInt MyFrame::GetFlaggedColumns(int flag) +{ + wxArrayInt ret; + for (size_t i=0; iGetColumnCount(); i++) + if (dataview_left->GetColumn(i)->GetFlags() & flag) + ret.Add(i); + return ret; +} + +void MyFrame::SetAlignment(const wxArrayInt &idx, bool header, wxAlignment align) +{ + // set to DEFAULT_ALIGN all columns except those + // contained in 'idx' which are set to 'align' + + for (size_t i=0; iGetColumnCount(); i++) + { + wxAlignment toset = DEFAULT_ALIGN; + if (idx.Index(i) != wxNOT_FOUND) + toset = align; + + if (header) + dataview_left->GetColumn(i)->SetAlignment(toset); + else + dataview_left->GetColumn(i)->GetRenderer()->SetAlignment(toset); + } +} + +void MyFrame::SetWidth(const wxArrayInt &idx, bool minwidth, int width) +{ + // set to wxDVC_DEFAULT_WIDTH wide all columns except those + // contained in 'idx' which are set to 'width' + + for (size_t i=0; iGetColumnCount(); i++) + { + int toset = minwidth ? wxDVC_DEFAULT_MINWIDTH : wxDVC_DEFAULT_WIDTH; + if (idx.Index(i) != wxNOT_FOUND) + toset = width; + + if (minwidth) + dataview_left->GetColumn(i)->SetMinWidth(toset); + else + dataview_left->GetColumn(i)->SetWidth(toset); + } } @@ -690,9 +895,8 @@ MySortingFrame::MySortingFrame(wxFrame *frame, wxChar *title, int x, int y, int dataview_left = new wxDataViewCtrl( main, ID_UNSORTED, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE ); - m_unsorted_model = new MyUnsortedTextModel; - dataview_left->AssociateModel( m_unsorted_model ); - m_unsorted_model->DecRef(); // don't leak memory + m_unsorted_model.reset(new MyUnsortedTextModel); + dataview_left->AssociateModel( m_unsorted_model.get() ); wxDataViewTextRenderer *text_renderer = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); @@ -707,9 +911,8 @@ MySortingFrame::MySortingFrame(wxFrame *frame, wxChar *title, int x, int y, int // Right wxDataViewCtrl using the sorting model dataview_right = new wxDataViewCtrl( main, ID_SORTED ); - m_sorted_model = new wxDataViewSortedListModel( m_unsorted_model ); - dataview_right->AssociateModel( m_sorted_model ); - m_sorted_model->DecRef(); // don't leak memory + m_sorted_model.reset(new wxDataViewSortedListModel( m_unsorted_model.get() )); + dataview_right->AssociateModel( m_sorted_model.get() ); text_renderer = new wxDataViewTextRenderer( wxT("string"), wxDATAVIEW_CELL_EDITABLE ); column = new wxDataViewColumn( wxT("editable"), text_renderer, 0, -1, diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index 8ebcfef112..73fa33d507 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -344,7 +344,7 @@ void wxDataViewSortedListModel::Resort() InitStatics(); m_array.Clear(); - unsigned int n = m_child->GetNumberOfRows(); + unsigned int n = m_child->GetRowCount(); unsigned int i; for (i = 0; i < n; i++) m_array.Add( i ); @@ -353,7 +353,7 @@ void wxDataViewSortedListModel::Resort() #if 0 static void Dump( wxDataViewListModel *model, unsigned int col ) { - unsigned int n = model->GetNumberOfRows(); + unsigned int n = model->GetRowCount(); unsigned int i; for (i = 0; i < n; i++) { @@ -579,22 +579,22 @@ bool wxDataViewSortedListModel::ChildCleared() return wxDataViewListModel::Cleared(); } -unsigned int wxDataViewSortedListModel::GetNumberOfRows() +unsigned int wxDataViewSortedListModel::GetRowCount() const { return m_array.GetCount(); } -unsigned int wxDataViewSortedListModel::GetNumberOfCols() +unsigned int wxDataViewSortedListModel::GetColumnCount() const { - return m_child->GetNumberOfCols(); + return m_child->GetColumnCount(); } -wxString wxDataViewSortedListModel::GetColType( unsigned int col ) +wxString wxDataViewSortedListModel::GetColumnType( unsigned int col ) const { - return m_child->GetColType( col ); + return m_child->GetColumnType( col ); } -void wxDataViewSortedListModel::GetValue( wxVariant &variant, unsigned int col, unsigned int row ) +void wxDataViewSortedListModel::GetValue( wxVariant &variant, unsigned int col, unsigned int row ) const { unsigned int child_row = m_array[row]; m_child->GetValue( variant, col, child_row ); @@ -701,10 +701,16 @@ bool wxDataViewSortedListModel::Cleared() IMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase, wxObject) -wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, wxDataViewCellMode mode ) +wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, + wxDataViewCellMode WXUNUSED(mode), + int WXUNUSED(align) ) { m_variantType = varianttype; - m_mode = mode; +} + +const wxDataViewCtrl* wxDataViewRendererBase::GetView() const +{ + return wx_const_cast(wxDataViewRendererBase*, this)->GetOwner()->GetOwner(); } // --------------------------------------------------------- @@ -713,19 +719,20 @@ wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, wxD IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase, wxObject) -wxDataViewColumnBase::wxDataViewColumnBase(const wxString& title, +wxDataViewColumnBase::wxDataViewColumnBase(const wxString& WXUNUSED(title), wxDataViewRenderer *renderer, unsigned int model_column, int WXUNUSED(width), wxAlignment WXUNUSED(align), - int flags ) + int WXUNUSED(flags)) { m_renderer = renderer; m_model_column = model_column; - m_flags = flags; - m_title = title; m_owner = NULL; m_renderer->SetOwner( (wxDataViewColumn*) this ); + + // NOTE: the wxDataViewColumn's ctor must store the width, align, flags + // parameters inside the native control! } wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap& bitmap, @@ -733,11 +740,10 @@ wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap& bitmap, unsigned int model_column, int WXUNUSED(width), wxAlignment WXUNUSED(align), - int flags ) + int WXUNUSED(flags) ) { m_renderer = renderer; m_model_column = model_column; - m_flags = flags; m_bitmap = bitmap; m_owner = NULL; m_renderer->SetOwner( (wxDataViewColumn*) this ); @@ -754,25 +760,27 @@ wxDataViewColumnBase::~wxDataViewColumnBase() } } -void wxDataViewColumnBase::SetTitle( const wxString &title ) +int wxDataViewColumnBase::GetFlags() const { - m_title = title; + int ret = 0; + + if (IsSortable()) + ret |= wxDATAVIEW_COL_SORTABLE; + if (IsResizeable()) + ret |= wxDATAVIEW_COL_RESIZABLE; + if (IsHidden()) + ret |= wxDATAVIEW_COL_HIDDEN; + + return ret; } -wxString wxDataViewColumnBase::GetTitle() +void wxDataViewColumnBase::SetFlags(int flags) { - return m_title; + SetSortable((flags & wxDATAVIEW_COL_SORTABLE) != 0); + SetResizeable((flags & wxDATAVIEW_COL_RESIZABLE) != 0); + SetHidden((flags & wxDATAVIEW_COL_HIDDEN) != 0); } -void wxDataViewColumnBase::SetBitmap( const wxBitmap &bitmap ) -{ - m_bitmap = bitmap; -} - -const wxBitmap &wxDataViewColumnBase::GetBitmap() -{ - return m_bitmap; -} // --------------------------------------------------------- // wxDataViewCtrlBase @@ -822,80 +830,80 @@ bool wxDataViewCtrlBase::AppendTextColumn( const wxString &label, unsigned int m wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewTextRenderer( wxT("string"), mode ), model_column, - width, align, flags ) ); + new wxDataViewTextRenderer( wxT("string"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewToggleRenderer( wxT("bool"), mode ), model_column, - width, align, flags ) ); + new wxDataViewToggleRenderer( wxT("bool"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ), model_column, - width, align, flags ) ); + new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendDateColumn( const wxString &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewDateRenderer( wxT("datetime"), mode), model_column, - width, align, flags ) ); + new wxDataViewDateRenderer( wxT("datetime"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendBitmapColumn( const wxString &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode ), model_column, - width, align, flags ) ); + new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendTextColumn( const wxBitmap &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewTextRenderer( wxT("string"), mode ), model_column, - width, align, flags ) ); + new wxDataViewTextRenderer( wxT("string"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewToggleRenderer( wxT("bool"), mode ), model_column, - width, align, flags ) ); + new wxDataViewToggleRenderer( wxT("bool"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode ), model_column, - width, align, flags ) ); + new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendDateColumn( const wxBitmap &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewDateRenderer( wxT("datetime"), mode ), model_column, - width, align, flags ) ); + new wxDataViewDateRenderer( wxT("datetime"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap &label, unsigned int model_column, wxDataViewCellMode mode, int width, wxAlignment align, int flags ) { return AppendColumn( new wxDataViewColumn( label, - new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode ), model_column, - width, align, flags ) ); + new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode, (int)align ), + model_column, width, align, flags ) ); } bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col ) @@ -906,7 +914,7 @@ bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col ) return true; } -unsigned int wxDataViewCtrlBase::GetNumberOfColumns() +unsigned int wxDataViewCtrlBase::GetColumnCount() const { return m_cols.GetCount(); } diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index c6996a685f..c9a8a6d3d2 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -48,6 +48,15 @@ class wxDataViewCtrl; +static const int SCROLL_UNIT_X = 15; + +// the cell padding on the left/right +static const int PADDING_RIGHTLEFT = 3; + +// the cell padding on the top/bottom +static const int PADDING_TOPBOTTOM = 1; + + //----------------------------------------------------------------------------- // wxDataViewHeaderWindow //----------------------------------------------------------------------------- @@ -73,11 +82,8 @@ public: // called on column addition/removal virtual void UpdateDisplay() { /* by default, do nothing */ } - // updates the n-th column's width - virtual void SetColumnWidth(unsigned int n, int width); - // returns the n-th column - wxDataViewColumn *GetColumn(unsigned int n) + virtual wxDataViewColumn *GetColumn(unsigned int n) { wxASSERT(m_owner); wxDataViewColumn *ret = m_owner->GetColumn(n); @@ -96,6 +102,7 @@ protected: // on wxMSW the header window (only that part however) can be made native! #if defined(__WXMSW__) && USE_NATIVE_HEADER_WINDOW +#define COLUMN_WIDTH_OFFSET 2 #define wxDataViewHeaderWindowMSW wxDataViewHeaderWindow class wxDataViewHeaderWindowMSW : public wxDataViewHeaderWindowBase @@ -103,10 +110,10 @@ class wxDataViewHeaderWindowMSW : public wxDataViewHeaderWindowBase public: wxDataViewHeaderWindowMSW( wxDataViewCtrl *parent, - wxWindowID id, - const wxPoint &pos = wxDefaultPosition, - const wxSize &size = wxDefaultSize, - const wxString &name = wxT("wxdataviewctrlheaderwindow") ) + wxWindowID id, + const wxPoint &pos = wxDefaultPosition, + const wxSize &size = wxDefaultSize, + const wxString &name = wxT("wxdataviewctrlheaderwindow") ) { Create(parent, id, pos, size, name); } @@ -117,7 +124,8 @@ public: ~wxDataViewHeaderWindowMSW(); - // called on column addition/removal + // called when any column setting is changed and/or changed + // the column count virtual void UpdateDisplay(); // called when the main window gets scrolled @@ -125,7 +133,13 @@ public: protected: virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result); - + virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags); + + unsigned int GetColumnIdxFromHeader(NMHEADER *nmHDR); + + wxDataViewColumn *GetColumnFromHeader(NMHEADER *nmHDR) + { return GetColumn(GetColumnIdxFromHeader(nmHDR)); } + private: DECLARE_DYNAMIC_CLASS(wxDataViewHeaderWindowMSW) }; @@ -133,6 +147,8 @@ private: #else // !defined(__WXMSW__) #define HEADER_WINDOW_HEIGHT 25 +#define HEADER_HORIZ_BORDER 5 +#define HEADER_VERT_BORDER 3 #define wxGenericDataViewHeaderWindow wxDataViewHeaderWindow class wxGenericDataViewHeaderWindow : public wxDataViewHeaderWindowBase @@ -178,6 +194,11 @@ protected: int m_minX; // minimal position beyond which the divider line // can't be dragged in logical coords + // the pen used to draw the current column width drag line + // when resizing the columsn + wxPen m_penCurrent; + + // internal utilities: void Init() @@ -191,6 +212,9 @@ protected: m_column = wxNOT_FOUND; m_currentX = 0; m_minX = 0; + + wxColour col = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); + m_penCurrent = wxPen(col, 1, wxSOLID); } void DrawCurrent(); @@ -285,6 +309,7 @@ public: void SetOwner( wxDataViewCtrl* owner ) { m_owner = owner; } wxDataViewCtrl *GetOwner() { return m_owner; } + const wxDataViewCtrl *GetOwner() const { return m_owner; } void OnPaint( wxPaintEvent &event ); void OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event); @@ -300,7 +325,7 @@ public: void OnRenameTimer(); void FinishEditing( wxTextCtrl *text ); - void ScrollWindow( int dx, int dy, const wxRect *rect ); + void ScrollWindow( int dx, int dy, const wxRect *rect = NULL ); bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; } void ChangeCurrentRow( unsigned int row ); @@ -308,11 +333,11 @@ public: bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); }; bool IsEmpty() { return GetRowCount() == 0; } - int GetCountPerPage(); - int GetEndOfLastCol(); - unsigned int GetFirstVisibleRow(); - unsigned int GetLastVisibleRow(); - unsigned int GetRowCount(); + int GetCountPerPage() const; + int GetEndOfLastCol() const; + unsigned int GetFirstVisibleRow() const; + unsigned int GetLastVisibleRow() const; + unsigned int GetRowCount() const; void Select( const wxArrayInt& aSelections ); void SelectAllRows( bool on ); @@ -325,6 +350,15 @@ public: void RefreshRows( unsigned int from, unsigned int to ); void RefreshRowsAfter( unsigned int firstRow ); + // returns the colour to be used for drawing the rules + wxColour GetRuleColour() const + { + return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); + } + + //void EnsureVisible( unsigned int row ); + wxRect GetLineRect( unsigned int row ) const; + private: wxDataViewCtrl *m_owner; int m_lineHeight; @@ -348,6 +382,9 @@ private: m_lineBeforeLastClicked, m_lineSelectSingleOnUp; + // the pen used to draw horiz/vertical rules + wxPen m_penRule; + private: DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow) DECLARE_EVENT_TABLE() @@ -390,10 +427,13 @@ public: IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase) wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewRendererBase( varianttype, mode ) + wxDataViewCellMode mode, + int align) : + wxDataViewRendererBase( varianttype, mode, align ) { m_dc = NULL; + m_align = align; + m_mode = mode; } wxDataViewRenderer::~wxDataViewRenderer() @@ -416,6 +456,7 @@ wxDC *wxDataViewRenderer::GetDC() return m_dc; } + // --------------------------------------------------------- // wxDataViewCustomRenderer // --------------------------------------------------------- @@ -423,8 +464,8 @@ wxDC *wxDataViewRenderer::GetDC() IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer) wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewRenderer( varianttype, mode, align ) { } @@ -435,8 +476,8 @@ wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewCustomRenderer) wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align ) { } @@ -447,7 +488,7 @@ bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) return true; } -bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) +bool wxDataViewTextRenderer::GetValue( wxVariant& WXUNUSED(value) ) const { return false; } @@ -460,24 +501,14 @@ bool wxDataViewTextRenderer::Render( wxRect cell, wxDC *dc, int state ) view->GetForegroundColour(); dc->SetTextForeground(col); - - // TODO: it would be much more efficient to create a clipping - // region for the entire column being rendered (in the OnPaint - // of wxDataViewMainWindow) instead of a single clip region for - // each cell. However it would mean that each renderer should - // respect the given wxRect's top & bottom coords, eventually - // violating only the left & right coords - however the user can - // make its own renderer and thus we cannot be sure of that. - dc->SetClippingRegion(cell); dc->DrawText( m_text, cell.x, cell.y ); - dc->DestroyClippingRegion(); return true; } -wxSize wxDataViewTextRenderer::GetSize() +wxSize wxDataViewTextRenderer::GetSize() const { - wxDataViewCtrl *view = GetOwner()->GetOwner(); + const wxDataViewCtrl *view = GetView(); if (!m_text.empty()) { int x,y; @@ -494,8 +525,8 @@ wxSize wxDataViewTextRenderer::GetSize() IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewCustomRenderer) wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align ) { } @@ -509,7 +540,7 @@ bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) return true; } -bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) +bool wxDataViewBitmapRenderer::GetValue( wxVariant& WXUNUSED(value) ) const { return false; } @@ -524,7 +555,7 @@ bool wxDataViewBitmapRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state return true; } -wxSize wxDataViewBitmapRenderer::GetSize() +wxSize wxDataViewBitmapRenderer::GetSize() const { if (m_bitmap.Ok()) return wxSize( m_bitmap.GetWidth(), m_bitmap.GetHeight() ); @@ -541,8 +572,8 @@ wxSize wxDataViewBitmapRenderer::GetSize() IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer, wxDataViewCustomRenderer) wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align ) { m_toggle = false; } @@ -554,7 +585,7 @@ bool wxDataViewToggleRenderer::SetValue( const wxVariant &value ) return true; } -bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) +bool wxDataViewToggleRenderer::GetValue( wxVariant &WXUNUSED(value) ) const { return false; } @@ -595,7 +626,7 @@ bool wxDataViewToggleRenderer::Activate( wxRect WXUNUSED(cell), return true; } -wxSize wxDataViewToggleRenderer::GetSize() +wxSize wxDataViewToggleRenderer::GetSize() const { return wxSize(20,20); } @@ -607,8 +638,8 @@ wxSize wxDataViewToggleRenderer::GetSize() IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer) wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, - const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) + const wxString &varianttype, wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align ) { m_label = label; m_value = 0; @@ -628,6 +659,12 @@ bool wxDataViewProgressRenderer::SetValue( const wxVariant &value ) return true; } +bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const +{ + value = (long) m_value; + return true; +} + bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) { double pct = (double)m_value / 100.0; @@ -644,7 +681,7 @@ bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(sta return true; } -wxSize wxDataViewProgressRenderer::GetSize() +wxSize wxDataViewProgressRenderer::GetSize() const { return wxSize(40,12); } @@ -708,8 +745,8 @@ void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event ) IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer) wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align ) { } @@ -720,6 +757,12 @@ bool wxDataViewDateRenderer::SetValue( const wxVariant &value ) return true; } +bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const +{ + value = m_date; + return true; +} + bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) ) { dc->SetFont( GetOwner()->GetOwner()->GetFont() ); @@ -729,9 +772,9 @@ bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) return true; } -wxSize wxDataViewDateRenderer::GetSize() +wxSize wxDataViewDateRenderer::GetSize() const { - wxDataViewCtrl* view = GetOwner()->GetOwner(); + const wxDataViewCtrl* view = GetView(); wxString tmp = m_date.FormatDate(); wxCoord x,y,d; view->GetTextExtent( tmp, &x, &y, &d ); @@ -769,8 +812,11 @@ wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *c int width, wxAlignment align, int flags ) : wxDataViewColumnBase( title, cell, model_column, width, align, flags ) { - m_align = align; - Init(width < 0 ? 80 : width); + SetAlignment(align); + SetTitle(title); + SetFlags(flags); + + Init(width < 0 ? wxDVC_DEFAULT_WIDTH : width); } wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, @@ -778,19 +824,48 @@ wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer * int width, wxAlignment align, int flags ) : wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags ) { - m_align = align; - Init(width < 0 ? 30 : width); + SetAlignment(align); + SetFlags(flags); + + Init(width < 0 ? wxDVC_TOGGLE_DEFAULT_WIDTH : width); } -void wxDataViewColumn::Init(int width) +wxDataViewColumn::~wxDataViewColumn() +{ +} + +void wxDataViewColumn::Init( int width ) { m_width = width; - m_fixedWidth = -1; + m_minWidth = wxDVC_DEFAULT_MINWIDTH; } -void wxDataViewColumn::SetSortable( bool WXUNUSED(sortable) ) +void wxDataViewColumn::SetResizeable( bool resizeable ) { - // TODO + if (resizeable) + m_flags |= wxDATAVIEW_COL_RESIZABLE; + else + m_flags &= ~wxDATAVIEW_COL_RESIZABLE; +} + +void wxDataViewColumn::SetHidden( bool hidden ) +{ + if (hidden) + m_flags |= wxDATAVIEW_COL_HIDDEN; + else + m_flags &= ~wxDATAVIEW_COL_HIDDEN; + + // tell our owner to e.g. update its scrollbars: + if (GetOwner()) + GetOwner()->OnColumnChange(); +} + +void wxDataViewColumn::SetSortable( bool sortable ) +{ + if (sortable) + m_flags |= wxDATAVIEW_COL_SORTABLE; + else + m_flags &= ~wxDATAVIEW_COL_SORTABLE; } void wxDataViewColumn::SetSortOrder( bool WXUNUSED(ascending) ) @@ -804,38 +879,27 @@ bool wxDataViewColumn::IsSortOrderAscending() const return true; } - -wxDataViewColumn::~wxDataViewColumn() +void wxDataViewColumn::SetInternalWidth( int width ) { + m_width = width; + + // the scrollbars of the wxDataViewCtrl needs to be recalculated! + if (m_owner && m_owner->m_clientArea) + m_owner->m_clientArea->RecalculateDisplay(); } -void wxDataViewColumn::SetTitle( const wxString &title ) +void wxDataViewColumn::SetWidth( int width ) { - wxDataViewColumnBase::SetTitle( title ); + m_owner->m_headerArea->UpdateDisplay(); + SetInternalWidth(width); } -void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) -{ - wxDataViewColumnBase::SetBitmap( bitmap ); - -} - -int wxDataViewColumn::GetWidth() const -{ - return m_width; -} //----------------------------------------------------------------------------- // wxDataViewHeaderWindowBase //----------------------------------------------------------------------------- -void wxDataViewHeaderWindowBase::SetColumnWidth(unsigned int n, int width) -{ - GetColumn(n)->m_width = width; - m_owner->m_clientArea->RecalculateDisplay(); -} - void wxDataViewHeaderWindowBase::SendEvent(wxEventType type, unsigned int n) { wxWindow *parent = GetParent(); @@ -899,10 +963,13 @@ bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl *parent, wxWindowID id, // to call wxDataViewHeaderWindow::MSWOnNotify wxAssociateWinWithHandle((HWND)m_hWnd, this); + // the following is required to get the default win's font for + // header windows and must be done befor sending the HDM_LAYOUT msg + SetFont(GetFont()); - RECT rcParent; - HDLAYOUT hdl; - WINDOWPOS wp; + RECT rcParent; + HDLAYOUT hdl; + WINDOWPOS wp; // Retrieve the bounding rectangle of the parent window's // client area, and then request size and position values @@ -930,9 +997,6 @@ bool wxDataViewHeaderWindowMSW::Create( wxDataViewCtrl *parent, wxWindowID id, SetMinSize(wxSize(-1, wp.cy)); SetMaxSize(wxSize(-1, wp.cy)); - // the following is required to get the default win's font for header windows - SetFont(GetFont()); - return true; } @@ -948,7 +1012,8 @@ void wxDataViewHeaderWindowMSW::UpdateDisplay() Header_DeleteItem((HWND)m_hWnd, 0); // add the updated array of columns to the header control - unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int cols = GetOwner()->GetColumnCount(); + unsigned int added = 0; for (unsigned int i = 0; i < cols; i++) { wxDataViewColumn *col = GetColumn( i ); @@ -957,15 +1022,64 @@ void wxDataViewHeaderWindowMSW::UpdateDisplay() HDITEM hdi; hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH; - hdi.pszText = (WCHAR*) col->GetTitle().c_str(); + hdi.pszText = (wxChar *) col->GetTitle().c_str(); hdi.cxy = col->GetWidth(); hdi.cchTextMax = sizeof(hdi.pszText)/sizeof(hdi.pszText[0]); hdi.fmt = HDF_LEFT | HDF_STRING; + + // lParam is reserved for application's use: + // we store there the column index to use it later in MSWOnNotify + // (since columns may have been hidden) + hdi.lParam = (LPARAM)i; + + // the native wxMSW implementation of the header window + // draws the column separator COLUMN_WIDTH_OFFSET pixels + // on the right: to correct this effect we make the column + // exactly COLUMN_WIDTH_OFFSET wider (for the first column): + if (i == 0) + hdi.cxy += COLUMN_WIDTH_OFFSET; + + switch (col->GetAlignment()) + { + case wxALIGN_LEFT: + hdi.fmt |= HDF_LEFT; + break; + case wxALIGN_CENTER: + case wxALIGN_CENTER_HORIZONTAL: + hdi.fmt |= HDF_CENTER; + break; + case wxALIGN_RIGHT: + hdi.fmt |= HDF_RIGHT; + break; + } - SendMessage((HWND)m_hWnd, HDM_INSERTITEM, (WPARAM)i, (LPARAM)&hdi); + SendMessage((HWND)m_hWnd, HDM_INSERTITEM, + (WPARAM)added, (LPARAM)&hdi); + added++; } } +unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER *nmHDR) +{ + unsigned int idx; + + // NOTE: we don't just return nmHDR->iItem because when there are + // hidden columns, nmHDR->iItem may be different from + // nmHDR->pitem->lParam + + if (nmHDR->pitem && nmHDR->pitem->mask & HDI_LPARAM) + { + idx = (unsigned int)nmHDR->pitem->lParam; + return idx; + } + + HDITEM item; + item.mask = HDI_LPARAM; + Header_GetItem((HWND)m_hWnd, nmHDR->iItem, &item); + + return (unsigned int)item.lParam; +} + bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { NMHDR *nmhdr = (NMHDR *)lParam; @@ -991,22 +1105,48 @@ bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARA // user has started to reorder a column break; + case HDN_ITEMCHANGING: + if (nmHDR->pitem != NULL && + (nmHDR->pitem->mask & HDI_WIDTH) != 0) + { + int minWidth = GetColumnFromHeader(nmHDR)->GetMinWidth(); + if (nmHDR->pitem->cxy < minWidth) + { + // do not allow the user to resize this column under + // its minimal width: + *result = TRUE; + } + } + break; + case HDN_ITEMCHANGED: // user is resizing a column case HDN_ENDTRACK: // user has finished resizing a column case HDN_ENDDRAG: // user has finished reordering a column // update the width of the modified column: - if ((nmHDR->pitem->mask & HDI_WIDTH) != 0 && - nmHDR->pitem != NULL) - SetColumnWidth(nmHDR->iItem, nmHDR->pitem->cxy); + if (nmHDR->pitem != NULL && + (nmHDR->pitem->mask & HDI_WIDTH) != 0) + { + unsigned int idx = GetColumnIdxFromHeader(nmHDR); + unsigned int w = nmHDR->pitem->cxy; + wxDataViewColumn *col = GetColumn(idx); + + // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET + if (idx == 0 && w > COLUMN_WIDTH_OFFSET) + w -= COLUMN_WIDTH_OFFSET; + + if (w >= (unsigned)col->GetMinWidth()) + col->SetInternalWidth(w); + } break; case HDN_ITEMCLICK: { + unsigned int idx = GetColumnIdxFromHeader(nmHDR); wxEventType evt = nmHDR->iButton == 0 ? wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK : wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK; - SendEvent(evt, nmHDR->iItem); + SendEvent(evt, idx); } break; @@ -1017,12 +1157,19 @@ bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARA // right clicks, so we need to handle NM_RCLICK POINT ptClick; - unsigned int column = - wxMSWGetColumnClicked(nmhdr, &ptClick); - + int column = wxMSWGetColumnClicked(nmhdr, &ptClick); if (column != wxNOT_FOUND) + { + HDITEM item; + item.mask = HDI_LPARAM; + Header_GetItem((HWND)m_hWnd, column, &item); + + // 'idx' may be different from 'column' if there are + // hidden columns... + unsigned int idx = (unsigned int)item.lParam; SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, - column); + idx); + } } break; @@ -1032,7 +1179,7 @@ bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARA case HDN_ITEMDBLCLICK: { - unsigned int idx = nmHDR->iItem; + unsigned int idx = GetColumnIdxFromHeader(nmHDR); int w = GetOwner()->GetBestColumnWidth(idx); // update the native control: @@ -1040,10 +1187,12 @@ bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARA ZeroMemory(&hd, sizeof(hd)); hd.mask = HDI_WIDTH; hd.cxy = w; - Header_SetItem(GetHwnd(), idx, &hd); + Header_SetItem(GetHwnd(), + nmHDR->iItem, // NOTE: we don't want 'idx' here! + &hd); // update the wxDataViewColumn class: - SetColumnWidth(idx, w); + GetColumn(idx)->SetInternalWidth(w); } break; @@ -1065,11 +1214,23 @@ void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx), int WXUNUSED(dy), m_owner->CalcUnscrolledPosition(0, 0, &x1, &y1); // put this window on top of our parent and - SetWindowPos((HWND)m_hWnd, HWND_TOP, -x1, y1, + SetWindowPos((HWND)m_hWnd, HWND_TOP, -x1, 0, ownerSz.GetWidth() + x1, ourSz.GetHeight(), SWP_SHOWWINDOW); } +void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(w), int WXUNUSED(h), + int WXUNUSED(f)) +{ + // the wxDataViewCtrl's internal wxBoxSizer will call this function when + // the wxDataViewCtrl window gets resized: the following dummy call + // to ScrollWindow() is required in order to get this header window + // correctly repainted when it's (horizontally) scrolled: + + ScrollWindow(0, 0); +} + #else // !defined(__WXMSW__) IMPLEMENT_ABSTRACT_CLASS(wxGenericDataViewHeaderWindow, wxWindow) @@ -1125,14 +1286,14 @@ void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) dc.SetFont( GetFont() ); - unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int cols = GetOwner()->GetColumnCount(); unsigned int i; int xpos = 0; for (i = 0; i < cols; i++) { wxDataViewColumn *col = GetColumn( i ); if (col->IsHidden()) - break; // don't draw it! + continue; // skip it! int cw = col->GetWidth(); int ch = h; @@ -1146,7 +1307,32 @@ void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) : (int)wxCONTROL_DISABLED ); - dc.DrawText( col->GetTitle(), xpos+3, 3 ); + // align as required the column title: + int x = xpos; + wxSize titleSz = dc.GetTextExtent(col->GetTitle()); + switch (col->GetAlignment()) + { + case wxALIGN_LEFT: + x += HEADER_HORIZ_BORDER; + break; + case wxALIGN_CENTER: + case wxALIGN_CENTER_HORIZONTAL: + x += (cw - titleSz.GetWidth() - 2 * HEADER_HORIZ_BORDER)/2; + break; + case wxALIGN_RIGHT: + x += cw - titleSz.GetWidth() - HEADER_HORIZ_BORDER; + break; + } + + // always center the title vertically: + int y = wxMax((ch - titleSz.GetHeight()) / 2, HEADER_VERT_BORDER); + + dc.SetClippingRegion( xpos+HEADER_HORIZ_BORDER, + HEADER_VERT_BORDER, + wxMax(cw - 2 * HEADER_HORIZ_BORDER, 1), // width + wxMax(ch - 2 * HEADER_VERT_BORDER, 1)); // height + dc.DrawText( col->GetTitle(), x, y ); + dc.DestroyClippingRegion(); xpos += cw; } @@ -1186,7 +1372,7 @@ void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event ) m_dirty = true; - SetColumnWidth(m_column, m_currentX - m_minX); + GetColumn(m_column)->SetWidth(m_currentX - m_minX); Refresh(); GetOwner()->Refresh(); @@ -1211,7 +1397,7 @@ void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event ) int xpos = 0; // find the column where this event occured - int countCol = m_owner->GetNumberOfColumns(); + int countCol = m_owner->GetColumnCount(); for (int column = 0; column < countCol; column++) { wxDataViewColumn *p = GetColumn(column); @@ -1242,7 +1428,7 @@ void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event ) bool resizeable = GetColumn(m_column)->IsResizeable(); if (event.LeftDClick() && resizeable) { - SetColumnWidth(m_column, GetOwner()->GetBestColumnWidth(m_column)); + GetColumn(m_column)->SetWidth(GetOwner()->GetBestColumnWidth(m_column)); Refresh(); } else if (event.LeftDown() || event.RightUp()) @@ -1289,16 +1475,11 @@ void wxGenericDataViewHeaderWindow::DrawCurrent() m_owner->ClientToScreen( &x2, &y2 ); wxScreenDC dc; - dc.SetLogicalFunction (wxINVERT); - //dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID)); - dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT),1, wxSOLID)); - dc.SetBrush (*wxTRANSPARENT_BRUSH); - + dc.SetLogicalFunction(wxINVERT); + dc.SetPen(m_penCurrent); + dc.SetBrush(*wxTRANSPARENT_BRUSH); AdjustDC(dc); - dc.DrawLine (x1, y1, x2, y2); - dc.SetLogicalFunction (wxCOPY); - dc.SetPen (wxNullPen); - dc.SetBrush (wxNullBrush); + dc.DrawLine(x1, y1, x2, y2); } void wxGenericDataViewHeaderWindow::AdjustDC(wxDC& dc) @@ -1517,6 +1698,7 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i #else 20; #endif + wxASSERT(m_lineHeight > 2*PADDING_TOPBOTTOM); m_dragCount = 0; m_dragStart = wxPoint(0,0); @@ -1529,6 +1711,8 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i SetBackgroundStyle( wxBG_STYLE_CUSTOM ); SetBackgroundColour( *wxWHITE ); + m_penRule = wxPen(GetRuleColour(), 1, wxSOLID); + UpdateDisplay(); } @@ -1546,11 +1730,14 @@ void wxDataViewMainWindow::OnRenameTimer() int xpos = 0; - unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int cols = GetOwner()->GetColumnCount(); unsigned int i; for (i = 0; i < cols; i++) { wxDataViewColumn *c = GetOwner()->GetColumn( i ); + if (c->IsHidden()) + continue; // skip it! + if (c == m_currentCol) break; xpos += c->GetWidth(); @@ -1600,7 +1787,10 @@ bool wxDataViewMainWindow::RowChanged( unsigned int WXUNUSED(row) ) bool wxDataViewMainWindow::ValueChanged( unsigned int WXUNUSED(col), unsigned int row ) { - wxRect rect( 0, row*m_lineHeight, 10000, m_lineHeight ); + // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 +#define MAX_VIRTUAL_WIDTH 100000 + + wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight ); m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); Refresh( true, &rect ); @@ -1644,16 +1834,8 @@ void wxDataViewMainWindow::RecalculateDisplay() return; } - int width = 0; - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - for (i = 0; i < cols; i++) - { - wxDataViewColumn *col = GetOwner()->GetColumn( i ); - width += col->GetWidth(); - } - - int height = model->GetNumberOfRows() * m_lineHeight; + int width = GetEndOfLastCol(); + int height = model->GetRowCount() * m_lineHeight; SetVirtualSize( width, height ); GetOwner()->SetScrollRate( 10, m_lineHeight ); @@ -1664,32 +1846,102 @@ void wxDataViewMainWindow::RecalculateDisplay() void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) { wxWindow::ScrollWindow( dx, dy, rect ); - GetOwner()->m_headerArea->ScrollWindow( dx, 0 ); + + if (GetOwner()->m_headerArea) + GetOwner()->m_headerArea->ScrollWindow( dx, 0 ); } void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { + wxDataViewListModel *model = GetOwner()->GetModel(); wxAutoBufferedPaintDC dc( this ); + // prepare the DC dc.SetBackground(GetBackgroundColour()); dc.Clear(); - GetOwner()->PrepareDC( dc ); - dc.SetFont( GetFont() ); wxRect update = GetUpdateRegion().GetBox(); m_owner->CalcUnscrolledPosition( update.x, update.y, &update.x, &update.y ); - wxDataViewListModel *model = GetOwner()->GetModel(); - + // compute which items needs to be redrawn unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) ); unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1), - (int)(model->GetNumberOfRows()-item_start) ); + (int)(model->GetRowCount() - item_start) ); + unsigned int item_last = item_start + item_count; - unsigned int item; - for (item = item_start; item < item_start+item_count; item++) + // compute which columns needs to be redrawn + unsigned int cols = GetOwner()->GetColumnCount(); + unsigned int col_start = 0; + unsigned int x_start = 0; + for (x_start = 0; col_start < cols; col_start++) + { + wxDataViewColumn *col = GetOwner()->GetColumn(col_start); + if (col->IsHidden()) + continue; // skip it! + + unsigned int w = col->GetWidth(); + if (x_start+w >= (unsigned int)update.x) + break; + + x_start += w; + } + + unsigned int col_last = col_start; + unsigned int x_last = x_start; + for (; col_last < cols; col_last++) + { + wxDataViewColumn *col = GetOwner()->GetColumn(col_last); + if (col->IsHidden()) + continue; // skip it! + + if (x_last > (unsigned int)update.GetRight()) + break; + + x_last += col->GetWidth(); + } + + // Draw horizontal rules if required + if ( m_owner->HasFlag(wxDV_HORIZ_RULES) ) + { + dc.SetPen(m_penRule); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + for (unsigned int i = item_start; i <= item_last+1; i++) + { + int y = i * m_lineHeight; + dc.DrawLine(x_start, y, x_last, y); + } + } + + // Draw vertical rules if required + if ( m_owner->HasFlag(wxDV_VERT_RULES) ) + { + dc.SetPen(m_penRule); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + + int x = x_start; + for (unsigned int i = col_start; i < col_last; i++) + { + wxDataViewColumn *col = GetOwner()->GetColumn(i); + if (col->IsHidden()) + continue; // skip it + + dc.DrawLine(x, item_start * m_lineHeight, + x, item_last * m_lineHeight); + + x += col->GetWidth(); + } + + // Draw last vertical rule + dc.DrawLine(x, item_start * m_lineHeight, + x, item_last * m_lineHeight); + } + + // redraw the background for the items which are selected/current + for (unsigned int item = item_start; item < item_last; item++) { bool selected = m_selection.Index( item ) != wxNOT_FOUND; if (selected || item == m_currentRow) @@ -1699,7 +1951,8 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) flags |= wxCONTROL_CURRENT; if (m_hasFocus) flags |= wxCONTROL_FOCUSED; - wxRect rect( 0, item*m_lineHeight, GetEndOfLastCol(), m_lineHeight ); + + wxRect rect( x_start, item*m_lineHeight, x_last, m_lineHeight ); wxRendererNative::Get().DrawItemSelectionRect ( this, @@ -1710,12 +1963,11 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) } } + // redraw all cells for all rows which must be repainted and for all columns wxRect cell_rect; - cell_rect.x = 0; - cell_rect.height = m_lineHeight; - unsigned int cols = GetOwner()->GetNumberOfColumns(); - unsigned int i; - for (i = 0; i < cols; i++) + cell_rect.x = x_start; + cell_rect.height = m_lineHeight; // -1 is for the horizontal rules + for (unsigned int i = col_start; i < col_last; i++) { wxDataViewColumn *col = GetOwner()->GetColumn( i ); wxDataViewRenderer *cell = col->GetRenderer(); @@ -1724,7 +1976,7 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) if (col->IsHidden()) continue; // skipt it! - for (item = item_start; item < item_start+item_count; item++) + for (unsigned int item = item_start; item < item_last; item++) { // get the cell value and set it into the renderer wxVariant value; @@ -1732,65 +1984,80 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) cell->SetValue( value ); // update the y offset - cell_rect.y = item*m_lineHeight; + cell_rect.y = item * m_lineHeight; // cannot be bigger than allocated space wxSize size = cell->GetSize(); - size.x = wxMin( size.x, cell_rect.width ); - size.y = wxMin( size.y, cell_rect.height ); + size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width ); + size.y = wxMin( size.y + 2*PADDING_TOPBOTTOM, cell_rect.height ); wxRect item_rect(cell_rect.GetTopLeft(), size); + int align = cell->GetAlignment(); // horizontal alignment: - if (col->GetAlignment() & wxALIGN_CENTER_HORIZONTAL) - item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2); - else if (col->GetAlignment() & wxALIGN_RIGHT) + item_rect.x = cell_rect.x; + if (align & wxALIGN_CENTER_HORIZONTAL) + item_rect.x = cell_rect.x + (cell_rect.width / 2) - (size.x / 2); + else if (align & wxALIGN_RIGHT) item_rect.x = cell_rect.x + cell_rect.width - size.x; //else: wxALIGN_LEFT is the default // vertical alignment: - if (col->GetAlignment() & wxALIGN_CENTER_VERTICAL) + item_rect.y = cell_rect.y; + if (align & wxALIGN_CENTER_VERTICAL) item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2); - else if (col->GetAlignment() & wxALIGN_BOTTOM) + else if (align & wxALIGN_BOTTOM) item_rect.y = cell_rect.y + cell_rect.height - size.y; //else: wxALIGN_TOP is the default - item_rect.y = cell_rect.y + (cell_rect.height / 2) - (size.y / 2); - - item_rect.width = size.x; - item_rect.height= size.y; + // add padding + item_rect.x += PADDING_RIGHTLEFT; + item_rect.y += PADDING_TOPBOTTOM; + item_rect.width = size.x - 2 * PADDING_RIGHTLEFT; + item_rect.height = size.y - 2 * PADDING_TOPBOTTOM; int state = 0; - //if (item == m_currentRow) -- seems wrong to me... if (m_selection.Index(item) != wxNOT_FOUND) state |= wxDATAVIEW_CELL_SELECTED; + // TODO: it would be much more efficient to create a clipping + // region for the entire column being rendered (in the OnPaint + // of wxDataViewMainWindow) instead of a single clip region for + // each cell. However it would mean that each renderer should + // respect the given wxRect's top & bottom coords, eventually + // violating only the left & right coords - however the user can + // make its own renderer and thus we cannot be sure of that. + dc.SetClippingRegion( item_rect ); cell->Render( item_rect, &dc, state ); + dc.DestroyClippingRegion(); } cell_rect.x += cell_rect.width; } } -int wxDataViewMainWindow::GetCountPerPage() +int wxDataViewMainWindow::GetCountPerPage() const { wxSize size = GetClientSize(); return size.y / m_lineHeight; } -int wxDataViewMainWindow::GetEndOfLastCol() +int wxDataViewMainWindow::GetEndOfLastCol() const { int width = 0; unsigned int i; - for (i = 0; i < GetOwner()->GetNumberOfColumns(); i++) + for (i = 0; i < GetOwner()->GetColumnCount(); i++) { - wxDataViewColumn *c = GetOwner()->GetColumn( i ); - width += c->GetWidth(); + const wxDataViewColumn *c = + wx_const_cast(wxDataViewCtrl*, GetOwner())->GetColumn( i ); + + if (!c->IsHidden()) + width += c->GetWidth(); } return width; } -unsigned int wxDataViewMainWindow::GetFirstVisibleRow() +unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const { int x = 0; int y = 0; @@ -1799,7 +2066,7 @@ unsigned int wxDataViewMainWindow::GetFirstVisibleRow() return y / m_lineHeight; } -unsigned int wxDataViewMainWindow::GetLastVisibleRow() +unsigned int wxDataViewMainWindow::GetLastVisibleRow() const { wxSize client_size = GetClientSize(); m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, @@ -1808,9 +2075,9 @@ unsigned int wxDataViewMainWindow::GetLastVisibleRow() return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 ); } -unsigned int wxDataViewMainWindow::GetRowCount() +unsigned int wxDataViewMainWindow::GetRowCount() const { - return GetOwner()->GetModel()->GetNumberOfRows(); + return wx_const_cast(wxDataViewCtrl*, GetOwner())->GetModel()->GetRowCount(); } void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row ) @@ -2009,7 +2276,18 @@ void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent RefreshRow( m_currentRow ); } - // MoveToFocus(); + //EnsureVisible( m_currentRow ); +} + +wxRect wxDataViewMainWindow::GetLineRect( unsigned int row ) const +{ + wxRect rect; + rect.x = 0; + rect.y = m_lineHeight * row; + rect.width = GetEndOfLastCol(); + rect.height = m_lineHeight; + + return rect; } void wxDataViewMainWindow::OnChar( wxKeyEvent &event ) @@ -2102,11 +2380,14 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event ) wxDataViewColumn *col = NULL; int xpos = 0; - unsigned int cols = GetOwner()->GetNumberOfColumns(); + unsigned int cols = GetOwner()->GetColumnCount(); unsigned int i; for (i = 0; i < cols; i++) { wxDataViewColumn *c = GetOwner()->GetColumn( i ); + if (c->IsHidden()) + continue; // skip it! + if (x < xpos + c->GetWidth()) { col = c; @@ -2368,12 +2649,17 @@ bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, #endif m_clientArea = new wxDataViewMainWindow( this, wxID_ANY ); - m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY ); + + if (HasFlag(wxDV_NO_HEADER)) + m_headerArea = NULL; + else + m_headerArea = new wxDataViewHeaderWindow( this, wxID_ANY ); SetTargetWindow( m_clientArea ); wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL ); - sizer->Add( m_headerArea, 0, wxGROW ); + if (m_headerArea) + sizer->Add( m_headerArea, 0, wxGROW ); sizer->Add( m_clientArea, 1, wxGROW ); SetSizer( sizer ); @@ -2432,12 +2718,18 @@ bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col ) if (!wxDataViewCtrlBase::AppendColumn(col)) return false; - m_clientArea->UpdateDisplay(); - m_headerArea->UpdateDisplay(); - + OnColumnChange(); return true; } +void wxDataViewCtrl::OnColumnChange() +{ + if (m_headerArea) + m_headerArea->UpdateDisplay(); + + m_clientArea->UpdateDisplay(); +} + void wxDataViewCtrl::SetSelection( int row ) { m_clientArea->SelectRow(row, true); diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 40b69f99e9..cc2dd4f4a7 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -235,7 +235,7 @@ wxgtk_list_store_get_n_columns (GtkTreeModel *tree_model) GtkWxListStore *list_store = (GtkWxListStore *) tree_model; g_return_val_if_fail (GTK_IS_WX_LIST_STORE (tree_model), 0); - return list_store->model->GetNumberOfCols(); + return list_store->model->GetColumnCount(); } static GType @@ -247,7 +247,7 @@ wxgtk_list_store_get_column_type (GtkTreeModel *tree_model, GType gtype = G_TYPE_INVALID; - wxString wxtype = list_store->model->GetColType( (unsigned int) index ); + wxString wxtype = list_store->model->GetColumnType( (unsigned int) index ); if (wxtype == wxT("string")) gtype = G_TYPE_STRING; @@ -270,7 +270,7 @@ wxgtk_list_store_get_iter (GtkTreeModel *tree_model, unsigned int i = (unsigned int)gtk_tree_path_get_indices (path)[0]; - if (i >= list_store->model->GetNumberOfRows()) + if (i >= list_store->model->GetRowCount()) return FALSE; iter->stamp = list_store->stamp; @@ -304,7 +304,7 @@ wxgtk_list_store_get_value (GtkTreeModel *tree_model, g_return_if_fail (GTK_IS_WX_LIST_STORE (tree_model) ); wxDataViewListModel *model = list_store->model; - wxString mtype = model->GetColType( (unsigned int) column ); + wxString mtype = model->GetColumnType( (unsigned int) column ); if (mtype == wxT("string")) { wxVariant variant; @@ -336,7 +336,7 @@ wxgtk_list_store_iter_next (GtkTreeModel *tree_model, if (n == -1) return FALSE; - if (n >= (int) list_store->model->GetNumberOfRows()-1) + if (n >= (int) list_store->model->GetRowCount()-1) return FALSE; iter->user_data = (gpointer) ++n; @@ -377,7 +377,7 @@ wxgtk_list_store_iter_n_children (GtkTreeModel *tree_model, GtkWxListStore *list_store = (GtkWxListStore *) tree_model; if (iter == NULL) - return (gint) list_store->model->GetNumberOfRows(); + return (gint) list_store->model->GetRowCount(); g_return_val_if_fail (list_store->stamp == iter->stamp, -1); @@ -399,7 +399,7 @@ wxgtk_list_store_iter_nth_child (GtkTreeModel *tree_model, if (n < 0) return FALSE; - if (n >= (gint) list_store->model->GetNumberOfRows()) + if (n >= (gint) list_store->model->GetRowCount()) return FALSE; iter->stamp = list_store->stamp; @@ -727,11 +727,11 @@ public: virtual bool Cleared(); virtual bool Freed() -{ - m_wx_model = NULL; - m_gtk_store = NULL; - return wxDataViewListModelNotifier::Freed(); -} + { + m_wx_model = NULL; + m_gtk_store = NULL; + return wxDataViewListModelNotifier::Freed(); + } GtkWxListStore *m_gtk_store; wxDataViewListModel *m_wx_model; @@ -750,7 +750,7 @@ wxGtkDataViewListModelNotifier::wxGtkDataViewListModelNotifier( bool wxGtkDataViewListModelNotifier::RowAppended() { - unsigned int pos = m_wx_model->GetNumberOfRows()-1; + unsigned int pos = m_wx_model->GetRowCount()-1; GtkTreeIter iter; iter.stamp = m_gtk_store->stamp; @@ -879,12 +879,130 @@ bool wxGtkDataViewListModelNotifier::Cleared() IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer, wxDataViewRendererBase) -wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewRendererBase( varianttype, mode ) +wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, wxDataViewCellMode mode, + int align ) : + wxDataViewRendererBase( varianttype, mode, align ) { m_renderer = NULL; + + // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor, + // after the m_renderer pointer has been initialized } +void wxDataViewRenderer::SetMode( wxDataViewCellMode mode ) +{ + GtkCellRendererMode gtkMode; + switch (mode) + { + case wxDATAVIEW_CELL_INERT: + gtkMode = GTK_CELL_RENDERER_MODE_INERT; + break; + case wxDATAVIEW_CELL_ACTIVATABLE: + gtkMode = GTK_CELL_RENDERER_MODE_ACTIVATABLE; + break; + case wxDATAVIEW_CELL_EDITABLE: + gtkMode = GTK_CELL_RENDERER_MODE_EDITABLE; + break; + } + + GValue gvalue = { 0, }; + g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() ); + g_value_set_enum( &gvalue, gtkMode ); + g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue ); + g_value_unset( &gvalue ); +} + +wxDataViewCellMode wxDataViewRenderer::GetMode() const +{ + wxDataViewCellMode ret; + + GValue gvalue; + g_object_get( G_OBJECT(m_renderer), "mode", &gvalue, NULL); + + switch (g_value_get_enum(&gvalue)) + { + case GTK_CELL_RENDERER_MODE_INERT: + ret = wxDATAVIEW_CELL_INERT; + break; + case GTK_CELL_RENDERER_MODE_ACTIVATABLE: + ret = wxDATAVIEW_CELL_ACTIVATABLE; + break; + case GTK_CELL_RENDERER_MODE_EDITABLE: + ret = wxDATAVIEW_CELL_EDITABLE; + break; + } + + g_value_unset( &gvalue ); + + return ret; +} + +void wxDataViewRenderer::SetAlignment( int align ) +{ + // horizontal alignment: + + gfloat xalign = 0.0; + if (align & wxALIGN_RIGHT) + xalign = 1.0; + else if (align & wxALIGN_CENTER_HORIZONTAL) + xalign = 0.5; + + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_FLOAT ); + g_value_set_float( &gvalue, xalign ); + g_object_set_property( G_OBJECT(m_renderer), "xalign", &gvalue ); + g_value_unset( &gvalue ); + + // vertical alignment: + + gfloat yalign = 0.0; + if (align & wxALIGN_BOTTOM) + yalign = 1.0; + else if (align & wxALIGN_CENTER_VERTICAL) + yalign = 0.5; + + GValue gvalue2 = { 0, }; + g_value_init( &gvalue2, G_TYPE_FLOAT ); + g_value_set_float( &gvalue2, yalign ); + g_object_set_property( G_OBJECT(m_renderer), "yalign", &gvalue2 ); + g_value_unset( &gvalue2 ); +} + +int wxDataViewRenderer::GetAlignment() const +{ + int ret = 0; + GValue gvalue; + + // horizontal alignment: + + g_object_get( G_OBJECT(m_renderer), "xalign", &gvalue, NULL ); + float xalign = g_value_get_float( &gvalue ); + if (xalign < 0.5) + ret |= wxALIGN_LEFT; + else if (xalign == 0.5) + ret |= wxALIGN_CENTER_HORIZONTAL; + else + ret |= wxALIGN_RIGHT; + g_value_unset( &gvalue ); + + + // vertical alignment: + + g_object_get( G_OBJECT(m_renderer), "yalign", &gvalue, NULL ); + float yalign = g_value_get_float( &gvalue ); + if (yalign < 0.5) + ret |= wxALIGN_TOP; + else if (yalign == 0.5) + ret |= wxALIGN_CENTER_VERTICAL; + else + ret |= wxALIGN_BOTTOM; + g_value_unset( &gvalue ); + + return ret; +} + + + // --------------------------------------------------------- // wxDataViewTextRenderer // --------------------------------------------------------- @@ -918,12 +1036,13 @@ static void wxGtkTextRendererEditedCallback( GtkCellRendererText *renderer, IMPLEMENT_CLASS(wxDataViewTextRenderer, wxDataViewRenderer) -wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewRenderer( varianttype, mode ) +wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode, + int align ) : + wxDataViewRenderer( varianttype, mode, align ) { - m_renderer = (void*) gtk_cell_renderer_text_new(); + m_renderer = (GtkWidget*) gtk_cell_renderer_text_new(); - if (m_mode & wxDATAVIEW_CELL_EDITABLE) + if (mode & wxDATAVIEW_CELL_EDITABLE) { GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_BOOLEAN ); @@ -933,6 +1052,9 @@ wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxD g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this ); } + + SetMode(mode); + SetAlignment(align); } bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) @@ -948,7 +1070,7 @@ bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) return true; } -bool wxDataViewTextRenderer::GetValue( wxVariant &value ) +bool wxDataViewTextRenderer::GetValue( wxVariant &value ) const { GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_STRING ); @@ -961,16 +1083,39 @@ bool wxDataViewTextRenderer::GetValue( wxVariant &value ) return true; } +void wxDataViewTextRenderer::SetAlignment( int align ) +{ + wxDataViewRenderer::SetAlignment(align); + + // horizontal alignment: + + PangoAlignment pangoAlign = PANGO_ALIGN_LEFT; + if (align & wxALIGN_RIGHT) + pangoAlign = PANGO_ALIGN_RIGHT; + else if (align & wxALIGN_CENTER_HORIZONTAL) + pangoAlign = PANGO_ALIGN_CENTER; + + GValue gvalue = { 0, }; + g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() ); + g_value_set_enum( &gvalue, pangoAlign ); + g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue ); + g_value_unset( &gvalue ); +} + // --------------------------------------------------------- // wxDataViewBitmapRenderer // --------------------------------------------------------- IMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer) -wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewRenderer( varianttype, mode ) +wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode, + int align ) : + wxDataViewRenderer( varianttype, mode, align ) { - m_renderer = (void*) gtk_cell_renderer_pixbuf_new(); + m_renderer = (GtkWidget*) gtk_cell_renderer_pixbuf_new(); + + SetMode(mode); + SetAlignment(align); } bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) @@ -1014,7 +1159,7 @@ bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) return false; } -bool wxDataViewBitmapRenderer::GetValue( wxVariant &value ) +bool wxDataViewBitmapRenderer::GetValue( wxVariant &value ) const { return false; } @@ -1061,31 +1206,27 @@ static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle *renderer, IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer) wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewRenderer( varianttype, mode, align ) { - m_renderer = (void*) gtk_cell_renderer_toggle_new(); + m_renderer = (GtkWidget*) gtk_cell_renderer_toggle_new(); - if (m_mode & wxDATAVIEW_CELL_ACTIVATABLE) + if (mode & wxDATAVIEW_CELL_ACTIVATABLE) { - g_signal_connect_after( m_renderer, "toggled", G_CALLBACK(wxGtkToggleRendererToggledCallback), this ); + g_signal_connect_after( m_renderer, "toggled", + G_CALLBACK(wxGtkToggleRendererToggledCallback), this ); } else { - GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_BOOLEAN ); g_value_set_boolean( &gvalue, false ); g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue ); g_value_unset( &gvalue ); - - GValue gvalue2 = { 0, }; - g_value_init( &gvalue2, gtk_cell_renderer_mode_get_type() ); - g_value_set_enum( &gvalue2, GTK_CELL_RENDERER_MODE_INERT ); - g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue2 ); - g_value_unset( &gvalue2 ); - } + + SetMode(mode); + SetAlignment(align); } bool wxDataViewToggleRenderer::SetValue( const wxVariant &value ) @@ -1101,7 +1242,7 @@ bool wxDataViewToggleRenderer::SetValue( const wxVariant &value ) return true; } -bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) +bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const { GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_BOOLEAN ); @@ -1146,32 +1287,27 @@ public: IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer) wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, - wxDataViewCellMode mode, bool no_init ) : - wxDataViewRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align, + bool no_init ) : + wxDataViewRenderer( varianttype, mode, align ) { m_dc = NULL; if (no_init) m_renderer = NULL; else - Init(); + Init(mode, align); } -bool wxDataViewCustomRenderer::Init() +bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align) { GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new(); renderer->cell = this; - m_renderer = (void*) renderer; + m_renderer = (GtkWidget*) renderer; - if (m_mode & wxDATAVIEW_CELL_ACTIVATABLE) - { - GValue gvalue = { 0, }; - g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() ); - g_value_set_enum( &gvalue, GTK_CELL_RENDERER_MODE_ACTIVATABLE ); - g_object_set_property( G_OBJECT(m_renderer), "mode", &gvalue ); - g_value_unset( &gvalue ); - } + SetMode(mode); + SetAlignment(align); return true; } @@ -1203,8 +1339,8 @@ wxDC *wxDataViewCustomRenderer::GetDC() IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer) wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, - const wxString &varianttype, wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode, true ) + const wxString &varianttype, wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align, true ) { m_label = label; m_value = 0; @@ -1212,7 +1348,7 @@ wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, #ifdef __WXGTK26__ if (!gtk_check_version(2,6,0)) { - m_renderer = (void*) gtk_cell_renderer_progress_new(); + m_renderer = (GtkWidget*) gtk_cell_renderer_progress_new(); GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_STRING ); @@ -1221,12 +1357,15 @@ wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, g_value_set_string( &gvalue, wxGTK_CONV_SYS(m_label) ); g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue ); g_value_unset( &gvalue ); + + SetMode(mode); + SetAlignment(align); } else #endif { // Use custom cell code - wxDataViewCustomRenderer::Init(); + wxDataViewCustomRenderer::Init(mode, align); } } @@ -1258,6 +1397,11 @@ bool wxDataViewProgressRenderer::SetValue( const wxVariant &value ) return true; } +bool wxDataViewProgressRenderer::GetValue( wxVariant &value ) const +{ + return false; +} + bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int state ) { double pct = (double)m_value / 100.0; @@ -1274,7 +1418,7 @@ bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int state ) return true; } -wxSize wxDataViewProgressRenderer::GetSize() +wxSize wxDataViewProgressRenderer::GetSize() const { return wxSize(40,12); } @@ -1331,9 +1475,11 @@ void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event ) IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer) wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype, - wxDataViewCellMode mode ) : - wxDataViewCustomRenderer( varianttype, mode ) + wxDataViewCellMode mode, int align ) : + wxDataViewCustomRenderer( varianttype, mode, align ) { + SetMode(mode); + SetAlignment(align); } bool wxDataViewDateRenderer::SetValue( const wxVariant &value ) @@ -1343,6 +1489,11 @@ bool wxDataViewDateRenderer::SetValue( const wxVariant &value ) return true; } +bool wxDataViewDateRenderer::GetValue( wxVariant &value ) const +{ + return false; +} + bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state ) { dc->SetFont( GetOwner()->GetOwner()->GetFont() ); @@ -1352,16 +1503,16 @@ bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state ) return true; } -wxSize wxDataViewDateRenderer::GetSize() +wxSize wxDataViewDateRenderer::GetSize() const { - wxDataViewCtrl* view = GetOwner()->GetOwner(); wxString tmp = m_date.FormatDate(); wxCoord x,y,d; - view->GetTextExtent( tmp, &x, &y, &d ); + GetView()->GetTextExtent( tmp, &x, &y, &d ); return wxSize(x,y+d); } -bool wxDataViewDateRenderer::Activate( wxRect cell, wxDataViewListModel *model, unsigned int col, unsigned int row ) +bool wxDataViewDateRenderer::Activate( wxRect cell, wxDataViewListModel *model, + unsigned int col, unsigned int row ) { wxVariant variant; model->GetValue( variant, col, row ); @@ -1442,37 +1593,10 @@ wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *c wxAlignment align, int flags ) : wxDataViewColumnBase( title, cell, model_column, width, align, flags ) { - m_isConnected = false; + Init( align, flags, width ); - GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle(); - - GtkTreeViewColumn *column = gtk_tree_view_column_new(); - m_column = (void*) column; - - gtk_tree_view_column_set_clickable( column, true ); - + gtk_tree_view_column_set_clickable( GTK_TREE_VIEW_COLUMN(m_column), TRUE ); SetTitle( title ); - - if (flags & wxDATAVIEW_COL_RESIZABLE) - gtk_tree_view_column_set_resizable( column, true ); - if (flags & wxDATAVIEW_COL_HIDDEN) - gtk_tree_view_column_set_visible( column, false ); - if (flags & wxDATAVIEW_COL_SORTABLE) - gtk_tree_view_column_set_sort_indicator( column, true ); - - if (width > 0) - gtk_tree_view_column_set_fixed_width( column, width ); - else - gtk_tree_view_column_set_fixed_width( column, 70 ); // FIXME - - gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED ); - - gtk_tree_view_column_pack_end( column, renderer, FALSE ); - - gtk_tree_view_column_set_cell_data_func( column, renderer, - wxGtkTreeCellDataFunc, (gpointer) cell, NULL ); - - SetAlignment(align); } wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell, @@ -1480,35 +1604,35 @@ wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer * wxAlignment align, int flags ) : wxDataViewColumnBase( bitmap, cell, model_column, width, align, flags ) { - m_isConnected = false; - - GtkCellRenderer *renderer = (GtkCellRenderer *) cell->GetGtkHandle(); - - GtkTreeViewColumn *column = gtk_tree_view_column_new(); - m_column = (void*) column; + Init( align, flags, width ); SetBitmap( bitmap ); +} - if (flags & wxDATAVIEW_COL_RESIZABLE) - gtk_tree_view_column_set_resizable( column, true ); - if (flags & wxDATAVIEW_COL_HIDDEN) - gtk_tree_view_column_set_visible( column, false ); - if (flags & wxDATAVIEW_COL_SORTABLE) - gtk_tree_view_column_set_sort_indicator( column, true ); +void wxDataViewColumn::Init(wxAlignment align, int flags, int width) +{ + m_isConnected = false; - if (width > 0) - gtk_tree_view_column_set_fixed_width( column, width ); - else - gtk_tree_view_column_set_fixed_width( column, 70 ); // FIXME - + GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle(); + GtkTreeViewColumn *column = gtk_tree_view_column_new(); + m_column = (GtkWidget*) column; + + SetFlags( flags ); + SetAlignment( align ); + + // NOTE: we prefer not to call SetMinWidth(wxDVC_DEFAULT_MINWIDTH); + // as GTK+ is smart and unless explicitely told, will set the minimal + // width to the title's lenght, which is a better default + + // the GTK_TREE_VIEW_COLUMN_FIXED is required by the "fixed height" mode + // that we use for the wxDataViewCtrl + gtk_tree_view_column_set_fixed_width( column, width < 0 ? wxDVC_DEFAULT_WIDTH : width ); gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED ); - gtk_tree_view_column_pack_end( column, renderer, FALSE ); + gtk_tree_view_column_pack_end( column, renderer, TRUE ); gtk_tree_view_column_set_cell_data_func( column, renderer, - wxGtkTreeCellDataFunc, (gpointer) cell, NULL ); - - SetAlignment(align); + wxGtkTreeCellDataFunc, (gpointer) GetRenderer(), NULL ); } wxDataViewColumn::~wxDataViewColumn() @@ -1522,7 +1646,7 @@ void wxDataViewColumn::OnInternalIdle() if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview)) { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); if (column->button) { g_signal_connect(column->button, "button_press_event", @@ -1537,22 +1661,20 @@ void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner ) { wxDataViewColumnBase::SetOwner( owner ); - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) ); } void wxDataViewColumn::SetTitle( const wxString &title ) { - wxDataViewColumnBase::SetTitle( title ); - - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); if (m_isConnected) { // disconnect before column->button gets recreated g_signal_handlers_disconnect_by_func( column->button, - (void*) gtk_dataview_header_button_press_callback, this); + (GtkWidget*) gtk_dataview_header_button_press_callback, this); m_isConnected = false; } @@ -1565,11 +1687,17 @@ void wxDataViewColumn::SetTitle( const wxString &title ) gtk_tree_view_column_set_widget( column, NULL ); } +wxString wxDataViewColumn::GetTitle() const +{ + const gchar *str = gtk_tree_view_column_get_title( GTK_TREE_VIEW_COLUMN(m_column) ); + return wxConvFileName->cMB2WX(str); +} + void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) { wxDataViewColumnBase::SetBitmap( bitmap ); - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); if (bitmap.Ok()) { GtkImage *gtk_image = GTK_IMAGE( gtk_image_new() ); @@ -1598,34 +1726,69 @@ void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) } } +void wxDataViewColumn::SetHidden( bool hidden ) +{ + gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden ); +} + +void wxDataViewColumn::SetResizeable( bool resizeable ) +{ + gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable ); +} + void wxDataViewColumn::SetAlignment( wxAlignment align ) { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); gfloat xalign = 0.0; if (align == wxALIGN_RIGHT) xalign = 1.0; - if (align == wxALIGN_CENTER) + if (align == wxALIGN_CENTER_HORIZONTAL || + align == wxALIGN_CENTER) xalign = 0.5; - gtk_tree_view_column_set_alignment( column, xalign ); + gtk_tree_view_column_set_alignment( column, xalign ); +} + +wxAlignment wxDataViewColumn::GetAlignment() const +{ + gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) ); + + if (xalign == 1.0) + return wxALIGN_RIGHT; + if (xalign == 0.5) + return wxALIGN_CENTER_HORIZONTAL; + + return wxALIGN_LEFT; } void wxDataViewColumn::SetSortable( bool sortable ) { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); gtk_tree_view_column_set_sort_indicator( column, sortable ); } bool wxDataViewColumn::IsSortable() const { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); return gtk_tree_view_column_get_sort_indicator( column ); } +bool wxDataViewColumn::IsResizeable() const +{ + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); + return gtk_tree_view_column_get_resizable( column ); +} + +bool wxDataViewColumn::IsHidden() const +{ + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); + return !gtk_tree_view_column_get_visible( column ); +} + void wxDataViewColumn::SetSortOrder( bool ascending ) { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); if (ascending) gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING ); @@ -1635,25 +1798,31 @@ void wxDataViewColumn::SetSortOrder( bool ascending ) bool wxDataViewColumn::IsSortOrderAscending() const { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)m_column; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column); return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING); } +void wxDataViewColumn::SetMinWidth( int width ) +{ + gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width ); +} + +int wxDataViewColumn::GetMinWidth() const +{ + return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) ); +} + int wxDataViewColumn::GetWidth() const { - return gtk_tree_view_column_get_width( (GtkTreeViewColumn *)m_column ); + return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) ); } -void wxDataViewColumn::SetFixedWidth( int width ) +void wxDataViewColumn::SetWidth( int width ) { - gtk_tree_view_column_set_fixed_width( (GtkTreeViewColumn *)m_column, width ); + gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width ); } -int wxDataViewColumn::GetFixedWidth() const -{ - return gtk_tree_view_column_get_fixed_width( (GtkTreeViewColumn *)m_column ); -} //----------------------------------------------------------------------------- // wxDataViewCtrl signal callbacks @@ -1737,6 +1906,27 @@ bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE ); } + gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview), (style & wxDV_NO_HEADER) == 0 ); + +#ifdef __WXGTK210__ + if (!gtk_check_version(2,10,0)) + { + GtkTreeViewGridLines grid = GTK_TREE_VIEW_GRID_LINES_NONE; + + if ((style & wxDV_HORIZ_RULES) != 0 && + (style & wxDV_VERT_RULES) != 0) + grid = GTK_TREE_VIEW_GRID_LINES_BOTH; + else if (style & wxDV_VERT_RULES) + grid = GTK_TREE_VIEW_GRID_LINES_VERTICAL; + else if (style & wxDV_HORIZ_RULES) + grid = GTK_TREE_VIEW_GRID_LINES_HORIZONTAL; + + gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview), grid ); + } + else +#endif + gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview), (style & wxDV_HORIZ_RULES) != 0 ); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); gtk_widget_show (m_treeview); @@ -1758,7 +1948,7 @@ void wxDataViewCtrl::OnInternalIdle() { wxWindow::OnInternalIdle(); - unsigned int cols = GetNumberOfColumns(); + unsigned int cols = GetColumnCount(); unsigned int i; for (i = 0; i < cols; i++) { diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 78c3fb1150..4cea3448e9 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -1770,7 +1770,7 @@ bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id) } // utility used by wxListCtrl::MSWOnNotify and by wxDataViewHeaderWindowMSW::MSWOnNotify -unsigned int wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick) +int wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick) { wxASSERT(nmhdr && ptClick);