1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qmacgesturerecognizer_p.h"
41 #include "qgesture.h"
42 #include "qgesture_p.h"
43 #include "qevent.h"
44 #include "qwidget.h"
45 #include "qdebug.h"
46 #include <QtCore/qcoreapplication.h>
47
48 #ifndef QT_NO_GESTURES
49
50 QT_BEGIN_NAMESPACE
51
QMacSwipeGestureRecognizer()52 QMacSwipeGestureRecognizer::QMacSwipeGestureRecognizer()
53 {
54 }
55
create(QObject *)56 QGesture *QMacSwipeGestureRecognizer::create(QObject * /*target*/)
57 {
58 return new QSwipeGesture;
59 }
60
61 QGestureRecognizer::Result
recognize(QGesture * gesture,QObject * obj,QEvent * event)62 QMacSwipeGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *event)
63 {
64 if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) {
65 QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
66 switch (ev->gestureType()) {
67 case Qt::SwipeNativeGesture: {
68 QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture);
69 g->setSwipeAngle(ev->value());
70 g->setHotSpot(ev->screenPos());
71 return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
72 break; }
73 default:
74 break;
75 }
76 }
77
78 return QGestureRecognizer::Ignore;
79 }
80
reset(QGesture * gesture)81 void QMacSwipeGestureRecognizer::reset(QGesture *gesture)
82 {
83 QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture);
84 g->setSwipeAngle(0);
85 QGestureRecognizer::reset(gesture);
86 }
87
88 ////////////////////////////////////////////////////////////////////////
89
QMacPinchGestureRecognizer()90 QMacPinchGestureRecognizer::QMacPinchGestureRecognizer()
91 {
92 }
93
create(QObject *)94 QGesture *QMacPinchGestureRecognizer::create(QObject * /*target*/)
95 {
96 return new QPinchGesture;
97 }
98
99 QGestureRecognizer::Result
recognize(QGesture * gesture,QObject * obj,QEvent * event)100 QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *event)
101 {
102 if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) {
103 QPinchGesture *g = static_cast<QPinchGesture *>(gesture);
104 QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
105 switch (ev->gestureType()) {
106 case Qt::BeginNativeGesture:
107 reset(gesture);
108 g->setStartCenterPoint(static_cast<QWidget*>(obj)->mapFromGlobal(ev->screenPos().toPoint()));
109 g->setCenterPoint(g->startCenterPoint());
110 g->setChangeFlags(QPinchGesture::CenterPointChanged);
111 g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
112 g->setHotSpot(ev->screenPos());
113 return QGestureRecognizer::MayBeGesture | QGestureRecognizer::ConsumeEventHint;
114 case Qt::RotateNativeGesture:
115 g->setLastScaleFactor(g->scaleFactor());
116 g->setLastRotationAngle(g->rotationAngle());
117 g->setRotationAngle(g->rotationAngle() + ev->value());
118 g->setChangeFlags(QPinchGesture::RotationAngleChanged);
119 g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
120 g->setHotSpot(ev->screenPos());
121 return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
122 case Qt::ZoomNativeGesture:
123 g->setLastScaleFactor(g->scaleFactor());
124 g->setLastRotationAngle(g->rotationAngle());
125 g->setScaleFactor(1 + ev->value());
126 g->setTotalScaleFactor(g->totalScaleFactor() * g->scaleFactor());
127 g->setChangeFlags(QPinchGesture::ScaleFactorChanged);
128 g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
129 g->setHotSpot(ev->screenPos());
130 return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
131 case Qt::SmartZoomNativeGesture:
132 g->setLastScaleFactor(g->scaleFactor());
133 g->setLastRotationAngle(g->rotationAngle());
134 g->setScaleFactor(ev->value() ? 1.7f : 1.0f);
135 g->setChangeFlags(QPinchGesture::ScaleFactorChanged);
136 g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
137 g->setHotSpot(ev->screenPos());
138 return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
139 case Qt::EndNativeGesture:
140 return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
141 default:
142 break;
143 }
144 }
145
146 return QGestureRecognizer::Ignore;
147 }
148
reset(QGesture * gesture)149 void QMacPinchGestureRecognizer::reset(QGesture *gesture)
150 {
151 QPinchGesture *g = static_cast<QPinchGesture *>(gesture);
152 g->setChangeFlags({});
153 g->setTotalChangeFlags({});
154 g->setScaleFactor(1.0f);
155 g->setTotalScaleFactor(1.0f);
156 g->setLastScaleFactor(1.0f);
157 g->setRotationAngle(0.0f);
158 g->setTotalRotationAngle(0.0f);
159 g->setLastRotationAngle(0.0f);
160 g->setCenterPoint(QPointF());
161 g->setStartCenterPoint(QPointF());
162 g->setLastCenterPoint(QPointF());
163 QGestureRecognizer::reset(gesture);
164 }
165
166 ////////////////////////////////////////////////////////////////////////
167
QMacPanGestureRecognizer()168 QMacPanGestureRecognizer::QMacPanGestureRecognizer() : _panCanceled(true)
169 {
170 }
171
create(QObject * target)172 QGesture *QMacPanGestureRecognizer::create(QObject *target)
173 {
174 if (!target)
175 return new QPanGesture;
176
177 if (QWidget *w = qobject_cast<QWidget *>(target)) {
178 w->setAttribute(Qt::WA_AcceptTouchEvents);
179 w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
180 return new QPanGesture;
181 }
182 return 0;
183 }
184
timerEvent(QTimerEvent * ev)185 void QMacPanGestureRecognizer::timerEvent(QTimerEvent *ev)
186 {
187 if (ev->timerId() == _panTimer.timerId()) {
188 if (_panTimer.isActive())
189 _panTimer.stop();
190 if (_target)
191 QCoreApplication::sendEvent(_target, ev);
192 }
193 }
194
195 QGestureRecognizer::Result
recognize(QGesture * gesture,QObject * target,QEvent * event)196 QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *event)
197 {
198 const int panBeginDelay = 300;
199 const int panBeginRadius = 3;
200
201 QPanGesture *g = static_cast<QPanGesture *>(gesture);
202
203 switch (event->type()) {
204 case QEvent::TouchBegin: {
205 const QTouchEvent *ev = static_cast<const QTouchEvent*>(event);
206 if (ev->touchPoints().size() == 1) {
207 reset(gesture);
208 _startPos = QCursor::pos();
209 _target = target;
210 _panTimer.start(panBeginDelay, this);
211 _panCanceled = false;
212 return QGestureRecognizer::MayBeGesture;
213 }
214 break;}
215 case QEvent::TouchEnd: {
216 if (_panCanceled)
217 break;
218
219 const QTouchEvent *ev = static_cast<const QTouchEvent*>(event);
220 if (ev->touchPoints().size() == 1)
221 return QGestureRecognizer::FinishGesture;
222 break;}
223 case QEvent::TouchUpdate: {
224 if (_panCanceled)
225 break;
226
227 const QTouchEvent *ev = static_cast<const QTouchEvent*>(event);
228 if (ev->touchPoints().size() == 1) {
229 if (_panTimer.isActive()) {
230 // INVARIANT: Still in maybeGesture. Check if the user
231 // moved his finger so much that it makes sense to cancel the pan:
232 const QPointF p = QCursor::pos();
233 if ((p - _startPos).manhattanLength() > panBeginRadius) {
234 _panCanceled = true;
235 _panTimer.stop();
236 return QGestureRecognizer::CancelGesture;
237 }
238 } else {
239 const QPointF p = QCursor::pos();
240 const QPointF posOffset = p - _startPos;
241 g->setLastOffset(g->offset());
242 g->setOffset(QPointF(posOffset.x(), posOffset.y()));
243 g->setHotSpot(_startPos);
244 return QGestureRecognizer::TriggerGesture;
245 }
246 } else if (_panTimer.isActive()) {
247 // I only want to cancel the pan if the user is pressing
248 // more than one finger, and the pan hasn't started yet:
249 _panCanceled = true;
250 _panTimer.stop();
251 return QGestureRecognizer::CancelGesture;
252 }
253 break;}
254 case QEvent::Timer: {
255 QTimerEvent *ev = static_cast<QTimerEvent *>(event);
256 if (ev->timerId() == _panTimer.timerId()) {
257 if (_panCanceled)
258 break;
259 // Begin new pan session!
260 _startPos = QCursor::pos();
261 g->setHotSpot(_startPos);
262 return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
263 }
264 break; }
265 default:
266 break;
267 }
268
269 return QGestureRecognizer::Ignore;
270 }
271
reset(QGesture * gesture)272 void QMacPanGestureRecognizer::reset(QGesture *gesture)
273 {
274 QPanGesture *g = static_cast<QPanGesture *>(gesture);
275 _startPos = QPointF();
276 _panCanceled = true;
277 _panTimer.stop();
278 g->setOffset(QPointF(0, 0));
279 g->setLastOffset(QPointF(0, 0));
280 g->setAcceleration(qreal(1));
281 QGestureRecognizer::reset(gesture);
282 }
283
284 QT_END_NAMESPACE
285
286 #endif // QT_NO_GESTURES
287