From 4523df5d9459f5e43ad2d04a5e79096a34d2b392 Mon Sep 17 00:00:00 2001 From: New Pagodi Date: Wed, 7 Aug 2019 21:35:45 -0500 Subject: [PATCH] Redirect mouse wheel events when STC autocomp is active While an autocompletion list is being shown, a native Scintilla window will use mouse wheel events to scroll the list instead of the editor window. Match this behavior with wxSTC by intercepting mouse wheel events and redirecting them to the list. --- src/stc/PlatWX.cpp | 2 +- src/stc/stc.cpp | 96 ++++++++++++++++++++++++++++++++++++++-------- src/stc/stc.cpp.in | 96 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 159 insertions(+), 35 deletions(-) diff --git a/src/stc/PlatWX.cpp b/src/stc/PlatWX.cpp index f122270e75..359b5c4383 100644 --- a/src/stc/PlatWX.cpp +++ b/src/stc/PlatWX.cpp @@ -2701,7 +2701,7 @@ wxSTCListBox::wxSTCListBox(wxWindow* parent, wxSTCListBoxVisualData* v, int ht) m_textTopGap(0), m_imageAreaWidth(0), m_imageAreaHeight(0) { wxVListBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, - wxBORDER_NONE); + wxBORDER_NONE, "AutoCompListBox"); m_imagePadding = FromDIP(1); m_textBoxToTextGap = FromDIP(3); diff --git a/src/stc/stc.cpp b/src/stc/stc.cpp index 789b44caf7..65a7a74684 100644 --- a/src/stc/stc.cpp +++ b/src/stc/stc.cpp @@ -46,6 +46,8 @@ #include "wx/tokenzr.h" #include "wx/mstream.h" #include "wx/image.h" +#include "wx/vlbox.h" +#include "wx/stack.h" #if wxUSE_FFILE #include "wx/ffile.h" #elif wxUSE_FILE @@ -5251,29 +5253,89 @@ void wxStyledTextCtrl::OnContextMenu(wxContextMenuEvent& evt) { void wxStyledTextCtrl::OnMouseWheel(wxMouseEvent& evt) { + // The default action of this method is to call m_swx->DoMouseWheel. + // However, it might be necessary to do something else depending on whether + // 1) the mouse wheel captures for the STC, + // 2) the event's position is in the STC's rect, and + // 3) and an autocompletion list is currently being shown. + // This table summarizes when each action is needed. + + // InRect | MouseWheelCaptures | Autocomp Active | action + // -------+--------------------+-----------------+------------------- + // true | true | true | scroll ac list + // true | true | false | default + // true | false | true | scroll ac list + // true | false | false | default + // false | true | true | scroll ac list + // false | true | false | default + // false | false | true | forward to parent + // false | false | false | forward to parent + // if the mouse wheel is not captured, test if the mouse // pointer is over the editor window and if not, don't // handle the message but pass it on. - if ( !GetMouseWheelCaptures() ) { - if ( !GetRect().Contains(evt.GetPosition()) ) { - wxWindow* parent = GetParent(); - if (parent != NULL) { - wxMouseEvent newevt(evt); - newevt.SetPosition( - parent->ScreenToClient(ClientToScreen(evt.GetPosition()))); - parent->ProcessWindowEvent(newevt); - } - return; + if ( !GetMouseWheelCaptures() && !GetRect().Contains(evt.GetPosition()) ) + { + wxWindow* parent = GetParent(); + if ( parent != NULL ) + { + wxMouseEvent newevt(evt); + newevt.SetPosition( + parent->ScreenToClient(ClientToScreen(evt.GetPosition()))); + parent->ProcessWindowEvent(newevt); } } + else if ( AutoCompActive() ) + { + // When the autocompletion popup is active, Scintilla uses the mouse + // wheel to scroll the autocomp list instead of the editor. - m_swx->DoMouseWheel(evt.GetWheelAxis(), - evt.GetWheelRotation(), - evt.GetWheelDelta(), - evt.GetLinesPerAction(), - evt.GetColumnsPerAction(), - evt.ControlDown(), - evt.IsPageScroll()); + // First try to find the list. It will be a wxVListBox named + // "AutoCompListBox". + wxWindow* curWin = this, *acListBox = NULL; + wxStack windows; + windows.push(curWin); + + while ( !windows.empty() ) + { + curWin = windows.top(); + windows.pop(); + + if ( curWin->IsKindOf(wxCLASSINFO(wxVListBox)) && + curWin->GetName() == "AutoCompListBox") + { + acListBox = curWin; + break; + } + + wxWindowList& children = curWin->GetChildren(); + wxWindowList::iterator it; + + for ( it = children.begin(); it!=children.end(); ++it ) + { + windows.push(*it); + } + } + + // Next if the list was found, send it a copy of this event. + if ( acListBox ) + { + wxMouseEvent newevt(evt); + newevt.SetPosition( + acListBox->ScreenToClient(ClientToScreen(evt.GetPosition()))); + acListBox->ProcessWindowEvent(newevt); + } + } + else + { + m_swx->DoMouseWheel(evt.GetWheelAxis(), + evt.GetWheelRotation(), + evt.GetWheelDelta(), + evt.GetLinesPerAction(), + evt.GetColumnsPerAction(), + evt.ControlDown(), + evt.IsPageScroll()); + } } diff --git a/src/stc/stc.cpp.in b/src/stc/stc.cpp.in index 833b8c9a33..198c4ccac4 100644 --- a/src/stc/stc.cpp.in +++ b/src/stc/stc.cpp.in @@ -46,6 +46,8 @@ #include "wx/tokenzr.h" #include "wx/mstream.h" #include "wx/image.h" +#include "wx/vlbox.h" +#include "wx/stack.h" #if wxUSE_FFILE #include "wx/ffile.h" #elif wxUSE_FILE @@ -778,29 +780,89 @@ void wxStyledTextCtrl::OnContextMenu(wxContextMenuEvent& evt) { void wxStyledTextCtrl::OnMouseWheel(wxMouseEvent& evt) { + // The default action of this method is to call m_swx->DoMouseWheel. + // However, it might be necessary to do something else depending on whether + // 1) the mouse wheel captures for the STC, + // 2) the event's position is in the STC's rect, and + // 3) and an autocompletion list is currently being shown. + // This table summarizes when each action is needed. + + // InRect | MouseWheelCaptures | Autocomp Active | action + // -------+--------------------+-----------------+------------------- + // true | true | true | scroll ac list + // true | true | false | default + // true | false | true | scroll ac list + // true | false | false | default + // false | true | true | scroll ac list + // false | true | false | default + // false | false | true | forward to parent + // false | false | false | forward to parent + // if the mouse wheel is not captured, test if the mouse // pointer is over the editor window and if not, don't // handle the message but pass it on. - if ( !GetMouseWheelCaptures() ) { - if ( !GetRect().Contains(evt.GetPosition()) ) { - wxWindow* parent = GetParent(); - if (parent != NULL) { - wxMouseEvent newevt(evt); - newevt.SetPosition( - parent->ScreenToClient(ClientToScreen(evt.GetPosition()))); - parent->ProcessWindowEvent(newevt); - } - return; + if ( !GetMouseWheelCaptures() && !GetRect().Contains(evt.GetPosition()) ) + { + wxWindow* parent = GetParent(); + if ( parent != NULL ) + { + wxMouseEvent newevt(evt); + newevt.SetPosition( + parent->ScreenToClient(ClientToScreen(evt.GetPosition()))); + parent->ProcessWindowEvent(newevt); } } + else if ( AutoCompActive() ) + { + // When the autocompletion popup is active, Scintilla uses the mouse + // wheel to scroll the autocomp list instead of the editor. - m_swx->DoMouseWheel(evt.GetWheelAxis(), - evt.GetWheelRotation(), - evt.GetWheelDelta(), - evt.GetLinesPerAction(), - evt.GetColumnsPerAction(), - evt.ControlDown(), - evt.IsPageScroll()); + // First try to find the list. It will be a wxVListBox named + // "AutoCompListBox". + wxWindow* curWin = this, *acListBox = NULL; + wxStack windows; + windows.push(curWin); + + while ( !windows.empty() ) + { + curWin = windows.top(); + windows.pop(); + + if ( curWin->IsKindOf(wxCLASSINFO(wxVListBox)) && + curWin->GetName() == "AutoCompListBox") + { + acListBox = curWin; + break; + } + + wxWindowList& children = curWin->GetChildren(); + wxWindowList::iterator it; + + for ( it = children.begin(); it!=children.end(); ++it ) + { + windows.push(*it); + } + } + + // Next if the list was found, send it a copy of this event. + if ( acListBox ) + { + wxMouseEvent newevt(evt); + newevt.SetPosition( + acListBox->ScreenToClient(ClientToScreen(evt.GetPosition()))); + acListBox->ProcessWindowEvent(newevt); + } + } + else + { + m_swx->DoMouseWheel(evt.GetWheelAxis(), + evt.GetWheelRotation(), + evt.GetWheelDelta(), + evt.GetLinesPerAction(), + evt.GetColumnsPerAction(), + evt.ControlDown(), + evt.IsPageScroll()); + } }