Browse Source

CIntObject now receives mouse position as point instead of SDL event

Ivan Savenko 2 years ago
parent
commit
214fc19e74

+ 6 - 6
client/adventureMap/CAdvMapInt.cpp

@@ -971,7 +971,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
 	heroList.redraw();
 }
 
-void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
+void CAdvMapInt::mouseMoved( const Point & cursorPosition )
 {
 #if defined(VCMI_ANDROID) || defined(VCMI_IOS)
 	if(swipeEnabled)
@@ -980,9 +980,9 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 	// adventure map scrolling with mouse
 	// currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed
 	// don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement
-	if(!CSDL_Ext::isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL)
+	if(!CSDL_Ext::isCtrlKeyDown() && isActive() && mode == EAdvMapMode::NORMAL)
 	{
-		if(sEvent.x<15)
+		if(cursorPosition.x<15)
 		{
 			scrollingDir |= LEFT;
 		}
@@ -990,7 +990,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 		{
 			scrollingDir &= ~LEFT;
 		}
-		if(sEvent.x>screen->w-15)
+		if(cursorPosition.x>screen->w-15)
 		{
 			scrollingDir |= RIGHT;
 		}
@@ -998,7 +998,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 		{
 			scrollingDir &= ~RIGHT;
 		}
-		if(sEvent.y<15)
+		if(cursorPosition.y<15)
 		{
 			scrollingDir |= UP;
 		}
@@ -1006,7 +1006,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
 		{
 			scrollingDir &= ~UP;
 		}
-		if(sEvent.y>screen->h-15)
+		if(cursorPosition.y>screen->h-15)
 		{
 			scrollingDir |= DOWN;
 		}

+ 1 - 1
client/adventureMap/CAdvMapInt.h

@@ -159,7 +159,7 @@ public:
 	int3 verifyPos(int3 ver);
 	void handleRightClick(std::string text, tribool down);
 	void keyPressed(const SDL_KeyboardEvent & key) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	bool isActive();
 
 	bool isHeroSleeping(const CGHeroInstance *hero);

+ 1 - 1
client/adventureMap/CMinimap.cpp

@@ -229,7 +229,7 @@ void CMinimap::hover(bool on)
 		GH.statusbar->clear();
 }
 
-void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent)
+void CMinimap::mouseMoved(const Point & cursorPosition)
 {
 	if(mouseState(EIntObjMouseBtnType::LEFT))
 		moveAdvMapSelection();

+ 1 - 1
client/adventureMap/CMinimap.h

@@ -53,7 +53,7 @@ protected:
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 	void hover (bool on) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 
 	void moveAdvMapSelection();
 

+ 15 - 16
client/adventureMap/CTerrainRect.cpp

@@ -110,32 +110,31 @@ void CTerrainRect::clickMiddle(tribool down, bool previousState)
 	handleSwipeStateChange((bool)down == true);
 }
 
-void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
+void CTerrainRect::mouseMoved(const Point & cursorPosition)
 {
-	handleHover(sEvent);
+	handleHover(cursorPosition);
 
 	if(!adventureInt->swipeEnabled)
 		return;
 
-	handleSwipeMove(sEvent);
+	handleSwipeMove(cursorPosition);
 }
 
-void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
+void CTerrainRect::handleSwipeMove(const Point & cursorPosition)
 {
 #if defined(VCMI_ANDROID) || defined(VCMI_IOS)
-	if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile
+	if(!GH.isMouseButtonPressed() || GH.multifinger) // any "button" is enough on mobile
+		return;
 #else
-	if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms
-#endif
-	{
+	if(!GH.isMouseButtonPressed(MouseButton::MIDDLE)) // swipe only works with middle mouse on other platforms
 		return;
-	}
+#endif
 
 	if(!isSwiping)
 	{
 		// try to distinguish if this touch was meant to be a swipe or just fat-fingering press
-		if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop ||
-		   abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop)
+		if(abs(cursorPosition.x - swipeInitialRealPos.x) > SwipeTouchSlop ||
+		   abs(cursorPosition.y - swipeInitialRealPos.y) > SwipeTouchSlop)
 		{
 			isSwiping = true;
 		}
@@ -144,9 +143,9 @@ void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
 	if(isSwiping)
 	{
 		adventureInt->swipeTargetPosition.x =
-			swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - sEvent.x) / 32;
+			swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - cursorPosition.x) / 32;
 		adventureInt->swipeTargetPosition.y =
-			swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - sEvent.y) / 32;
+			swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - cursorPosition.y) / 32;
 		adventureInt->swipeMovementRequested = true;
 	}
 }
@@ -155,7 +154,7 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
 {
 	if(btnPressed)
 	{
-		swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0);
+		swipeInitialRealPos = Point(GH.getCursorPosition().x, GH.getCursorPosition().y);
 		swipeInitialMapPos = int3(adventureInt->position);
 		return true;
 	}
@@ -167,9 +166,9 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
 	return false;
 }
 
-void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent)
+void CTerrainRect::handleHover(const Point & cursorPosition)
 {
-	int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y);
+	int3 tHovered = whichTileIsIt(cursorPosition.x, cursorPosition.y);
 	int3 pom = adventureInt->verifyPos(tHovered);
 
 	if(tHovered != pom) //tile outside the map

+ 4 - 4
client/adventureMap/CTerrainRect.h

@@ -27,12 +27,12 @@ class CTerrainRect : public CIntObject
 	std::shared_ptr<CFadeAnimation> fadeAnim;
 
 	int3 swipeInitialMapPos;
-	int3 swipeInitialRealPos;
+	Point swipeInitialRealPos;
 	bool isSwiping;
 	static constexpr float SwipeTouchSlop = 16.0f;
 
-	void handleHover(const SDL_MouseMotionEvent & sEvent);
-	void handleSwipeMove(const SDL_MouseMotionEvent & sEvent);
+	void handleHover(const Point & cursorPosition);
+	void handleSwipeMove(const Point & cursorPosition);
 	/// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled
 	bool handleSwipeStateChange(bool btnPressed);
 public:
@@ -48,7 +48,7 @@ public:
 	void clickRight(tribool down, bool previousState) override;
 	void clickMiddle(tribool down, bool previousState) override;
 	void hover(bool on) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	void show(SDL_Surface * to) override;
 	void showAll(SDL_Surface * to) override;
 	void showAnim(SDL_Surface * to);

+ 2 - 2
client/battle/BattleFieldController.cpp

@@ -98,9 +98,9 @@ void BattleFieldController::createHeroes()
 		owner.defendingHero = std::make_shared<BattleHero>(owner, owner.defendingHeroInstance, true);
 }
 
-void BattleFieldController::mouseMoved(const SDL_MouseMotionEvent &event)
+void BattleFieldController::mouseMoved(const Point & cursorPosition)
 {
-	if (!pos.isInside(event.x, event.y))
+	if (!pos.isInside(cursorPosition))
 	{
 		owner.actionsController->onHoverEnded();
 		return;

+ 1 - 1
client/battle/BattleFieldController.h

@@ -62,7 +62,7 @@ class BattleFieldController : public CIntObject
 
 	BattleHex::EDir selectAttackDirection(BattleHex myNumber, const Point & point);
 
-	void mouseMoved(const SDL_MouseMotionEvent &event) override;
+	void mouseMoved(const Point & cursorPosition) override;
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 

+ 36 - 9
client/gui/CGuiHandler.cpp

@@ -203,7 +203,12 @@ void CGuiHandler::handleEvents()
 	{
 		continueEventHandling = true;
 		SDL_Event currentEvent = SDLEventsQueue.front();
-		cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
+
+		if (currentEvent.type == SDL_MOUSEMOTION)
+		{
+			cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
+			mouseButtonsMask = currentEvent.motion.state;
+		}
 		SDLEventsQueue.pop();
 
 		// In a sequence of mouse motion events, skip all but the last one.
@@ -546,7 +551,9 @@ void CGuiHandler::handleMouseMotion(const SDL_Event & current)
 		elem->hovered = true;
 	}
 
-	handleMoveInterested(current.motion);
+	// do not send motion events for events outside our window
+	//if (current.motion.windowID == 0)
+		handleMoveInterested(current.motion);
 }
 
 void CGuiHandler::simpleRedraw()
@@ -566,7 +573,7 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
 	{
 		if(elem->strongInterest || Rect::createAround(elem->pos, 1).isInside( motion.x, motion.y)) //checking bounds including border fixes bug #2476
 		{
-			(elem)->mouseMoved(motion);
+			(elem)->mouseMoved(Point(motion.x, motion.y));
 		}
 	}
 }
@@ -612,13 +619,16 @@ void CGuiHandler::renderFrame()
 
 
 CGuiHandler::CGuiHandler()
-	: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false),
-    multifinger(false)
+	: lastClick(-500, -500)
+	, lastClickTime(0)
+	, defActionsDef(0)
+	, captureChildren(false)
+	, multifinger(false)
+	, mouseButtonsMask(0)
+	, continueEventHandling(true)
+	, curInt(nullptr)
+	, statusbar(nullptr)
 {
-	continueEventHandling = true;
-	curInt = nullptr;
-	statusbar = nullptr;
-
 	// Creates the FPS manager and sets the framerate to 48 which is doubled the value of the original Heroes 3 FPS rate
 	mainFPSmng = new CFramerateManager(60);
 	//do not init CFramerateManager here --AVS
@@ -642,6 +652,23 @@ const Point & CGuiHandler::getCursorPosition() const
 	return cursorPosition;
 }
 
+bool CGuiHandler::isMouseButtonPressed() const
+{
+	return mouseButtonsMask > 0;
+}
+
+bool CGuiHandler::isMouseButtonPressed(MouseButton button) const
+{
+	static_assert(static_cast<uint32_t>(MouseButton::LEFT)   == SDL_BUTTON_LEFT,   "mismatch between VCMI and SDL enum!");
+	static_assert(static_cast<uint32_t>(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!");
+	static_assert(static_cast<uint32_t>(MouseButton::RIGHT)  == SDL_BUTTON_RIGHT,  "mismatch between VCMI and SDL enum!");
+	static_assert(static_cast<uint32_t>(MouseButton::EXTRA1) == SDL_BUTTON_X1,     "mismatch between VCMI and SDL enum!");
+	static_assert(static_cast<uint32_t>(MouseButton::EXTRA2) == SDL_BUTTON_X2,     "mismatch between VCMI and SDL enum!");
+
+	uint32_t index = static_cast<uint32_t>(button);
+	return mouseButtonsMask & SDL_BUTTON(index);
+}
+
 void CGuiHandler::drawFPSCounter()
 {
 	static SDL_Rect overlay = { 0, 0, 64, 32};

+ 17 - 0
client/gui/CGuiHandler.h

@@ -43,6 +43,15 @@ enum EUserEvent
 	INTERFACE_CHANGED
 };
 
+enum class MouseButton
+{
+	LEFT   = 1,
+	MIDDLE = 2,
+	RIGHT  = 3,
+	EXTRA1 = 4,
+	EXTRA2 = 5
+};
+
 // A fps manager which holds game updates at a constant rate
 class CFramerateManager
 {
@@ -71,6 +80,7 @@ public:
 
 private:
 	Point cursorPosition;
+	uint32_t mouseButtonsMask;
 
 	std::vector<std::shared_ptr<IShowActivatable>> disposed;
 
@@ -107,8 +117,15 @@ public:
 	//objs to blit
 	std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
 
+	/// returns current position of mouse cursor, relative to vcmi window
 	const Point & getCursorPosition() const;
 
+	/// returns true if at least one mouse button is pressed
+	bool isMouseButtonPressed() const;
+
+	/// returns true if specified mouse button is pressed
+	bool isMouseButtonPressed(MouseButton button) const;
+
 	IUpdateable *curInt;
 
 	Point lastClick;

+ 1 - 2
client/gui/CIntObject.h

@@ -19,7 +19,6 @@ class CPicture;
 struct SDL_KeyboardEvent;
 struct SDL_TextInputEvent;
 struct SDL_TextEditingEvent;
-struct SDL_MouseMotionEvent;
 
 using boost::logic::tribool;
 
@@ -130,7 +129,7 @@ public:
 
 	//mouse movement handling
 	bool strongInterest; //if true - report all mouse movements, if not - only when hovered
-	virtual void mouseMoved (const SDL_MouseMotionEvent & sEvent){}
+	virtual void mouseMoved (const Point & cursorPosition){}
 
 	//time handling
 	void setTimer(int msToTrigger);//set timer delay and activate timer if needed.

+ 5 - 5
client/widgets/Buttons.cpp

@@ -555,22 +555,22 @@ void CSlider::sliderClicked()
 		addUsedEvents(MOVE);
 }
 
-void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
+void CSlider::mouseMoved (const Point & cursorPosition)
 {
 	double v = 0;
 	if(horizontal)
 	{
-		if(	std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2+40  ||  std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2  )
+		if(	std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2+40  ||  std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2  )
 			return;
-		v = sEvent.x - pos.x - 24;
+		v = cursorPosition.x - pos.x - 24;
 		v *= positions;
 		v /= (pos.w - 48);
 	}
 	else
 	{
-		if(std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2+40  ||  std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2  )
+		if(std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2+40  ||  std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2  )
 			return;
-		v = sEvent.y - pos.y - 24;
+		v = cursorPosition.y - pos.y - 24;
 		v *= positions;
 		v /= (pos.h - 48);
 	}

+ 1 - 1
client/widgets/Buttons.h

@@ -273,7 +273,7 @@ public:
 	void keyPressed(const SDL_KeyboardEvent & key) override;
 	void wheelScrolled(bool down, bool in) override;
 	void clickLeft(tribool down, bool previousState) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	void showAll(SDL_Surface * to) override;
 
 	 /// @param position coordinates of slider

+ 3 - 3
client/windows/CCastleInterface.cpp

@@ -241,11 +241,11 @@ std::string CBuildingRect::getSubtitle()//hover text for building
 	}
 }
 
-void CBuildingRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
+void CBuildingRect::mouseMoved (const Point & cursorPosition)
 {
-	if(area && pos.isInside(sEvent.x, sEvent.y))
+	if(area && pos.isInside(cursorPosition.x, cursorPosition.y))
 	{
-		if(area->isTransparent(GH.getCursorPosition() - pos.topLeft())) //hovered pixel is inside this building
+		if(area->isTransparent(cursorPosition - pos.topLeft())) //hovered pixel is inside this building
 		{
 			if(parent->selectedBuilding == this)
 			{

+ 1 - 1
client/windows/CCastleInterface.h

@@ -68,7 +68,7 @@ public:
 	void hover(bool on) override;
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
+	void mouseMoved (const Point & cursorPosition) override;
 	void show(SDL_Surface * to) override;
 	void showAll(SDL_Surface * to) override;
 };

+ 1 - 1
client/windows/CQuestLog.h

@@ -66,7 +66,7 @@ class CQuestMinimap : public CMinimap
 
 	void clickLeft(tribool down, bool previousState) override{}; //minimap ignores clicking on its surface
 	void iconClicked();
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent) override{};
+	void mouseMoved (const Point & cursorPosition) override{};
 
 public:
 	const QuestInfo * currentQuest;