From 689839ed87a01bedf66340e7e59cd3cd8332c793 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Thu, 17 Feb 2011 11:01:22 +0000 Subject: [PATCH] Backport for for #12143: Click anywhere inside wxListBox generates wxEVT_COMMAND_LISTBOX_SELECTED event Needs wxUSE_LISTBOX_SELECTION_FIX to be set to 1 in include/wx/msw/listbox.h since it is not binary compatible. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@66941 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/listbox.h | 15 ++++++++++ src/msw/listbox.cpp | 61 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/include/wx/msw/listbox.h b/include/wx/msw/listbox.h index d4eb27141c..d693fd7945 100644 --- a/include/wx/msw/listbox.h +++ b/include/wx/msw/listbox.h @@ -14,6 +14,10 @@ #if wxUSE_LISTBOX +// Fixing spurious selection events breaks binary compatibility, so this is normally 0. +// See ticket #12143 +#define wxUSE_LISTBOX_SELECTION_FIX 0 + // ---------------------------------------------------------------------------- // simple types // ---------------------------------------------------------------------------- @@ -133,6 +137,10 @@ public: return GetCompositeControlsDefaultAttributes(variant); } +#if wxUSE_LISTBOX_SELECTION_FIX + virtual WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); +#endif + protected: virtual void DoSetSelection(int n, bool select); virtual int DoAppend(const wxString& item); @@ -158,6 +166,13 @@ protected: wxListBoxItemsArray m_aItems; #endif +#if wxUSE_LISTBOX_SELECTION_FIX + // flag set to true when we get a keyboard event and reset to false when we + // get a mouse one: this is used to find the correct item for the selection + // event + bool m_selectedByKeyboard; +#endif + private: DECLARE_DYNAMIC_CLASS_NO_COPY(wxListBox) }; diff --git a/src/msw/listbox.cpp b/src/msw/listbox.cpp index 7f00565941..e9da58159d 100644 --- a/src/msw/listbox.cpp +++ b/src/msw/listbox.cpp @@ -145,6 +145,9 @@ wxListBox::wxListBox() { m_noItems = 0; m_selected = 0; +#if wxUSE_LISTBOX_SELECTION_FIX + m_selectedByKeyboard = false; +#endif } bool wxListBox::Create(wxWindow *parent, @@ -702,7 +705,46 @@ wxSize wxListBox::DoGetBestSize() const bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) { wxEventType evtType; - int n; + int n = wxNOT_FOUND; + +#if wxUSE_LISTBOX_SELECTION_FIX + if ( param == LBN_SELCHANGE ) + { + evtType = wxEVT_COMMAND_LISTBOX_SELECTED; + if ( m_selectedByKeyboard ) + { + // We shouldn't use the mouse position to find the item as mouse + // can be anywhere, ask the listbox itself. Notice that this can't + // be used when the item is selected using the mouse however as + // LB_GETCARETINDEX will always return a valid item, even if the + // mouse is clicked below all the items, which is why we find the + // item ourselves below in this case. + n = SendMessage(GetHwnd(), LB_GETCARETINDEX, 0, 0); + } + //else: n will be determined below from the mouse position + + // NB: conveniently enough, LB_ERR is the same as wxNOT_FOUND + } + else if ( param == LBN_DBLCLK ) + { + evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED; + n = HitTest(ScreenToClient(wxGetMousePosition())); + } + else + { + // some event we're not interested in + return false; + } + + // Find the item position if it was a mouse-generated selection event or a + // double click event (which is always generated using the mouse) + if ( n == wxNOT_FOUND ) + { + const DWORD pos = ::GetMessagePos(); + const wxPoint pt(GET_X_LPARAM(pos), GET_Y_LPARAM(pos)); + n = HitTest(ScreenToClient(wxPoint(pt))); + } +#else if ( param == LBN_SELCHANGE ) { evtType = wxEVT_COMMAND_LISTBOX_SELECTED; @@ -720,6 +762,7 @@ bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) // some event we're not interested in return false; } +#endif // retrieve the affected item if ( n == wxNOT_FOUND ) @@ -740,6 +783,22 @@ bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) return GetEventHandler()->ProcessEvent(event); } +#if wxUSE_LISTBOX_SELECTION_FIX +WXLRESULT +wxListBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ + // Remember whether there was a keyboard or mouse event before + // LBN_SELCHANGE: this allows us to correctly determine the item affected + // by it in MSWCommand() above in any case. + if ( WM_KEYFIRST <= nMsg && nMsg <= WM_KEYLAST ) + m_selectedByKeyboard = true; + else if ( WM_MOUSEFIRST <= nMsg && nMsg <= WM_MOUSELAST ) + m_selectedByKeyboard = false; + + return wxListBoxBase::MSWWindowProc(nMsg, wParam, lParam); +} +#endif + // ---------------------------------------------------------------------------- // wxCheckListBox support // ----------------------------------------------------------------------------