فهرست منبع

Implemented pinch gesture to scale adventure map

Ivan Savenko 2 سال پیش
والد
کامیت
0f2a339ab5

+ 47 - 3
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);
 }

+ 4 - 0
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);

+ 9 - 0
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;

+ 1 - 0
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);

+ 2 - 0
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) {}
 

+ 23 - 1
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<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());

+ 4 - 0
client/mapView/MapViewActions.h

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

+ 2 - 2
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;