From d8ec0aa001aeb44c99a8e63c90134ebc382a3e34 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 28 Nov 2021 19:19:59 +0100 Subject: [PATCH] Support sort indicators in wxListCtrl header --- include/wx/generic/listctrl.h | 7 +++ include/wx/generic/private/listctrl.h | 4 ++ include/wx/listbase.h | 8 +++ include/wx/msw/listctrl.h | 14 +++++ interface/wx/listctrl.h | 66 ++++++++++++++++++++ src/generic/listctrl.cpp | 76 ++++++++++++++++++++++- src/msw/listctrl.cpp | 88 +++++++++++++++++++++++++++ 7 files changed, 262 insertions(+), 1 deletion(-) diff --git a/include/wx/generic/listctrl.h b/include/wx/generic/listctrl.h index 022d2d1316..9a7e3979cf 100644 --- a/include/wx/generic/listctrl.h +++ b/include/wx/generic/listctrl.h @@ -115,6 +115,13 @@ public: virtual bool IsItemChecked(long item) const wxOVERRIDE; virtual void CheckItem(long item, bool check) wxOVERRIDE; + void EnableSortIndicator(const bool enable = true) wxOVERRIDE; + bool IsSortIndicatorEnabled() const wxOVERRIDE; + void ShowSortIndicator(const int idx, const bool ascending = true) wxOVERRIDE; + void RemoveSortIndicator() wxOVERRIDE; + int GetSortIndicator() const wxOVERRIDE; + bool IsAscendingSortIndicator() const wxOVERRIDE; + void SetSingleStyle( long style, bool add = true ) ; void SetWindowStyleFlag( long style ) wxOVERRIDE; void RecreateWindow() {} diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h index ae0b82fe21..0996bed842 100644 --- a/include/wx/generic/private/listctrl.h +++ b/include/wx/generic/private/listctrl.h @@ -381,6 +381,10 @@ public: int m_colToSend; int m_widthToSend; + bool m_enableSortCol; + bool m_sortAsc; + int m_sortCol; + virtual wxWindow *GetMainWindowOfCompositeControl() wxOVERRIDE { return GetParent(); } virtual void OnInternalIdle() wxOVERRIDE; diff --git a/include/wx/listbase.h b/include/wx/listbase.h index 3441b3b84c..ce4fc2aedb 100644 --- a/include/wx/listbase.h +++ b/include/wx/listbase.h @@ -446,6 +446,14 @@ public: virtual bool IsItemChecked(long WXUNUSED(item)) const { return false; } virtual void CheckItem(long WXUNUSED(item), bool WXUNUSED(check)) { } + // Sort indicator in header. + virtual void EnableSortIndicator(const bool WXUNUSED(enable) = true) { } + virtual bool IsSortIndicatorEnabled() const { return false; } + virtual void ShowSortIndicator(const int WXUNUSED(idx), const bool WXUNUSED(ascending) = true) { } + virtual void RemoveSortIndicator() { } + virtual int GetSortIndicator() const { return -1; } + virtual bool IsAscendingSortIndicator() const { return true; } + protected: // Return pointer to the corresponding m_imagesXXX. const wxWithImages* GetImages(int which) const; diff --git a/include/wx/msw/listctrl.h b/include/wx/msw/listctrl.h index 720ee52d9b..cdbe92cc6d 100644 --- a/include/wx/msw/listctrl.h +++ b/include/wx/msw/listctrl.h @@ -225,6 +225,14 @@ public: virtual bool IsItemChecked(long item) const wxOVERRIDE; virtual void CheckItem(long item, bool check) wxOVERRIDE; + // Sort indicator in header + void EnableSortIndicator(const bool enable = true) wxOVERRIDE; + bool IsSortIndicatorEnabled() const wxOVERRIDE; + void ShowSortIndicator(const int idx, const bool ascending = true) wxOVERRIDE; + void RemoveSortIndicator() wxOVERRIDE; + int GetSortIndicator() const wxOVERRIDE; + bool IsAscendingSortIndicator() const wxOVERRIDE; + // Gets the number of selected items in the list control int GetSelectedItemCount() const; @@ -418,6 +426,10 @@ protected: int m_colCount; // Windows doesn't have GetColumnCount so must // keep track of inserted/deleted columns + bool m_enableSortCol; + bool m_sortAsc; + int m_sortCol; + // all wxMSWListItemData objects we use wxVector m_internalData; @@ -445,6 +457,8 @@ private: // in-place editor control. void OnCharHook(wxKeyEvent& event); + // Draw the sort arrow arror in the header. + void DrawSortArrow(); // Object using for header custom drawing if necessary, may be NULL. wxMSWListHeaderCustomDraw* m_headerCustomDraw; diff --git a/interface/wx/listctrl.h b/interface/wx/listctrl.h index 1629b6c510..bc6c1ac9a4 100644 --- a/interface/wx/listctrl.h +++ b/interface/wx/listctrl.h @@ -1420,6 +1420,72 @@ public: */ void ExtendRulesAndAlternateColour(bool extend = true); + /** + Enable or disable showing a sort indicator in the header bar. + Sort indicators are only shown in report view. + + When clicking on the header of a column, this column will get the sort- + indicator in ascending order, or toggle it in the opposite order. To + sort the list, call SortItems() in EVT_LIST_COL_CLICK. + + @note In wxMSW, this will disable the header icon of the column. + + @param enable + If @true, enable showing a sort indicator, otherwise disable. + + @since 3.1.6 + */ + void EnableSortIndicator(const bool enable); + + /** + Returns true if a sort indicator is enabled. + + @see EnableSortIndicator() + + @since 3.1.6 + */ + bool IsSortIndicatorEnabled() const; + + /** + Show the sort indicator of a specific column in a specific direction. + Sort indicators have to be enabled using EnableSortIndicator(). + + @note This does not actually sort the list, use SortItems() for this. + + @param idx + The column to set the sort indicator for. + If @c -1 is given, then the currently shown sort indicator + will be removed. + @param ascending + If @true or @false show the sort indicator corresponding to + ascending or descending sort order respectively. + + @since 3.1.6 + */ + void ShowSortIndicator(const int idx, const bool ascending = true); + + /** + Remove the sort indicator from the column being used as sort key. + + @since 3.1.6 + */ + int RemoveSortIndicator() const; + + /** + Returns the column that shows the sort indicator. + + @since 3.1.6 + */ + int GetSortIndicator() const; + + /** + Returns @true if the sort indicator direction is ascending, + @false when the direction is descending. + + @since 3.1.6 + */ + bool IsAscendingSortIndicator() const; + protected: /** diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index befb26bc2b..f62ad4408d 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -981,6 +981,10 @@ wxListHeaderWindow::wxListHeaderWindow() m_owner = NULL; m_resizeCursor = NULL; + + m_enableSortCol = false; + m_sortAsc = true; + m_sortCol = -1; } bool wxListHeaderWindow::Create( wxWindow *win, @@ -1099,6 +1103,15 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) flags |= wxCONTROL_SELECTED; #endif + wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE; + if ( !m_owner->IsVirtual() && m_enableSortCol && i == m_sortCol ) + { + if ( m_sortAsc ) + sortArrow = wxHDR_SORT_ICON_UP; + else + sortArrow = wxHDR_SORT_ICON_DOWN; + } + if (i == 0) flags |= wxCONTROL_SPECIAL; // mark as first column @@ -1107,7 +1120,8 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) this, dc, wxRect(x, HEADER_OFFSET_Y, cw, ch), - flags + flags, + sortArrow ); // see if we have enough space for the column label @@ -1320,6 +1334,12 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) colItem.SetState(state & ~wxLIST_STATE_SELECTED); m_owner->SetColumn(i, colItem); } + + if ( m_sortCol != m_column ) + m_sortAsc = true; + else + m_sortAsc = !m_sortAsc; + m_sortCol = m_column; } SendListEvent( event.LeftDown() @@ -5064,6 +5084,60 @@ bool wxGenericListCtrl::IsItemChecked(long item) const return m_mainWin->IsItemChecked(item); } +void wxGenericListCtrl::EnableSortIndicator(const bool enable) +{ + if ( m_headerWin ) + { + m_headerWin->m_enableSortCol = enable; + Refresh(); + } +} + +bool wxGenericListCtrl::IsSortIndicatorEnabled() const +{ + return m_headerWin && m_headerWin->m_enableSortCol; +} + +void wxGenericListCtrl::ShowSortIndicator(const int idx, const bool ascending) +{ + if ( idx == -1 ) + { + RemoveSortIndicator(); + } + else if ( m_headerWin ) + { + m_headerWin->m_sortCol = idx; + m_headerWin->m_sortAsc = ascending; + Refresh(); + } +} + +void wxGenericListCtrl::RemoveSortIndicator() +{ + if ( m_headerWin ) + { + m_headerWin->m_sortCol = -1; + m_headerWin->m_sortAsc = true; + Refresh(); + } +} + +int wxGenericListCtrl::GetSortIndicator() const +{ + if ( m_headerWin ) + return m_headerWin->m_sortCol; + + return -1; +} + +bool wxGenericListCtrl::IsAscendingSortIndicator() const +{ + if ( m_headerWin ) + return m_headerWin->m_sortAsc; + + return true; +} + void wxGenericListCtrl::SetSingleStyle( long style, bool add ) { wxASSERT_MSG( !(style & wxLC_VIRTUAL), diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index b13e48bfd2..756c517d37 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -278,6 +278,10 @@ void wxListCtrl::Init() m_colCount = 0; m_textCtrl = NULL; + m_enableSortCol = false; + m_sortAsc = true; + m_sortCol = -1; + m_hasAnyAttr = false; m_headerCustomDraw = NULL; @@ -1452,6 +1456,48 @@ bool wxListCtrl::IsItemChecked(long item) const return ListView_GetCheckState(GetHwnd(), (UINT)item) != 0; } +void wxListCtrl::EnableSortIndicator(const bool enable) +{ + m_enableSortCol = enable; + DrawSortArrow(); +} + +bool wxListCtrl::IsSortIndicatorEnabled() const +{ + return m_enableSortCol; +} + +void wxListCtrl::ShowSortIndicator(const int idx, const bool ascending) +{ + if ( idx == -1 ) + { + RemoveSortIndicator(); + } + else + { + m_sortCol = idx; + m_sortAsc = ascending; + DrawSortArrow(); + } +} + +void wxListCtrl::RemoveSortIndicator() +{ + m_sortCol = -1; + m_sortAsc = true; + DrawSortArrow(); +} + +int wxListCtrl::GetSortIndicator() const +{ + return m_sortCol; +} + +bool wxListCtrl::IsAscendingSortIndicator() const +{ + return m_sortAsc; +} + // Gets the number of selected items in the list control int wxListCtrl::GetSelectedItemCount() const { @@ -2045,6 +2091,8 @@ long wxListCtrl::DoInsertColumn(long col, const wxListItem& item) SetColumnWidth(n, wxLIST_AUTOSIZE_USEHEADER); } + DrawSortArrow(); + return n; } @@ -2419,6 +2467,13 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) break; case LVN_COLUMNCLICK: + if ( m_sortCol != nmLV->iSubItem ) + m_sortAsc = true; + else + m_sortAsc = !m_sortAsc; + m_sortCol = nmLV->iSubItem; + DrawSortArrow(); + eventType = wxEVT_LIST_COL_CLICK; event.m_itemIndex = -1; event.m_col = nmLV->iSubItem; @@ -3361,6 +3416,39 @@ void wxListCtrl::OnCharHook(wxKeyEvent& event) event.Skip(); } +void wxListCtrl::DrawSortArrow() +{ + if ( HasFlag(wxLC_SORT_ASCENDING) || HasFlag(wxLC_SORT_DESCENDING) ) + { + m_sortCol = 0; + m_sortAsc = HasFlag(wxLC_SORT_ASCENDING); + } + + LV_COLUMN lvCol; + wxZeroMemory(lvCol); + lvCol.mask = LVCF_FMT; + + for ( int col = 0; col < m_colCount; ++col ) + { + if ( ListView_GetColumn(GetHwnd(), col, &lvCol) ) + { + if ( !IsVirtual() && m_enableSortCol && col == m_sortCol ) + { + if ( m_sortAsc ) + lvCol.fmt = (lvCol.fmt & ~HDF_SORTDOWN) | HDF_SORTUP; + else + lvCol.fmt = (lvCol.fmt & ~HDF_SORTUP) | HDF_SORTDOWN; + } + else + { + lvCol.fmt = lvCol.fmt & ~(HDF_SORTDOWN | HDF_SORTUP); + } + + ListView_SetColumn(GetHwnd(), col, &lvCol); + } + } +} + WXLRESULT wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) {