diff --git a/docs/changes.txt b/docs/changes.txt index 81c64a89c6..290420065b 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -85,8 +85,10 @@ All (GUI): - Fix vertical scrollbar visibility in wxStyledTextCtrl (yenwu, NewPagodi). - Fix bug with not being able to select AUI tab after dragging. - Make wxDataViewCtrl::Expand() expand ancestors in native ports too. +- Add wxDataViewTextRenderer::EnableMarkup(). - Add wxDataViewCtrl::SetHeaderAttr(). - Add wxListCtrl::SetHeaderAttr(). +- Add support for using markup in wxDataViewCtrl text items. - Implement auto complete in generic wxSearchCtrl (Eric Jensen). wxGTK: diff --git a/include/wx/generic/dvrenderers.h b/include/wx/generic/dvrenderers.h index a56beaf034..3e7f6825af 100644 --- a/include/wx/generic/dvrenderers.h +++ b/include/wx/generic/dvrenderers.h @@ -53,6 +53,11 @@ public: wxDataViewTextRenderer( const wxString &varianttype = GetDefaultType(), wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, int align = wxDVR_DEFAULT_ALIGNMENT ); + virtual ~wxDataViewTextRenderer(); + +#if wxUSE_MARKUP + void EnableMarkup(bool enable = true); +#endif // wxUSE_MARKUP virtual bool SetValue( const wxVariant &value ); virtual bool GetValue( wxVariant &value ) const; @@ -69,7 +74,11 @@ public: protected: wxString m_text; -protected: +private: +#if wxUSE_MARKUP + class wxMarkupText *m_markupText; +#endif // wxUSE_MARKUP + wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer); }; diff --git a/include/wx/generic/private/markuptext.h b/include/wx/generic/private/markuptext.h index 1d9569229e..eba3f2252d 100644 --- a/include/wx/generic/private/markuptext.h +++ b/include/wx/generic/private/markuptext.h @@ -15,6 +15,8 @@ class WXDLLIMPEXP_FWD_CORE wxDC; class WXDLLIMPEXP_FWD_CORE wxRect; +class wxMarkupParserOutput; + // ---------------------------------------------------------------------------- // wxMarkupText: allows to measure and draw the text containing markup. // ---------------------------------------------------------------------------- @@ -53,6 +55,11 @@ public: // The same rules for mnemonics as in the ctor apply to this string. void SetMarkup(const wxString& markup) { m_markup = markup; } + // This is a convenience method which can be used with the string in which + // mnemonics should be completely ignored, i.e. not interpreted in any way + // but just handled as ordinary characters. + void SetMarkupText(const wxString& markup); + // Return the width and height required by the given string and optionally // the height of the visible part above the baseline (i.e. ascent minus @@ -70,6 +77,18 @@ public: // and set the clipping region before rendering if necessary. void Render(wxDC& dc, const wxRect& rect, int flags); + // Similar to Render(), but uses wxRendererNative::DrawItemText() instead + // of generic wxDC::DrawLabel(), so is more suitable for use in controls + // that already use DrawItemText() for its items. + // + // The meaning of the flags here is different than in the overload above: + // they're passed to DrawItemText() and Render_ShowAccels is not supported + // here. + void RenderItemText(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int rendererFlags); + private: wxString m_markup; }; diff --git a/include/wx/gtk/dvrenderers.h b/include/wx/gtk/dvrenderers.h index 68e4d4a980..3305203057 100644 --- a/include/wx/gtk/dvrenderers.h +++ b/include/wx/gtk/dvrenderers.h @@ -31,6 +31,10 @@ public: wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, int align = wxDVR_DEFAULT_ALIGNMENT ); +#if wxUSE_MARKUP + void EnableMarkup(bool enable = true); +#endif // wxUSE_MARKUP + virtual bool SetValue( const wxVariant &value ) wxOVERRIDE { return SetTextValue(value); @@ -58,6 +62,14 @@ protected: bool SetTextValue(const wxString& str); bool GetTextValue(wxString& str) const; + // Return the name of the GtkCellRendererText property to use: "text" or + // "markup". + const char* GetTextPropertyName() const; + +#if wxUSE_MARKUP + // True if we should interpret markup in our text. + bool m_useMarkup; +#endif // wxUSE_MARKUP wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer); }; diff --git a/include/wx/osx/dvrenderers.h b/include/wx/osx/dvrenderers.h index 4da26441a6..c62a19ffb5 100644 --- a/include/wx/osx/dvrenderers.h +++ b/include/wx/osx/dvrenderers.h @@ -55,6 +55,10 @@ public: wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, int align = wxDVR_DEFAULT_ALIGNMENT); +#if wxUSE_MARKUP && wxOSX_USE_COCOA + void EnableMarkup(bool enable = true); +#endif // wxUSE_MARKUP && Cocoa + virtual bool MacRender(); virtual void OSXOnCellChanged(NSObject *value, @@ -62,6 +66,11 @@ public: unsigned col); private: +#if wxUSE_MARKUP && wxOSX_USE_COCOA + // True if we should interpret markup in our text. + bool m_useMarkup; +#endif // wxUSE_MARKUP && Cocoa + wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer); }; diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index 2c29c76049..e68a589097 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -1966,6 +1966,49 @@ public: wxDataViewTextRenderer(const wxString& varianttype = GetDefaultType(), wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT, int align = wxDVR_DEFAULT_ALIGNMENT ); + + /** + Enable interpretation of markup in the item data. + + If this method is called with @true argument, markup (@ref + wxControl::SetLabelMarkup()) in the data of the items in this column + will be interpreted, which can be used for a more fine-grained + appearance control than just setting an attribute, which affects all of + the item text. + + For example, as shown in the @ref page_samples_dataview, after creating + a column using a markup-enabled renderer: + @code + wxDataViewTextRenderer* renderer = new wxDataViewTextRenderer(); + renderer->EnableMarkup(); + dataViewCtrl->AppendColumn(new wxDataViewColumn("title", renderer, 0)); + @endcode + + The overridden model wxDataViewModel::GetValue() method may return + values containing markup for this column: + @code + void MyModel::GetValue(wxVariant& variant, + const wxDataViewItem& item, + unsigned int col) const + { + if ( col == 0 && item == ... ) + { + variant = "light and " + "dark blue"; + } + + ... + } + @endcode + + @note Currently wxDataViewIconTextRenderer only provides EnableMarkup() + EnableMarkup() in wxGTK, but not under the other platforms, so you + should only use it for plain wxDataViewTextRenderer columns, + without icons, in portable code. + + @since 3.1.1 + */ + void EnableMarkup(bool enable = true); }; diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index fca7630647..6cd58d97b6 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -702,9 +702,14 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l m_ctrl[1]->AppendDateColumn("date", MyListModel::Col_Date); + + wxDataViewTextRenderer* const markupRenderer = new wxDataViewTextRenderer(); +#if wxUSE_MARKUP + markupRenderer->EnableMarkup(); +#endif // wxUSE_MARKUP m_attributes = new wxDataViewColumn("attributes", - new wxDataViewTextRenderer, + markupRenderer, MyListModel::Col_TextWithAttr, wxCOL_WIDTH_AUTOSIZE, wxALIGN_RIGHT, diff --git a/samples/dataview/mymodels.cpp b/samples/dataview/mymodels.cpp index bf6b219206..1ee62f8083 100644 --- a/samples/dataview/mymodels.cpp +++ b/samples/dataview/mymodels.cpp @@ -436,7 +436,14 @@ void MyListModel::GetValueByRow( wxVariant &variant, { static const char *labels[5] = { - "blue", "green", "red", "bold cyan", "default", + // These strings will look wrong without wxUSE_MARKUP, but + // it's just a sample, so we don't care. + "light and " + "dark blue", + "growing green", + "emphatic red", + "bold cyan", + "dull default", }; variant = labels[row % 5]; diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index e4e5521bd8..f8dcfee354 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -1005,7 +1005,7 @@ wxDataViewCustomRendererBase::RenderText(const wxString& text, int flags = 0; if ( state & wxDATAVIEW_CELL_SELECTED ) - flags |= wxCONTROL_SELECTED | wxCONTROL_FOCUSED; + flags |= wxCONTROL_SELECTED; if ( !GetOwner()->GetOwner()->IsEnabled() ) flags |= wxCONTROL_DISABLED; diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index a18f8a5cd2..24d8a36010 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -50,6 +50,7 @@ #include "wx/selstore.h" #include "wx/stopwatch.h" #include "wx/weakref.h" +#include "wx/generic/private/markuptext.h" #include "wx/generic/private/widthcalc.h" //----------------------------------------------------------------------------- @@ -1004,12 +1005,48 @@ wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxDataViewCellMode mode, int align ) : wxDataViewRenderer( varianttype, mode, align ) { +#if wxUSE_MARKUP + m_markupText = NULL; +#endif // wxUSE_MARKUP } +wxDataViewTextRenderer::~wxDataViewTextRenderer() +{ +#if wxUSE_MARKUP + delete m_markupText; +#endif // wxUSE_MARKUP +} + +#if wxUSE_MARKUP +void wxDataViewTextRenderer::EnableMarkup(bool enable) +{ + if ( enable ) + { + if ( !m_markupText ) + { + m_markupText = new wxMarkupText(wxString()); + } + } + else + { + if ( m_markupText ) + { + delete m_markupText; + m_markupText = NULL; + } + } +} +#endif // wxUSE_MARKUP + bool wxDataViewTextRenderer::SetValue( const wxVariant &value ) { m_text = value.GetString(); +#if wxUSE_MARKUP + if ( m_markupText ) + m_markupText->SetMarkupText(m_text); +#endif // wxUSE_MARKUP + return true; } @@ -1038,14 +1075,39 @@ bool wxDataViewTextRenderer::GetValueFromEditorCtrl( wxWindow *editor, wxVariant bool wxDataViewTextRenderer::Render(wxRect rect, wxDC *dc, int state) { - RenderText(m_text, 0, rect, dc, state); +#if wxUSE_MARKUP + if ( m_markupText ) + { + int flags = 0; + if ( state & wxDATAVIEW_CELL_SELECTED ) + flags |= wxCONTROL_SELECTED; + m_markupText->RenderItemText(GetView(), *dc, rect, flags); + } + else +#endif // wxUSE_MARKUP + RenderText(m_text, 0, rect, dc, state); + return true; } wxSize wxDataViewTextRenderer::GetSize() const { if (!m_text.empty()) + { +#if wxUSE_MARKUP + if ( m_markupText ) + { + wxDataViewCtrl* const view = GetView(); + wxClientDC dc(view); + if ( GetAttr().HasFont() ) + dc.SetFont(GetAttr().GetEffectiveFont(view->GetFont())); + + return m_markupText->Measure(dc); + } +#endif // wxUSE_MARKUP + return GetTextExtent(m_text); + } else return wxSize(wxDVC_DEFAULT_RENDERER_SIZE,wxDVC_DEFAULT_RENDERER_SIZE); } diff --git a/src/generic/markuptext.cpp b/src/generic/markuptext.cpp index 6516e791c0..d226246814 100644 --- a/src/generic/markuptext.cpp +++ b/src/generic/markuptext.cpp @@ -30,6 +30,8 @@ #include "wx/dc.h" #endif // WX_PRECOMP +#include "wx/renderer.h" + #include "wx/generic/private/markuptext.h" #include "wx/private/markupparserattr.h" @@ -132,35 +134,6 @@ public: m_origTextBackground = dc.GetTextBackground(); } - virtual void OnText(const wxString& text_) wxOVERRIDE - { - wxString text; - int indexAccel = wxControl::FindAccelIndex(text_, &text); - if ( !(m_flags & wxMarkupText::Render_ShowAccels) ) - indexAccel = wxNOT_FOUND; - - // Adjust the position (unfortunately we need to do this manually as - // there is no notion of current text position in wx API) rectangle to - // ensure that all text segments use the same baseline (as there is - // nothing equivalent to Windows SetTextAlign(TA_BASELINE) neither). - wxRect rect(m_rect); - rect.x = m_pos; - - int descent; - m_dc.GetTextExtent(text, &rect.width, &rect.height, &descent); - rect.height -= descent; - rect.y += m_rect.height - rect.height; - - wxRect bounds; - m_dc.DrawLabel(text, wxBitmap(), - rect, wxALIGN_LEFT | wxALIGN_TOP, - indexAccel, - &bounds); - - // TODO-MULTILINE-MARKUP: Must update vertical position too. - m_pos += bounds.width; - } - virtual void OnAttrStart(const Attr& attr) wxOVERRIDE { m_dc.SetFont(attr.font); @@ -202,7 +175,7 @@ public: } } -private: +protected: wxDC& m_dc; const wxRect m_rect; const int m_flags; @@ -217,12 +190,96 @@ private: wxDECLARE_NO_COPY_CLASS(wxMarkupParserRenderOutput); }; +// An output renderer suitable for control labels. +class wxMarkupParserRenderLabelOutput : public wxMarkupParserRenderOutput +{ +public: + wxMarkupParserRenderLabelOutput(wxDC& dc, + const wxRect& rect, + int flags) + : wxMarkupParserRenderOutput(dc, rect, flags) + { + } + + virtual void OnText(const wxString& text_) wxOVERRIDE + { + wxString text; + int indexAccel = wxControl::FindAccelIndex(text_, &text); + if ( !(m_flags & wxMarkupText::Render_ShowAccels) ) + indexAccel = wxNOT_FOUND; + + // Adjust the position (unfortunately we need to do this manually as + // there is no notion of current text position in wx API) rectangle to + // ensure that all text segments use the same baseline (as there is + // nothing equivalent to Windows SetTextAlign(TA_BASELINE) neither). + wxRect rect(m_rect); + rect.x = m_pos; + + int descent; + m_dc.GetTextExtent(text, &rect.width, &rect.height, &descent); + rect.height -= descent; + rect.y += m_rect.height - rect.height; + + wxRect bounds; + m_dc.DrawLabel(text, wxBitmap(), + rect, wxALIGN_LEFT | wxALIGN_TOP, + indexAccel, + &bounds); + + m_pos += bounds.width; + } +}; + +// An output renderer suitable for multi-item controls items. +class wxMarkupParserRenderItemOutput : public wxMarkupParserRenderOutput +{ +public: + wxMarkupParserRenderItemOutput(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int rendererFlags) + : wxMarkupParserRenderOutput(dc, rect, wxMarkupText::Render_Default), + m_win(win), + m_rendererFlags(rendererFlags), + m_renderer(&wxRendererNative::Get()) + { + } + + virtual void OnText(const wxString& text) wxOVERRIDE + { + wxRect rect(m_rect); + rect.x = m_pos; + + m_renderer->DrawItemText(m_win, + m_dc, + wxControl::RemoveMnemonics(text), + rect, + wxALIGN_LEFT | wxALIGN_CENTRE_VERTICAL, + m_rendererFlags, + wxELLIPSIZE_NONE); + + m_pos += m_dc.GetTextExtent(text).x; + } + +private: + wxWindow* const m_win; + int const m_rendererFlags; + wxRendererNative* const m_renderer; + + wxDECLARE_NO_COPY_CLASS(wxMarkupParserRenderItemOutput); +}; + } // anonymous namespace // ============================================================================ // wxMarkupText implementation // ============================================================================ +void wxMarkupText::SetMarkupText(const wxString& markup) +{ + m_markup = wxControl::EscapeMnemonics(markup); +} + wxSize wxMarkupText::Measure(wxDC& dc, int *visibleHeight) const { wxMarkupParserMeasureOutput out(dc, visibleHeight); @@ -245,7 +302,17 @@ void wxMarkupText::Render(wxDC& dc, const wxRect& rect, int flags) wxRect rectText(rect.GetPosition(), Measure(dc, &visibleHeight)); rectText.height = visibleHeight; - wxMarkupParserRenderOutput out(dc, rectText.CentreIn(rect), flags); + wxMarkupParserRenderLabelOutput out(dc, rectText.CentreIn(rect), flags); + wxMarkupParser parser(out); + parser.Parse(m_markup); +} + +void wxMarkupText::RenderItemText(wxWindow *win, + wxDC& dc, + const wxRect& rect, + int rendererFlags) +{ + wxMarkupParserRenderItemOutput out(win, dc, rect, rendererFlags); wxMarkupParser parser(out); parser.Parse(m_markup); } diff --git a/src/generic/renderg.cpp b/src/generic/renderg.cpp index b76c96b9bf..1961141fc4 100644 --- a/src/generic/renderg.cpp +++ b/src/generic/renderg.cpp @@ -938,14 +938,7 @@ wxRendererGeneric::DrawItemText(wxWindow* WXUNUSED(win), wxColour textColour; if ( flags & wxCONTROL_SELECTED ) { - if ( flags & wxCONTROL_FOCUSED ) - { - textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); - } - else // !focused - { - textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT); - } + textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); } else if ( flags & wxCONTROL_DISABLED ) { diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 8be64c4633..9a3c82e39c 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -2277,6 +2277,10 @@ wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxD int align ) : wxDataViewRenderer( varianttype, mode, align ) { +#if wxUSE_MARKUP + m_useMarkup = false; +#endif // wxUSE_MARKUP + GtkWxCellRendererText *text_renderer = gtk_wx_cell_renderer_text_new(); text_renderer->wx_renderer = this; m_renderer = (GtkCellRenderer*) text_renderer; @@ -2298,12 +2302,29 @@ wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString &varianttype, wxD SetAlignment(align); } +#if wxUSE_MARKUP +void wxDataViewTextRenderer::EnableMarkup(bool enable) +{ + m_useMarkup = enable; +} +#endif // wxUSE_MARKUP + +const char* wxDataViewTextRenderer::GetTextPropertyName() const +{ +#if wxUSE_MARKUP + if ( m_useMarkup ) + return "markup"; +#endif // wxUSE_MARKUP + + return "text"; +} + bool wxDataViewTextRenderer::SetTextValue(const wxString& str) { GValue gvalue = G_VALUE_INIT; g_value_init( &gvalue, G_TYPE_STRING ); g_value_set_string( &gvalue, wxGTK_CONV_FONT( str, GetOwner()->GetOwner()->GetFont() ) ); - g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue ); + g_object_set_property( G_OBJECT(m_renderer), GetTextPropertyName(), &gvalue ); g_value_unset( &gvalue ); return true; @@ -2313,7 +2334,7 @@ bool wxDataViewTextRenderer::GetTextValue(wxString& str) const { GValue gvalue = G_VALUE_INIT; g_value_init( &gvalue, G_TYPE_STRING ); - g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue ); + g_object_get_property( G_OBJECT(m_renderer), GetTextPropertyName(), &gvalue ); str = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ), const_cast(this)->GetOwner()->GetOwner()->GetFont() ); g_value_unset( &gvalue ); diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index db4f96d6d1..427945316c 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -30,6 +30,10 @@ #include "wx/stopwatch.h" #include "wx/dcgraph.h" +#if wxUSE_MARKUP + #include "wx/osx/cocoa/private/markuptoattr.h" +#endif // wxUSE_MARKUP + // ============================================================================ // Constants used locally // ============================================================================ @@ -2730,6 +2734,10 @@ wxDataViewTextRenderer::wxDataViewTextRenderer(const wxString& varianttype, int align) : wxDataViewRenderer(varianttype,mode,align) { +#if wxUSE_MARKUP + m_useMarkup = false; +#endif // wxUSE_MARKUP + NSTextFieldCell* cell; @@ -2739,8 +2747,27 @@ wxDataViewTextRenderer::wxDataViewTextRenderer(const wxString& varianttype, [cell release]; } +#if wxUSE_MARKUP + +void wxDataViewTextRenderer::EnableMarkup(bool enable) +{ + m_useMarkup = enable; +} + +#endif // wxUSE_MARKUP + bool wxDataViewTextRenderer::MacRender() { +#if wxUSE_MARKUP + if ( m_useMarkup ) + { + wxMarkupToAttrString toAttr(GetView(), GetValue().GetString()); + + [GetNativeData()->GetItemCell() setAttributedStringValue:toAttr.GetNSAttributedString()]; + return true; + } +#endif // wxUSE_MARKUP + [GetNativeData()->GetItemCell() setObjectValue:wxCFStringRef(GetValue().GetString()).AsNSString()]; return true; }