diff --git a/include/wx/dvrenderers.h b/include/wx/dvrenderers.h index eb617e982b..a5d6b4f339 100644 --- a/include/wx/dvrenderers.h +++ b/include/wx/dvrenderers.h @@ -96,6 +96,16 @@ enum wxDataViewCellRenderState wxDATAVIEW_CELL_FOCUSED = 8 }; +// helper for fine-tuning rendering of values depending on row's state +class WXDLLIMPEXP_ADV wxDataViewValueAdjuster +{ +public: + virtual ~wxDataViewValueAdjuster() {} + + // changes the value to have appearance suitable for highlighted rows + virtual wxVariant MakeHighlighted(const wxVariant& value) const { return value; } +}; + class WXDLLIMPEXP_ADV wxDataViewRendererBase: public wxObject { public: @@ -190,6 +200,10 @@ public: // Send wxEVT_DATAVIEW_ITEM_EDITING_STARTED event. void NotifyEditingStarted(const wxDataViewItem& item); + // Sets the transformer for fine-tuning rendering of values depending on row's state + void SetValueAdjuster(wxDataViewValueAdjuster *transformer) + { delete m_valueAdjuster; m_valueAdjuster = transformer; } + protected: // These methods are called from PrepareForItem() and should do whatever is // needed for the current platform to ensure that the item is rendered @@ -197,6 +211,10 @@ protected: virtual void SetAttr(const wxDataViewItemAttr& attr) = 0; virtual void SetEnabled(bool enabled) = 0; + // Return whether the currently rendered item is on a highlighted row + // (typically selection with dark background). For internal use only. + virtual bool IsHighlighted() const = 0; + // Called from {Cancel,Finish}Editing() to cleanup m_editorCtrl void DestroyEditControl(); @@ -211,6 +229,8 @@ protected: wxWeakRef m_editorCtrl; wxDataViewItem m_item; // Item being currently edited, if valid. + wxDataViewValueAdjuster *m_valueAdjuster; + // internal utility, may be used anywhere the window associated with the // renderer is required wxDataViewCtrl* GetView() const; diff --git a/include/wx/generic/dvrenderer.h b/include/wx/generic/dvrenderer.h index c60238406e..a2acca831e 100644 --- a/include/wx/generic/dvrenderer.h +++ b/include/wx/generic/dvrenderer.h @@ -52,6 +52,12 @@ public: const wxMouseEvent* WXUNUSED(mouseEvent)) { return false; } + void SetState(int state) { m_state = state; } + +protected: + virtual bool IsHighlighted() const wxOVERRIDE + { return m_state & wxDATAVIEW_CELL_SELECTED; } + private: int m_align; wxDataViewCellMode m_mode; @@ -60,6 +66,8 @@ private: wxDC *m_dc; + int m_state; + wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRenderer); }; diff --git a/include/wx/gtk/dvrenderer.h b/include/wx/gtk/dvrenderer.h index a99be60bcf..da5d540e2b 100644 --- a/include/wx/gtk/dvrenderer.h +++ b/include/wx/gtk/dvrenderer.h @@ -64,6 +64,8 @@ public: // different from the editor control widget for the custom renderers virtual GtkWidget* GtkGetEditorWidget() const; + void GtkSetCurrentItem(const wxDataViewItem& item) { m_itemBeingRendered = item; } + private: // Change the mode at GTK level without touching m_mode, this is useful for // temporarily making the renderer insensitive but does mean that GetMode() @@ -74,6 +76,8 @@ protected: virtual void SetAttr(const wxDataViewItemAttr& attr) wxOVERRIDE; virtual void SetEnabled(bool enabled) wxOVERRIDE; + virtual bool IsHighlighted() const wxOVERRIDE; + virtual void GtkOnCellChanged(const wxVariant& value, const wxDataViewItem& item, unsigned col); @@ -93,6 +97,9 @@ protected: // doing this bool m_usingDefaultAttrs; + // the item currently being rendered + wxDataViewItem m_itemBeingRendered; + protected: wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRenderer); }; diff --git a/include/wx/osx/dvrenderer.h b/include/wx/osx/dvrenderer.h index 29631be0fe..67116f1185 100644 --- a/include/wx/osx/dvrenderer.h +++ b/include/wx/osx/dvrenderer.h @@ -93,6 +93,8 @@ protected: void SetEnabled(bool WXUNUSED(enabled)) wxOVERRIDE { }; #endif + virtual bool IsHighlighted() const wxOVERRIDE; + private: // contains the alignment flags int m_alignment; diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 18c5f333c2..1d4659b177 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -1925,6 +1925,28 @@ public: */ virtual bool SetValue(const wxVariant& value) = 0; + /** + Set the transformer object to be used to customize values before they + are rendered. + + Can be used to change the value if it is shown on a highlighted row + (i.e. in selection) which typically has dark background. It is useful + in combination with wxDataViewTextRenderer with markup and can be used + e.g. to remove background color attributes inside selection, as a + lightweight alternative to implementing an entire + wxDataViewCustomRenderer specialization. + + @a transformer can be @NULL to reset any transformer currently being + used. + + Takes ownership of @a transformer. + + @see wxDataViewValueAdjuster + + @since 3.1.1 + */ + void SetValueAdjuster(wxDataViewValueAdjuster *transformer); + /** Before data is committed to the data model, it is passed to this method where it can be checked for validity. This can also be @@ -3662,3 +3684,66 @@ public: }; + +/** + @class wxDataViewValueAdjuster + + This class can be used with wxDataViewRenderer::SetValueAdjuster() to + customize rendering of model values with standard renderers. + + Can be used to change the value if it is shown on a highlighted row (i.e. + in selection) which typically has dark background. It is useful in + combination with wxDataViewTextRenderer with markup and can be used e.g. to + remove background color attributes inside selection, as a lightweight + alternative to implementing an entire wxDataViewCustomRenderer + specialization. + + @example + // Markup renderer that removes bgcolor attributes when in selection + class DataViewMarkupRenderer : public wxDataViewTextRenderer + { + public: + DataViewMarkupRenderer() + { + EnableMarkup(); + SetValueAdjuster(new Adjuster()); + } + + private: + class Adjuster : public wxDataViewValueAdjuster + { + public: + wxVariant MakeHighlighted(const wxVariant& value) const override + { + wxString s = value.GetString(); + size_t pos = s.find(" bgcolor=\""); + if (pos != wxString::npos) + { + size_t pos2 = s.find('"', pos + 10); + s.erase(pos, pos2 - pos + 1); + return s; + } + return value; + } + }; + }; + @endexample + + @since 3.1.1 + + @library{wxadv} + @category{dvc} +*/ +class wxDataViewValueAdjuster +{ +public: + /** + Change value for rendering when highlighted. + + Override to customize the value when it is shown in a highlighted + (selected) row, typically on a dark background. + + Default implementation returns @a value unmodified. + */ + virtual wxVariant MakeHighlighted(const wxVariant& value) const; +}; diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index 9957669610..8b2cd6a7b4 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -658,12 +658,14 @@ wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, { m_variantType = varianttype; m_owner = NULL; + m_valueAdjuster = NULL; } wxDataViewRendererBase::~wxDataViewRendererBase() { if ( m_editorCtrl ) DestroyEditControl(); + delete m_valueAdjuster; } wxDataViewCtrl* wxDataViewRendererBase::GetView() const @@ -830,7 +832,14 @@ wxDataViewRendererBase::PrepareForItem(const wxDataViewModel *model, // Now check if we have a value and remember it for rendering it later. // Notice that we do it even if it's null, as the cell should be empty then // and not show the last used value. - const wxVariant& value = CheckedGetValue(model, item, column); + wxVariant value = CheckedGetValue(model, item, column); + + if ( m_valueAdjuster ) + { + if ( IsHighlighted() ) + value = m_valueAdjuster->MakeHighlighted(value); + } + SetValue(value); if ( !value.IsNull() ) diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 02b2572d7b..7c13c9b497 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -969,6 +969,7 @@ wxDataViewRenderer::wxDataViewRenderer( const wxString &varianttype, m_mode = mode; m_ellipsizeMode = wxELLIPSIZE_MIDDLE; m_dc = NULL; + m_state = 0; } wxDataViewRenderer::~wxDataViewRenderer() @@ -2264,10 +2265,16 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) cell_rect.y = GetLineStart( item ); cell_rect.height = GetLineHeight( item ); + bool selected = m_selection.IsSelected(item); + + int state = 0; + if (m_hasFocus && selected) + state |= wxDATAVIEW_CELL_SELECTED; + + cell->SetState(state); cell->PrepareForItem(model, dataitem, col->GetModelColumn()); // draw the background - bool selected = m_selection.IsSelected(item); if ( !selected ) DrawCellBackground( cell, dc, cell_rect ); @@ -2323,10 +2330,6 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) if ( item_rect.width <= 0 ) continue; - int state = 0; - if (m_hasFocus && selected) - 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 diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 61315761a0..7f90301b9b 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -2128,6 +2128,12 @@ wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const return mode; } +bool wxDataViewRenderer::IsHighlighted() const +{ + return m_itemBeingRendered.IsOk() && + GetOwner()->GetOwner()->IsSelected(m_itemBeingRendered); +} + void wxDataViewRenderer::GtkOnTextEdited(const char *itempath, const wxString& str) { @@ -3078,6 +3084,7 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column), return; } + cell->GtkSetCurrentItem(item); cell->PrepareForItem(wx_model, item, column); } diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 170353197a..f43d031ef8 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -2767,6 +2767,11 @@ wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const return GetNativeData()->GetEllipsizeMode(); } +bool wxDataViewRenderer::IsHighlighted() const +{ + return [GetNativeData()->GetColumnCell() backgroundStyle] == NSBackgroundStyleDark; +} + void wxDataViewRenderer::OSXOnCellChanged(NSObject *object, const wxDataViewItem& item,