mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 10:40:20 +03:00
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:
@@ -13,6 +13,7 @@ namespace EE { namespace Scene {
|
||||
|
||||
class Node;
|
||||
class MouseEvent;
|
||||
class MouseWheelEvent;
|
||||
class KeyEvent;
|
||||
class DropEvent;
|
||||
class TextEvent;
|
||||
@@ -135,6 +136,7 @@ class EE_API Event {
|
||||
OnShowFindReplace,
|
||||
OnHideFindReplace,
|
||||
OnTooltipCreated,
|
||||
MouseWheel,
|
||||
NoEvent = eeINDEX_NOT_FOUND
|
||||
};
|
||||
|
||||
@@ -150,6 +152,8 @@ class EE_API Event {
|
||||
|
||||
const MouseEvent* asMouseEvent() const;
|
||||
|
||||
const MouseWheelEvent* asMouseWheelEvent() const;
|
||||
|
||||
const KeyEvent* asKeyEvent() const;
|
||||
|
||||
const DropEvent* asDropEvent() const;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <eepp/scene/nodefocusreason.hpp>
|
||||
#include <eepp/system/time.hpp>
|
||||
#include <eepp/window/keycodes.hpp>
|
||||
#include <vector>
|
||||
|
||||
using namespace EE::System;
|
||||
using namespace EE::Math;
|
||||
@@ -147,6 +148,11 @@ class EE_API EventDispatcher {
|
||||
Time mElapsed;
|
||||
Uint32 mCurFocusId{ 0 };
|
||||
std::map<Uint32, FocusCallback> mFocusCbs;
|
||||
struct PendingMouseWheelEvent {
|
||||
Vector2f offset;
|
||||
bool flipped;
|
||||
};
|
||||
std::vector<PendingMouseWheelEvent> mPendingMouseWheelEvents;
|
||||
|
||||
virtual void inputCallback( InputEvent* event );
|
||||
};
|
||||
|
||||
@@ -22,6 +22,22 @@ class EE_API MouseEvent : public Event {
|
||||
Uint32 mFlags;
|
||||
};
|
||||
|
||||
class EE_API MouseWheelEvent : public Event {
|
||||
public:
|
||||
MouseWheelEvent( Node* node, const Vector2i& position, const Vector2f& offset, bool flipped );
|
||||
|
||||
const Vector2i& getPosition() const;
|
||||
|
||||
const Vector2f& getOffset() const;
|
||||
|
||||
bool isFlipped() const;
|
||||
|
||||
protected:
|
||||
Vector2i mPosition;
|
||||
Vector2f mOffset;
|
||||
bool mFlipped;
|
||||
};
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2124,8 +2124,10 @@ class EE_API Node : public Transformable {
|
||||
/**
|
||||
* @brief Handles mouse wheel scroll events.
|
||||
*
|
||||
* Called when the mouse wheel is scrolled. Default implementation returns 0 so the event can
|
||||
* bubble to an ancestor that implements scrolling.
|
||||
* Called when the mouse wheel is scrolled. The default implementation dispatches an
|
||||
* Event::MouseWheel callback and consumes the event when a listener is registered; otherwise it
|
||||
* returns 0 so the event can bubble to an ancestor. Overrides decide whether to invoke the base
|
||||
* implementation, consistently with the other input event handlers.
|
||||
*
|
||||
* @param offset Scroll offset vector.
|
||||
* @param flipped Whether the scroll direction is flipped (e.g., on Mac).
|
||||
|
||||
@@ -87,6 +87,10 @@ class UICodeEditorPlugin {
|
||||
|
||||
virtual bool onMouseUp( UICodeEditor*, const Vector2i&, const Uint32& ) { return false; }
|
||||
|
||||
virtual bool onMouseWheel( UICodeEditor*, const Vector2i&, const Vector2f&, bool ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool onMouseClick( UICodeEditor*, const Vector2i&, const Uint32& ) { return false; }
|
||||
|
||||
virtual bool onMouseDoubleClick( UICodeEditor*, const Vector2i&, const Uint32& ) {
|
||||
|
||||
@@ -25,6 +25,10 @@ const MouseEvent* Event::asMouseEvent() const {
|
||||
return static_cast<const MouseEvent*>( this );
|
||||
}
|
||||
|
||||
const MouseWheelEvent* Event::asMouseWheelEvent() const {
|
||||
return static_cast<const MouseWheelEvent*>( this );
|
||||
}
|
||||
|
||||
const KeyEvent* Event::asKeyEvent() const {
|
||||
return static_cast<const KeyEvent*>( this );
|
||||
}
|
||||
|
||||
@@ -79,8 +79,9 @@ void EventDispatcher::inputCallback( InputEvent* event ) {
|
||||
event->textediting.length );
|
||||
break;
|
||||
case InputEvent::MouseWheel:
|
||||
sendMouseWheel( { event->wheel.x, event->wheel.y },
|
||||
event->wheel.direction == InputEvent::WheelEvent::Flipped );
|
||||
mPendingMouseWheelEvents.push_back(
|
||||
{ { event->wheel.x, event->wheel.y },
|
||||
event->wheel.direction == InputEvent::WheelEvent::Flipped } );
|
||||
break;
|
||||
case InputEvent::SysWM:
|
||||
case InputEvent::VideoResize:
|
||||
@@ -124,6 +125,13 @@ void EventDispatcher::update( const Time& time ) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( !mPendingMouseWheelEvents.empty() ) {
|
||||
std::vector<PendingMouseWheelEvent> pendingMouseWheelEvents;
|
||||
pendingMouseWheelEvents.swap( mPendingMouseWheelEvents );
|
||||
for ( const auto& event : pendingMouseWheelEvents )
|
||||
sendMouseWheel( event.offset, event.flipped );
|
||||
}
|
||||
|
||||
if ( mDisableMousePress || mJustDisabledMousePress ) {
|
||||
mJustDisabledMousePress = false;
|
||||
return;
|
||||
|
||||
@@ -17,4 +17,20 @@ const Uint32& MouseEvent::getFlags() const {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
MouseWheelEvent::MouseWheelEvent( Node* node, const Vector2i& position, const Vector2f& offset,
|
||||
bool flipped ) :
|
||||
Event( node, Event::MouseWheel ), mPosition( position ), mOffset( offset ), mFlipped( flipped ) {}
|
||||
|
||||
const Vector2i& MouseWheelEvent::getPosition() const {
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
const Vector2f& MouseWheelEvent::getOffset() const {
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
bool MouseWheelEvent::isFlipped() const {
|
||||
return mFlipped;
|
||||
}
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
+12
-2
@@ -387,8 +387,18 @@ Uint32 Node::onMouseLeave( const Vector2i& Pos, const Uint32& Flags ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Uint32 Node::onMouseWheel( const Vector2f&, bool ) {
|
||||
return 0;
|
||||
Uint32 Node::onMouseWheel( const Vector2f& offset, bool flipped ) {
|
||||
if ( !hasEventsOfType( Event::MouseWheel ) )
|
||||
return 0;
|
||||
|
||||
const Vector2i position =
|
||||
getEventDispatcher() ? getEventDispatcher()->getMousePos() : Vector2i::Zero;
|
||||
MouseWheelEvent event( this, position, offset, flipped );
|
||||
sendEvent( &event );
|
||||
|
||||
// A registered listener consumes the wheel event. Overrides can intentionally avoid calling
|
||||
// this implementation to handle the wheel without dispatching the generic event callback.
|
||||
return 1;
|
||||
}
|
||||
|
||||
Uint32 Node::onCalculateDrag( const Vector2f&, const Uint32& ) {
|
||||
|
||||
@@ -1921,7 +1921,13 @@ Uint32 UICodeEditor::onMouseUp( const Vector2i& position, const Uint32& flags )
|
||||
return UIWidget::onMouseUp( position, flags );
|
||||
}
|
||||
|
||||
Uint32 UICodeEditor::onMouseWheel( const Vector2f& offset, bool ) {
|
||||
Uint32 UICodeEditor::onMouseWheel( const Vector2f& offset, bool flipped ) {
|
||||
const Vector2i position = getEventDispatcher() ? getEventDispatcher()->getMousePos()
|
||||
: Vector2i::Zero;
|
||||
for ( auto& plugin : mPlugins )
|
||||
if ( plugin->onMouseWheel( this, position, offset, flipped ) )
|
||||
return 1;
|
||||
|
||||
Input* input = getInput();
|
||||
if ( input->isKeyModPressed() )
|
||||
return 1;
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
#include "utest.h"
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/scene/scenemanager.hpp>
|
||||
#include <eepp/ui/uiapplication.hpp>
|
||||
#include <eepp/ui/uicodeeditor.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uiscrollbar.hpp>
|
||||
#include <eepp/ui/uiscrollview.hpp>
|
||||
#include <eepp/window/engine.hpp>
|
||||
#include <eepp/window/input.hpp>
|
||||
#include <eepp/window/inputevent.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::System;
|
||||
@@ -15,6 +21,39 @@ class ScrollingTestEditor : public UICodeEditor {
|
||||
using UICodeEditor::onMouseWheel;
|
||||
};
|
||||
|
||||
class WheelInterceptPlugin : public UICodeEditorPlugin {
|
||||
public:
|
||||
std::string getId() override { return "WheelInterceptPlugin"; }
|
||||
std::string getTitle() override { return getId(); }
|
||||
std::string getDescription() override { return getId(); }
|
||||
bool isReady() const override { return true; }
|
||||
void onRegister( UICodeEditor* ) override {}
|
||||
void onUnregister( UICodeEditor* ) override {}
|
||||
bool onMouseWheel( UICodeEditor*, const Vector2i& position, const Vector2f& offset,
|
||||
bool flipped ) override {
|
||||
++calls;
|
||||
lastPosition = position;
|
||||
lastOffset = offset;
|
||||
lastFlipped = flipped;
|
||||
return true;
|
||||
}
|
||||
|
||||
int calls{ 0 };
|
||||
Vector2i lastPosition;
|
||||
Vector2f lastOffset;
|
||||
bool lastFlipped{ false };
|
||||
};
|
||||
|
||||
class WheelOverrideWidget : public UIWidget {
|
||||
public:
|
||||
Uint32 onMouseWheel( const Vector2f&, bool ) override {
|
||||
++calls;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int calls{ 0 };
|
||||
};
|
||||
|
||||
UTEST( UIScrolling, SceneSmoothScrollingDefaultsCanBeInheritedSnapshottedAndAppliedNow ) {
|
||||
UIApplication app(
|
||||
WindowSettings{ 320, 240, "eepp - scrolling test" },
|
||||
@@ -86,3 +125,131 @@ UTEST( UIScrolling, CodeEditorKeepsLegacyWheelStepButSoftensFractionalMomentumTa
|
||||
|
||||
eeDelete( editor );
|
||||
}
|
||||
|
||||
UTEST( UIScrolling, WheelEventRebuildsHoverStateAndBubblesWhenEditorCannotScroll ) {
|
||||
UIApplication app(
|
||||
WindowSettings{ 320, 240, "eepp - wheel bubbling test" },
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
auto* scene = app.getUI();
|
||||
auto* scrollView = UIScrollView::New();
|
||||
scrollView->setPixelsSize( 280, 160 );
|
||||
scrollView->setParent( scene->getRoot() );
|
||||
auto* content = UIWidget::New();
|
||||
content->setPixelsSize( 260, 600 );
|
||||
content->setParent( scrollView );
|
||||
auto* editor = UICodeEditor::New();
|
||||
editor->setPixelsSize( 240, 80 );
|
||||
editor->setParent( content );
|
||||
scene->flushDirtyStyleAndLayout();
|
||||
|
||||
ASSERT_TRUE( scrollView->getVerticalScrollBar()->isEnabled() );
|
||||
EXPECT_NEAR( scrollView->getVerticalScrollBar()->getValue(), 0.f, 0.0001f );
|
||||
app.getWindow()->getInput()->setMousePos(
|
||||
editor->convertToWorldSpace( { 20.f, 20.f } ).asInt() );
|
||||
|
||||
InputEvent event{};
|
||||
event.Type = InputEvent::MouseWheel;
|
||||
event.WinID = app.getWindow()->getWindowID();
|
||||
event.wheel.x = 0.f;
|
||||
event.wheel.y = -1.f;
|
||||
event.wheel.direction = InputEvent::WheelEvent::Normal;
|
||||
ASSERT_TRUE( app.getWindow()->getInput()->pushEvent( event ) );
|
||||
Engine::instance()->updateInput();
|
||||
SceneManager::instance()->update();
|
||||
|
||||
EXPECT_GT( scrollView->getVerticalScrollBar()->getValue(), 0.f );
|
||||
}
|
||||
|
||||
UTEST( UIScrolling, CodeEditorPluginCanConsumePreciseWheelBeforeEditorScrolls ) {
|
||||
UIApplication app(
|
||||
WindowSettings{ 320, 240, "eepp - wheel plugin test" },
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
auto* editor = eeNew( ScrollingTestEditor, () );
|
||||
editor->setPixelsSize( 160, 80 );
|
||||
editor->setParent( app.getUI()->getRoot() );
|
||||
editor->getDocument().textInput( String( 100, '\n' ) );
|
||||
app.getUI()->flushDirtyStyleAndLayout();
|
||||
editor->setScrollY( 100.f );
|
||||
app.getWindow()->getInput()->setMousePos( { 25, 35 } );
|
||||
SceneManager::instance()->update();
|
||||
|
||||
WheelInterceptPlugin plugin;
|
||||
editor->registerPlugin( &plugin );
|
||||
EXPECT_EQ( 1u, editor->onMouseWheel( { 0.f, -0.25f }, true ) );
|
||||
EXPECT_EQ( plugin.calls, 1 );
|
||||
EXPECT_EQ( plugin.lastPosition.x, 25 );
|
||||
EXPECT_EQ( plugin.lastPosition.y, 35 );
|
||||
EXPECT_NEAR( plugin.lastOffset.x, 0.f, 0.0001f );
|
||||
EXPECT_NEAR( plugin.lastOffset.y, -0.25f, 0.0001f );
|
||||
EXPECT_TRUE( plugin.lastFlipped );
|
||||
EXPECT_NEAR( editor->getScroll().y, 100.f, 0.0001f );
|
||||
editor->unregisterPlugin( &plugin );
|
||||
|
||||
eeDelete( editor );
|
||||
}
|
||||
|
||||
UTEST( UIScrolling, MouseWheelListenerConsumesBeforeScrollableAncestor ) {
|
||||
UIApplication app(
|
||||
WindowSettings{ 320, 240, "eepp - wheel listener test" },
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
auto* scene = app.getUI();
|
||||
auto* scrollView = UIScrollView::New();
|
||||
scrollView->setPixelsSize( 280, 160 );
|
||||
scrollView->setParent( scene->getRoot() );
|
||||
auto* content = UIWidget::New();
|
||||
content->setPixelsSize( 260, 600 );
|
||||
content->setParent( scrollView );
|
||||
auto* child = UIWidget::New();
|
||||
child->setPixelsSize( 240, 80 );
|
||||
child->setParent( content );
|
||||
scene->flushDirtyStyleAndLayout();
|
||||
|
||||
int wheelEvents = 0;
|
||||
Vector2f receivedOffset;
|
||||
child->on( Event::MouseWheel, [&]( const Event* event ) {
|
||||
++wheelEvents;
|
||||
receivedOffset = event->asMouseWheelEvent()->getOffset();
|
||||
} );
|
||||
app.getWindow()->getInput()->setMousePos( child->convertToWorldSpace( { 20.f, 20.f } ).asInt() );
|
||||
|
||||
InputEvent event{};
|
||||
event.Type = InputEvent::MouseWheel;
|
||||
event.WinID = app.getWindow()->getWindowID();
|
||||
event.wheel.x = 0.f;
|
||||
event.wheel.y = -1.25f;
|
||||
event.wheel.direction = InputEvent::WheelEvent::Normal;
|
||||
ASSERT_TRUE( app.getWindow()->getInput()->pushEvent( event ) );
|
||||
Engine::instance()->updateInput();
|
||||
SceneManager::instance()->update();
|
||||
|
||||
EXPECT_EQ( wheelEvents, 1 );
|
||||
EXPECT_NEAR( receivedOffset.y, -1.25f, 0.0001f );
|
||||
EXPECT_NEAR( scrollView->getVerticalScrollBar()->getValue(), 0.f, 0.0001f );
|
||||
}
|
||||
|
||||
UTEST( UIScrolling, MouseWheelOverrideCanSuppressListenerDispatch ) {
|
||||
UIApplication app(
|
||||
WindowSettings{ 320, 240, "eepp - wheel override test" },
|
||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||
auto* widget = eeNew( WheelOverrideWidget, () );
|
||||
widget->setPixelsSize( 160, 80 );
|
||||
widget->setParent( app.getUI()->getRoot() );
|
||||
app.getUI()->flushDirtyStyleAndLayout();
|
||||
|
||||
int wheelEvents = 0;
|
||||
widget->on( Event::MouseWheel, [&]( const Event* ) { ++wheelEvents; } );
|
||||
app.getWindow()->getInput()->setMousePos(
|
||||
widget->convertToWorldSpace( { 20.f, 20.f } ).asInt() );
|
||||
|
||||
InputEvent event{};
|
||||
event.Type = InputEvent::MouseWheel;
|
||||
event.WinID = app.getWindow()->getWindowID();
|
||||
event.wheel.y = -1.f;
|
||||
event.wheel.direction = InputEvent::WheelEvent::Normal;
|
||||
ASSERT_TRUE( app.getWindow()->getInput()->pushEvent( event ) );
|
||||
Engine::instance()->updateInput();
|
||||
SceneManager::instance()->update();
|
||||
|
||||
EXPECT_EQ( widget->calls, 1 );
|
||||
EXPECT_EQ( wheelEvents, 0 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user