From 418a96d44c354376a1077ec3b3372fa0079a0347 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 17 Dec 2015 14:27:53 +0100 Subject: [PATCH 1/4] Support native MSW check-boxes in wxListCtrl. --- include/wx/listbase.h | 10 +++++++++ include/wx/msw/listctrl.h | 6 +++++ src/common/listctrlcmn.cpp | 2 ++ src/msw/listctrl.cpp | 46 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/include/wx/listbase.h b/include/wx/listbase.h index 07e70447c8..88e964b652 100644 --- a/include/wx/listbase.h +++ b/include/wx/listbase.h @@ -460,6 +460,12 @@ public: void SetAlternateRowColour(const wxColour& colour); wxColour GetAlternateRowColour() const { return m_alternateRowColour.GetBackgroundColour(); } + //checkboxes + virtual bool HasCheckboxes() const { return false; } + virtual void EnableCheckboxes(bool WXUNUSED(enable) = true) { } + virtual bool IsItemChecked(long WXUNUSED(item)) const { return false; } + virtual void CheckItem(long WXUNUSED(item), bool WXUNUSED(check)) { } + protected: // Real implementations methods to which our public forwards. virtual long DoInsertColumn(long col, const wxListItem& info) = 0; @@ -563,6 +569,8 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_COL_BEGIN_DRAG, wxListEve wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_COL_DRAGGING, wxListEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_COL_END_DRAG, wxListEvent ); wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_ITEM_FOCUSED, wxListEvent ); +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_ITEM_CHECKED, wxListEvent ); +wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_CORE, wxEVT_LIST_ITEM_UNCHECKED, wxListEvent ); typedef void (wxEvtHandler::*wxListEventFunction)(wxListEvent&); @@ -593,6 +601,8 @@ typedef void (wxEvtHandler::*wxListEventFunction)(wxListEvent&); #define EVT_LIST_ITEM_MIDDLE_CLICK(id, fn) wx__DECLARE_LISTEVT(ITEM_MIDDLE_CLICK, id, fn) #define EVT_LIST_ITEM_ACTIVATED(id, fn) wx__DECLARE_LISTEVT(ITEM_ACTIVATED, id, fn) #define EVT_LIST_ITEM_FOCUSED(id, fn) wx__DECLARE_LISTEVT(ITEM_FOCUSED, id, fn) +#define EVT_LIST_ITEM_CHECKED(id, fn) wx__DECLARE_LISTEVT(ITEM_CHECKED, id, fn) +#define EVT_LIST_ITEM_UNCHECKED(id, fn) wx__DECLARE_LISTEVT(ITEM_UNCHECKED, id, fn) #define EVT_LIST_CACHE_HINT(id, fn) wx__DECLARE_LISTEVT(CACHE_HINT, id, fn) diff --git a/include/wx/msw/listctrl.h b/include/wx/msw/listctrl.h index 48449f8b1c..facef5eff0 100644 --- a/include/wx/msw/listctrl.h +++ b/include/wx/msw/listctrl.h @@ -216,6 +216,12 @@ public: void SetItemFont( long item, const wxFont &f); wxFont GetItemFont( long item ) const; + // Checkbox state of an item + bool HasCheckboxes() const; + void EnableCheckboxes(bool enable = true); + bool IsItemChecked(long item) const; + void CheckItem(long item, bool check); + // Gets the number of selected items in the list control int GetSelectedItemCount() const; diff --git a/src/common/listctrlcmn.cpp b/src/common/listctrlcmn.cpp index 0b4ddf6a5e..25f29b8042 100644 --- a/src/common/listctrlcmn.cpp +++ b/src/common/listctrlcmn.cpp @@ -52,6 +52,8 @@ wxDEFINE_EVENT( wxEVT_LIST_ITEM_RIGHT_CLICK, wxListEvent ); wxDEFINE_EVENT( wxEVT_LIST_ITEM_MIDDLE_CLICK, wxListEvent ); wxDEFINE_EVENT( wxEVT_LIST_ITEM_ACTIVATED, wxListEvent ); wxDEFINE_EVENT( wxEVT_LIST_ITEM_FOCUSED, wxListEvent ); +wxDEFINE_EVENT( wxEVT_LIST_ITEM_CHECKED, wxListEvent ); +wxDEFINE_EVENT( wxEVT_LIST_ITEM_UNCHECKED, wxListEvent ); wxDEFINE_EVENT( wxEVT_LIST_CACHE_HINT, wxListEvent ); // ----------------------------------------------------------------------------- diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 2019554161..6f58ced593 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -1211,6 +1211,28 @@ wxFont wxListCtrl::GetItemFont( long item ) const return f; } +bool wxListCtrl::HasCheckboxes() const +{ + DWORD currStyle = ListView_GetExtendedListViewStyle(GetHwnd()); + return ((currStyle & LVS_EX_CHECKBOXES) > 0); +} + +void wxListCtrl::EnableCheckboxes(bool enable) +{ + DWORD cbStyle = enable ? LVS_EX_CHECKBOXES : 0; + ListView_SetExtendedListViewStyleEx(GetHwnd(), LVS_EX_CHECKBOXES, cbStyle); +} + +void wxListCtrl::CheckItem(long item, bool state) +{ + ListView_SetCheckState(GetHwnd(), (UINT)item, (BOOL)state); +} + +bool wxListCtrl::IsItemChecked(long item) const +{ + return (ListView_GetCheckState(GetHwnd(), (UINT)item) != 0); +} + // Gets the number of selected items in the list control int wxListCtrl::GetSelectedItemCount() const { @@ -2213,6 +2235,30 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) ? wxEVT_LIST_ITEM_SELECTED : wxEVT_LIST_ITEM_DESELECTED; } + + if ((stNew & LVIS_STATEIMAGEMASK) != (stOld & LVIS_STATEIMAGEMASK)) + { + if (stOld == INDEXTOSTATEIMAGEMASK(0)) + { + // item does not yet have a state + // occurs when checkboxes are enabled and when a new item is added + eventType = wxEVT_NULL; + } + else if (stNew == INDEXTOSTATEIMAGEMASK(1)) + { + eventType = wxEVT_LIST_ITEM_UNCHECKED; + } + else if (stNew == INDEXTOSTATEIMAGEMASK(2)) + { + eventType = wxEVT_LIST_ITEM_CHECKED; + } + else { + eventType = wxEVT_NULL; + wxLogDebug(wxT("Unknown LVIS_STATEIMAGE state: %u"), stNew); + } + + event.m_itemIndex = iItem; + } } if ( eventType == wxEVT_NULL ) From 9166500f30eacfd77da6ca27edbde7f42437265d Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 17 Dec 2015 14:29:00 +0100 Subject: [PATCH 2/4] Documentation for wxListCtrl checkboxes. --- interface/wx/listctrl.h | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/interface/wx/listctrl.h b/interface/wx/listctrl.h index ccf1fbfb78..73ab7d017a 100644 --- a/interface/wx/listctrl.h +++ b/interface/wx/listctrl.h @@ -256,6 +256,12 @@ enum @event{EVT_LIST_CACHE_HINT(id, func)} Prepare cache for a virtual list control. Processes a @c wxEVT_LIST_CACHE_HINT event type. + @event{EVT_LIST_ITEM_CHECKED(id, func)} + The item has been checked. + Processes a @c wxEVT_LIST_ITEM_CHECKED event type (new since wxWidgets 3.1.0). + @event{EVT_LIST_ITEM_UNCHECKED(id, func)} + The item has been unchecked. + Processes a @c wxEVT_LIST_ITEM_UNCHECKED event type (new since wxWidgets 3.1.0). @endEventTable @note Under wxMSW this control uses wxSystemThemedControl for an explorer @@ -1221,6 +1227,54 @@ public: */ bool SortItems(wxListCtrlCompare fnSortCallBack, wxIntPtr data); + /** + Returns true if checkboxes are enabled for list items. + + @since 3.1.0 + + @onlyfor{wxmsw} + */ + bool GetCheckboxesEnabled() const; + + /** + Enable or disable checkboxes for list items. + + @param enable + If @true, enable checkboxes, otherwise disable checkboxes. + + @since 3.1.0 + + @onlyfor{wxmsw} + */ + void EnableCheckboxes(bool enable = true); + + /** + Return true if the checkbox if a wxListItem is checked. + + @param item + Item (zero-based) index. + + @since 3.1.0 + + @onlyfor{wxmsw} + */ + bool IsItemChecked(long item) const; + + /** + Check or uncheck a wxListItem. + + @param item + Item (zero-based) index. + + @param check + If @true, check the item, otherwise uncheck. + + @since 3.1.0 + + @onlyfor{wxmsw} + */ + void CheckItem(long item, bool check); + protected: /** @@ -1343,6 +1397,10 @@ protected: A column has been resized by the user. @event{EVT_LIST_CACHE_HINT(id, func)} Prepare cache for a virtual list control + @event{EVT_LIST_ITEM_CHECKED(id, func)} + The item has been checked (new since wxWidgets 3.1.0). + @event{EVT_LIST_ITEM_UNCHECKED(id, func)} + The item has been unchecked (new since wxWidgets 3.1.0). @endEventTable @@ -1456,6 +1514,8 @@ wxEventType wxEVT_LIST_COL_BEGIN_DRAG; wxEventType wxEVT_LIST_COL_DRAGGING; wxEventType wxEVT_LIST_COL_END_DRAG; wxEventType wxEVT_LIST_ITEM_FOCUSED; +wxEventType wxEVT_LIST_ITEM_CHECKED; +wxEventType wxEVT_LIST_ITEM_UNCHECKED; /** From 5326132c21f083dd2d872b42fc6ee82d7ec08bea Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 17 Dec 2015 14:29:41 +0100 Subject: [PATCH 3/4] Updated wxListCtrl sample with check-boxes functionality. --- samples/listctrl/listtest.cpp | 69 +++++++++++++++++++++++++++++++++++ samples/listctrl/listtest.h | 9 +++++ 2 files changed, 78 insertions(+) diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index d91afe13a6..5a95a2b626 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -154,11 +154,15 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(LIST_MAC_USE_GENERIC, MyFrame::OnToggleMacUseGeneric) #endif // __WXOSX__ EVT_MENU(LIST_FIND, MyFrame::OnFind) + EVT_MENU(LIST_TOGGLE_CHECKBOX, MyFrame::OnToggleItemCheckbox) + EVT_MENU(LIST_GET_CHECKBOX, MyFrame::OnGetItemCheckbox) + EVT_MENU(LIST_TOGGLE_CHECKBOXES, MyFrame::OnToggleCheckboxes) EVT_UPDATE_UI(LIST_SHOW_COL_INFO, MyFrame::OnUpdateUIEnableInReport) EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateUIEnableInReport) EVT_UPDATE_UI(LIST_TOGGLE_MULTI_SEL, MyFrame::OnUpdateToggleMultiSel) + EVT_UPDATE_UI(LIST_TOGGLE_CHECKBOXES, MyFrame::OnUpdateToggleCheckboxes) EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateToggleHeader) EVT_UPDATE_UI(LIST_ROW_LINES, MyFrame::OnUpdateRowLines) wxEND_EVENT_TABLE() @@ -261,6 +265,12 @@ MyFrame::MyFrame(const wxChar *title) menuList->AppendCheckItem(LIST_TOGGLE_HEADER, "Toggle &header\tCtrl-H"); menuList->Check(LIST_TOGGLE_HEADER, true); menuList->AppendCheckItem(LIST_TOGGLE_BELL, "Toggle &bell on no match"); + menuList->AppendSeparator(); + menuList->AppendCheckItem(LIST_TOGGLE_CHECKBOXES, + wxT("&Enable Checkboxes")); + menuList->Check(LIST_TOGGLE_CHECKBOXES, true); + menuList->Append(LIST_TOGGLE_CHECKBOX, wxT("Toggle the item checkbox state")); + menuList->Append(LIST_GET_CHECKBOX, wxT("Get the item checkbox state")); wxMenu *menuCol = new wxMenu; menuCol->Append(LIST_SET_FG_COL, wxT("&Foreground colour...")); @@ -835,6 +845,22 @@ void MyFrame::OnUpdateToggleMultiSel(wxUpdateUIEvent& event) event.Check(!m_listCtrl->HasFlag(wxLC_SINGLE_SEL)); } +void MyFrame::OnToggleCheckboxes(wxCommandEvent& WXUNUSED(event)) +{ + m_listCtrl->EnableCheckboxes(!m_listCtrl->HasCheckboxes()); + + m_logWindow->WriteText(wxString::Format(wxT("Checkboxes: %s\n"), + m_listCtrl->HasCheckboxes() ? wxT("enabled") : wxT("disabled"))); +} + +void MyFrame::OnUpdateToggleCheckboxes(wxUpdateUIEvent& event) +{ + bool cbEnabled = m_listCtrl->HasCheckboxes(); + event.Check(cbEnabled); + GetMenuBar()->Enable(LIST_TOGGLE_CHECKBOX, cbEnabled); + GetMenuBar()->Enable(LIST_GET_CHECKBOX, cbEnabled); +} + void MyFrame::OnUpdateToggleHeader(wxUpdateUIEvent& event) { event.Check(!m_listCtrl->HasFlag(wxLC_NO_HEADER)); @@ -893,6 +919,33 @@ void MyFrame::OnEdit(wxCommandEvent& WXUNUSED(event)) } } +void MyFrame::OnToggleItemCheckbox(wxCommandEvent& WXUNUSED(event)) +{ + long item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + while (item != -1) + { + bool checked = m_listCtrl->IsItemChecked(item); + m_listCtrl->CheckItem(item, !checked); + + item = m_listCtrl->GetNextItem(item, wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + } +} + +void MyFrame::OnGetItemCheckbox(wxCommandEvent& WXUNUSED(event)) +{ + long item = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + while (item != -1) + { + bool checked = m_listCtrl->IsItemChecked(item); + + wxLogMessage(wxT("Item %ld is %s"), item, checked ? wxT("checked") : wxT("unchecked")); + + item = m_listCtrl->GetNextItem(item, wxLIST_NEXT_ALL, + wxLIST_STATE_SELECTED); + } +} + void MyFrame::OnDelete(wxCommandEvent& WXUNUSED(event)) { if ( m_listCtrl->GetItemCount() ) @@ -935,6 +988,8 @@ wxBEGIN_EVENT_TABLE(MyListCtrl, wxListCtrl) EVT_LIST_KEY_DOWN(LIST_CTRL, MyListCtrl::OnListKeyDown) EVT_LIST_ITEM_ACTIVATED(LIST_CTRL, MyListCtrl::OnActivated) EVT_LIST_ITEM_FOCUSED(LIST_CTRL, MyListCtrl::OnFocused) + EVT_LIST_ITEM_CHECKED(LIST_CTRL, MyListCtrl::OnChecked) + EVT_LIST_ITEM_UNCHECKED(LIST_CTRL, MyListCtrl::OnUnChecked) EVT_LIST_COL_CLICK(LIST_CTRL, MyListCtrl::OnColClick) EVT_LIST_COL_RIGHT_CLICK(LIST_CTRL, MyListCtrl::OnColRightClick) @@ -1118,6 +1173,20 @@ void MyListCtrl::OnFocused(wxListEvent& event) event.Skip(); } +void MyListCtrl::OnChecked(wxListEvent& event) +{ + LogEvent(event, wxT("OnChecked")); + + event.Skip(); +} + +void MyListCtrl::OnUnChecked(wxListEvent& event) +{ + LogEvent(event, wxT("OnUnChecked")); + + event.Skip(); +} + void MyListCtrl::OnListKeyDown(wxListEvent& event) { long item; diff --git a/samples/listctrl/listtest.h b/samples/listctrl/listtest.h index cc8e84b3b5..29024eb724 100644 --- a/samples/listctrl/listtest.h +++ b/samples/listctrl/listtest.h @@ -61,6 +61,8 @@ public: void OnListKeyDown(wxListEvent& event); void OnActivated(wxListEvent& event); void OnFocused(wxListEvent& event); + void OnChecked(wxListEvent& event); + void OnUnChecked(wxListEvent& event); void OnCacheHint(wxListEvent& event); void OnChar(wxKeyEvent& event); @@ -146,9 +148,13 @@ protected: void OnToggleMacUseGeneric(wxCommandEvent& event); #endif // __WXOSX__ void OnFind(wxCommandEvent& event); + void OnToggleItemCheckbox(wxCommandEvent& event); + void OnGetItemCheckbox(wxCommandEvent& event); + void OnToggleCheckboxes(wxCommandEvent& event); void OnUpdateUIEnableInReport(wxUpdateUIEvent& event); void OnUpdateToggleMultiSel(wxUpdateUIEvent& event); + void OnUpdateToggleCheckboxes(wxUpdateUIEvent& event); void OnUpdateToggleHeader(wxUpdateUIEvent& event); void OnUpdateRowLines(wxUpdateUIEvent& event); @@ -217,6 +223,9 @@ enum LIST_TOGGLE_MULTI_SEL, LIST_TOGGLE_HEADER, LIST_TOGGLE_BELL, + LIST_TOGGLE_CHECKBOX, + LIST_GET_CHECKBOX, + LIST_TOGGLE_CHECKBOXES, LIST_TOGGLE_FIRST, LIST_SHOW_COL_INFO, LIST_SHOW_SEL_INFO, From c57c281c440af26be7a5277e4d6f6d7348cd3dba Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Fri, 15 Jan 2016 20:48:39 +0100 Subject: [PATCH 4/4] Silenced unused value warning in 64bit builds with GCC. --- src/msw/listctrl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index 6f58ced593..a43545cb09 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -1219,8 +1219,9 @@ bool wxListCtrl::HasCheckboxes() const void wxListCtrl::EnableCheckboxes(bool enable) { - DWORD cbStyle = enable ? LVS_EX_CHECKBOXES : 0; - ListView_SetExtendedListViewStyleEx(GetHwnd(), LVS_EX_CHECKBOXES, cbStyle); + LPARAM newStyle = enable ? LVS_EX_CHECKBOXES : 0; + DWORD oldStyle = ListView_SetExtendedListViewStyleEx(GetHwnd(), LVS_EX_CHECKBOXES, newStyle); + wxUnusedVar(oldStyle); } void wxListCtrl::CheckItem(long item, bool state)