diff --git a/client/eventsSDL/InputSourceTouch.cpp b/client/eventsSDL/InputSourceTouch.cpp index e7395d22b..bd5ad8211 100644 --- a/client/eventsSDL/InputSourceTouch.cpp +++ b/client/eventsSDL/InputSourceTouch.cpp @@ -204,7 +204,12 @@ void InputSourceTouch::handleUpdate() Point InputSourceTouch::convertTouchToMouse(const SDL_TouchFingerEvent & tfinger) { - return Point(tfinger.x * GH.screenDimensions().x, tfinger.y * GH.screenDimensions().y); + return convertTouchToMouse(tfinger.x, tfinger.y); +} + +Point InputSourceTouch::convertTouchToMouse(float x, float y) +{ + return Point(x * GH.screenDimensions().x, y * GH.screenDimensions().y); } bool InputSourceTouch::hasTouchInputDevice() const @@ -225,12 +230,51 @@ bool InputSourceTouch::isMouseButtonPressed(MouseButton button) const void InputSourceTouch::emitPanningEvent(const SDL_TouchFingerEvent & tfinger) { - Point distance(-tfinger.dx * GH.screenDimensions().x, -tfinger.dy * GH.screenDimensions().y); + Point distance = convertTouchToMouse(-tfinger.dx, -tfinger.dy); GH.events().dispatchGesturePanning(lastTapPosition, convertTouchToMouse(tfinger), distance); } void InputSourceTouch::emitPinchEvent(const SDL_TouchFingerEvent & tfinger) { - // TODO + int fingers = SDL_GetNumTouchFingers(tfinger.touchId); + + if (fingers < 2) + return; + + bool otherFingerFound = false; + double otherX; + double otherY; + + for (int i = 0; i < fingers; ++i) + { + SDL_Finger * finger = SDL_GetTouchFinger(tfinger.touchId, i); + + if (finger && finger->id != tfinger.fingerId) + { + otherX = finger->x * GH.screenDimensions().x; + otherY = finger->y * GH.screenDimensions().y; + otherFingerFound = true; + break; + } + } + + if (!otherFingerFound) + return; // should be impossible, but better to avoid weird edge cases + + float thisX = tfinger.x * GH.screenDimensions().x; + float thisY = tfinger.y * GH.screenDimensions().y; + float deltaX = tfinger.dx * GH.screenDimensions().x; + float deltaY = tfinger.dy * GH.screenDimensions().y; + + float oldX = thisX - deltaX - otherX; + float oldY = thisY - deltaY - otherY; + float newX = thisX - otherX; + float newY = thisY - otherY; + + double distanceOld = std::sqrt(oldX * oldX + oldY + oldY); + double distanceNew = std::sqrt(newX * newX + newY + newY); + + if (distanceOld > params.pinchSensitivityThreshold) + GH.events().dispatchGesturePinch(lastTapPosition, distanceNew / distanceOld); } diff --git a/client/eventsSDL/InputSourceTouch.h b/client/eventsSDL/InputSourceTouch.h index 91d55d3c5..1bfb982dc 100644 --- a/client/eventsSDL/InputSourceTouch.h +++ b/client/eventsSDL/InputSourceTouch.h @@ -81,6 +81,9 @@ struct TouchInputParameters /// moving finger for distance larger than specified will be qualified as panning gesture instead of long press uint32_t panningSensitivityThreshold = 10; + /// gesture will be qualified as pinch if distance between fingers is at least specified here + uint32_t pinchSensitivityThreshold = 10; + bool useRelativeMode = false; }; @@ -93,6 +96,7 @@ class InputSourceTouch Point lastTapPosition; Point convertTouchToMouse(const SDL_TouchFingerEvent & current); + Point convertTouchToMouse(float x, float y); void emitPanningEvent(const SDL_TouchFingerEvent & tfinger); void emitPinchEvent(const SDL_TouchFingerEvent & tfinger); diff --git a/client/gui/EventDispatcher.cpp b/client/gui/EventDispatcher.cpp index 3ae8e6880..fcbf7efc9 100644 --- a/client/gui/EventDispatcher.cpp +++ b/client/gui/EventDispatcher.cpp @@ -254,6 +254,15 @@ void EventDispatcher::dispatchGesturePanning(const Point & initialPosition, cons } } +void EventDispatcher::dispatchGesturePinch(const Point & initialPosition, double distance) +{ + for(auto it : panningInterested) + { + if (it->isPanning()) + it->gesturePinch(initialPosition, distance); + } +} + void EventDispatcher::dispatchMouseMoved(const Point & position) { EventReceiversList newlyHovered; diff --git a/client/gui/EventDispatcher.h b/client/gui/EventDispatcher.h index e4d43c54d..b93a3c529 100644 --- a/client/gui/EventDispatcher.h +++ b/client/gui/EventDispatcher.h @@ -65,6 +65,7 @@ public: void dispatchGesturePanningStarted(const Point & initialPosition); void dispatchGesturePanningEnded(const Point & initialPosition, const Point & finalPosition); void dispatchGesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance); + void dispatchGesturePinch(const Point & initialPosition, double distance); /// Text input events void dispatchTextInput(const std::string & text); diff --git a/client/gui/EventsReceiver.h b/client/gui/EventsReceiver.h index 33a46cba1..cf1a548c9 100644 --- a/client/gui/EventsReceiver.h +++ b/client/gui/EventsReceiver.h @@ -42,6 +42,8 @@ protected: /// Called when user pans screen by specified distance virtual void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) {} + virtual void gesturePinch(const Point & centerPosition, double lastUpdateFactor) {} + virtual void wheelScrolled(int distance) {} virtual void mouseMoved(const Point & cursorPosition) {} diff --git a/client/mapView/MapViewActions.cpp b/client/mapView/MapViewActions.cpp index 84c129eac..035ab1079 100644 --- a/client/mapView/MapViewActions.cpp +++ b/client/mapView/MapViewActions.cpp @@ -20,11 +20,15 @@ #include "../gui/CursorHandler.h" #include "../gui/MouseButton.h" +#include "../CPlayerInterface.h" +#include "../adventureMap/CInGameConsole.h" + #include "../../lib/CConfigHandler.h" MapViewActions::MapViewActions(MapView & owner, const std::shared_ptr & model) : model(model) , owner(owner) + , pinchZoomFactor(1.0) { pos.w = model->getPixelsVisibleDimensions().x; pos.h = model->getPixelsVisibleDimensions().y; @@ -66,7 +70,7 @@ void MapViewActions::mouseMoved(const Point & cursorPosition) void MapViewActions::wheelScrolled(int distance) { - adventureInt->hotkeyZoom(distance); + adventureInt->hotkeyZoom(distance * 4); } void MapViewActions::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) @@ -74,6 +78,24 @@ void MapViewActions::gesturePanning(const Point & initialPosition, const Point & owner.onMapSwiped(lastUpdateDistance); } +void MapViewActions::gesturePinch(const Point & centerPosition, double lastUpdateFactor) +{ + double newZoom = pinchZoomFactor * lastUpdateFactor; + + int newZoomSteps = std::round(std::log(newZoom) / std::log(1.01)); + int oldZoomSteps = std::round(std::log(pinchZoomFactor) / std::log(1.01)); + + if (newZoomSteps != oldZoomSteps) + adventureInt->hotkeyZoom(newZoomSteps - oldZoomSteps); + + pinchZoomFactor = newZoom; +} + +void MapViewActions::panning(bool on, const Point & initialPosition, const Point & finalPosition) +{ + pinchZoomFactor = 1.0; +} + void MapViewActions::handleHover(const Point & cursorPosition) { int3 tile = model->getTileAtPoint(cursorPosition - pos.topLeft()); diff --git a/client/mapView/MapViewActions.h b/client/mapView/MapViewActions.h index 62a9ce5d9..15fda0727 100644 --- a/client/mapView/MapViewActions.h +++ b/client/mapView/MapViewActions.h @@ -22,6 +22,8 @@ class MapViewActions : public CIntObject std::shared_ptr model; std::shared_ptr context; + double pinchZoomFactor; + void handleHover(const Point & cursorPosition); public: @@ -32,7 +34,9 @@ public: void clickLeft(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override; void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override; + void gesturePinch(const Point & centerPosition, double lastUpdateFactor) override; void hover(bool on) override; + void panning(bool on, const Point & initialPosition, const Point & finalPosition) override; void mouseMoved(const Point & cursorPosition) override; void wheelScrolled(int distance) override; }; diff --git a/client/mapView/MapViewController.cpp b/client/mapView/MapViewController.cpp index 2dd070417..ae866f516 100644 --- a/client/mapView/MapViewController.cpp +++ b/client/mapView/MapViewController.cpp @@ -91,9 +91,9 @@ void MapViewController::modifyTileSize(int stepsChange) // so, zooming in for 5 steps will put game at 1.1^5 = 1.61 scale // try to determine current zooming level and change it by requested number of steps double currentZoomFactor = model->getSingleTileSize().x / 32.0; - double currentZoomSteps = std::round(std::log(currentZoomFactor) / std::log(1.1)); + double currentZoomSteps = std::round(std::log(currentZoomFactor) / std::log(1.01)); double newZoomSteps = stepsChange != 0 ? currentZoomSteps + stepsChange : stepsChange; - double newZoomFactor = std::pow(1.1, newZoomSteps); + double newZoomFactor = std::pow(1.01, newZoomSteps); Point currentZoom = model->getSingleTileSize(); Point desiredZoom = Point(32,32) * newZoomFactor;