More fixes for wxSTC auto-completion popup window, notably send the
scroll events to the correct window.

See https://github.com/wxWidgets/wxWidgets/pull/1482
This commit is contained in:
Vadim Zeitlin
2019-08-20 19:56:01 +02:00
4 changed files with 180 additions and 55 deletions

View File

@@ -2117,24 +2117,27 @@ PRectangle Window::GetMonitorRect(Point pt) {
// Do not activate the window when it is shown. // Do not activate the window when it is shown.
bool wxSTCPopupBase::Show(bool show) bool wxSTCPopupBase::Show(bool show)
{ {
if ( !wxWindowBase::Show(show) )
return false;
if ( show ) if ( show )
{ {
HWND hWnd = reinterpret_cast<HWND>(GetHandle()); // Check if the window is changing from hidden to shown.
if ( GetName() == "wxSTCCallTip" ) bool changingVisibility = wxWindowBase::Show(true);
::AnimateWindow(hWnd, 25, AW_BLEND);
else
::ShowWindow(hWnd, SW_SHOWNA );
::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, if ( changingVisibility )
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); {
HWND hWnd = reinterpret_cast<HWND>(GetHandle());
if ( GetName() == "wxSTCCallTip" )
::AnimateWindow(hWnd, 25, AW_BLEND);
else
::ShowWindow(hWnd, SW_SHOWNA );
::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
return changingVisibility;
} }
else else
wxPopupWindow::Show(false); return wxPopupWindow::Show(false);
return true;
} }
// Do not activate in response to mouse clicks on this window. // Do not activate in response to mouse clicks on this window.
@@ -2224,7 +2227,7 @@ PRectangle Window::GetMonitorRect(Point pt) {
#endif // __WXOSX_COCOA__ #endif // __WXOSX_COCOA__
wxSTCPopupWindow::wxSTCPopupWindow(wxWindow* parent) wxSTCPopupWindow::wxSTCPopupWindow(wxWindow* parent)
:wxSTCPopupBase(parent), m_initialPosition(wxDefaultPosition) :wxSTCPopupBase(parent), m_lastKnownPosition(wxDefaultPosition)
{ {
#if !wxSTC_POPUP_IS_CUSTOM #if !wxSTC_POPUP_IS_CUSTOM
Bind(wxEVT_SET_FOCUS, &wxSTCPopupWindow::OnFocus, this); Bind(wxEVT_SET_FOCUS, &wxSTCPopupWindow::OnFocus, this);
@@ -2275,9 +2278,7 @@ bool wxSTCPopupWindow::AcceptsFocus() const
void wxSTCPopupWindow::DoSetSize(int x, int y, int width, int height, int flags) void wxSTCPopupWindow::DoSetSize(int x, int y, int width, int height, int flags)
{ {
if ( m_initialPosition == wxDefaultPosition m_lastKnownPosition = wxPoint(x, y);
&& x != wxDefaultCoord && y != wxDefaultCoord )
m_initialPosition = wxPoint(x, y);
// convert coords to screen coords since we're a top-level window // convert coords to screen coords since we're a top-level window
if (x != wxDefaultCoord) if (x != wxDefaultCoord)
@@ -2291,8 +2292,8 @@ void wxSTCPopupWindow::DoSetSize(int x, int y, int width, int height, int flags)
void wxSTCPopupWindow::OnParentMove(wxMoveEvent& event) void wxSTCPopupWindow::OnParentMove(wxMoveEvent& event)
{ {
if ( m_initialPosition != wxDefaultPosition ) if ( m_lastKnownPosition.IsFullySpecified() )
SetPosition(m_initialPosition); SetPosition(m_lastKnownPosition);
event.Skip(); event.Skip();
} }
@@ -2700,7 +2701,7 @@ wxSTCListBox::wxSTCListBox(wxWindow* parent, wxSTCListBoxVisualData* v, int ht)
m_textTopGap(0), m_imageAreaWidth(0), m_imageAreaHeight(0) m_textTopGap(0), m_imageAreaWidth(0), m_imageAreaHeight(0)
{ {
wxVListBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVListBox::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxBORDER_NONE); wxBORDER_NONE, "AutoCompListBox");
m_imagePadding = FromDIP(1); m_imagePadding = FromDIP(1);
m_textBoxToTextGap = FromDIP(3); m_textBoxToTextGap = FromDIP(3);

View File

@@ -150,7 +150,7 @@ protected:
#endif #endif
private: private:
wxPoint m_initialPosition; wxPoint m_lastKnownPosition;
wxWindow* m_tlw; wxWindow* m_tlw;
}; };

View File

@@ -46,6 +46,8 @@
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
#include "wx/mstream.h" #include "wx/mstream.h"
#include "wx/image.h" #include "wx/image.h"
#include "wx/vlbox.h"
#include "wx/stack.h"
#if wxUSE_FFILE #if wxUSE_FFILE
#include "wx/ffile.h" #include "wx/ffile.h"
#elif wxUSE_FILE #elif wxUSE_FILE
@@ -5251,29 +5253,89 @@ void wxStyledTextCtrl::OnContextMenu(wxContextMenuEvent& evt) {
void wxStyledTextCtrl::OnMouseWheel(wxMouseEvent& 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 // if the mouse wheel is not captured, test if the mouse
// pointer is over the editor window and if not, don't // pointer is over the editor window and if not, don't
// handle the message but pass it on. // handle the message but pass it on.
if ( !GetMouseWheelCaptures() ) { if ( !GetMouseWheelCaptures() && !GetRect().Contains(evt.GetPosition()) )
if ( !GetRect().Contains(evt.GetPosition()) ) { {
wxWindow* parent = GetParent(); wxWindow* parent = GetParent();
if (parent != NULL) { if ( parent != NULL )
wxMouseEvent newevt(evt); {
newevt.SetPosition( wxMouseEvent newevt(evt);
parent->ScreenToClient(ClientToScreen(evt.GetPosition()))); newevt.SetPosition(
parent->ProcessWindowEvent(newevt); parent->ScreenToClient(ClientToScreen(evt.GetPosition())));
} parent->ProcessWindowEvent(newevt);
return;
} }
} }
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(), // First try to find the list. It will be a wxVListBox named
evt.GetWheelRotation(), // "AutoCompListBox".
evt.GetWheelDelta(), wxWindow* curWin = this, *acListBox = NULL;
evt.GetLinesPerAction(), wxStack<wxWindow*> windows;
evt.GetColumnsPerAction(), windows.push(curWin);
evt.ControlDown(),
evt.IsPageScroll()); 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());
}
} }

View File

@@ -46,6 +46,8 @@
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
#include "wx/mstream.h" #include "wx/mstream.h"
#include "wx/image.h" #include "wx/image.h"
#include "wx/vlbox.h"
#include "wx/stack.h"
#if wxUSE_FFILE #if wxUSE_FFILE
#include "wx/ffile.h" #include "wx/ffile.h"
#elif wxUSE_FILE #elif wxUSE_FILE
@@ -778,29 +780,89 @@ void wxStyledTextCtrl::OnContextMenu(wxContextMenuEvent& evt) {
void wxStyledTextCtrl::OnMouseWheel(wxMouseEvent& 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 // if the mouse wheel is not captured, test if the mouse
// pointer is over the editor window and if not, don't // pointer is over the editor window and if not, don't
// handle the message but pass it on. // handle the message but pass it on.
if ( !GetMouseWheelCaptures() ) { if ( !GetMouseWheelCaptures() && !GetRect().Contains(evt.GetPosition()) )
if ( !GetRect().Contains(evt.GetPosition()) ) { {
wxWindow* parent = GetParent(); wxWindow* parent = GetParent();
if (parent != NULL) { if ( parent != NULL )
wxMouseEvent newevt(evt); {
newevt.SetPosition( wxMouseEvent newevt(evt);
parent->ScreenToClient(ClientToScreen(evt.GetPosition()))); newevt.SetPosition(
parent->ProcessWindowEvent(newevt); parent->ScreenToClient(ClientToScreen(evt.GetPosition())));
} parent->ProcessWindowEvent(newevt);
return;
} }
} }
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(), // First try to find the list. It will be a wxVListBox named
evt.GetWheelRotation(), // "AutoCompListBox".
evt.GetWheelDelta(), wxWindow* curWin = this, *acListBox = NULL;
evt.GetLinesPerAction(), wxStack<wxWindow*> windows;
evt.GetColumnsPerAction(), windows.push(curWin);
evt.ControlDown(),
evt.IsPageScroll()); 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());
}
} }