From 9d9b0c51c88258130ad1d5e7167dc6937707d0bc Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Tue, 19 Nov 2019 21:07:04 +0200 Subject: [PATCH 1/5] A test button to the listctrl sample --- samples/listctrl/listtest.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index 1c4213098b..ce9019dcc7 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -53,6 +53,8 @@ // Constants and globals // ---------------------------------------------------------------------------- +wxButton *m_button; + const wxChar *SMALL_VIRTUAL_VIEW_ITEMS[][2] = { { wxT("Cat"), wxT("meow") }, @@ -308,8 +310,12 @@ MyFrame::MyFrame(const wxString& title) CreateStatusBar(); #endif // wxUSE_STATUSBAR + m_button = new wxButton(m_panel, wxID_ANY, "Do something with the selected item"); + m_button->Enable(false); + wxBoxSizer* const sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(m_listCtrl, wxSizerFlags(2).Expand().Border()); + sizer->Add(m_button, wxSizerFlags(2)); sizer->Add(m_logWindow, wxSizerFlags(1).Expand().Border()); m_panel->SetSizer(sizer); @@ -1184,7 +1190,9 @@ void MyListCtrl::OnDeleteAllItems(wxListEvent& event) void MyListCtrl::OnSelected(wxListEvent& event) { - LogEvent(event, "OnSelected"); + m_button->Enable(true); + + LogEvent(event, "OnSelected"); if ( GetWindowStyle() & wxLC_REPORT ) { @@ -1206,6 +1214,8 @@ void MyListCtrl::OnSelected(wxListEvent& event) void MyListCtrl::OnDeselected(wxListEvent& event) { + if (GetSelectedItemCount() == 0) + m_button->Enable(false); LogEvent(event, "OnDeselected"); } @@ -1258,7 +1268,7 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event) if ( !wxGetKeyState(WXK_SHIFT) ) { - LogEvent(event, "OnListKeyDown"); + //LogEvent(event, "OnListKeyDown"); event.Skip(); } @@ -1409,7 +1419,7 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event) wxFALLTHROUGH; default: - LogEvent(event, "OnListKeyDown"); + //LogEvent(event, "OnListKeyDown"); event.Skip(); } From 96b83a1523bc48411a8690a90aaf83cef62f49bb Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Tue, 12 Nov 2019 21:22:05 +0200 Subject: [PATCH 2/5] Make virtual lists send DESELECTED events consistently on both implementations In the case when a listctrl is clicked outside of any item, the item is visually deselected, and it is logical that a DESELECTED is sent. For non-virtual lists this would happen, but for virtual lists it would either happen or not happen depending on implementation (MSW/generic) and mode (single/multi). From now on the DESELECTED event is always sent. --- interface/wx/listctrl.h | 2 +- src/generic/listctrl.cpp | 7 ++- src/msw/listctrl.cpp | 112 ++++++++++++++++++++------------------- 3 files changed, 65 insertions(+), 56 deletions(-) diff --git a/interface/wx/listctrl.h b/interface/wx/listctrl.h index fc7b0a101c..766d3a646f 100644 --- a/interface/wx/listctrl.h +++ b/interface/wx/listctrl.h @@ -1442,7 +1442,7 @@ protected: control itself when this event is generated, see @ref overview_events_with_mouse_capture "event handling overview". @event{EVT_LIST_ITEM_DESELECTED(id, func)} - The item has been deselected. + The item has been deselected. GetIndex() may be -1 with virtual lists. @event{EVT_LIST_ITEM_ACTIVATED(id, func)} The item has been activated (ENTER or double click). @event{EVT_LIST_ITEM_FOCUSED(id, func)} diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 141531cc75..b4363d0769 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -2447,7 +2447,8 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) else m_dragCount = 0; - // The only mouse event that can be generated without any valid item is + // The only mouse events that can be generated without any valid item are + // wxEVT_LIST_ITEM_DESELECTED for virtual lists, and // wxEVT_LIST_ITEM_RIGHT_CLICK as it can be useful to have a global // popup menu for the list control itself which should be shown even when // the user clicks outside of any item. @@ -2467,6 +2468,10 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) { // reset the selection and bail out HighlightAll(false); + // generate a DESELECTED event for + // virtual multi-selection lists + if ( IsVirtual() && !IsSingleSel() ) + SendNotify( m_lineLastClicked, wxEVT_LIST_ITEM_DESELECTED ); } return; diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index dc9297fefe..e0c492a810 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -2470,74 +2470,78 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) case LVN_ITEMCHANGED: // we translate this catch all message into more interesting // (and more easy to process) wxWidgets events - - // first of all, we deal with the state change events only and - // only for valid items (item == -1 for the virtual list - // control) - if ( nmLV->uChanged & LVIF_STATE && iItem != -1 ) { // temp vars for readability const UINT stOld = nmLV->uOldState; const UINT stNew = nmLV->uNewState; - event.m_item.SetId(iItem); - event.m_item.SetMask(wxLIST_MASK_TEXT | - wxLIST_MASK_IMAGE | - wxLIST_MASK_DATA); - GetItem(event.m_item); - - // has the focus changed? - if ( !(stOld & LVIS_FOCUSED) && (stNew & LVIS_FOCUSED) ) + // first of all, we deal with the state change events only and + // only for valid items (item == -1 for the virtual list + // control) + if ( nmLV->uChanged & LVIF_STATE && + (iItem != -1 || (stNew & LVIS_SELECTED) != (stOld & LVIS_SELECTED))) { - eventType = wxEVT_LIST_ITEM_FOCUSED; - event.m_itemIndex = iItem; - } - if ( (stNew & LVIS_SELECTED) != (stOld & LVIS_SELECTED) ) - { - if ( eventType != wxEVT_NULL ) + event.m_item.SetId(iItem); + event.m_item.SetMask(wxLIST_MASK_TEXT | + wxLIST_MASK_IMAGE | + wxLIST_MASK_DATA); + if (iItem != -1) + GetItem(event.m_item); + + // has the focus changed? + if ( !(stOld & LVIS_FOCUSED) && (stNew & LVIS_FOCUSED) ) { - // focus and selection have both changed: send the - // focus event from here and the selection one - // below - event.SetEventType(eventType); - (void)HandleWindowEvent(event); - } - else // no focus event to send - { - // then need to set m_itemIndex as it wasn't done - // above + eventType = wxEVT_LIST_ITEM_FOCUSED; event.m_itemIndex = iItem; } - eventType = stNew & LVIS_SELECTED - ? wxEVT_LIST_ITEM_SELECTED - : wxEVT_LIST_ITEM_DESELECTED; - } + if ( (stNew & LVIS_SELECTED) != (stOld & LVIS_SELECTED) ) + { + if ( eventType != wxEVT_NULL ) + { + // focus and selection have both changed: send the + // focus event from here and the selection one + // below + event.SetEventType(eventType); + (void)HandleWindowEvent(event); + } + else // no focus event to send + { + // then need to set m_itemIndex as it wasn't done + // above + event.m_itemIndex = iItem; + } - 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(wxS("Unknown LVIS_STATEIMAGE state: %u"), stNew); + eventType = stNew & LVIS_SELECTED + ? wxEVT_LIST_ITEM_SELECTED + : wxEVT_LIST_ITEM_DESELECTED; } - event.m_itemIndex = iItem; + 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(wxS("Unknown LVIS_STATEIMAGE state: %u"), stNew); + } + + event.m_itemIndex = iItem; + } } } From fa16bc05dad41022944a7be4f3cbe95f5e8b0ad4 Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Tue, 26 May 2020 14:32:44 +0300 Subject: [PATCH 3/5] Test DESELECTED events in both virtual and non-virtual listctrls. --- tests/controls/listbasetest.cpp | 11 ++++++++ tests/controls/virtlistctrltest.cpp | 42 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/tests/controls/listbasetest.cpp b/tests/controls/listbasetest.cpp index 40c2a53437..2bee21811d 100644 --- a/tests/controls/listbasetest.cpp +++ b/tests/controls/listbasetest.cpp @@ -203,6 +203,7 @@ void ListBaseTestCase::ItemClick() EventCounter focused(list, wxEVT_LIST_ITEM_FOCUSED); EventCounter activated(list, wxEVT_LIST_ITEM_ACTIVATED); EventCounter rclick(list, wxEVT_LIST_ITEM_RIGHT_CLICK); + EventCounter deselected(list, wxEVT_LIST_ITEM_DESELECTED); wxUIActionSimulator sim; @@ -224,6 +225,15 @@ void ListBaseTestCase::ItemClick() sim.MouseClick(wxMOUSE_BTN_RIGHT); wxYield(); + // We want a point within the listctrl but below any items + point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 50); + + sim.MouseMove(point); + wxYield(); + + sim.MouseClick(); + wxYield(); + // when the first item was selected the focus changes to it, but not // on subsequent clicks @@ -234,6 +244,7 @@ void ListBaseTestCase::ItemClick() #ifndef _WX_GENERIC_LISTCTRL_H_ CPPUNIT_ASSERT_EQUAL(1, focused.GetCount()); CPPUNIT_ASSERT_EQUAL(1, selected.GetCount()); + CPPUNIT_ASSERT_EQUAL(1, deselected.GetCount()); #endif CPPUNIT_ASSERT_EQUAL(1, activated.GetCount()); CPPUNIT_ASSERT_EQUAL(1, rclick.GetCount()); diff --git a/tests/controls/virtlistctrltest.cpp b/tests/controls/virtlistctrltest.cpp index de52896460..403041129b 100644 --- a/tests/controls/virtlistctrltest.cpp +++ b/tests/controls/virtlistctrltest.cpp @@ -23,6 +23,8 @@ #endif // WX_PRECOMP #include "wx/listctrl.h" +#include "testableframe.h" +#include "wx/uiaction.h" // ---------------------------------------------------------------------------- // test class @@ -39,9 +41,11 @@ public: private: CPPUNIT_TEST_SUITE( VirtListCtrlTestCase ); CPPUNIT_TEST( UpdateSelection ); + WXUISIM_TEST( DeselectedEvent ); CPPUNIT_TEST_SUITE_END(); void UpdateSelection(); + void DeselectedEvent(); wxListCtrl *m_list; @@ -105,4 +109,42 @@ void VirtListCtrlTestCase::UpdateSelection() CPPUNIT_ASSERT_EQUAL( 1, m_list->GetSelectedItemCount() ); } +void VirtListCtrlTestCase::DeselectedEvent() +{ +#if wxUSE_UIACTIONSIMULATOR + m_list->AppendColumn("Col0"); + m_list->SetItemCount(1); + wxListCtrl* const list = m_list; + + EventCounter selected(list, wxEVT_LIST_ITEM_SELECTED); + EventCounter deselected(list, wxEVT_LIST_ITEM_DESELECTED); + + wxUIActionSimulator sim; + + wxRect pos; + list->GetItemRect(0, pos); + + //We move in slightly so we are not on the edge + wxPoint point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 10); + + sim.MouseMove(point); + wxYield(); + + sim.MouseClick(); + wxYield(); + + // We want a point within the listctrl but below any items + point = list->ClientToScreen(pos.GetPosition()) + wxPoint(10, 50); + + sim.MouseMove(point); + wxYield(); + + sim.MouseClick(); + wxYield(); + + CPPUNIT_ASSERT_EQUAL(1, selected.GetCount()); + CPPUNIT_ASSERT_EQUAL(1, deselected.GetCount()); +#endif +} + #endif // wxUSE_LISTCTRL From cc21b1bff2c7c4d1944e590f1732bb04054cd9ee Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 13 Jun 2020 22:49:22 +0200 Subject: [PATCH 4/5] Revert "A test button to the listctrl sample" This reverts commit 9d9b0c51c88258130ad1d5e7167dc6937707d0bc as it was only meant for temporary testing and shouldn't be merged. --- samples/listctrl/listtest.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index ce9019dcc7..1c4213098b 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -53,8 +53,6 @@ // Constants and globals // ---------------------------------------------------------------------------- -wxButton *m_button; - const wxChar *SMALL_VIRTUAL_VIEW_ITEMS[][2] = { { wxT("Cat"), wxT("meow") }, @@ -310,12 +308,8 @@ MyFrame::MyFrame(const wxString& title) CreateStatusBar(); #endif // wxUSE_STATUSBAR - m_button = new wxButton(m_panel, wxID_ANY, "Do something with the selected item"); - m_button->Enable(false); - wxBoxSizer* const sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(m_listCtrl, wxSizerFlags(2).Expand().Border()); - sizer->Add(m_button, wxSizerFlags(2)); sizer->Add(m_logWindow, wxSizerFlags(1).Expand().Border()); m_panel->SetSizer(sizer); @@ -1190,9 +1184,7 @@ void MyListCtrl::OnDeleteAllItems(wxListEvent& event) void MyListCtrl::OnSelected(wxListEvent& event) { - m_button->Enable(true); - - LogEvent(event, "OnSelected"); + LogEvent(event, "OnSelected"); if ( GetWindowStyle() & wxLC_REPORT ) { @@ -1214,8 +1206,6 @@ void MyListCtrl::OnSelected(wxListEvent& event) void MyListCtrl::OnDeselected(wxListEvent& event) { - if (GetSelectedItemCount() == 0) - m_button->Enable(false); LogEvent(event, "OnDeselected"); } @@ -1268,7 +1258,7 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event) if ( !wxGetKeyState(WXK_SHIFT) ) { - //LogEvent(event, "OnListKeyDown"); + LogEvent(event, "OnListKeyDown"); event.Skip(); } @@ -1419,7 +1409,7 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event) wxFALLTHROUGH; default: - //LogEvent(event, "OnListKeyDown"); + LogEvent(event, "OnListKeyDown"); event.Skip(); } From 6f0a2b66b44202ce42f25c5a53f50dc944eb1d2f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 13 Jun 2020 22:50:36 +0200 Subject: [PATCH 5/5] Remove hard TAB from the recently added test No real changes. --- tests/controls/virtlistctrltest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/controls/virtlistctrltest.cpp b/tests/controls/virtlistctrltest.cpp index 403041129b..b82cbef788 100644 --- a/tests/controls/virtlistctrltest.cpp +++ b/tests/controls/virtlistctrltest.cpp @@ -112,7 +112,7 @@ void VirtListCtrlTestCase::UpdateSelection() void VirtListCtrlTestCase::DeselectedEvent() { #if wxUSE_UIACTIONSIMULATOR - m_list->AppendColumn("Col0"); + m_list->AppendColumn("Col0"); m_list->SetItemCount(1); wxListCtrl* const list = m_list;