Fix mouse wheel bubbling and plugin event handling

- Queue native wheel events until hover state has been rebuilt, restoring
  scroll propagation from children that cannot scroll to their scrollable
  ancestors.

  - Add MouseWheelEvent and UICodeEditorPlugin::onMouseWheel() so plugins can
  consume precise wheel input before the editor handles it. Migrate
  autocomplete and AI Assistant wheel handlers to the new API while
  preserving the existing virtual event dispatch semantics.

  - Add regressions for wheel bubbling, plugin interception, generic wheel
  listeners, and override-based callback suppression.
This commit is contained in:
Martín Lucas Golini
2026-09-14 17:58:06 -03:00
parent 6bccec171e
commit 51afa1870a
14 changed files with 265 additions and 22 deletions
+10 -10
View File
@@ -643,9 +643,9 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) :
}
} );
mModelBtn->onClick( [this]( auto ) { execute( "ai-select-model" ); } );
mModelBtn->on( Event::MouseUp, [this]( const Event* event ) {
const auto mouseEvent = event->asMouseEvent();
if ( !( mouseEvent->getFlags() & ( EE_BUTTON_WUMASK | EE_BUTTON_WDMASK ) ) )
mModelBtn->on( Event::MouseWheel, [this]( const Event* event ) {
const auto wheelEvent = event->asMouseWheelEvent();
if ( wheelEvent->getOffset().y == 0.f )
return;
if ( nullptr == mLocateModelTable->getModel() ) {
@@ -656,9 +656,9 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) :
selectModel( mCurModel );
}
if ( mouseEvent->getFlags() & EE_BUTTON_WUMASK ) {
if ( wheelEvent->getOffset().y > 0.f ) {
mLocateModelTable->moveSelection( -1 );
} else if ( mouseEvent->getFlags() & EE_BUTTON_WDMASK ) {
} else {
mLocateModelTable->moveSelection( 1 );
}
@@ -674,9 +674,9 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) :
mAgentBtn->onClick( [this]( auto ) { execute( "ai-select-agent" ); } );
mAgentConfigBtn = findByClass<UIPushButton>( "agent_config_ui" );
mAgentConfigBtn->onClick( [this]( auto ) { showAgentConfigWindow(); } );
mAgentBtn->on( Event::MouseUp, [this]( const Event* event ) {
const auto mouseEvent = event->asMouseEvent();
if ( !( mouseEvent->getFlags() & ( EE_BUTTON_WUMASK | EE_BUTTON_WDMASK ) ) )
mAgentBtn->on( Event::MouseWheel, [this]( const Event* event ) {
const auto wheelEvent = event->asMouseWheelEvent();
if ( wheelEvent->getOffset().y == 0.f )
return;
if ( nullptr == mLocateAgentTable->getModel() ) {
@@ -687,9 +687,9 @@ LLMChatUI::LLMChatUI( PluginManager* manager ) :
selectModel( mCurModel );
}
if ( mouseEvent->getFlags() & EE_BUTTON_WUMASK ) {
if ( wheelEvent->getOffset().y > 0.f ) {
mLocateAgentTable->moveSelection( -1 );
} else if ( mouseEvent->getFlags() & EE_BUTTON_WDMASK ) {
} else {
mLocateAgentTable->moveSelection( 1 );
}
@@ -2436,18 +2436,18 @@ bool AutoCompletePlugin::onMouseDown( UICodeEditor* editor, const Vector2i& posi
return false;
}
bool AutoCompletePlugin::onMouseUp( UICodeEditor* editor, const Vector2i& position,
const Uint32& flags ) {
bool AutoCompletePlugin::onMouseWheel( UICodeEditor* editor, const Vector2i& position,
const Vector2f& offset, bool ) {
if ( mSuggestions.empty() || !mSuggestionsEditor || mSuggestionsEditor != editor )
return false;
Vector2f localPos( editor->convertToNodeSpace( position.asFloat() ) );
if ( mBoxRect.contains( localPos ) ) {
if ( flags & EE_BUTTON_WUMASK ) {
if ( offset.y > 0.f ) {
mSuggestionsStartIndex = eemax( 0, mSuggestionsStartIndex - mSuggestionsMaxVisible );
editor->invalidateDraw();
return true;
} else if ( flags & EE_BUTTON_WDMASK ) {
} else if ( offset.y < 0.f ) {
mSuggestionsStartIndex =
eemax( 0, eemin( (int)mSuggestions.size() - mSuggestionsMaxVisible,
mSuggestionsStartIndex + mSuggestionsMaxVisible ) );
@@ -117,7 +117,7 @@ class AutoCompletePlugin : public Plugin {
bool onMouseDown( UICodeEditor*, const Vector2i&, const Uint32& ) override;
bool onMouseUp( UICodeEditor*, const Vector2i&, const Uint32& ) override;
bool onMouseWheel( UICodeEditor*, const Vector2i&, const Vector2f&, bool ) override;
bool onMouseDoubleClick( UICodeEditor*, const Vector2i&, const Uint32& ) override;