From 214fc19e749789703ef4524e72f7ce9da7af8164 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 2 Feb 2023 15:49:23 +0200 Subject: [PATCH] CIntObject now receives mouse position as point instead of SDL event --- client/adventureMap/CAdvMapInt.cpp | 12 +++---- client/adventureMap/CAdvMapInt.h | 2 +- client/adventureMap/CMinimap.cpp | 2 +- client/adventureMap/CMinimap.h | 2 +- client/adventureMap/CTerrainRect.cpp | 33 +++++++++--------- client/adventureMap/CTerrainRect.h | 8 ++--- client/battle/BattleFieldController.cpp | 4 +-- client/battle/BattleFieldController.h | 2 +- client/gui/CGuiHandler.cpp | 45 ++++++++++++++++++++----- client/gui/CGuiHandler.h | 17 ++++++++++ client/gui/CIntObject.h | 3 +- client/widgets/Buttons.cpp | 10 +++--- client/widgets/Buttons.h | 2 +- client/windows/CCastleInterface.cpp | 6 ++-- client/windows/CCastleInterface.h | 2 +- client/windows/CQuestLog.h | 2 +- 16 files changed, 97 insertions(+), 55 deletions(-) diff --git a/client/adventureMap/CAdvMapInt.cpp b/client/adventureMap/CAdvMapInt.cpp index e7a6139d0..7fd40d60b 100644 --- a/client/adventureMap/CAdvMapInt.cpp +++ b/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; } diff --git a/client/adventureMap/CAdvMapInt.h b/client/adventureMap/CAdvMapInt.h index ea7c07e80..e4cf8dfc4 100644 --- a/client/adventureMap/CAdvMapInt.h +++ b/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); diff --git a/client/adventureMap/CMinimap.cpp b/client/adventureMap/CMinimap.cpp index 9e0f41c5e..7d7c398b6 100644 --- a/client/adventureMap/CMinimap.cpp +++ b/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(); diff --git a/client/adventureMap/CMinimap.h b/client/adventureMap/CMinimap.h index f7df33b2f..eb872681e 100644 --- a/client/adventureMap/CMinimap.h +++ b/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(); diff --git a/client/adventureMap/CTerrainRect.cpp b/client/adventureMap/CTerrainRect.cpp index 1bf788967..944b62e09 100644 --- a/client/adventureMap/CTerrainRect.cpp +++ b/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 -#else - if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms -#endif - { + if(!GH.isMouseButtonPressed() || GH.multifinger) // any "button" is enough on mobile return; - } +#else + 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(swipeInitialRealPos.x - sEvent.x) / 32; + swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - cursorPosition.x) / 32; adventureInt->swipeTargetPosition.y = - swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; + swipeInitialMapPos.y + static_cast(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 diff --git a/client/adventureMap/CTerrainRect.h b/client/adventureMap/CTerrainRect.h index 4945f905f..e657d7f07 100644 --- a/client/adventureMap/CTerrainRect.h +++ b/client/adventureMap/CTerrainRect.h @@ -27,12 +27,12 @@ class CTerrainRect : public CIntObject std::shared_ptr 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); diff --git a/client/battle/BattleFieldController.cpp b/client/battle/BattleFieldController.cpp index 522e506d3..61d8a0542 100644 --- a/client/battle/BattleFieldController.cpp +++ b/client/battle/BattleFieldController.cpp @@ -98,9 +98,9 @@ void BattleFieldController::createHeroes() owner.defendingHero = std::make_shared(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; diff --git a/client/battle/BattleFieldController.h b/client/battle/BattleFieldController.h index 0fa0e2910..ec998fd62 100644 --- a/client/battle/BattleFieldController.h +++ b/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; diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index ae9b0624f..7b0078f54 100644 --- a/client/gui/CGuiHandler.cpp +++ b/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(MouseButton::LEFT) == SDL_BUTTON_LEFT, "mismatch between VCMI and SDL enum!"); + static_assert(static_cast(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!"); + static_assert(static_cast(MouseButton::RIGHT) == SDL_BUTTON_RIGHT, "mismatch between VCMI and SDL enum!"); + static_assert(static_cast(MouseButton::EXTRA1) == SDL_BUTTON_X1, "mismatch between VCMI and SDL enum!"); + static_assert(static_cast(MouseButton::EXTRA2) == SDL_BUTTON_X2, "mismatch between VCMI and SDL enum!"); + + uint32_t index = static_cast(button); + return mouseButtonsMask & SDL_BUTTON(index); +} + void CGuiHandler::drawFPSCounter() { static SDL_Rect overlay = { 0, 0, 64, 32}; diff --git a/client/gui/CGuiHandler.h b/client/gui/CGuiHandler.h index ae4220008..4d2410538 100644 --- a/client/gui/CGuiHandler.h +++ b/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> disposed; @@ -107,8 +117,15 @@ public: //objs to blit std::vector> 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; diff --git a/client/gui/CIntObject.h b/client/gui/CIntObject.h index a61fe5d6f..2a4f6d68d 100644 --- a/client/gui/CIntObject.h +++ b/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. diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp index 514d62cea..ae873c4cc 100644 --- a/client/widgets/Buttons.cpp +++ b/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); } diff --git a/client/widgets/Buttons.h b/client/widgets/Buttons.h index 33f0533ce..0e016f7df 100644 --- a/client/widgets/Buttons.h +++ b/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 diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 9de836afb..f08f56bf2 100644 --- a/client/windows/CCastleInterface.cpp +++ b/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) { diff --git a/client/windows/CCastleInterface.h b/client/windows/CCastleInterface.h index b8410856c..a5f2b961e 100644 --- a/client/windows/CCastleInterface.h +++ b/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; }; diff --git a/client/windows/CQuestLog.h b/client/windows/CQuestLog.h index 9654d0481..a82e3ac8a 100644 --- a/client/windows/CQuestLog.h +++ b/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;