1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-19 21:10:12 +02:00

Implemented pinch gesture to scale adventure map

This commit is contained in:
Ivan Savenko 2023-05-31 16:15:15 +03:00
parent a08ff1e6ef
commit 0f2a339ab5
8 changed files with 92 additions and 6 deletions

View File

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

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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) {}

View File

@ -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<MapViewModel> & 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());

View File

@ -22,6 +22,8 @@ class MapViewActions : public CIntObject
std::shared_ptr<MapViewModel> model;
std::shared_ptr<IMapRendererContext> 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;
};

View File

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