diff --git a/docs/changes.txt b/docs/changes.txt index 8bf63bcef4..874ae50525 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -71,6 +71,7 @@ All (GUI): - Add support for wxSL_MIN_MAX_LABELS and wxSL_VALUE_LABEL to XRC (ousnius). - Update Scintilla to v3.6.3 (Paul Kulchenko). - Make wxDataViewCtrl::Expand() expand ancestors in native ports too. +- Add wxListCtrl::SetHeaderAttr(). wxGTK: diff --git a/include/wx/listbase.h b/include/wx/listbase.h index 841b4c00fa..221052ac8b 100644 --- a/include/wx/listbase.h +++ b/include/wx/listbase.h @@ -411,6 +411,9 @@ public: void SetAlternateRowColour(const wxColour& colour); wxColour GetAlternateRowColour() const { return m_alternateRowColour.GetBackgroundColour(); } + // Header attributes support: only implemented in wxMSW currently. + virtual bool SetHeaderAttr(const wxItemAttr& WXUNUSED(attr)) { return false; } + // Checkboxes support: only implemented in wxMSW currently. virtual bool HasCheckboxes() const { return false; } virtual bool EnableCheckboxes(bool WXUNUSED(enable) = true) { return false; } diff --git a/include/wx/msw/listctrl.h b/include/wx/msw/listctrl.h index 1790454cce..95e2e883b2 100644 --- a/include/wx/msw/listctrl.h +++ b/include/wx/msw/listctrl.h @@ -16,6 +16,7 @@ #include "wx/vector.h" class wxMSWListItemData; +class wxMSWListHeaderCustomDraw; // define this symbol to indicate the availability of SetColumnsOrder() and // related functions @@ -115,6 +116,9 @@ public: bool SetForegroundColour(const wxColour& col); bool SetBackgroundColour(const wxColour& col); + // Header attributes + virtual bool SetHeaderAttr(const wxItemAttr& attr) wxOVERRIDE; + // Gets information about this column bool GetColumn(int col, wxListItem& item) const; @@ -461,6 +465,10 @@ private: void OnCharHook(wxKeyEvent& event); + // Object using for header custom drawing if necessary, may be NULL. + wxMSWListHeaderCustomDraw* m_headerCustomDraw; + + wxDECLARE_DYNAMIC_CLASS(wxListCtrl); wxDECLARE_EVENT_TABLE(); wxDECLARE_NO_COPY_CLASS(wxListCtrl); diff --git a/interface/wx/listctrl.h b/interface/wx/listctrl.h index c1538bfd1c..022743c8a6 100644 --- a/interface/wx/listctrl.h +++ b/interface/wx/listctrl.h @@ -1052,6 +1052,25 @@ public: */ bool SetColumnsOrder(const wxArrayInt& orders); + /** + Change the font and the colours used for the list control header. + + This method can be used to change the appearance of the header shown by + the control in report mode (unless @c wxLC_NO_HEADER style is used). + + Currently it is implemented only for wxMSW and does nothing in the + other ports. + + @param attr The object containing the font and text and background + colours to use. It may be default, i.e. not specify any custom font + nor colours, to reset any previously set custom attribute. + @return @true if the attributes have been updated or @false if this is + not supported by the current platform. + + @since 3.1.1 + */ + bool SetHeaderAttr(const wxItemAttr& attr); + /** Sets the image list associated with the control. diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index e839398409..abb07423c0 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -137,6 +137,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(LIST_SET_FG_COL, MyFrame::OnSetFgColour) EVT_MENU(LIST_SET_BG_COL, MyFrame::OnSetBgColour) EVT_MENU(LIST_ROW_LINES, MyFrame::OnSetRowLines) + EVT_MENU(LIST_CUSTOM_HEADER_ATTR, MyFrame::OnCustomHeaderAttr) EVT_MENU(LIST_TOGGLE_MULTI_SEL, MyFrame::OnToggleMultiSel) EVT_MENU(LIST_SHOW_COL_INFO, MyFrame::OnShowColInfo) EVT_MENU(LIST_SHOW_SEL_INFO, MyFrame::OnShowSelInfo) @@ -160,6 +161,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateUIEnableInReport) EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateUIEnableInReport) + EVT_UPDATE_UI(LIST_CUSTOM_HEADER_ATTR, MyFrame::OnUpdateUIEnableInReport) EVT_UPDATE_UI(LIST_TOGGLE_MULTI_SEL, MyFrame::OnUpdateToggleMultiSel) EVT_UPDATE_UI(LIST_TOGGLE_CHECKBOXES, MyFrame::OnUpdateToggleCheckboxes) @@ -276,6 +278,7 @@ MyFrame::MyFrame(const wxChar *title) menuCol->Append(LIST_SET_FG_COL, wxT("&Foreground colour...")); menuCol->Append(LIST_SET_BG_COL, wxT("&Background colour...")); menuCol->AppendCheckItem(LIST_ROW_LINES, wxT("Alternating colours")); + menuCol->AppendCheckItem(LIST_CUSTOM_HEADER_ATTR, "&Custom header attributes"); wxMenuBar *menubar = new wxMenuBar; menubar->Append(menuFile, wxT("&File")); @@ -894,6 +897,20 @@ void MyFrame::OnSetRowLines(wxCommandEvent& event) m_listCtrl->Refresh(); } +void MyFrame::OnCustomHeaderAttr(wxCommandEvent& event) +{ + wxItemAttr attr; + if ( event.IsChecked() ) + { + attr.SetTextColour(*wxBLUE); + attr.SetFont(wxFontInfo(24).Italic()); + } + //else: leave it as default to disable custom header attributes + + if ( !m_listCtrl->SetHeaderAttr(attr) ) + wxLogMessage("Sorry, header attributes not supported on this platform"); +} + void MyFrame::OnAdd(wxCommandEvent& WXUNUSED(event)) { m_listCtrl->InsertItem(m_listCtrl->GetItemCount(), wxT("Appended item")); diff --git a/samples/listctrl/listtest.h b/samples/listctrl/listtest.h index 7494dfec97..be4e8adc3f 100644 --- a/samples/listctrl/listtest.h +++ b/samples/listctrl/listtest.h @@ -132,6 +132,7 @@ protected: void OnSetFgColour(wxCommandEvent& event); void OnSetBgColour(wxCommandEvent& event); void OnSetRowLines(wxCommandEvent& event); + void OnCustomHeaderAttr(wxCommandEvent& event); void OnToggleMultiSel(wxCommandEvent& event); void OnShowColInfo(wxCommandEvent& event); void OnShowSelInfo(wxCommandEvent& event); @@ -221,6 +222,7 @@ enum LIST_SET_FG_COL, LIST_SET_BG_COL, LIST_ROW_LINES, + LIST_CUSTOM_HEADER_ATTR, LIST_TOGGLE_MULTI_SEL, LIST_TOGGLE_HEADER, LIST_TOGGLE_BELL, diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 450fee8cda..6a04fe2da3 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -42,6 +42,7 @@ #include "wx/vector.h" #include "wx/msw/private.h" +#include "wx/msw/private/customdraw.h" #include "wx/msw/private/keyboard.h" // Currently gcc doesn't define NMLVFINDITEM, and DMC only defines @@ -229,6 +230,34 @@ public: wxDECLARE_NO_COPY_CLASS(wxMSWListItemData); }; +// wxMSWListHeaderCustomDraw: custom draw helper for the header +class wxMSWListHeaderCustomDraw : public wxMSWImpl::CustomDraw +{ +public: + wxMSWListHeaderCustomDraw() + { + } + + // Make this field public to let wxListCtrl update it directly when its + // header attributes change. + wxItemAttr m_attr; + +private: + virtual bool HasCustomDrawnItems() const wxOVERRIDE + { + // We only exist if the header does need to be custom drawn. + return true; + } + + virtual const wxItemAttr* + GetItemAttr(DWORD_PTR WXUNUSED(dwItemSpec)) const wxOVERRIDE + { + // We use the same attribute for all items for now. + return &m_attr; + } +}; + + wxBEGIN_EVENT_TABLE(wxListCtrl, wxListCtrlBase) EVT_PAINT(wxListCtrl::OnPaint) EVT_CHAR_HOOK(wxListCtrl::OnCharHook) @@ -255,6 +284,8 @@ void wxListCtrl::Init() m_textCtrl = NULL; m_hasAnyAttr = false; + + m_headerCustomDraw = NULL; } bool wxListCtrl::Create(wxWindow *parent, @@ -434,6 +465,8 @@ wxListCtrl::~wxListCtrl() delete m_imageListSmall; if (m_ownsImageListState) delete m_imageListState; + + delete m_headerCustomDraw; } // ---------------------------------------------------------------------------- @@ -520,6 +553,68 @@ bool wxListCtrl::SetBackgroundColour(const wxColour& col) return true; } +bool wxListCtrl::SetHeaderAttr(const wxItemAttr& attr) +{ + // We need to propagate the change of the font to the native header window + // as it also affects its layout. + bool fontChanged; + + // Start or stop custom drawing the header. + if ( attr.IsDefault() ) + { + if ( !m_headerCustomDraw ) + { + // Nothing changed, skip refreshing the control below. + return true; + } + + fontChanged = m_headerCustomDraw->m_attr.HasFont(); + + delete m_headerCustomDraw; + m_headerCustomDraw = NULL; + } + else // We do have custom attributes. + { + if ( !m_headerCustomDraw ) + m_headerCustomDraw = new wxMSWListHeaderCustomDraw(); + + if ( m_headerCustomDraw->m_attr == attr ) + { + // As above, skip refresh. + return true; + } + + fontChanged = attr.GetFont() != m_headerCustomDraw->m_attr.GetFont(); + + m_headerCustomDraw->m_attr = attr; + } + + if ( HWND hwndHdr = ListView_GetHeader(GetHwnd()) ) + { + if ( fontChanged ) + { + // Don't just reset the font if no font is specified, as the header + // uses the same font as the listview control and not the ugly + // default GUI font by default. + const wxFont& font = attr.HasFont() ? attr.GetFont() : GetFont(); + + // We need to tell the header about its new font to let it compute + // its new height. + ::SendMessage(hwndHdr, WM_SETFONT, + (WPARAM)GetHfontOf(font), MAKELPARAM(TRUE, 0)); + } + + // Refreshing the listview makes it notice the change in height of its + // header and redraws it too. We probably could do something less than + // a full refresh, but it doesn't seem to be worth it, the header + // attributes won't be changed that often, so keep it simple for now. + Refresh(); + } + //else: header not shown or not in report view? + + return true; +} + // Gets information about this column bool wxListCtrl::GetColumn(int col, wxListItem& item) const { @@ -2085,6 +2180,15 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) // doesn't seem to have any negative consequences return true; + case NM_CUSTOMDRAW: + if ( m_headerCustomDraw ) + { + *result = m_headerCustomDraw->HandleCustomDraw(lParam); + if ( *result != CDRF_DODEFAULT ) + return true; + } + wxFALLTHROUGH; + default: ignore = true; }