Fixed input event ordering. Fixes radial menu show/hide logic
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 824 B |
Before Width: | Height: | Size: 832 B After Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 517 B |
BIN
Mods/vcmi/Data/radialMenu/statusBar.png
Normal file
After Width: | Height: | Size: 97 B |
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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<RadialMenu>(pos.center(), owner, this);
|
||||
if (!on)
|
||||
return;
|
||||
|
||||
std::vector<RadialMenuConfig> 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<RadialMenu>(pos.center(), menuElements);
|
||||
}
|
||||
|
||||
void CGarrisonSlot::update()
|
||||
|
@ -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<void()> & callback)
|
||||
RadialMenuItem::RadialMenuItem(const std::string & imageName, const std::string & hoverText, const std::function<void()> & 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<RadialMenuConfig> & 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<CFilledTexture>("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<void()>& callback )
|
||||
void RadialMenu::addItem(const Point & offset, const std::string & path, const std::string & hoverText, const std::function<void()>& callback )
|
||||
{
|
||||
auto item = std::make_shared<RadialMenuItem>(path, callback);
|
||||
auto item = std::make_shared<RadialMenuItem>(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)
|
||||
|
@ -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<void()> callback;
|
||||
};
|
||||
|
||||
class RadialMenuItem : public CIntObject
|
||||
{
|
||||
friend class RadialMenu;
|
||||
|
||||
std::shared_ptr<IImage> image;
|
||||
std::shared_ptr<CPicture> picture;
|
||||
public:
|
||||
std::function<void()> callback;
|
||||
std::string hoverText;
|
||||
|
||||
RadialMenuItem(const std::string& imageName, const std::function<void()>& callback);
|
||||
public:
|
||||
RadialMenuItem(const std::string & imageName, const std::string & hoverText, const std::function<void()> & 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<std::shared_ptr<RadialMenuItem>> items;
|
||||
|
||||
std::shared_ptr<CFilledTexture> statusBarBackground;
|
||||
std::shared_ptr<CGStatusBar> statusBar;
|
||||
|
||||
void addItem(const Point & offset, const std::string & path, const std::function<void()>& callback );
|
||||
void addItem(const Point & offset, const std::string & path, const std::string & hoverText, const std::function<void()> & callback);
|
||||
|
||||
public:
|
||||
RadialMenu(const Point & positionToCenter, CGarrisonInt * army, CGarrisonSlot * slot);
|
||||
RadialMenu(const Point & positionToCenter, const std::vector<RadialMenuConfig> & 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;
|
||||
};
|
||||
|