From 96b83a1523bc48411a8690a90aaf83cef62f49bb Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Tue, 12 Nov 2019 21:22:05 +0200 Subject: [PATCH] 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; + } } }