From 6459750a61e3e38088f178aef8b281f07e138f9f Mon Sep 17 00:00:00 2001 From: Patrick Baran Date: Mon, 28 Sep 2026 18:23:46 +0100 Subject: [PATCH 1/3] Preserve mouse capture per pointer --- Engine/system/api/iosapi.mm | 5 + Engine/system/eventdispatcher.cpp | 38 +++-- Engine/system/eventdispatcher.h | 7 +- Tests/tests/eventdispatcher_test.cpp | 202 +++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 11 deletions(-) diff --git a/Engine/system/api/iosapi.mm b/Engine/system/api/iosapi.mm index 8539dbd0..59b36883 100644 --- a/Engine/system/api/iosapi.mm +++ b/Engine/system/api/iosapi.mm @@ -268,6 +268,11 @@ -(id)init { return self; } +- (void)setView:(UIView*)view { + view.multipleTouchEnabled = YES; + [super setView:view]; + } + - (void)viewDidLoad { [super viewDidLoad]; self.extendedLayoutIncludesOpaqueBars = YES; diff --git a/Engine/system/eventdispatcher.cpp b/Engine/system/eventdispatcher.cpp index f48c270d..a3217488 100644 --- a/Engine/system/eventdispatcher.cpp +++ b/Engine/system/eventdispatcher.cpp @@ -27,7 +27,8 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { Event::MouseDown ); e1.ignore(); - auto& btn = mouseUp[e.button]; + const MouseCapture capture = {e.mouseID,e.button}; + std::weak_ptr btn; for(auto i:overlays) { if(!i->bind(wnd)) continue; @@ -37,6 +38,7 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { if(e1.type()==MouseEvent::MouseDown) { mouseLast = btn; mouseLastBtn = e.button; + mouseLastId = e.mouseID; } } @@ -52,8 +54,13 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { mouseLast = btn; mouseLastTime = Application::tickCount(); mouseLastBtn = e.button; + mouseLastId = e.mouseID; } + if(btn.expired()) + mouseUp.erase(capture); else + mouseUp[capture] = btn; + if(auto w = btn.lock()) { if(w->widget->focusPolicy() & ClickFocus) { w->widget->implSetFocus(true,Event::FocusReason::ClickReason); @@ -64,8 +71,11 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { void EventDispatcher::dispatchMouseUp(Widget& /*wnd*/, MouseEvent &e) { ++mouseEvCount; - auto ptr = mouseUp[e.button]; - mouseUp[e.button].reset(); + auto it = mouseUp.find({e.mouseID,e.button}); + if(it==mouseUp.end()) + return; + auto ptr = it->second; + mouseUp.erase(it); if(auto w = ptr.lock()) { auto p = e.pos() - w->widget->mapToRoot(Point()); @@ -82,13 +92,14 @@ void EventDispatcher::dispatchMouseUp(Widget& /*wnd*/, MouseEvent &e) { void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { auto btn = Event::ButtonNone; - for(uint8_t i=0; ifirst.first==e.mouseID; ++i) + if(!i->second.expired()) { + btn = i->first.second; break; } - if(auto w = lock(mouseUp[btn])) { + const MouseCapture capture = {e.mouseID,btn}; + if(auto w = lock(capture)) { auto p = e.pos() - w->widget->mapToRoot(Point()); MouseEvent e0( p.x, p.y, @@ -102,7 +113,7 @@ void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { return; } - if(auto w = lock(mouseUp[btn])) { + if(auto w = lock(capture)) { auto p = e.pos() - w->widget->mapToRoot(Point()); MouseEvent e1( p.x, p.y, @@ -113,7 +124,7 @@ void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { Event::MouseMove ); w->widget->mouseMoveEvent(e1); if(e.isAccepted()) { - implSetMouseOver(mouseUp[btn].lock(),e); + implSetMouseOver(lock(capture),e); return; } } @@ -304,7 +315,7 @@ std::shared_ptr EventDispatcher::implDispatch(Widget& w, MouseEvent auto last = mouseLast.lock(); bool dblClick = false; uint64_t time = Application::tickCount(); - if(time-mouseLastTime<1000 && mouseLastBtn==event.button && last!=nullptr && last->widget==it.owner) { + if(time-mouseLastTime<1000 && mouseLastBtn==event.button && mouseLastId==event.mouseID && last!=nullptr && last->widget==it.owner) { dblClick = true; } event.accept(); @@ -521,6 +532,13 @@ std::shared_ptr EventDispatcher::lock(std::weak_ptr& w return nullptr; } +std::shared_ptr EventDispatcher::lock(const MouseCapture& capture) { + auto it = mouseUp.find(capture); + if(it==mouseUp.end()) + return nullptr; + return lock(it->second); + } + Event::Modifier EventDispatcher::mkModifier() const { uint8_t ret = 0; if(keyMod.ctrlL || keyMod.ctrlR) diff --git a/Engine/system/eventdispatcher.h b/Engine/system/eventdispatcher.h index fe9d0f8e..b0e9417d 100644 --- a/Engine/system/eventdispatcher.h +++ b/Engine/system/eventdispatcher.h @@ -4,6 +4,7 @@ #include #include +#include namespace Tempest { @@ -33,6 +34,8 @@ class EventDispatcher final { void dispatchDestroyWindow(SystemApi::Window* w); private: + using MouseCapture = std::pair; + std::shared_ptr implDispatch(Tempest::Widget &w, Tempest::MouseEvent& event); std::shared_ptr implDispatch(Tempest::Widget &w, Tempest::FocusEvent& event); void implMouseWheel(Widget &w, MouseEvent &event); @@ -44,9 +47,10 @@ class EventDispatcher final { void handleModKey(const KeyEvent& e); std::shared_ptr lock(std::weak_ptr& w); + std::shared_ptr lock(const MouseCapture& capture); Widget* customRoot = nullptr; - std::weak_ptr mouseUp[Event::MouseButton::ButtonLast]; + std::map> mouseUp; std::weak_ptr mouseLast; std::weak_ptr mouseOver; @@ -54,6 +58,7 @@ class EventDispatcher final { std::vector overlays; Event::MouseButton mouseLastBtn = Event::MouseButton::ButtonNone; + int mouseLastId = 0; uint64_t mouseLastTime = 0; uint64_t mouseEvCount = 0; diff --git a/Tests/tests/eventdispatcher_test.cpp b/Tests/tests/eventdispatcher_test.cpp index 5df4e00c..4d8d4200 100644 --- a/Tests/tests/eventdispatcher_test.cpp +++ b/Tests/tests/eventdispatcher_test.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -80,3 +82,203 @@ TEST(main,EventDispatcher_MouseEvent) { EXPECT_EQ(b0.up, 1); EXPECT_EQ(b0.move,1); } + +namespace { +struct PointerWidget : Widget { + std::vector events; + std::function onDown, onDrag, onUp; + int doubleClicks = 0; + + void mouseDownEvent(MouseEvent& e) override { + events.push_back(e); + if(onDown) + onDown(e); + } + void mouseDoubleClickEvent(MouseEvent& e) override { + ++doubleClicks; + mouseDownEvent(e); + } + void mouseDragEvent(MouseEvent& e) override { + events.push_back(e); + if(onDrag) + onDrag(e); + } + void mouseMoveEvent(MouseEvent& e) override { + events.push_back(e); + } + void mouseUpEvent(MouseEvent& e) override { + events.push_back(e); + if(onUp) + onUp(e); + } + }; + +struct PointerDispatch : Test { + Widget root; + EventDispatcher dispatcher{root}; + PointerWidget& left = root.addWidget(new PointerWidget()); + PointerWidget& right = root.addWidget(new PointerWidget()); + + PointerDispatch() { + root.resize(200,100); + left.setGeometry(0,0,100,100); + right.setGeometry(100,0,100,100); + } + + void send(Event::Type type, int id, int x, Event::MouseButton button=Event::ButtonLeft) { + MouseEvent e(x,20,button,Event::M_NoModifier,0,id,type); + switch(type) { + case Event::MouseDown: dispatcher.dispatchMouseDown(root,e); break; + case Event::MouseUp: dispatcher.dispatchMouseUp(root,e); break; + case Event::MouseMove: dispatcher.dispatchMouseMove(root,e); break; + default: FAIL(); + } + } + }; +} + +TEST_F(PointerDispatch,SeparateWidgets) { + for(int first:{0,1}) { + left.events.clear(); + right.events.clear(); + send(Event::MouseDown,0,20); + send(Event::MouseDown,1,120); + send(Event::MouseMove,0,150); + send(Event::MouseMove,1,50); + send(Event::MouseUp,first,50); + send(Event::MouseMove,1-first,150); + send(Event::MouseUp,1-first,150); + + for(int id:{0,1}) { + auto& events = id==0 ? left.events : right.events; + ASSERT_EQ(events.size(),id==first ? 3u : 4u); + EXPECT_EQ(events.front().type(),Event::MouseDown); + EXPECT_EQ(events[1].type(),Event::MouseDrag); + EXPECT_EQ(events[1].x,id==0 ? 150 : -50); + EXPECT_EQ(events.back().type(),Event::MouseUp); + for(auto& e:events) + EXPECT_EQ(e.mouseID,id); + } + } + } + +TEST_F(PointerDispatch,SameWidget) { + send(Event::MouseDown,0,20); + send(Event::MouseDown,1,30); + send(Event::MouseMove,0,150); + send(Event::MouseMove,1,160); + send(Event::MouseUp,1,160); + send(Event::MouseUp,0,150); + EXPECT_EQ(left.doubleClicks,0); + ASSERT_EQ(left.events.size(),6u); + EXPECT_EQ(left.events[2].mouseID,0); + EXPECT_EQ(left.events[3].mouseID,1); + EXPECT_EQ(left.events[4].mouseID,1); + EXPECT_EQ(left.events[5].mouseID,0); + EXPECT_EQ(left.events[4].type(),Event::MouseUp); + EXPECT_EQ(left.events[5].type(),Event::MouseUp); + } + +TEST_F(PointerDispatch,MouseButtonsAndDoubleClick) { + send(Event::MouseDown,0,20); + send(Event::MouseDown,0,120,Event::ButtonRight); + send(Event::MouseMove,0,180); + send(Event::MouseUp,0,180); + send(Event::MouseMove,0,20); + send(Event::MouseUp,0,20,Event::ButtonRight); + ASSERT_EQ(left.events.size(),3u); + ASSERT_EQ(right.events.size(),3u); + EXPECT_EQ(left.events[1].button,Event::ButtonLeft); + EXPECT_EQ(right.events[1].button,Event::ButtonRight); + send(Event::MouseDown,0,120,Event::ButtonRight); + EXPECT_EQ(right.doubleClicks,1); + send(Event::MouseUp,0,120,Event::ButtonRight); + EXPECT_EQ(right.events.back().type(),Event::MouseUp); + } + +TEST_F(PointerDispatch,UncapturedPointer) { + send(Event::MouseDown,0,20); + send(Event::MouseUp,1,120); + send(Event::MouseMove,1,120); + send(Event::MouseMove,0,120); + send(Event::MouseUp,0,120); + ASSERT_EQ(left.events.size(),3u); + EXPECT_EQ(left.events[1].type(),Event::MouseDrag); + EXPECT_EQ(left.events[2].type(),Event::MouseUp); + ASSERT_EQ(right.events.size(),1u); + EXPECT_EQ(right.events[0].type(),Event::MouseMove); + EXPECT_EQ(right.events[0].mouseID,1); + } + +TEST_F(PointerDispatch,NestedReleaseDuringDown) { + left.onDown = [&](MouseEvent&) { send(Event::MouseUp,0,20); }; + send(Event::MouseDown,1,120); + send(Event::MouseDown,0,20); + send(Event::MouseMove,0,150); + send(Event::MouseUp,1,150); + ASSERT_EQ(left.events.size(),1u); + ASSERT_EQ(right.events.size(),3u); + EXPECT_EQ(right.events[1].type(),Event::MouseMove); + EXPECT_EQ(right.events[1].mouseID,0); + EXPECT_EQ(right.events[2].type(),Event::MouseUp); + EXPECT_EQ(right.events[2].mouseID,1); + } + +TEST_F(PointerDispatch,NestedReleaseDuringDrag) { + left.onDrag = [&](MouseEvent& e) { + send(Event::MouseUp,0,20); + e.ignore(); + }; + send(Event::MouseDown,0,20); + send(Event::MouseMove,0,120); + ASSERT_EQ(left.events.size(),3u); + EXPECT_EQ(left.events.back().type(),Event::MouseUp); + ASSERT_EQ(right.events.size(),1u); + EXPECT_EQ(right.events[0].type(),Event::MouseMove); + } + +TEST_F(PointerDispatch,NestedDownDuringRelease) { + left.onUp = [&](MouseEvent&) { send(Event::MouseDown,0,120); }; + send(Event::MouseDown,0,20); + send(Event::MouseUp,0,20); + send(Event::MouseMove,0,20); + send(Event::MouseUp,0,20); + ASSERT_EQ(left.events.size(),2u); + ASSERT_EQ(right.events.size(),3u); + EXPECT_EQ(right.events[1].type(),Event::MouseDrag); + EXPECT_EQ(right.events[2].type(),Event::MouseUp); + } + +TEST_F(PointerDispatch,DeletedCapture) { + send(Event::MouseDown,0,20); + send(Event::MouseDown,1,120); + delete &left; + send(Event::MouseMove,0,120); + send(Event::MouseUp,0,120); + send(Event::MouseMove,1,20); + send(Event::MouseUp,1,20); + ASSERT_EQ(right.events.size(),4u); + EXPECT_EQ(right.events[1].type(),Event::MouseMove); + EXPECT_EQ(right.events[1].mouseID,0); + EXPECT_EQ(right.events[2].type(),Event::MouseDrag); + EXPECT_EQ(right.events[2].mouseID,1); + EXPECT_EQ(right.events[3].type(),Event::MouseUp); + EXPECT_EQ(right.events[3].mouseID,1); + } + +TEST_F(PointerDispatch,DeletedDuringDown) { + struct ClosingWidget : Widget { + void mouseDownEvent(MouseEvent&) override { delete this; } + }; + auto& closing = root.addWidget(new ClosingWidget()); + closing.setGeometry(0,0,100,100); + send(Event::MouseDown,1,120); + send(Event::MouseDown,0,20); + send(Event::MouseMove,0,120); + send(Event::MouseUp,1,120); + ASSERT_EQ(right.events.size(),3u); + EXPECT_EQ(right.events[1].type(),Event::MouseMove); + EXPECT_EQ(right.events[1].mouseID,0); + EXPECT_EQ(right.events[2].type(),Event::MouseUp); + EXPECT_EQ(right.events[2].mouseID,1); + } From 3d27b5e6abc29f22055f5cc5f6022b5b1ce35bac Mon Sep 17 00:00:00 2001 From: Patrick Baran Date: Thu, 1 Oct 2026 21:20:12 +0100 Subject: [PATCH 2/3] Use a vector for mouse capture entries --- Engine/system/eventdispatcher.cpp | 54 +++++++++++++++------------- Engine/system/eventdispatcher.h | 12 ++++--- Tests/tests/eventdispatcher_test.cpp | 43 ++++++++++++++++++++++ 3 files changed, 80 insertions(+), 29 deletions(-) diff --git a/Engine/system/eventdispatcher.cpp b/Engine/system/eventdispatcher.cpp index a3217488..5b126429 100644 --- a/Engine/system/eventdispatcher.cpp +++ b/Engine/system/eventdispatcher.cpp @@ -27,7 +27,6 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { Event::MouseDown ); e1.ignore(); - const MouseCapture capture = {e.mouseID,e.button}; std::weak_ptr btn; for(auto i:overlays) { if(!i->bind(wnd)) @@ -57,9 +56,13 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { mouseLastId = e.mouseID; } - if(btn.expired()) - mouseUp.erase(capture); else - mouseUp[capture] = btn; + for(auto i=mouseUp.begin(); i!=mouseUp.end(); ++i) + if(i->id==e.mouseID && i->button==e.button) { + mouseUp.erase(i); + break; + } + if(!btn.expired()) + mouseUp.push_back({e.button,e.mouseID,btn}); if(auto w = btn.lock()) { if(w->widget->focusPolicy() & ClickFocus) { @@ -71,11 +74,13 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { void EventDispatcher::dispatchMouseUp(Widget& /*wnd*/, MouseEvent &e) { ++mouseEvCount; - auto it = mouseUp.find({e.mouseID,e.button}); - if(it==mouseUp.end()) - return; - auto ptr = it->second; - mouseUp.erase(it); + std::weak_ptr ptr; + for(auto i=mouseUp.begin(); i!=mouseUp.end(); ++i) + if(i->id==e.mouseID && i->button==e.button) { + ptr = i->ref; + mouseUp.erase(i); + break; + } if(auto w = ptr.lock()) { auto p = e.pos() - w->widget->mapToRoot(Point()); @@ -91,15 +96,14 @@ void EventDispatcher::dispatchMouseUp(Widget& /*wnd*/, MouseEvent &e) { } void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { - auto btn = Event::ButtonNone; - for(auto i=mouseUp.lower_bound({e.mouseID,Event::ButtonNone}); i!=mouseUp.end() && i->first.first==e.mouseID; ++i) - if(!i->second.expired()) { - btn = i->first.second; - break; - } - - const MouseCapture capture = {e.mouseID,btn}; - if(auto w = lock(capture)) { + auto btn = Event::ButtonLast; + for(auto& i:mouseUp) + if(i.id==e.mouseID && i.buttonwidget->mapToRoot(Point()); MouseEvent e0( p.x, p.y, @@ -113,7 +117,7 @@ void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { return; } - if(auto w = lock(capture)) { + if(auto w = lock(e.mouseID,btn)) { auto p = e.pos() - w->widget->mapToRoot(Point()); MouseEvent e1( p.x, p.y, @@ -124,7 +128,7 @@ void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { Event::MouseMove ); w->widget->mouseMoveEvent(e1); if(e.isAccepted()) { - implSetMouseOver(lock(capture),e); + implSetMouseOver(lock(e.mouseID,btn),e); return; } } @@ -532,11 +536,11 @@ std::shared_ptr EventDispatcher::lock(std::weak_ptr& w return nullptr; } -std::shared_ptr EventDispatcher::lock(const MouseCapture& capture) { - auto it = mouseUp.find(capture); - if(it==mouseUp.end()) - return nullptr; - return lock(it->second); +std::shared_ptr EventDispatcher::lock(int id, Event::MouseButton button) { + for(auto& i:mouseUp) + if(i.id==id && i.button==button) + return lock(i.ref); + return nullptr; } Event::Modifier EventDispatcher::mkModifier() const { diff --git a/Engine/system/eventdispatcher.h b/Engine/system/eventdispatcher.h index b0e9417d..5dfd1e2a 100644 --- a/Engine/system/eventdispatcher.h +++ b/Engine/system/eventdispatcher.h @@ -4,7 +4,7 @@ #include #include -#include +#include namespace Tempest { @@ -34,7 +34,11 @@ class EventDispatcher final { void dispatchDestroyWindow(SystemApi::Window* w); private: - using MouseCapture = std::pair; + struct MouseCapture { + Event::MouseButton button = {}; + int id = 0; + std::weak_ptr ref = {}; + }; std::shared_ptr implDispatch(Tempest::Widget &w, Tempest::MouseEvent& event); std::shared_ptr implDispatch(Tempest::Widget &w, Tempest::FocusEvent& event); @@ -47,10 +51,10 @@ class EventDispatcher final { void handleModKey(const KeyEvent& e); std::shared_ptr lock(std::weak_ptr& w); - std::shared_ptr lock(const MouseCapture& capture); + std::shared_ptr lock(int id, Event::MouseButton button); Widget* customRoot = nullptr; - std::map> mouseUp; + std::vector mouseUp; std::weak_ptr mouseLast; std::weak_ptr mouseOver; diff --git a/Tests/tests/eventdispatcher_test.cpp b/Tests/tests/eventdispatcher_test.cpp index 4d8d4200..94ba35d7 100644 --- a/Tests/tests/eventdispatcher_test.cpp +++ b/Tests/tests/eventdispatcher_test.cpp @@ -196,6 +196,30 @@ TEST_F(PointerDispatch,MouseButtonsAndDoubleClick) { EXPECT_EQ(right.events.back().type(),Event::MouseUp); } +TEST_F(PointerDispatch,MouseButtonsReverseOrder) { + send(Event::MouseDown,0,120,Event::ButtonRight); + send(Event::MouseDown,0,20); + send(Event::MouseMove,0,180); + ASSERT_EQ(left.events.size(),2u); + ASSERT_EQ(right.events.size(),1u); + EXPECT_EQ(left.events.back().type(),Event::MouseDrag); + EXPECT_EQ(left.events.back().button,Event::ButtonLeft); + send(Event::MouseUp,0,180); + send(Event::MouseUp,0,180,Event::ButtonRight); + } + +TEST_F(PointerDispatch,RepeatedDownReplacesCapture) { + send(Event::MouseDown,0,20); + send(Event::MouseDown,0,120); + send(Event::MouseMove,0,20); + send(Event::MouseUp,0,20); + send(Event::MouseUp,0,20); + ASSERT_EQ(left.events.size(),1u); + ASSERT_EQ(right.events.size(),3u); + EXPECT_EQ(right.events[1].type(),Event::MouseDrag); + EXPECT_EQ(right.events[2].type(),Event::MouseUp); + } + TEST_F(PointerDispatch,UncapturedPointer) { send(Event::MouseDown,0,20); send(Event::MouseUp,1,120); @@ -237,6 +261,25 @@ TEST_F(PointerDispatch,NestedReleaseDuringDrag) { EXPECT_EQ(right.events[0].type(),Event::MouseMove); } +TEST_F(PointerDispatch,NestedDownDuringDrag) { + left.onDrag = [&](MouseEvent& e) { + send(Event::MouseDown,1,120); + e.ignore(); + }; + send(Event::MouseDown,0,20); + send(Event::MouseMove,0,120); + ASSERT_EQ(left.events.size(),3u); + EXPECT_EQ(left.events.back().type(),Event::MouseMove); + EXPECT_EQ(left.events.back().mouseID,0); + send(Event::MouseUp,0,120); + send(Event::MouseMove,1,20); + send(Event::MouseUp,1,20); + ASSERT_EQ(right.events.size(),3u); + EXPECT_EQ(right.events[1].type(),Event::MouseDrag); + EXPECT_EQ(right.events[1].mouseID,1); + EXPECT_EQ(right.events[2].type(),Event::MouseUp); + } + TEST_F(PointerDispatch,NestedDownDuringRelease) { left.onUp = [&](MouseEvent&) { send(Event::MouseDown,0,120); }; send(Event::MouseDown,0,20); From 6d6f1e4204e39548291e27f252699994b36e32a1 Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 5 Oct 2026 23:34:51 +0200 Subject: [PATCH 3/3] cleanups --- Engine/system/eventdispatcher.cpp | 36 +++++++++++++++++-------------- Engine/system/eventdispatcher.h | 3 ++- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Engine/system/eventdispatcher.cpp b/Engine/system/eventdispatcher.cpp index 5b126429..66c10303 100644 --- a/Engine/system/eventdispatcher.cpp +++ b/Engine/system/eventdispatcher.cpp @@ -56,13 +56,7 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { mouseLastId = e.mouseID; } - for(auto i=mouseUp.begin(); i!=mouseUp.end(); ++i) - if(i->id==e.mouseID && i->button==e.button) { - mouseUp.erase(i); - break; - } - if(!btn.expired()) - mouseUp.push_back({e.button,e.mouseID,btn}); + reset(e.mouseID, e.button, btn); if(auto w = btn.lock()) { if(w->widget->focusPolicy() & ClickFocus) { @@ -74,14 +68,7 @@ void EventDispatcher::dispatchMouseDown(Widget& wnd, MouseEvent &e) { void EventDispatcher::dispatchMouseUp(Widget& /*wnd*/, MouseEvent &e) { ++mouseEvCount; - std::weak_ptr ptr; - for(auto i=mouseUp.begin(); i!=mouseUp.end(); ++i) - if(i->id==e.mouseID && i->button==e.button) { - ptr = i->ref; - mouseUp.erase(i); - break; - } - + std::weak_ptr ptr = reset(e.mouseID, e.button); if(auto w = ptr.lock()) { auto p = e.pos() - w->widget->mapToRoot(Point()); MouseEvent e1( p.x, @@ -98,8 +85,9 @@ void EventDispatcher::dispatchMouseUp(Widget& /*wnd*/, MouseEvent &e) { void EventDispatcher::dispatchMouseMove(Widget& wnd, MouseEvent &e) { auto btn = Event::ButtonLast; for(auto& i:mouseUp) - if(i.id==e.mouseID && i.button EventDispatcher::lock(int id, Event::MouseButton bu return nullptr; } +std::weak_ptr EventDispatcher::reset(int id, Event::MouseButton button, const std::weak_ptr& w) { + for(auto i=mouseUp.begin(); i!=mouseUp.end(); ++i) + if(i->id==id && i->button==button) { + auto ptr = i->ref; + if(w.expired()) { + mouseUp.erase(i); + } else { + i->ref = w; + } + return ptr.lock(); + } + if(!w.expired()) + mouseUp.push_back({button,id,w}); + return {}; + } + Event::Modifier EventDispatcher::mkModifier() const { uint8_t ret = 0; if(keyMod.ctrlL || keyMod.ctrlR) diff --git a/Engine/system/eventdispatcher.h b/Engine/system/eventdispatcher.h index 5dfd1e2a..db2d916e 100644 --- a/Engine/system/eventdispatcher.h +++ b/Engine/system/eventdispatcher.h @@ -37,7 +37,7 @@ class EventDispatcher final { struct MouseCapture { Event::MouseButton button = {}; int id = 0; - std::weak_ptr ref = {}; + std::weak_ptr ref = {}; }; std::shared_ptr implDispatch(Tempest::Widget &w, Tempest::MouseEvent& event); @@ -52,6 +52,7 @@ class EventDispatcher final { std::shared_ptr lock(std::weak_ptr& w); std::shared_ptr lock(int id, Event::MouseButton button); + std::weak_ptr reset(int id, Event::MouseButton button, const std::weak_ptr& w = {}); Widget* customRoot = nullptr; std::vector mouseUp;