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; | ||||
| }; | ||||
|   | ||||