summaryrefslogtreecommitdiff
path: root/src/location/quickmapitems/qquickgeomapgesturearea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/location/quickmapitems/qquickgeomapgesturearea.cpp')
-rw-r--r--src/location/quickmapitems/qquickgeomapgesturearea.cpp1876
1 files changed, 0 insertions, 1876 deletions
diff --git a/src/location/quickmapitems/qquickgeomapgesturearea.cpp b/src/location/quickmapitems/qquickgeomapgesturearea.cpp
deleted file mode 100644
index c5547278..00000000
--- a/src/location/quickmapitems/qquickgeomapgesturearea.cpp
+++ /dev/null
@@ -1,1876 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtLocation module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qquickgeomapgesturearea_p.h"
-#include "qdeclarativegeomap_p.h"
-#include "error_messages_p.h"
-
-#include <QDebug>
-#include <QPropertyAnimation>
-#include <QtGui/QGuiApplication>
-#include <QtGui/qevent.h>
-#if QT_CONFIG(wheelevent)
-#include <QtGui/QWheelEvent>
-#endif
-#include <QtGui/QMatrix4x4>
-#include <QtGui/QStyleHints>
-#include <QtQml/qqmlinfo.h>
-#include <QtQuick/QQuickWindow>
-#include "qgeomap_p.h"
-#include <QtPositioning/private/qdoublevector2d_p.h>
-#include <QtPositioning/private/qlocationutils_p.h>
-#include <QtPositioningQuick/private/qquickgeocoordinateanimation_p.h>
-
-#include "math.h"
-#include <cmath>
-
-#define QML_MAP_FLICK_DEFAULTMAXVELOCITY 2500
-#define QML_MAP_FLICK_MINIMUMDECELERATION 500
-#define QML_MAP_FLICK_DEFAULTDECELERATION 2500
-#define QML_MAP_FLICK_MAXIMUMDECELERATION 10000
-
-#define QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD 38
-// FlickThreshold determines how far the "mouse" must have moved
-// before we perform a flick.
-static const int FlickThreshold = 20;
-// Really slow flicks can be annoying.
-static const qreal MinimumFlickVelocity = 75.0;
-// Tolerance for detecting two finger sliding start
-static const qreal MaximumParallelPosition = 40.0; // in degrees
-// Tolerance for detecting parallel sliding
-static const qreal MaximumParallelSlidingAngle = 4.0; // in degrees
-// Tolerance for starting rotation
-static const qreal MinimumRotationStartingAngle = 15.0; // in degrees
-// Tolerance for starting pinch
-static const qreal MinimumPinchDelta = 40; // in pixels
-// Tolerance for starting tilt when sliding vertical
-static const qreal MinimumPanToTiltDelta = 80; // in pixels;
-
-static qreal distanceBetweenTouchPoints(const QPointF &p1, const QPointF &p2)
-{
- return QLineF(p1, p2).length();
-}
-
-static qreal angleFromPoints(const QPointF &p1, const QPointF &p2)
-{
- return QLineF(p1, p2).angle();
-}
-
-// Keeps it in +- 180
-static qreal touchAngle(const QPointF &p1, const QPointF &p2)
-{
- qreal angle = angleFromPoints(p1, p2);
- if (angle > 180)
- angle -= 360;
- return angle;
-}
-
-// Deals with angles crossing the +-180 edge, assumes that the delta can't be > 180
-static qreal angleDelta(const qreal angle1, const qreal angle2)
-{
- qreal delta = angle1 - angle2;
- if (delta > 180.0) // detect crossing angle1 positive, angle2 negative, rotation counterclockwise, difference negative
- delta = angle1 - angle2 - 360.0;
- else if (delta < -180.0) // detect crossing angle1 negative, angle2 positive, rotation clockwise, difference positive
- delta = angle1 - angle2 + 360.0;
-
- return delta;
-}
-
-static bool pointDragged(const QPointF &pOld, const QPointF &pNew)
-{
- static const int startDragDistance = qApp->styleHints()->startDragDistance();
- return ( qAbs(pNew.x() - pOld.x()) > startDragDistance
- || qAbs(pNew.y() - pOld.y()) > startDragDistance);
-}
-
-static qreal vectorSize(const QPointF &vector)
-{
- return std::sqrt(vector.x() * vector.x() + vector.y() * vector.y());
-}
-
-// This linearizes the angles around 0, and keep it linear around 180, allowing to differentiate
-// touch angles that are supposed to be parallel (0 or 180 depending on what finger goes first)
-static qreal touchAngleTilting(const QPointF &p1, const QPointF &p2)
-{
- qreal angle = angleFromPoints(p1, p2);
- if (angle > 270)
- angle -= 360;
- return angle;
-}
-
-static bool movingParallelVertical(const QPointF &p1old, const QPointF &p1new, const QPointF &p2old, const QPointF &p2new)
-{
- if (!pointDragged(p1old, p1new) || !pointDragged(p2old, p2new))
- return false;
-
- QPointF v1 = p1new - p1old;
- QPointF v2 = p2new - p2old;
- qreal v1v2size = vectorSize(v1 + v2);
-
- if (v1v2size < vectorSize(v1) || v1v2size < vectorSize(v2)) // going in opposite directions
- return false;
-
- const qreal newAngle = touchAngleTilting(p1new, p2new);
- const qreal oldAngle = touchAngleTilting(p1old, p2old);
- const qreal angleDiff = angleDelta(newAngle, oldAngle);
-
- if (qAbs(angleDiff) > MaximumParallelSlidingAngle)
- return false;
-
- return true;
-}
-
-QT_BEGIN_NAMESPACE
-
-
-/*!
- \qmltype MapPinchEvent
- \instantiates QGeoMapPinchEvent
- \inqmlmodule QtLocation
-
- \brief MapPinchEvent type provides basic information about pinch event.
-
- MapPinchEvent type provides basic information about pinch event. They are
- present in handlers of MapPinch (for example pinchStarted/pinchUpdated). Events are only
- guaranteed to be valid for the duration of the handler.
-
- Except for the \l accepted property, all properties are read-only.
-
- \section2 Example Usage
-
- The following example enables the pinch gesture on a map and reacts to the
- finished event.
-
- \code
- Map {
- id: map
- gesture.enabled: true
- gesture.onPinchFinished:{
- var coordinate1 = map.toCoordinate(gesture.point1)
- var coordinate2 = map.toCoordinate(gesture.point2)
- console.log("Pinch started at:")
- console.log(" Points (" + gesture.point1.x + ", " + gesture.point1.y + ") - (" + gesture.point2.x + ", " + gesture.point2.y + ")")
- console.log(" Coordinates (" + coordinate1.latitude + ", " + coordinate1.longitude + ") - (" + coordinate2.latitude + ", " + coordinate2.longitude + ")")
- }
- }
- \endcode
-
- \ingroup qml-QtLocation5-maps
- \since QtLocation 5.0
-*/
-
-/*!
- \qmlproperty QPoint QtLocation::MapPinchEvent::center
-
- This read-only property holds the current center point.
-*/
-
-/*!
- \qmlproperty real QtLocation::MapPinchEvent::angle
-
- This read-only property holds the current angle between the two points in
- the range -180 to 180. Positive values for the angles mean counter-clockwise
- while negative values mean the clockwise direction. Zero degrees is at the
- 3 o'clock position.
-*/
-
-/*!
- \qmlproperty QPoint QtLocation::MapPinchEvent::point1
- \qmlproperty QPoint QtLocation::MapPinchEvent::point2
-
- These read-only properties hold the actual touch points generating the pinch.
- The points are not in any particular order.
-*/
-
-/*!
- \qmlproperty int QtLocation::MapPinchEvent::pointCount
-
- This read-only property holds the number of points currently touched.
- The MapPinch will not react until two touch points have initiated a gesture,
- but will remain active until all touch points have been released.
-*/
-
-/*!
- \qmlproperty bool QtLocation::MapPinchEvent::accepted
-
- Setting this property to false in the \c MapPinch::onPinchStarted handler
- will result in no further pinch events being generated, and the gesture
- ignored.
-*/
-
-/*!
- \qmltype MapGestureArea
- \instantiates QQuickGeoMapGestureArea
-
- \inqmlmodule QtLocation
-
- \brief The MapGestureArea type provides Map gesture interaction.
-
- MapGestureArea objects are used as part of a Map, to provide for panning,
- flicking and pinch-to-zoom gesture used on touch displays, as well as two finger rotation
- and two finger parallel vertical sliding to tilt the map.
- On platforms supporting \l QWheelEvent, using the scroll wheel alone, or in combination with
- key modifiers Shift or Control will also zoom, rotate or tilt the map, respectively.
-
- A MapGestureArea is automatically created with a new Map and available with
- the \l{Map::gesture}{gesture} property. This is the only way
- to create a MapGestureArea, and once created this way cannot be destroyed
- without its parent Map.
-
- The two most commonly used properties of the MapGestureArea are the \l enabled
- and \l acceptedGestures properties. Both of these must be set before a
- MapGestureArea will have any effect upon interaction with the Map.
- The \l flickDeceleration property controls how quickly the map pan slows after contact
- is released while panning the map.
-
- \section2 Performance
-
- The MapGestureArea, when enabled, must process all incoming touch events in
- order to track the shape and size of the "pinch". The overhead added on
- touch events can be considered constant time.
-
- \section2 Example Usage
-
- The following example enables the pinch and pan gestures on the map, but not flicking. So the
- map scrolling will halt immediately on releasing the mouse button / touch.
-
- \code
- Map {
- gesture.enabled: true
- gesture.acceptedGestures: MapGestureArea.PinchGesture | MapGestureArea.PanGesture
- }
- \endcode
-
- \ingroup qml-QtLocation5-maps
- \since QtLocation 5.0
-*/
-
-/*!
- \qmlproperty bool QtLocation::MapGestureArea::enabled
-
- This property holds whether the gestures are enabled.
-*/
-
-/*!
- \qmlproperty bool QtLocation::MapGestureArea::pinchActive
-
- This read-only property holds whether the pinch gesture is active.
-*/
-
-/*!
- \qmlproperty bool QtLocation::MapGestureArea::panActive
-
- This read-only property holds whether the pan gesture is active.
-
- \note Change notifications for this property were introduced in Qt 5.5.
-*/
-
-/*!
- \qmlproperty bool QtLocation::MapGestureArea::rotationActive
-
- This read-only property holds whether the two-finger rotation gesture is active.
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlproperty bool QtLocation::MapGestureArea::tiltActive
-
- This read-only property holds whether the two-finger tilt gesture is active.
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlproperty real QtLocation::MapGestureArea::maximumZoomLevelChange
-
- This property holds the maximum zoom level change per pinch, essentially
- meant to be used for setting the zoom sensitivity.
-
- It is an indicative measure calculated from the dimensions of the
- map area, roughly corresponding how much zoom level could change with
- maximum pinch zoom. Default value is 4.0, maximum value is 10.0
-*/
-
-/*!
- \qmlproperty real MapGestureArea::flickDeceleration
-
- This property holds the rate at which a flick will decelerate.
-
- The default value is 2500.
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::pinchStarted(PinchEvent event)
-
- This signal is emitted when a pinch gesture is started.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onPinchStarted.
-
- \sa pinchUpdated, pinchFinished
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::pinchUpdated(PinchEvent event)
-
- This signal is emitted as the user's fingers move across the map,
- after the \l pinchStarted signal is emitted.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onPinchUpdated.
-
- \sa pinchStarted, pinchFinished
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::pinchFinished(PinchEvent event)
-
- This signal is emitted at the end of a pinch gesture.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onPinchFinished.
-
- \sa pinchStarted, pinchUpdated
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::panStarted()
-
- This signal is emitted when the map begins to move due to user
- interaction. Typically this means that the user is dragging a finger -
- or a mouse with one of more mouse buttons pressed - on the map.
-
- The corresponding handler is \c onPanStarted.
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::panFinished()
-
- This signal is emitted when the map stops moving due to user
- interaction. If a flick was generated, this signal is
- emitted before flick starts. If a flick was not
- generated, this signal is emitted when the
- user stops dragging - that is a mouse or touch release.
-
- The corresponding handler is \c onPanFinished.
-
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::flickStarted()
-
- This signal is emitted when the map is flicked. A flick
- starts from the point where the mouse or touch was released,
- while still in motion.
-
- The corresponding handler is \c onFlickStarted.
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::flickFinished()
-
- This signal is emitted when the map stops moving due to a flick.
-
- The corresponding handler is \c onFlickFinished.
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::rotationStarted(PinchEvent event)
-
- This signal is emitted when a two-finger rotation gesture is started.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onRotationStarted.
-
- \sa rotationUpdated(), rotationFinished()
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::rotationUpdated(PinchEvent event)
-
- This signal is emitted as the user's fingers move across the map,
- after the \l rotationStarted() signal is emitted.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onRotationUpdated.
-
- \sa rotationStarted(), rotationFinished()
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::rotationFinished(PinchEvent event)
-
- This signal is emitted at the end of a two-finger rotation gesture.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onRotationFinished.
-
- \sa rotationStarted(), rotationUpdated()
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::tiltStarted(PinchEvent event)
-
- This signal is emitted when a two-finger tilt gesture is started.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onTiltStarted.
-
- \sa tiltUpdated(), tiltFinished()
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::tiltUpdated(PinchEvent event)
-
- This signal is emitted as the user's fingers move across the map,
- after the \l tiltStarted signal is emitted.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onTiltUpdated.
-
- \sa tiltStarted(), tiltFinished()
-
- \since QtLocation 5.9
-*/
-
-/*!
- \qmlsignal QtLocation::MapGestureArea::tiltFinished(PinchEvent event)
-
- This signal is emitted at the end of a two-finger tilt gesture.
-
- Information about the pinch event is provided in \a event.
-
- The corresponding handler is \c onTiltFinished.
-
- \sa tiltStarted(), tiltUpdated()
-
- \since QtLocation 5.9
-*/
-
-QQuickGeoMapGestureArea::QQuickGeoMapGestureArea(QDeclarativeGeoMap *map)
- : QQuickItem(map), m_declarativeMap(map)
-{
- m_touchPointState = touchPoints0;
- m_pinchState = pinchInactive;
- m_flickState = flickInactive;
- m_rotationState = rotationInactive;
- m_tiltState = tiltInactive;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setMap(QGeoMap *map)
-{
- if (m_map || !map)
- return;
-
- m_map = map;
- m_flick.m_animation = new QQuickGeoCoordinateAnimation(this);
- m_flick.m_animation->setTargetObject(m_declarativeMap);
- m_flick.m_animation->setProperty(QStringLiteral("center"));
- m_flick.m_animation->setEasing(QEasingCurve(QEasingCurve::OutQuad));
- connect(m_flick.m_animation, &QQuickAbstractAnimation::stopped, this, &QQuickGeoMapGestureArea::handleFlickAnimationStopped);
- m_map->setAcceptedGestures(panEnabled(), flickEnabled(), pinchEnabled(), rotationEnabled(), tiltEnabled());
-}
-
-/*!
- \qmlproperty bool QtQuick::MapGestureArea::preventStealing
- This property holds whether the mouse events may be stolen from this
- MapGestureArea.
-
- If a Map is placed within an item that filters child mouse
- and touch events, such as Flickable, the mouse and touch events
- may be stolen from the MapGestureArea if a gesture is recognized
- by the parent item, e.g. a flick gesture. If preventStealing is
- set to \c true, no item will steal the mouse and touch events.
-
- Note that setting preventStealing to \c true once an item has started
- stealing events has no effect until the next press event.
-
- By default this property is set to \c false.
-*/
-
-bool QQuickGeoMapGestureArea::preventStealing() const
-{
- return m_preventStealing;
-}
-
-void QQuickGeoMapGestureArea::setPreventStealing(bool prevent)
-{
- if (prevent != m_preventStealing) {
- m_preventStealing = prevent;
- m_declarativeMap->setKeepMouseGrab(m_preventStealing && m_enabled);
- m_declarativeMap->setKeepTouchGrab(m_preventStealing && m_enabled);
- emit preventStealingChanged();
- }
-}
-
-QQuickGeoMapGestureArea::~QQuickGeoMapGestureArea()
-{
-}
-
-/*!
- \qmlproperty enumeration QtLocation::MapGestureArea::acceptedGestures
-
- This property holds a bit field of gestures that are accepted. By default,
- all gestures are enabled.
-
- \value MapGestureArea.NoGesture
- Don't support any additional gestures (value: 0x0000).
-
- \value MapGestureArea.PinchGesture
- Support the map pinch gesture (value: 0x0001).
-
- \value MapGestureArea.PanGesture
- Support the map pan gesture (value: 0x0002).
-
- \value MapGestureArea.FlickGesture
- Support the map flick gesture (value: 0x0004).
-
- \value MapGestureArea.RotationGesture
- Support the map rotation gesture (value: 0x0008).
-
- \value MapGestureArea.TiltGesture
- Support the map tilt gesture (value: 0x0010).
-*/
-
-QQuickGeoMapGestureArea::AcceptedGestures QQuickGeoMapGestureArea::acceptedGestures() const
-{
- return m_acceptedGestures;
-}
-
-
-void QQuickGeoMapGestureArea::setAcceptedGestures(AcceptedGestures acceptedGestures)
-{
- if (acceptedGestures == m_acceptedGestures)
- return;
- m_acceptedGestures = acceptedGestures;
-
- if (enabled()) {
- setPanEnabled(acceptedGestures & PanGesture);
- setFlickEnabled(acceptedGestures & FlickGesture);
- setPinchEnabled(acceptedGestures & PinchGesture);
- setRotationEnabled(acceptedGestures & RotationGesture);
- setTiltEnabled(acceptedGestures & TiltGesture);
- }
-
- if (m_map)
- m_map->setAcceptedGestures(panEnabled(), flickEnabled(), pinchEnabled(), rotationEnabled(), tiltEnabled());
-
- emit acceptedGesturesChanged();
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::isPinchActive() const
-{
- return m_pinchState == pinchActive;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::isRotationActive() const
-{
- return m_rotationState == rotationActive;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::isTiltActive() const
-{
- return m_tiltState == tiltActive;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::isPanActive() const
-{
- return m_flickState == panActive || m_flickState == flickActive;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::enabled() const
-{
- return m_enabled;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setEnabled(bool enabled)
-{
- if (enabled == m_enabled)
- return;
- m_enabled = enabled;
-
- if (enabled) {
- setPanEnabled(m_acceptedGestures & PanGesture);
- setFlickEnabled(m_acceptedGestures & FlickGesture);
- setPinchEnabled(m_acceptedGestures & PinchGesture);
- setRotationEnabled(m_acceptedGestures & RotationGesture);
- setTiltEnabled(m_acceptedGestures & TiltGesture);
- } else {
- setPanEnabled(false);
- setFlickEnabled(false);
- setPinchEnabled(false);
- setRotationEnabled(false);
- setTiltEnabled(false);
- }
- if (m_map)
- m_map->setAcceptedGestures(panEnabled(), flickEnabled(), pinchEnabled(), rotationEnabled(), tiltEnabled());
-
- emit enabledChanged();
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::pinchEnabled() const
-{
- return m_pinch.m_pinchEnabled;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setPinchEnabled(bool enabled)
-{
- m_pinch.m_pinchEnabled = enabled;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::rotationEnabled() const
-{
- return m_pinch.m_rotationEnabled;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setRotationEnabled(bool enabled)
-{
- m_pinch.m_rotationEnabled = enabled;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::tiltEnabled() const
-{
- return m_pinch.m_tiltEnabled;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setTiltEnabled(bool enabled)
-{
- m_pinch.m_tiltEnabled = enabled;
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::panEnabled() const
-{
- return m_flick.m_panEnabled;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setPanEnabled(bool enabled)
-{
- if (enabled == m_flick.m_panEnabled)
- return;
- m_flick.m_panEnabled = enabled;
-
- // unlike the pinch, the pan existing functionality is to stop immediately
- if (!enabled) {
- stopPan();
- m_flickState = flickInactive;
- }
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::flickEnabled() const
-{
- return m_flick.m_flickEnabled;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setFlickEnabled(bool enabled)
-{
- if (enabled == m_flick.m_flickEnabled)
- return;
- m_flick.m_flickEnabled = enabled;
- // unlike the pinch, the flick existing functionality is to stop immediately
- if (!enabled) {
- bool stateActive = (m_flickState != flickInactive);
- stopFlick();
- if (stateActive) {
- if (m_flick.m_panEnabled)
- m_flickState = panActive;
- else
- m_flickState = flickInactive;
- }
- }
-}
-
-/*!
- \internal
- Used internally to set the minimum zoom level of the gesture area.
- The caller is responsible to only send values that are valid
- for the map plugin. Negative values are ignored.
- */
-void QQuickGeoMapGestureArea::setMinimumZoomLevel(qreal min)
-{
- // TODO: remove m_zoom.m_minimum and m_maximum and use m_declarativeMap directly instead.
- if (min >= 0)
- m_pinch.m_zoom.m_minimum = min;
-}
-
-/*!
- \internal
- */
-qreal QQuickGeoMapGestureArea::minimumZoomLevel() const
-{
- return m_pinch.m_zoom.m_minimum;
-}
-
-/*!
- \internal
- Used internally to set the maximum zoom level of the gesture area.
- The caller is responsible to only send values that are valid
- for the map plugin. Negative values are ignored.
- */
-void QQuickGeoMapGestureArea::setMaximumZoomLevel(qreal max)
-{
- if (max >= 0)
- m_pinch.m_zoom.m_maximum = max;
-}
-
-/*!
- \internal
- */
-qreal QQuickGeoMapGestureArea::maximumZoomLevel() const
-{
- return m_pinch.m_zoom.m_maximum;
-}
-
-/*!
- \internal
-*/
-qreal QQuickGeoMapGestureArea::maximumZoomLevelChange() const
-{
- return m_pinch.m_zoom.maximumChange;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setMaximumZoomLevelChange(qreal maxChange)
-{
- if (maxChange == m_pinch.m_zoom.maximumChange || maxChange < 0.1 || maxChange > 10.0)
- return;
- m_pinch.m_zoom.maximumChange = maxChange;
- emit maximumZoomLevelChangeChanged();
-}
-
-/*!
- \internal
-*/
-qreal QQuickGeoMapGestureArea::flickDeceleration() const
-{
- return m_flick.m_deceleration;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::setFlickDeceleration(qreal deceleration)
-{
- if (deceleration < QML_MAP_FLICK_MINIMUMDECELERATION)
- deceleration = QML_MAP_FLICK_MINIMUMDECELERATION;
- else if (deceleration > QML_MAP_FLICK_MAXIMUMDECELERATION)
- deceleration = QML_MAP_FLICK_MAXIMUMDECELERATION;
- if (deceleration == m_flick.m_deceleration)
- return;
- m_flick.m_deceleration = deceleration;
- emit flickDecelerationChanged();
-}
-
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::handleMousePressEvent(QMouseEvent *event)
-{
- if (m_map && m_map->handleEvent(event)) {
- event->accept();
- return;
- }
-
- handleTouchEvent(event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::handleMouseMoveEvent(QMouseEvent *event)
-{
- if (m_map && m_map->handleEvent(event)) {
- event->accept();
- return;
- }
-
- handleTouchEvent(event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::handleMouseReleaseEvent(QMouseEvent *event)
-{
- if (m_map && m_map->handleEvent(event)) {
- event->accept();
- return;
- }
-
- handleTouchEvent(event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::handleTouchUngrabEvent()
-{
- m_touchPoints.clear();
- update();
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::handleTouchEvent(QPointerEvent *event)
-{
- if (m_map && m_map->handleEvent(event)) {
- event->accept();
- return;
- }
-
- // m_touchPoints.clear();
-
- // Update the points we are going to use ourselves.
- for (const auto &point: event->points()){
- auto grabber = qobject_cast<QQuickItem*>(event->exclusiveGrabber(point));
- // qDebug() << event->type() << point.state() << point << grabber;
-
- bool canBeGrabbed = grabber == nullptr || grabber == m_declarativeMap || (!grabber->keepTouchGrab() && !grabber->keepMouseGrab());
- // if (canBeGrabbed) m_touchPoints << point;
-
- //TODO: Testing shows that events are not always propagated with full set of points.
- // Therefore, it can happen that our first point is a different point for a moment
- // and that will trigger pan or pinch right away. So we keep track of points by their states
- // an IDs but then testing shows that sometimes not all points are finished with Release.
- // They just dissapear. Child MouseArea will 'eat up' second touch point if first point
- // is grabbed by child ListView, for example. Maybe it's a bug in 6.2 RC?
- if (point.state() == QEventPoint::Released || !canBeGrabbed){
- for (qsizetype i = 0; i < m_touchPoints.count(); ++i) {
- if (m_touchPoints.at(i).id() == point.id()){
- m_touchPoints.removeAt(i);
- }
- }
- }else{
- bool replaced = false;
- for (qsizetype i = 0; i < m_touchPoints.count(); ++i) {
- if (m_touchPoints.at(i).id() == point.id()){
- m_touchPoints.replace(i, point);
- replaced = true;
- }
- }
- if (!replaced){
- m_touchPoints << point;
- }
- }
-
- }
- // qDebug() << "m_touchPoints.count=" << m_touchPoints.count();
- update();
-
- if (isPanActive()){
- // In case we are pannin, we are using only the first point
- // We let others to grab the second, if needed.
- if (m_touchPoints.count() > 0){
- event->setExclusiveGrabber(m_touchPoints.at(0), m_declarativeMap);
- }
- }else if (isActive()){
- for (const auto &point: m_touchPoints) {
- event->setExclusiveGrabber(point, m_declarativeMap);
- }
- }
-}
-
-#if QT_CONFIG(wheelevent)
-void QQuickGeoMapGestureArea::handleWheelEvent(QWheelEvent *event)
-{
- if (!m_map)
- return;
-
- if (m_map->handleEvent(event)) {
- event->accept();
- return;
- }
-
- const QGeoCoordinate &wheelGeoPos = m_declarativeMap->toCoordinate(event->position(), false);
- const QPointF &preZoomPoint = event->position();
-
- // Not using AltModifier as, for some reason, it causes angleDelta to be 0
- if (event->modifiers() & Qt::ShiftModifier && rotationEnabled()) {
- emit rotationStarted(&m_pinch.m_event);
- // First set bearing
- const double bearingDelta = event->angleDelta().y() * qreal(0.05);
- m_declarativeMap->setBearing(m_declarativeMap->bearing() + bearingDelta, wheelGeoPos);
- emit rotationUpdated(&m_pinch.m_event);
- emit rotationFinished(&m_pinch.m_event);
- } else if (event->modifiers() & Qt::ControlModifier && tiltEnabled()) {
- emit tiltStarted(&m_pinch.m_event);
- const double tiltDelta = event->angleDelta().y() * qreal(0.05);
- m_declarativeMap->setTilt(m_declarativeMap->tilt() + tiltDelta);
- emit tiltUpdated(&m_pinch.m_event);
- emit tiltFinished(&m_pinch.m_event);
- } else if (pinchEnabled()) {
- const double zoomLevelDelta = event->angleDelta().y() * qreal(0.001);
- // Gesture area should always honor maxZL, but Map might not.
- m_declarativeMap->setZoomLevel(qMin<qreal>(m_declarativeMap->zoomLevel() + zoomLevelDelta, maximumZoomLevel()),
- false);
- const QPointF &postZoomPoint = m_declarativeMap->fromCoordinate(wheelGeoPos, false);
-
- if (preZoomPoint != postZoomPoint) // need to re-anchor the wheel geoPos to the event position
- m_declarativeMap->alignCoordinateToPoint(wheelGeoPos, preZoomPoint);
- }
- // event->accept();
-}
-#endif
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::clearTouchData()
-{
- m_flickVector = QVector2D();
- m_touchPointsCentroid.setX(0);
- m_touchPointsCentroid.setY(0);
- m_touchCenterCoord.setLongitude(0);
- m_touchCenterCoord.setLatitude(0);
- m_startCoord.setLongitude(0);
- m_startCoord.setLatitude(0);
-}
-
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updateFlickParameters(const QPointF &pos)
-{
- // Take velocity samples every sufficient period of time, used later to determine the flick
- // duration and speed (when mouse is released).
- qreal elapsed = qreal(m_lastPosTime.elapsed());
-
- if (elapsed >= QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD) {
- elapsed /= 1000.;
- qreal vel = distanceBetweenTouchPoints(pos, m_lastPos) / elapsed;
- m_flickVector = (QVector2D(pos) - QVector2D(m_lastPos)).normalized();
- m_flickVector *= qBound<qreal>(-m_flick.m_maxVelocity, vel, m_flick.m_maxVelocity);
-
- m_lastPos = pos;
- m_lastPosTime.restart();
- }
-}
-
-void QQuickGeoMapGestureArea::setTouchPointState(const QQuickGeoMapGestureArea::TouchPointState state)
-{
- m_touchPointState = state;
-}
-
-void QQuickGeoMapGestureArea::setFlickState(const QQuickGeoMapGestureArea::FlickState state)
-{
- m_flickState = state;
-}
-
-void QQuickGeoMapGestureArea::setTiltState(const QQuickGeoMapGestureArea::TiltState state)
-{
- m_tiltState = state;
-}
-
-void QQuickGeoMapGestureArea::setRotationState(const QQuickGeoMapGestureArea::RotationState state)
-{
- m_rotationState = state;
-}
-
-void QQuickGeoMapGestureArea::setPinchState(const QQuickGeoMapGestureArea::PinchState state)
-{
- m_pinchState = state;
-}
-
-/*!
- \internal
-*/
-
-bool QQuickGeoMapGestureArea::isActive() const
-{
- return isPanActive() || isPinchActive() || isRotationActive() || isTiltActive();
-}
-
-/*!
- \internal
-*/
-// simplify the gestures by using a state-machine format (easy to move to a future state machine)
-void QQuickGeoMapGestureArea::update()
-{
- if (!m_map)
- return;
- // First state machine is for the number of touch points
-
- //combine touch with mouse event
- m_allPoints.clear();
- m_allPoints << m_touchPoints;
- std::sort(m_allPoints.begin(), m_allPoints.end(), [](const QTouchEvent::TouchPoint &tp1, const QTouchEvent::TouchPoint &tp2) { return tp1.id() < tp2.id(); });
-
- touchPointStateMachine();
-
- // Parallel state machine for tilt. Tilt goes first as it blocks anything else, when started.
- // But tilting can also only start if nothing else is active.
- if (isTiltActive() || m_pinch.m_tiltEnabled)
- tiltStateMachine();
-
- // Parallel state machine for pinch
- if (isPinchActive() || m_pinch.m_pinchEnabled)
- pinchStateMachine();
-
- // Parallel state machine for rotation.
- if (isRotationActive() || m_pinch.m_rotationEnabled)
- rotationStateMachine();
-
- // Parallel state machine for pan (since you can pan at the same time as pinching)
- // The stopPan function ensures that pan stops immediately when disabled,
- // but the isPanActive() below allows pan continue its current gesture if you disable
- // the whole gesture.
- // Pan goes last because it does reanchoring in updatePan() which makes the map
- // properly rotate around the touch point centroid.
- if (isPanActive() || m_flick.m_flickEnabled || m_flick.m_panEnabled)
- panStateMachine();
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::touchPointStateMachine()
-{
- // Transitions:
- switch (m_touchPointState) {
- case touchPoints0:
- if (m_allPoints.count() == 1) {
- clearTouchData();
- startOneTouchPoint();
- setTouchPointState(touchPoints1);
- } else if (m_allPoints.count() >= 2) {
- clearTouchData();
- startTwoTouchPoints();
- setTouchPointState(touchPoints2);
- }
- break;
- case touchPoints1:
- if (m_allPoints.count() == 0) {
- setTouchPointState(touchPoints0);
- } else if (m_allPoints.count() == 2) {
- m_touchCenterCoord = m_declarativeMap->toCoordinate(m_touchPointsCentroid, false);
- startTwoTouchPoints();
- setTouchPointState(touchPoints2);
- }
- break;
- case touchPoints2:
- if (m_allPoints.count() == 0) {
- setTouchPointState(touchPoints0);
- } else if (m_allPoints.count() == 1) {
- m_touchCenterCoord = m_declarativeMap->toCoordinate(m_touchPointsCentroid, false);
- startOneTouchPoint();
- setTouchPointState(touchPoints1);
- }
- break;
- };
-
- // Update
- switch (m_touchPointState) {
- case touchPoints0:
- break; // do nothing if no touch points down
- case touchPoints1:
- updateOneTouchPoint();
- break;
- case touchPoints2:
- updateTwoTouchPoints();
- break;
- }
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::startOneTouchPoint()
-{
- m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_lastPos = m_sceneStartPoint1;
- m_lastPosTime.start();
- QGeoCoordinate startCoord = m_declarativeMap->toCoordinate(m_sceneStartPoint1, false);
- // ensures a smooth transition for panning
- m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
- m_touchCenterCoord.longitude());
- m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
- m_touchCenterCoord.latitude());
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updateOneTouchPoint()
-{
- m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePressPosition());
- m_touchPointsCentroid = mapFromScene(m_allPoints.at(0).scenePosition());
- updateFlickParameters(m_touchPointsCentroid);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::startTwoTouchPoints()
-{
- m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_sceneStartPoint2 = mapFromScene(m_allPoints.at(1).scenePosition());
- QPointF startPos = (m_sceneStartPoint1 + m_sceneStartPoint2) * 0.5;
- m_lastPos = startPos;
- m_lastPosTime.start();
- QGeoCoordinate startCoord = m_declarativeMap->toCoordinate(startPos, false);
- m_startCoord.setLongitude(m_startCoord.longitude() + startCoord.longitude() -
- m_touchCenterCoord.longitude());
- m_startCoord.setLatitude(m_startCoord.latitude() + startCoord.latitude() -
- m_touchCenterCoord.latitude());
- m_twoTouchAngleStart = touchAngle(m_sceneStartPoint1, m_sceneStartPoint2); // Initial angle used for calculating rotation
- m_distanceBetweenTouchPointsStart = distanceBetweenTouchPoints(m_sceneStartPoint1, m_sceneStartPoint2);
- m_twoTouchPointsCentroidStart = (m_sceneStartPoint1 + m_sceneStartPoint2) / 2;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updateTwoTouchPoints()
-{
- m_sceneStartPoint1 = mapFromScene(m_allPoints.at(0).scenePressPosition());
- QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_sceneStartPoint2 = mapFromScene(m_allPoints.at(1).scenePressPosition());
- QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition());
- m_distanceBetweenTouchPoints = distanceBetweenTouchPoints(p1, p2);
- m_touchPointsCentroid = (p1 + p2) / 2;
- updateFlickParameters(m_touchPointsCentroid);
-
- m_twoTouchAngle = touchAngle(p1, p2);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::tiltStateMachine()
-{
- TiltState lastState = m_tiltState;
- // Transitions:
- switch (m_tiltState) {
- case tiltInactive:
- if (m_allPoints.count() >= 2) {
- if (!isRotationActive() && !isPinchActive() && canStartTilt()) { // only gesture that can be overridden: pan/flick
- m_declarativeMap->setKeepTouchGrab(true);
- startTilt();
- setTiltState(tiltActive);
- } else {
- setTiltState(tiltInactiveTwoPoints);
- }
- }
- break;
- case tiltInactiveTwoPoints:
- if (m_allPoints.count() <= 1) {
- setTiltState(tiltInactive);
- } else {
- if (!isRotationActive() && !isPinchActive() && canStartTilt()) { // only gesture that can be overridden: pan/flick
- m_declarativeMap->setKeepTouchGrab(true);
- startTilt();
- setTiltState(tiltActive);
- }
- }
- break;
- case tiltActive:
- if (m_allPoints.count() <= 1) {
- setTiltState(tiltInactive);
- m_declarativeMap->setKeepTouchGrab(m_preventStealing);
- endTilt();
- }
- break;
- }
- // This line implements an exclusive state machine, where the transitions and updates don't
- // happen on the same frame
- if (m_tiltState != lastState) {
- emit tiltActiveChanged();
- return;
- }
-
- // Update
- switch (m_tiltState) {
- case tiltInactive:
- case tiltInactiveTwoPoints:
- break; // do nothing
- case tiltActive:
- updateTilt();
- break;
- }
-}
-
-bool validateTouchAngleForTilting(const qreal angle)
-{
- return ((qAbs(angle) - 180.0) < MaximumParallelPosition) || (qAbs(angle) < MaximumParallelPosition);
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::canStartTilt()
-{
- if (m_allPoints.count() >= 2) {
- QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition());
- QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition());
- if (validateTouchAngleForTilting(m_twoTouchAngle)
- && movingParallelVertical(m_sceneStartPoint1, p1, m_sceneStartPoint2, p2)
- && qAbs(m_twoTouchPointsCentroidStart.y() - m_touchPointsCentroid.y()) > MinimumPanToTiltDelta) {
- m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
- m_pinch.m_event.setAngle(m_twoTouchAngle);
- m_pinch.m_event.setPoint1(p1);
- m_pinch.m_event.setPoint2(p2);
- m_pinch.m_event.setPointCount(m_allPoints.count());
- m_pinch.m_event.setAccepted(true);
- emit tiltStarted(&m_pinch.m_event);
- return true;
- }
- }
- return false;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::startTilt()
-{
- if (isPanActive()) {
- stopPan();
- setFlickState(flickInactive);
- }
-
- m_pinch.m_tilt.m_startTouchCentroid = m_touchPointsCentroid;
- m_pinch.m_tilt.m_startTilt = m_declarativeMap->tilt();
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updateTilt()
-{
- // Calculate the new tilt
- qreal verticalDisplacement = (m_touchPointsCentroid - m_pinch.m_tilt.m_startTouchCentroid).y();
-
- // Approach: 10pixel = 1 degree.
- qreal tilt = verticalDisplacement / 10.0;
- qreal newTilt = m_pinch.m_tilt.m_startTilt - tilt;
- m_declarativeMap->setTilt(newTilt);
-
- m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
- m_pinch.m_event.setAngle(m_twoTouchAngle);
- m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition());
- m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
- m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
- m_pinch.m_event.setPointCount(m_allPoints.count());
- m_pinch.m_event.setAccepted(true);
-
- emit tiltUpdated(&m_pinch.m_event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::endTilt()
-{
- QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
- QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
- m_pinch.m_event.setCenter((p1 + p2) / 2);
- m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
- m_pinch.m_event.setPoint1(p1);
- m_pinch.m_event.setPoint2(p2);
- m_pinch.m_event.setAccepted(true);
- m_pinch.m_event.setPointCount(0);
- emit tiltFinished(&m_pinch.m_event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::rotationStateMachine()
-{
- RotationState lastState = m_rotationState;
- // Transitions:
- switch (m_rotationState) {
- case rotationInactive:
- if (m_allPoints.count() >= 2) {
- if (!isTiltActive() && canStartRotation()) {
- m_declarativeMap->setKeepTouchGrab(true);
- startRotation();
- setRotationState(rotationActive);
- } else {
- setRotationState(rotationInactiveTwoPoints);
- }
- }
- break;
- case rotationInactiveTwoPoints:
- if (m_allPoints.count() <= 1) {
- setRotationState(rotationInactive);
- } else {
- if (!isTiltActive() && canStartRotation()) {
- m_declarativeMap->setKeepTouchGrab(true);
- startRotation();
- setRotationState(rotationActive);
- }
- }
- break;
- case rotationActive:
- if (m_allPoints.count() <= 1) {
- setRotationState(rotationInactive);
- m_declarativeMap->setKeepTouchGrab(m_preventStealing);
- endRotation();
- }
- break;
- }
- // This line implements an exclusive state machine, where the transitions and updates don't
- // happen on the same frame
- if (m_rotationState != lastState) {
- emit rotationActiveChanged();
- return;
- }
-
- // Update
- switch (m_rotationState) {
- case rotationInactive:
- case rotationInactiveTwoPoints:
- break; // do nothing
- case rotationActive:
- updateRotation();
- break;
- }
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::canStartRotation()
-{
- if (m_allPoints.count() >= 2) {
- QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition());
- QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition());
- if (pointDragged(m_sceneStartPoint1, p1) || pointDragged(m_sceneStartPoint2, p2)) {
- qreal delta = angleDelta(m_twoTouchAngleStart, m_twoTouchAngle);
- if (qAbs(delta) < MinimumRotationStartingAngle) {
- return false;
- }
- m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
- m_pinch.m_event.setAngle(m_twoTouchAngle);
- m_pinch.m_event.setPoint1(p1);
- m_pinch.m_event.setPoint2(p2);
- m_pinch.m_event.setPointCount(m_allPoints.count());
- m_pinch.m_event.setAccepted(true);
- emit rotationStarted(&m_pinch.m_event);
- return m_pinch.m_event.accepted();
- }
- }
- return false;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::startRotation()
-{
- m_pinch.m_rotation.m_startBearing = m_declarativeMap->bearing();
- m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle;
- m_pinch.m_rotation.m_totalAngle = 0.0;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updateRotation()
-{
- // Calculate the new bearing
- qreal angle = angleDelta(m_pinch.m_rotation.m_previousTouchAngle, m_twoTouchAngle);
- if (qAbs(angle) < 0.2) // avoiding too many updates
- return;
-
- m_pinch.m_rotation.m_previousTouchAngle = m_twoTouchAngle;
- m_pinch.m_rotation.m_totalAngle += angle;
- qreal newBearing = m_pinch.m_rotation.m_startBearing - m_pinch.m_rotation.m_totalAngle;
- m_declarativeMap->setBearing(newBearing);
-
- m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
- m_pinch.m_event.setAngle(m_twoTouchAngle);
- m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition());
- m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
- m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
- m_pinch.m_event.setPointCount(m_allPoints.count());
- m_pinch.m_event.setAccepted(true);
-
- emit rotationUpdated(&m_pinch.m_event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::endRotation()
-{
- QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
- QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
- m_pinch.m_event.setCenter((p1 + p2) / 2);
- m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
- m_pinch.m_event.setPoint1(p1);
- m_pinch.m_event.setPoint2(p2);
- m_pinch.m_event.setAccepted(true);
- m_pinch.m_event.setPointCount(0);
- emit rotationFinished(&m_pinch.m_event);
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::pinchStateMachine()
-{
- PinchState lastState = m_pinchState;
- // Transitions:
- switch (m_pinchState) {
- case pinchInactive:
- if (m_allPoints.count() >= 2) {
- if (!isTiltActive() && canStartPinch()) {
- m_declarativeMap->setKeepTouchGrab(true);
- startPinch();
- setPinchState(pinchActive);
- } else {
- setPinchState(pinchInactiveTwoPoints);
- }
- }
- break;
- case pinchInactiveTwoPoints:
- if (m_allPoints.count() <= 1) {
- setPinchState(pinchInactive);
- } else {
- if (!isTiltActive() && canStartPinch()) {
- m_declarativeMap->setKeepTouchGrab(true);
- startPinch();
- setPinchState(pinchActive);
- }
- }
- break;
- case pinchActive:
- if (m_allPoints.count() <= 1) { // Once started, pinch goes off only when finger(s) are release
- setPinchState(pinchInactive);
- m_declarativeMap->setKeepTouchGrab(m_preventStealing);
- endPinch();
- }
- break;
- }
- // This line implements an exclusive state machine, where the transitions and updates don't
- // happen on the same frame
- if (m_pinchState != lastState) {
- emit pinchActiveChanged();
- return;
- }
-
- // Update
- switch (m_pinchState) {
- case pinchInactive:
- case pinchInactiveTwoPoints:
- break; // do nothing
- case pinchActive:
- updatePinch();
- break;
- }
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::canStartPinch()
-{
- if (m_allPoints.count() >= 2) {
- QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition());
- QPointF p2 = mapFromScene(m_allPoints.at(1).scenePosition());
- if (qAbs(m_distanceBetweenTouchPoints - m_distanceBetweenTouchPointsStart) > MinimumPinchDelta) {
- m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
- m_pinch.m_event.setAngle(m_twoTouchAngle);
- m_pinch.m_event.setPoint1(p1);
- m_pinch.m_event.setPoint2(p2);
- m_pinch.m_event.setPointCount(m_allPoints.count());
- m_pinch.m_event.setAccepted(true);
- emit pinchStarted(&m_pinch.m_event);
- return m_pinch.m_event.accepted();
- }
- }
- return false;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::startPinch()
-{
- m_pinch.m_startDist = m_distanceBetweenTouchPoints;
- m_pinch.m_zoom.m_previous = m_declarativeMap->zoomLevel();
- m_pinch.m_lastAngle = m_twoTouchAngle;
-
- m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition());
-
- m_pinch.m_zoom.m_start = m_declarativeMap->zoomLevel();
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updatePinch()
-{
- // Calculate the new zoom level if we have distance ( >= 2 touchpoints), otherwise stick with old.
- qreal newZoomLevel = m_pinch.m_zoom.m_previous;
- if (m_distanceBetweenTouchPoints) {
- newZoomLevel =
- // How much further/closer the current touchpoints are (in pixels) compared to pinch start
- ((m_distanceBetweenTouchPoints - m_pinch.m_startDist) *
- // How much one pixel corresponds in units of zoomlevel (and multiply by above delta)
- (m_pinch.m_zoom.maximumChange / ((width() + height()) / 2))) +
- // Add to starting zoom level. Sign of (dist-pinchstartdist) takes care of zoom in / out
- m_pinch.m_zoom.m_start;
- }
-
- m_pinch.m_event.setCenter(mapFromScene(m_touchPointsCentroid));
- m_pinch.m_event.setAngle(m_twoTouchAngle);
-
- m_pinch.m_lastPoint1 = mapFromScene(m_allPoints.at(0).scenePosition());
- m_pinch.m_lastPoint2 = mapFromScene(m_allPoints.at(1).scenePosition());
- m_pinch.m_event.setPoint1(m_pinch.m_lastPoint1);
- m_pinch.m_event.setPoint2(m_pinch.m_lastPoint2);
- m_pinch.m_event.setPointCount(m_allPoints.count());
- m_pinch.m_event.setAccepted(true);
-
- m_pinch.m_lastAngle = m_twoTouchAngle;
- emit pinchUpdated(&m_pinch.m_event);
-
- if (m_acceptedGestures & PinchGesture) {
- // Take maximum and minimumzoomlevel into account
- qreal perPinchMinimumZoomLevel = qMax(m_pinch.m_zoom.m_start - m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_minimum);
- qreal perPinchMaximumZoomLevel = qMin(m_pinch.m_zoom.m_start + m_pinch.m_zoom.maximumChange, m_pinch.m_zoom.m_maximum);
- newZoomLevel = qMin(qMax(perPinchMinimumZoomLevel, newZoomLevel), perPinchMaximumZoomLevel);
- m_declarativeMap->setZoomLevel(qMin<qreal>(newZoomLevel, maximumZoomLevel()), false);
- m_pinch.m_zoom.m_previous = newZoomLevel;
- }
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::endPinch()
-{
- QPointF p1 = mapFromScene(m_pinch.m_lastPoint1);
- QPointF p2 = mapFromScene(m_pinch.m_lastPoint2);
- m_pinch.m_event.setCenter((p1 + p2) / 2);
- m_pinch.m_event.setAngle(m_pinch.m_lastAngle);
- m_pinch.m_event.setPoint1(p1);
- m_pinch.m_event.setPoint2(p2);
- m_pinch.m_event.setAccepted(true);
- m_pinch.m_event.setPointCount(0);
- emit pinchFinished(&m_pinch.m_event);
- m_pinch.m_startDist = 0;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::panStateMachine()
-{
- FlickState lastState = m_flickState;
-
- // Transitions
- switch (m_flickState) {
- case flickInactive:
- if (!isTiltActive() && canStartPan()) {
- // Update startCoord_ to ensure smooth start for panning when going over startDragDistance
- QGeoCoordinate newStartCoord = m_declarativeMap->toCoordinate(m_touchPointsCentroid, false);
- m_startCoord.setLongitude(newStartCoord.longitude());
- m_startCoord.setLatitude(newStartCoord.latitude());
- m_declarativeMap->setKeepMouseGrab(true);
- m_declarativeMap->setKeepTouchGrab(true);
- setFlickState(panActive);
- }
- break;
- case panActive:
- if (m_allPoints.count() == 0) {
- if (!tryStartFlick())
- {
- setFlickState(flickInactive);
- // mark as inactive for use by camera
- if (m_pinchState == pinchInactive && m_rotationState == rotationInactive && m_tiltState == tiltInactive) {
- m_declarativeMap->setKeepMouseGrab(m_preventStealing);
- m_declarativeMap->setKeepTouchGrab(m_preventStealing);
- m_map->prefetchData();
- }
- emit panFinished();
- } else {
- setFlickState(flickActive);
- emit panFinished();
- emit flickStarted();
- }
- }
- break;
- case flickActive:
- if (m_allPoints.count() > 0) { // re touched before movement ended
- stopFlick();
- m_declarativeMap->setKeepMouseGrab(true);
- m_declarativeMap->setKeepTouchGrab(true);
- setFlickState(panActive);
- }
- break;
- }
-
- if (m_flickState != lastState)
- emit panActiveChanged();
-
- // Update
- switch (m_flickState) {
- case flickInactive: // do nothing
- break;
- case panActive:
- updatePan();
- // this ensures 'panStarted' occurs after the pan has actually started
- if (lastState != panActive)
- emit panStarted();
- break;
- case flickActive:
- break;
- }
-}
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::canStartPan()
-{
- if (m_allPoints.count() == 0 || (m_acceptedGestures & PanGesture) == 0)
- return false;
-
- // Check if thresholds for normal panning are met.
- // (normal panning vs flicking: flicking will start from mouse release event).
- const int startDragDistance = qApp->styleHints()->startDragDistance() * 2;
- QPointF p1 = mapFromScene(m_allPoints.at(0).scenePosition());
- int dyFromPress = int(p1.y() - m_sceneStartPoint1.y());
- int dxFromPress = int(p1.x() - m_sceneStartPoint1.x());
- if ((qAbs(dyFromPress) >= startDragDistance || qAbs(dxFromPress) >= startDragDistance))
- return true;
-
- return false;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::updatePan()
-{
- m_declarativeMap->alignCoordinateToPoint(m_startCoord, m_touchPointsCentroid);
-}
-
-/*!
- \internal
-*/
-bool QQuickGeoMapGestureArea::tryStartFlick()
-{
- if ((m_acceptedGestures & FlickGesture) == 0)
- return false;
- // if we drag then pause before release we should not cause a flick.
- qreal flickSpeed = 0.0;
- if (m_lastPosTime.elapsed() < QML_MAP_FLICK_VELOCITY_SAMPLE_PERIOD)
- flickSpeed = m_flickVector.length();
-
- int flickTime = 0;
- int flickPixels = 0;
- QVector2D flickVector;
-
- if (qAbs(flickSpeed) > MinimumFlickVelocity
- && distanceBetweenTouchPoints(m_touchPointsCentroid, m_sceneStartPoint1) > FlickThreshold) {
- qreal acceleration = m_flick.m_deceleration;
- if ((flickSpeed > 0.0f) == (m_flick.m_deceleration > 0.0f))
- acceleration = acceleration * -1.0f;
- flickTime = static_cast<int>(-1000 * flickSpeed / acceleration);
- flickPixels = (flickTime * flickSpeed) / 2000.0;
- flickVector = m_flickVector.normalized() * flickPixels;
- }
-
- if (flickTime > 0) {
- startFlick(flickVector.x(), flickVector.y(), flickTime);
- return true;
- }
- return false;
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::startFlick(int dx, int dy, int timeMs)
-{
- if (!m_flick.m_animation)
- return;
- if (timeMs < 0)
- return;
-
- QGeoCoordinate animationStartCoordinate = m_declarativeMap->center();
-
- if (m_flick.m_animation->isRunning())
- m_flick.m_animation->stop();
- QGeoCoordinate animationEndCoordinate = m_declarativeMap->center();
- m_flick.m_animation->setDuration(timeMs);
-
- QPointF delta(dx, dy);
- QMatrix4x4 matBearing;
- matBearing.rotate(m_map->cameraData().bearing(), 0, 0, 1);
- delta = matBearing.map(delta);
-
- double zoom = pow(2.0, m_declarativeMap->zoomLevel());
- double longitude = animationStartCoordinate.longitude() - (delta.x() / zoom);
- double latitude = animationStartCoordinate.latitude() + (delta.y() / zoom);
-
- if (delta.x() > 0)
- m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::West);
- else
- m_flick.m_animation->setDirection(QQuickGeoCoordinateAnimation::East);
-
- //keep animation in correct bounds
- animationEndCoordinate.setLongitude(QLocationUtils::wrapLong(longitude));
- animationEndCoordinate.setLatitude(QLocationUtils::clipLat(latitude, QLocationUtils::mercatorMaxLatitude()));
-
- m_flick.m_animation->setFrom(animationStartCoordinate);
- m_flick.m_animation->setTo(animationEndCoordinate);
- m_flick.m_animation->start();
-}
-
-void QQuickGeoMapGestureArea::stopPan()
-{
- if (m_flickState == flickActive) {
- stopFlick();
- } else if (m_flickState == panActive) {
- m_flickVector = QVector2D();
- setFlickState(flickInactive);
- m_declarativeMap->setKeepMouseGrab(m_preventStealing);
- emit panFinished();
- emit panActiveChanged();
- m_map->prefetchData();
- }
-}
-
-/*!
- \internal
-*/
-void QQuickGeoMapGestureArea::stopFlick()
-{
- if (!m_flick.m_animation)
- return;
- m_flickVector = QVector2D();
- if (m_flick.m_animation->isRunning())
- m_flick.m_animation->stop();
- else
- handleFlickAnimationStopped();
-}
-
-void QQuickGeoMapGestureArea::handleFlickAnimationStopped()
-{
- m_declarativeMap->setKeepMouseGrab(m_preventStealing);
- if (m_flickState == flickActive) {
- setFlickState(flickInactive);
- emit flickFinished();
- emit panActiveChanged();
- m_map->prefetchData();
- }
-}
-
-QT_END_NAMESPACE