1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtLocation module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #ifndef QQUICKGEOMAPGESTUREAREA_P_H
38 #define QQUICKGEOMAPGESTUREAREA_P_H
39 
40 //
41 //  W A R N I N G
42 //  -------------
43 //
44 // This file is not part of the Qt API.  It exists purely as an
45 // implementation detail.  This header file may change from version to
46 // version without notice, or even be removed.
47 //
48 // We mean it.
49 //
50 
51 #include <QtLocation/private/qlocationglobal_p.h>
52 
53 #include <QtCore/QPointer>
54 #include <QtQuick/QQuickItem>
55 #include <QTouchEvent>
56 #include <QDebug>
57 #include <QElapsedTimer>
58 #include <QtPositioning/qgeocoordinate.h>
59 #include <QtGui/QVector2D>
60 
61 QT_BEGIN_NAMESPACE
62 
63 class QGraphicsSceneMouseEvent;
64 class QQuickGeoCoordinateAnimation;
65 class QDeclarativeGeoMap;
66 class QTouchEvent;
67 class QWheelEvent;
68 class QGeoMap;
69 
70 class Q_LOCATION_PRIVATE_EXPORT QGeoMapPinchEvent : public QObject
71 {
72     Q_OBJECT
73 
Q_PROPERTY(QPointF center READ center)74     Q_PROPERTY(QPointF center READ center)
75     Q_PROPERTY(qreal angle READ angle)
76     Q_PROPERTY(QPointF point1 READ point1)
77     Q_PROPERTY(QPointF point2 READ point2)
78     Q_PROPERTY(int pointCount READ pointCount)
79     Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
80 
81 public:
82     QGeoMapPinchEvent(const QPointF &center, qreal angle,
83                                  const QPointF &point1, const QPointF &point2,
84                                  int pointCount = 0, bool accepted = true)
85         : QObject(), m_center(center), m_angle(angle),
86           m_point1(point1), m_point2(point2),
87         m_pointCount(pointCount), m_accepted(accepted) {}
QGeoMapPinchEvent()88     QGeoMapPinchEvent()
89         : QObject(),
90           m_angle(0.0),
91           m_pointCount(0),
92           m_accepted(true) {}
93 
center()94     QPointF center() const { return m_center; }
setCenter(const QPointF & center)95     void setCenter(const QPointF &center) { m_center = center; }
angle()96     qreal angle() const { return m_angle; }
setAngle(qreal angle)97     void setAngle(qreal angle) { m_angle = angle; }
point1()98     QPointF point1() const { return m_point1; }
setPoint1(const QPointF & p)99     void setPoint1(const QPointF &p) { m_point1 = p; }
point2()100     QPointF point2() const { return m_point2; }
setPoint2(const QPointF & p)101     void setPoint2(const QPointF &p) { m_point2 = p; }
pointCount()102     int pointCount() const { return m_pointCount; }
setPointCount(int count)103     void setPointCount(int count) { m_pointCount = count; }
accepted()104     bool accepted() const { return m_accepted; }
setAccepted(bool a)105     void setAccepted(bool a) { m_accepted = a; }
106 
107 private:
108     QPointF m_center;
109     qreal m_angle;
110     QPointF m_point1;
111     QPointF m_point2;
112     int m_pointCount;
113     bool m_accepted;
114 };
115 
116 class Q_LOCATION_PRIVATE_EXPORT QQuickGeoMapGestureArea: public QQuickItem
117 {
118     Q_OBJECT
119     Q_ENUMS(GeoMapGesture)
120     Q_FLAGS(AcceptedGestures)
121 
122     Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
123     Q_PROPERTY(bool pinchActive READ isPinchActive NOTIFY pinchActiveChanged)
124     Q_PROPERTY(bool panActive READ isPanActive NOTIFY panActiveChanged)
125     Q_PROPERTY(bool rotationActive READ isRotationActive NOTIFY rotationActiveChanged)
126     Q_PROPERTY(bool tiltActive READ isTiltActive NOTIFY tiltActiveChanged)
127     Q_PROPERTY(AcceptedGestures acceptedGestures READ acceptedGestures WRITE setAcceptedGestures NOTIFY acceptedGesturesChanged)
128     Q_PROPERTY(qreal maximumZoomLevelChange READ maximumZoomLevelChange WRITE setMaximumZoomLevelChange NOTIFY maximumZoomLevelChangeChanged)
129     Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged)
130     Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1)
131 
132 public:
133     QQuickGeoMapGestureArea(QDeclarativeGeoMap *map);
134     ~QQuickGeoMapGestureArea();
135 
136     enum GeoMapGesture {
137         NoGesture = 0x0000,
138         PinchGesture = 0x0001,
139         PanGesture = 0x0002,
140         FlickGesture = 0x0004,
141         RotationGesture = 0x0008,
142         TiltGesture = 0x0010
143     };
144 
145     Q_DECLARE_FLAGS(AcceptedGestures, GeoMapGesture)
146 
147     AcceptedGestures acceptedGestures() const;
148     void setAcceptedGestures(AcceptedGestures acceptedGestures);
149 
150     bool isPinchActive() const;
151     bool isRotationActive() const;
152     bool isTiltActive() const;
153     bool isPanActive() const;
154     bool isActive() const;
155 
156     bool enabled() const;
157     void setEnabled(bool enabled);
158 
159     qreal maximumZoomLevelChange() const;
160     void setMaximumZoomLevelChange(qreal maxChange);
161 
162     qreal flickDeceleration() const;
163     void setFlickDeceleration(qreal deceleration);
164 
165     void handleTouchEvent(QTouchEvent *event);
166 #if QT_CONFIG(wheelevent)
167     void handleWheelEvent(QWheelEvent *event);
168 #endif
169     void handleMousePressEvent(QMouseEvent *event);
170     void handleMouseMoveEvent(QMouseEvent *event);
171     void handleMouseReleaseEvent(QMouseEvent *event);
172     void handleMouseUngrabEvent();
173     void handleTouchUngrabEvent();
174 
175     void setMinimumZoomLevel(qreal min);
176     qreal minimumZoomLevel() const;
177 
178     void setMaximumZoomLevel(qreal max);
179     qreal maximumZoomLevel() const;
180 
181     void setMap(QGeoMap* map);
182 
183     bool preventStealing() const;
184     void setPreventStealing(bool prevent);
185 
186 Q_SIGNALS:
187     void panActiveChanged();
188     void pinchActiveChanged();
189     void rotationActiveChanged();
190     void tiltActiveChanged();
191     void enabledChanged();
192     void maximumZoomLevelChangeChanged();
193     void acceptedGesturesChanged();
194     void flickDecelerationChanged();
195     void pinchStarted(QGeoMapPinchEvent *pinch);
196     void pinchUpdated(QGeoMapPinchEvent *pinch);
197     void pinchFinished(QGeoMapPinchEvent *pinch);
198     void panStarted();
199     void panFinished();
200     void flickStarted();
201     void flickFinished();
202     void rotationStarted(QGeoMapPinchEvent *pinch);
203     void rotationUpdated(QGeoMapPinchEvent *pinch);
204     void rotationFinished(QGeoMapPinchEvent *pinch);
205     void tiltStarted(QGeoMapPinchEvent *pinch);
206     void tiltUpdated(QGeoMapPinchEvent *pinch);
207     void tiltFinished(QGeoMapPinchEvent *pinch);
208     void preventStealingChanged();
209 private:
210     void update();
211 
212     // Create general data relating to the touch points
213     void touchPointStateMachine();
214     void startOneTouchPoint();
215     void updateOneTouchPoint();
216     void startTwoTouchPoints();
217     void updateTwoTouchPoints();
218 
219     // All two fingers vertical parallel panning related code, which encompasses tilting
220     void tiltStateMachine();
221     bool canStartTilt();
222     void startTilt();
223     void updateTilt();
224     void endTilt();
225 
226     // All two fingers rotation related code, which encompasses rotation
227     void rotationStateMachine();
228     bool canStartRotation();
229     void startRotation();
230     void updateRotation();
231     void endRotation();
232 
233     // All pinch related code, which encompasses zoom
234     void pinchStateMachine();
235     bool canStartPinch();
236     void startPinch();
237     void updatePinch();
238     void endPinch();
239 
240     // Pan related code (regardles of number of touch points),
241     // includes the flick based panning after letting go
242     void panStateMachine();
243     bool canStartPan();
244     void updatePan();
245     bool tryStartFlick();
246     void startFlick(int dx, int dy, int timeMs = 0);
247     void stopFlick();
248 
249     bool pinchEnabled() const;
250     void setPinchEnabled(bool enabled);
251     bool rotationEnabled() const;
252     void setRotationEnabled(bool enabled);
253     bool tiltEnabled() const;
254     void setTiltEnabled(bool enabled);
255     bool panEnabled() const;
256     void setPanEnabled(bool enabled);
257     bool flickEnabled() const;
258     void setFlickEnabled(bool enabled);
259 
260 private Q_SLOTS:
261     void handleFlickAnimationStopped();
262 
263 
264 private:
265     void stopPan();
266     void clearTouchData();
267     void updateFlickParameters(const QPointF &pos);
268 
269 private:
270     QGeoMap* m_map;
271     QDeclarativeGeoMap *m_declarativeMap;
272     bool m_enabled;
273 
274     // This should be intended as a "two fingers gesture" struct
275     struct Pinch
276     {
PinchPinch277         Pinch() : m_pinchEnabled(true), m_rotationEnabled(true), m_tiltEnabled(true),
278                   m_startDist(0), m_lastAngle(0.0) {}
279 
280         QGeoMapPinchEvent m_event;
281         bool m_pinchEnabled;
282         bool m_rotationEnabled;
283         bool m_tiltEnabled;
284         struct Zoom
285         {
ZoomPinch::Zoom286             Zoom() : m_minimum(0.0), m_maximum(30.0), m_start(0.0), m_previous(0.0),
287                      maximumChange(4.0) {}
288             qreal m_minimum;
289             qreal m_maximum;
290             qreal m_start;
291             qreal m_previous;
292             qreal maximumChange;
293         } m_zoom;
294 
295         struct Rotation
296         {
RotationPinch::Rotation297             Rotation() : m_startBearing(0.0), m_previousTouchAngle(0.0), m_totalAngle(0.0) {}
298             qreal m_startBearing;
299             qreal m_previousTouchAngle; // needed for detecting crossing +- 180 in a safer way
300             qreal m_totalAngle;
301         } m_rotation;
302 
303         struct Tilt
304         {
TiltPinch::Tilt305             Tilt() {}
306             QPointF m_startTouchCentroid;
307             qreal m_startTilt;
308         } m_tilt;
309 
310         QPointF m_lastPoint1;
311         QPointF m_lastPoint2;
312         qreal m_startDist;
313         qreal m_lastAngle;
314      } m_pinch;
315 
316     AcceptedGestures m_acceptedGestures;
317 
318     struct Pan
319     {
PanPan320         Pan() : m_maxVelocity(2500), m_deceleration(2500), m_animation(0), m_flickEnabled(true), m_panEnabled(true) {}
321 
322         qreal m_maxVelocity;
323         qreal m_deceleration;
324         QQuickGeoCoordinateAnimation *m_animation;
325         bool m_flickEnabled;
326         bool m_panEnabled;
327     } m_flick;
328 
329 
330     // these are calculated regardless of gesture or number of touch points
331     QVector2D m_flickVector;
332     QElapsedTimer m_lastPosTime;
333     QPointF m_lastPos;
334     QVector<QTouchEvent::TouchPoint> m_allPoints;
335     QVector<QTouchEvent::TouchPoint> m_touchPoints;
336     QScopedPointer<QTouchEvent::TouchPoint> m_mousePoint;
337     QPointF m_sceneStartPoint1;
338 
339     // only set when two points in contact
340     QPointF m_sceneStartPoint2;
341     QGeoCoordinate m_startCoord;
342     QGeoCoordinate m_touchCenterCoord;
343     qreal m_twoTouchAngle;
344     qreal m_twoTouchAngleStart;
345     qreal m_distanceBetweenTouchPoints;
346     qreal m_distanceBetweenTouchPointsStart;
347     QPointF m_twoTouchPointsCentroidStart;
348     QPointF m_touchPointsCentroid;
349     bool m_preventStealing;
350     bool m_panEnabled;
351 
352 private:
353     // prototype state machine...
354     enum TouchPointState
355     {
356         touchPoints0,
357         touchPoints1,
358         touchPoints2
359     } m_touchPointState;
360 
361     enum PinchState
362     {
363         pinchInactive,
364         pinchInactiveTwoPoints,
365         pinchActive
366     } m_pinchState;
367 
368     enum RotationState
369     {
370         rotationInactive,
371         rotationInactiveTwoPoints,
372         rotationActive
373     } m_rotationState;
374 
375     enum TiltState
376     {
377         tiltInactive,
378         tiltInactiveTwoPoints,
379         tiltActive
380     } m_tiltState;
381 
382     enum FlickState
383     {
384         flickInactive,
385         panActive,
386         flickActive
387     } m_flickState;
388 
389     inline void setTouchPointState(const TouchPointState state);
390     inline void setFlickState(const FlickState state);
391     inline void setTiltState(const TiltState state);
392     inline void setRotationState(const RotationState state);
393     inline void setPinchState(const PinchState state);
394 };
395 
396 QT_END_NAMESPACE
397 QML_DECLARE_TYPE(QQuickGeoMapGestureArea)
398 
399 #endif // QQUICKGEOMAPGESTUREAREA_P_H
400