From b7a89f8746b8861712b4e066aaeca4f93083afea Mon Sep 17 00:00:00 2001 From: Tobias Taschner Date: Thu, 17 Sep 2015 14:38:03 +0200 Subject: [PATCH] Add wxRendererNative::DrawItemText() for list-like controls Add a new method that should be used for drawing the elements of list-like controls (i.e. wx{List,Tree,DataView}Ctrl and similar). Implement it for wxMSW natively and provide a straightforward generic fallback for the other ports. See #16414. --- docs/changes.txt | 1 + include/wx/msw/uxtheme.h | 23 ++++++++++++++ include/wx/renderer.h | 16 ++++++++++ interface/wx/renderer.h | 23 ++++++++++++++ samples/render/render.cpp | 12 +++++++ src/generic/renderg.cpp | 47 ++++++++++++++++++++++++++++ src/msw/renderer.cpp | 66 +++++++++++++++++++++++++++++++++++++++ src/msw/uxtheme.cpp | 1 + 8 files changed, 189 insertions(+) diff --git a/docs/changes.txt b/docs/changes.txt index e9f5597b1f..60173464f4 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -97,6 +97,7 @@ All (GUI): - Add support for sorting wxDataViewCtrl by multiple columns (Trigve). - Allow dropping data on wxDataViewCtrl background (Laurent Poujoulat). - Add wxRendererNative::DrawGauge() (Tobias Taschner). +- Add wxRendererNative::DrawItemText() (Tobias Taschner). - Add wxHtmlWindow::SetDefaultHTMLCursor() (Jeff A. Marr). - Add default ctor and Create() to wxContextHelpButton (Hanmac). - Send events when toggling wxPropertyGrid nodes from keyboard (Armel Asselin). diff --git a/include/wx/msw/uxtheme.h b/include/wx/msw/uxtheme.h index 5c4eae981d..f15973e305 100644 --- a/include/wx/msw/uxtheme.h +++ b/include/wx/msw/uxtheme.h @@ -84,10 +84,32 @@ private: wxDECLARE_NO_COPY_CLASS(wxUxThemeFont); }; +typedef int(__stdcall *DTT_CALLBACK_PROC)(HDC hdc, const wchar_t * pszText, int cchText, RECT * prc, unsigned int dwFlags, WXLPARAM lParam); + +typedef struct _DTTOPTS +{ + DWORD dwSize; + DWORD dwFlags; + COLORREF crText; + COLORREF crBorder; + COLORREF crShadow; + int iTextShadowType; + POINT ptShadowOffset; + int iBorderSize; + int iFontPropId; + int iColorPropId; + int iStateId; + BOOL fApplyOverlay; + int iGlowSize; + DTT_CALLBACK_PROC pfnDrawTextCallback; + WXLPARAM lParam; +} DTTOPTS, *PDTTOPTS; + typedef HTHEME (__stdcall *PFNWXUOPENTHEMEDATA)(HWND, const wchar_t *); typedef HRESULT (__stdcall *PFNWXUCLOSETHEMEDATA)(HTHEME); typedef HRESULT (__stdcall *PFNWXUDRAWTHEMEBACKGROUND)(HTHEME, HDC, int, int, const RECT *, const RECT *); typedef HRESULT (__stdcall *PFNWXUDRAWTHEMETEXT)(HTHEME, HDC, int, int, const wchar_t *, int, DWORD, DWORD, const RECT *); +typedef HRESULT (__stdcall *PFNWXUDRAWTHEMETEXTEX)(HTHEME, HDC, int, int, const wchar_t *, int, DWORD, RECT *, const DTTOPTS *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEBACKGROUNDCONTENTRECT)(HTHEME, HDC, int, int, const RECT *, RECT *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEBACKGROUNDEXTENT)(HTHEME, HDC, int, int, const RECT *, RECT *); typedef HRESULT (__stdcall *PFNWXUGETTHEMEPARTSIZE)(HTHEME, HDC, int, int, const RECT *, /* enum */ THEMESIZE, SIZE *); @@ -161,6 +183,7 @@ public: wxUX_THEME_DECLARE(PFNWXUCLOSETHEMEDATA, CloseThemeData) wxUX_THEME_DECLARE(PFNWXUDRAWTHEMEBACKGROUND, DrawThemeBackground) wxUX_THEME_DECLARE(PFNWXUDRAWTHEMETEXT, DrawThemeText) + wxUX_THEME_DECLARE(PFNWXUDRAWTHEMETEXTEX, DrawThemeTextEx) wxUX_THEME_DECLARE(PFNWXUGETTHEMEBACKGROUNDCONTENTRECT, GetThemeBackgroundContentRect) wxUX_THEME_DECLARE(PFNWXUGETTHEMEBACKGROUNDEXTENT, GetThemeBackgroundExtent) wxUX_THEME_DECLARE(PFNWXUGETTHEMEPARTSIZE, GetThemePartSize) diff --git a/include/wx/renderer.h b/include/wx/renderer.h index 3dede7aa0f..173ae122f9 100644 --- a/include/wx/renderer.h +++ b/include/wx/renderer.h @@ -329,6 +329,14 @@ public: int max, int flags = 0) = 0; + // Draw text using the appropriate color for normal and selected states. + virtual void DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align = wxALIGN_LEFT | wxALIGN_TOP, + int flags = 0) = 0; + // geometry functions // ------------------ @@ -515,6 +523,14 @@ public: int flags = 0) { m_rendererNative.DrawGauge(win, dc, rect, value, max, flags); } + virtual void DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align = wxALIGN_LEFT | wxALIGN_TOP, + int flags = 0) + { m_rendererNative.DrawItemText(win, dc, text, rect, align, flags); } + virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win) { return m_rendererNative.GetSplitterParams(win); } diff --git a/interface/wx/renderer.h b/interface/wx/renderer.h index c33f532e0a..37eb17b260 100644 --- a/interface/wx/renderer.h +++ b/interface/wx/renderer.h @@ -405,10 +405,33 @@ public: (otherwise the selection rectangle is e.g. often grey and not blue). This may be ignored by the renderer or deduced by the code directly from the @a win. + + @see DrawItemText() */ virtual void DrawItemSelectionRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0) = 0; + + /** + Draw item text in the correct color based on selection status. + + Background of the text should be painted with DrawItemSelectionRect(). + + The supported @a flags are @c wxCONTROL_SELECTED for items + which are selected. + @c wxCONTROL_FOCUSED may be used to indicate if the control has the focus. + @c wxCONTROL_DISABLED may be used to indicate if the control is disabled. + + @since 3.1.0 + @see DrawItemSelectionRect() + */ + virtual void DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align = wxALIGN_LEFT | wxALIGN_TOP, + int flags = 0) = 0; + /** Draw a blank push button that looks very similar to wxButton. diff --git a/samples/render/render.cpp b/samples/render/render.cpp index 08500f87c6..f0623855fc 100644 --- a/samples/render/render.cpp +++ b/samples/render/render.cpp @@ -276,6 +276,18 @@ private: wxRect(x2, y, widthGauge, heightGauge), 25, 100, m_flags); y += lineHeight + heightGauge; + + const wxCoord heightListItem = 48; + const wxCoord widthListItem = 260; + + dc.DrawText("DrawItemSelectionRect()", x1, y); + wxRendererNative::GetDefault().DrawItemSelectionRect(this, dc, + wxRect(x2, y, widthListItem, heightListItem), m_flags | wxCONTROL_SELECTED); + + wxRendererNative::GetDefault().DrawItemText(this, dc, "DrawItemText()", + wxRect(x2, y, widthListItem, heightListItem).Inflate(-2, -2), m_align, m_flags | wxCONTROL_SELECTED); + + y += lineHeight + heightListItem; } int m_flags; diff --git a/src/generic/renderg.cpp b/src/generic/renderg.cpp index 5519784724..74578c9aed 100644 --- a/src/generic/renderg.cpp +++ b/src/generic/renderg.cpp @@ -138,6 +138,13 @@ public: virtual void DrawGauge(wxWindow* win, wxDC& dc, const wxRect& rect, int value, int max, int flags = 0) wxOVERRIDE; + virtual void DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align = wxALIGN_LEFT | wxALIGN_TOP, + int flags = 0) wxOVERRIDE; + virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win) wxOVERRIDE; virtual wxRendererVersion GetVersion() const wxOVERRIDE @@ -832,6 +839,46 @@ void wxRendererGeneric::DrawGauge(wxWindow* win, dc.DrawRectangle(progRect); } +void +wxRendererGeneric::DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align, + int flags) +{ + // Determine text color + wxColour textColour; + if ( flags & wxCONTROL_SELECTED ) + { + if ( flags & wxCONTROL_FOCUSED ) + { + textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + } + else // !focused + { + textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT); + } + } + else if ( flags & wxCONTROL_DISABLED ) + { + textColour = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); + } + else // enabled but not selected + { + textColour = win->GetForegroundColour(); + } + + const wxString paintText = wxControl::Ellipsize(text, dc, + wxELLIPSIZE_END, + rect.GetWidth()); + + // Draw text + dc.SetTextForeground(textColour); + dc.SetTextBackground(wxTransparentColour); + dc.DrawLabel(paintText, rect, align); +} + // ---------------------------------------------------------------------------- // A module to allow cleanup of generic renderer. // ---------------------------------------------------------------------------- diff --git a/src/msw/renderer.cpp b/src/msw/renderer.cpp index c08ff3f14d..2e9eb80a80 100644 --- a/src/msw/renderer.cpp +++ b/src/msw/renderer.cpp @@ -111,6 +111,9 @@ #define LISS_HOTSELECTED 6 #define LVP_LISTITEM 1 + + #define DTT_TEXTCOLOR (1UL << 0) // crText has been specified + #define DTT_STATEID (1UL << 8) // IStateId has been specified #endif #if defined(__WXWINCE__) @@ -323,6 +326,12 @@ public: int max, int flags = 0); + virtual void DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align = wxALIGN_LEFT | wxALIGN_TOP, + int flags = 0); virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win); @@ -881,6 +890,63 @@ wxRendererXP::DrawItemSelectionRect(wxWindow *win, } } +void wxRendererXP::DrawItemText(wxWindow* win, + wxDC& dc, + const wxString& text, + const wxRect& rect, + int align, + int flags) +{ + wxUxThemeHandle hTheme(win, L"LISTVIEW"); + + int itemState = LISS_NORMAL; + if ( flags & wxCONTROL_SELECTED ) + itemState = LISS_SELECTED; + if ( !(flags & wxCONTROL_FOCUSED) ) + itemState = LISS_SELECTEDNOTFOCUS; + if ( flags & wxCONTROL_DISABLED ) + itemState |= LISS_DISABLED; + + wxUxThemeEngine* te = wxUxThemeEngine::Get(); + if ( te->IsThemePartDefined(hTheme, LVP_LISTITEM, itemState) ) + { + RECT rc; + wxCopyRectToRECT(rect, rc); + + DTTOPTS textOpts; + textOpts.dwSize = sizeof(textOpts); + textOpts.dwFlags = DTT_STATEID; + textOpts.iStateId = itemState; + if (flags & wxCONTROL_DISABLED) + { + textOpts.dwFlags |= DTT_TEXTCOLOR; + textOpts.crText = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT).GetPixel(); + } + + DWORD textFlags = DT_NOPREFIX | DT_END_ELLIPSIS; + if ( align & wxALIGN_CENTER ) + textFlags |= DT_CENTER; + else if ( align & wxALIGN_RIGHT ) + textFlags |= DT_RIGHT; + else + textFlags |= DT_LEFT; + + if ( align & wxALIGN_BOTTOM ) + textFlags |= DT_BOTTOM; + else if ( align & wxALIGN_CENTER_VERTICAL ) + textFlags |= DT_VCENTER; + else + textFlags |= DT_TOP; + + te->DrawThemeTextEx(hTheme, dc.GetHDC(), LVP_LISTITEM, itemState, + text.wchar_str(), -1, textFlags, &rc, &textOpts); + } + else + { + m_rendererNative.DrawItemText(win, dc, text, rect, align, flags); + } +} + // Uses the theme to draw the border and fill for something like a wxTextCtrl void wxRendererXP::DrawTextCtrl(wxWindow* win, wxDC& dc, diff --git a/src/msw/uxtheme.cpp b/src/msw/uxtheme.cpp index a67c9635e4..1b29e14f77 100644 --- a/src/msw/uxtheme.cpp +++ b/src/msw/uxtheme.cpp @@ -124,6 +124,7 @@ bool wxUxThemeEngine::Initialize() RESOLVE_UXTHEME_FUNCTION(PFNWXUCLOSETHEMEDATA, CloseThemeData); RESOLVE_UXTHEME_FUNCTION(PFNWXUDRAWTHEMEBACKGROUND, DrawThemeBackground); RESOLVE_UXTHEME_FUNCTION(PFNWXUDRAWTHEMETEXT, DrawThemeText); + RESOLVE_UXTHEME_FUNCTION(PFNWXUDRAWTHEMETEXTEX, DrawThemeTextEx); RESOLVE_UXTHEME_FUNCTION(PFNWXUGETTHEMEBACKGROUNDCONTENTRECT, GetThemeBackgroundContentRect); RESOLVE_UXTHEME_FUNCTION(PFNWXUGETTHEMEBACKGROUNDEXTENT, GetThemeBackgroundExtent); RESOLVE_UXTHEME_FUNCTION(PFNWXUGETTHEMEPARTSIZE, GetThemePartSize);