From e3f5ab57f2697398042700f1c84fa7a3a964e598 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 16 Jul 2023 17:56:47 +0300 Subject: [PATCH] Fixed input event ordering. Fixes radial menu show/hide logic --- .../{stackMove.png => heroMove.png} | Bin .../{stackSwap.png => heroSwap.png} | Bin .../{stackEmpty.png => itemEmpty.png} | Bin Mods/vcmi/Data/radialMenu/statusBar.png | Bin 0 -> 97 bytes client/eventsSDL/InputSourceMouse.cpp | 4 +- client/gui/EventDispatcher.cpp | 22 +++++---- client/gui/EventsReceiver.cpp | 15 ++++-- client/gui/EventsReceiver.h | 3 -- client/widgets/CGarrisonInt.cpp | 14 +++++- client/widgets/RadialMenu.cpp | 45 ++++-------------- client/widgets/RadialMenu.h | 39 ++++++++------- 11 files changed, 67 insertions(+), 75 deletions(-) rename Mods/vcmi/Data/radialMenu/{stackMove.png => heroMove.png} (100%) rename Mods/vcmi/Data/radialMenu/{stackSwap.png => heroSwap.png} (100%) rename Mods/vcmi/Data/radialMenu/{stackEmpty.png => itemEmpty.png} (100%) create mode 100644 Mods/vcmi/Data/radialMenu/statusBar.png diff --git a/Mods/vcmi/Data/radialMenu/stackMove.png b/Mods/vcmi/Data/radialMenu/heroMove.png similarity index 100% rename from Mods/vcmi/Data/radialMenu/stackMove.png rename to Mods/vcmi/Data/radialMenu/heroMove.png diff --git a/Mods/vcmi/Data/radialMenu/stackSwap.png b/Mods/vcmi/Data/radialMenu/heroSwap.png similarity index 100% rename from Mods/vcmi/Data/radialMenu/stackSwap.png rename to Mods/vcmi/Data/radialMenu/heroSwap.png diff --git a/Mods/vcmi/Data/radialMenu/stackEmpty.png b/Mods/vcmi/Data/radialMenu/itemEmpty.png similarity index 100% rename from Mods/vcmi/Data/radialMenu/stackEmpty.png rename to Mods/vcmi/Data/radialMenu/itemEmpty.png diff --git a/Mods/vcmi/Data/radialMenu/statusBar.png b/Mods/vcmi/Data/radialMenu/statusBar.png new file mode 100644 index 0000000000000000000000000000000000000000..1234e754305961f81903680bd97546e18c0a8811 GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^&wyBjkr_xX{&)EmkYWq)332^@KO4wgrr6a9q{KX3 t978G?lMnE}`u~{C-fhd96*_SY43Dn=>qy^tw+N_$!PC{xWt~$(69Cz>9y|a5 literal 0 HcmV?d00001 diff --git a/client/eventsSDL/InputSourceMouse.cpp b/client/eventsSDL/InputSourceMouse.cpp index 7d35b6797..cf2b80785 100644 --- a/client/eventsSDL/InputSourceMouse.cpp +++ b/client/eventsSDL/InputSourceMouse.cpp @@ -30,14 +30,14 @@ void InputSourceMouse::handleEventMouseMotion(const SDL_MouseMotionEvent & motio Point newPosition(motion.x, motion.y); Point distance(-motion.xrel, -motion.yrel); + mouseButtonsMask = motion.state; + if (mouseButtonsMask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) GH.events().dispatchGesturePanning(middleClickPosition, newPosition, distance); else if (mouseButtonsMask & SDL_BUTTON(SDL_BUTTON_LEFT)) GH.events().dispatchMouseDragged(newPosition, distance); else GH.input().setCursorPosition(newPosition); - - mouseButtonsMask = motion.state; } void InputSourceMouse::handleEventMouseButtonDown(const SDL_MouseButtonEvent & button) diff --git a/client/gui/EventDispatcher.cpp b/client/gui/EventDispatcher.cpp index 19ed96b6f..068cbb8b3 100644 --- a/client/gui/EventDispatcher.cpp +++ b/client/gui/EventDispatcher.cpp @@ -243,39 +243,41 @@ void EventDispatcher::dispatchGesturePanningStarted(const Point & initialPositio for(auto it : copied) { - if (it->receiveEvent(initialPosition, AEventsReceiver::GESTURE)) + if (!vstd::contains(panningInterested, it)) + continue; + + if (!it->isGesturing() && it->receiveEvent(initialPosition, AEventsReceiver::GESTURE)) { - it->gesture(true, initialPosition, initialPosition); it->panningState = true; + it->gesture(true, initialPosition, initialPosition); } } } void EventDispatcher::dispatchGesturePanningEnded(const Point & initialPosition, const Point & finalPosition) { + dispatchGesturePanningStarted(initialPosition); auto copied = panningInterested; for(auto it : copied) { if (it->isGesturing()) { - it->gesture(false, initialPosition, finalPosition); it->panningState = false; + it->gesture(false, initialPosition, finalPosition); } } } void EventDispatcher::dispatchGesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) { + dispatchGesturePanningStarted(initialPosition); auto copied = panningInterested; for(auto it : copied) { - if (!it->isGesturing() && it->receiveEvent(initialPosition, AEventsReceiver::GESTURE)) - { - it->gesture(true, initialPosition, initialPosition); - it->panningState = true; - } + if (!vstd::contains(panningInterested, it)) + continue; if (it->isGesturing()) it->gesturePanning(initialPosition, currentPosition, lastUpdateDistance); @@ -309,16 +311,16 @@ void EventDispatcher::dispatchMouseMoved(const Point & distance, const Point & p { if (elem->isHovered()) { - elem->hover(false); elem->hoveredState = false; + elem->hover(false); } } } for(auto & elem : newlyHovered) { - elem->hover(true); elem->hoveredState = true; + elem->hover(true); } //sending active, MotionInterested objects mouseMoved() call diff --git a/client/gui/EventsReceiver.cpp b/client/gui/EventsReceiver.cpp index aa44124b3..2dbed3a33 100644 --- a/client/gui/EventsReceiver.cpp +++ b/client/gui/EventsReceiver.cpp @@ -37,11 +37,6 @@ bool AEventsReceiver::isActive() const return activeState; } -bool AEventsReceiver::isMouseLeftButtonPressed() const -{ - return mouseClickedState; -} - void AEventsReceiver::activateEvents(ui16 what) { assert((what & GENERAL) || (activeState & GENERAL)); @@ -62,4 +57,14 @@ void AEventsReceiver::deactivateEvents(ui16 what) what = activeState; } GH.events().deactivateElement(this, what & activeState); + + if (!(activeState & GESTURE) && panningState) + panningState = false; + + if (!(activeState & LCLICK) && mouseClickedState) + mouseClickedState = false; + +// FIXME: might lead to regressions, recheck before enabling +// if (!(activeState & HOVER)) +// hoveredState = false; } diff --git a/client/gui/EventsReceiver.h b/client/gui/EventsReceiver.h index af94c9290..37aeb5fa4 100644 --- a/client/gui/EventsReceiver.h +++ b/client/gui/EventsReceiver.h @@ -99,7 +99,4 @@ public: /// Returns true if element is currently active and may receive events bool isActive() const; - - /// Returns true if left mouse button was pressed when inside this element - bool isMouseLeftButtonPressed() const; }; diff --git a/client/widgets/CGarrisonInt.cpp b/client/widgets/CGarrisonInt.cpp index 3d52d9a0c..bbb57dda6 100644 --- a/client/widgets/CGarrisonInt.cpp +++ b/client/widgets/CGarrisonInt.cpp @@ -347,8 +347,18 @@ void CGarrisonSlot::clickPressed(const Point & cursorPosition) void CGarrisonSlot::gesture(bool on, const Point & initialPosition, const Point & finalPosition) { - if (on) - GH.windows().createAndPushWindow(pos.center(), owner, this); + if (!on) + return; + + std::vector menuElements = { + { RadialMenuConfig::ITEM_NW, "stackMerge", "", [this](){owner->bulkMergeStacks(this);} }, + { RadialMenuConfig::ITEM_NE, "stackInfo", "", [this](){viewInfo();} }, + { RadialMenuConfig::ITEM_WW, "stackSplitOne", "", [this](){splitIntoParts(this->getGarrison(), 1); } }, + { RadialMenuConfig::ITEM_EE, "stackSplitEqual", "", [this](){owner->bulkSmartSplitStack(this);} }, + { RadialMenuConfig::ITEM_SW, "heroMove", "", [this](){owner->moveStackToAnotherArmy(this);} }, + }; + + GH.windows().createAndPushWindow(pos.center(), menuElements); } void CGarrisonSlot::update() diff --git a/client/widgets/RadialMenu.cpp b/client/widgets/RadialMenu.cpp index 88aa5b376..d13fd1931 100644 --- a/client/widgets/RadialMenu.cpp +++ b/client/widgets/RadialMenu.cpp @@ -16,10 +16,10 @@ #include "../gui/CGuiHandler.h" #include "../gui/WindowHandler.h" #include "../render/IImage.h" -#include "CGarrisonInt.h" -RadialMenuItem::RadialMenuItem(const std::string & imageName, const std::function & callback) +RadialMenuItem::RadialMenuItem(const std::string & imageName, const std::string & hoverText, const std::function & callback) : callback(callback) + , hoverText(hoverText) { OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; @@ -35,42 +35,20 @@ bool RadialMenuItem::isInside(const Point & position) return !image->isTransparent(localPosition); } -void RadialMenuItem::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) -{ - -} - -void RadialMenuItem::gesture(bool on, const Point & initialPosition, const Point & finalPosition) -{ - -} - -RadialMenu::RadialMenu(const Point & positionToCenter, CGarrisonInt * army, CGarrisonSlot * slot) +RadialMenu::RadialMenu(const Point & positionToCenter, const std::vector & menuConfig) { OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; pos += positionToCenter; - bool isExchange = army->upperArmy() && army->lowerArmy(); // two armies exist - - addItem(Point(0,0), "stackEmpty", [](){}); + addItem(Point(0,0), "itemEmpty", "", [](){}); Point itemSize = items.back()->pos.dimensions(); moveBy(-itemSize / 2); - addItem(ITEM_NW, "stackMerge", [=](){army->bulkMergeStacks(slot);}); - addItem(ITEM_NE, "stackInfo", [=](){slot->viewInfo();}); + for (auto const & item : menuConfig) + addItem(item.itemPosition, item.imageName, item.hoverText, item.callback); - addItem(ITEM_WW, "stackSplitOne", [=](){slot->splitIntoParts(slot->getGarrison(), 1); }); - addItem(ITEM_EE, "stackSplitEqual", [=](){army->bulkSmartSplitStack(slot);}); - - if (isExchange) - { - addItem(ITEM_SW, "stackMove", [=](){army->moveStackToAnotherArmy(slot);}); - //FIXME: addItem(ITEM_SE, "stackSplitDialog", [=](){slot->split();}); - } - - //statusBarBackground = std::make_shared("DiBoxBck", Rect(-itemSize.x * 2, -100, itemSize.x * 4, 20)); - //statusBar = CGStatusBar::create(statusBarBackground); + statusBar = CGStatusBar::create(-80, -100, "radialMenu/statusBar"); for(const auto & item : items) pos = pos.include(item->pos); @@ -80,9 +58,9 @@ RadialMenu::RadialMenu(const Point & positionToCenter, CGarrisonInt * army, CGar addUsedEvents(GESTURE); } -void RadialMenu::addItem(const Point & offset, const std::string & path, const std::function& callback ) +void RadialMenu::addItem(const Point & offset, const std::string & path, const std::string & hoverText, const std::function& callback ) { - auto item = std::make_shared(path, callback); + auto item = std::make_shared(path, hoverText, callback); item->moveBy(offset); @@ -94,11 +72,6 @@ void RadialMenu::gesturePanning(const Point & initialPosition, const Point & cur } -void RadialMenu::show(Canvas & to) -{ - showAll(to); -} - void RadialMenu::gesture(bool on, const Point & initialPosition, const Point & finalPosition) { if (!on) diff --git a/client/widgets/RadialMenu.h b/client/widgets/RadialMenu.h index 10ac3229d..e9df78d06 100644 --- a/client/widgets/RadialMenu.h +++ b/client/widgets/RadialMenu.h @@ -15,44 +15,49 @@ class IImage; class CGarrisonInt; class CGarrisonSlot; -class CFilledTexture; class CGStatusBar; +struct RadialMenuConfig +{ + static constexpr Point ITEM_NW = Point(-40, -70); + static constexpr Point ITEM_NE = Point(+40, -70); + static constexpr Point ITEM_WW = Point(-80, 0); + static constexpr Point ITEM_EE = Point(+80, 0); + static constexpr Point ITEM_SW = Point(-40, +70); + static constexpr Point ITEM_SE = Point(+40, +70); + + Point itemPosition; + std::string imageName; + std::string hoverText; + std::function callback; +}; class RadialMenuItem : public CIntObject { + friend class RadialMenu; + std::shared_ptr image; std::shared_ptr picture; -public: std::function callback; + std::string hoverText; - RadialMenuItem(const std::string& imageName, const std::function& callback); +public: + RadialMenuItem(const std::string & imageName, const std::string & hoverText, const std::function & callback); bool isInside(const Point & position); - - void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override; - void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override; }; class RadialMenu : public CIntObject { - static constexpr Point ITEM_NW = Point( -40, -70); - static constexpr Point ITEM_NE = Point( +40, -70); - static constexpr Point ITEM_WW = Point( -80, 0); - static constexpr Point ITEM_EE = Point( +80, 0); - static constexpr Point ITEM_SW = Point( -40, +70); - static constexpr Point ITEM_SE = Point( +40, +70); - std::vector> items; - std::shared_ptr statusBarBackground; std::shared_ptr statusBar; - void addItem(const Point & offset, const std::string & path, const std::function& callback ); + void addItem(const Point & offset, const std::string & path, const std::string & hoverText, const std::function & callback); + public: - RadialMenu(const Point & positionToCenter, CGarrisonInt * army, CGarrisonSlot * slot); + RadialMenu(const Point & positionToCenter, const std::vector & menuConfig); void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override; void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override; - void show(Canvas & to) override; };