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 "qstandardgestures_p.h"
41 #include "qgesture.h"
42 #include "qgesture_p.h"
43 #include "qevent.h"
44 #include "qwidget.h"
45 #include "qabstractscrollarea.h"
46 #if QT_CONFIG(graphicsview)
47 #include <qgraphicssceneevent.h>
48 #endif
49 #include "qdebug.h"
50 
51 #ifndef QT_NO_GESTURES
52 
53 QT_BEGIN_NAMESPACE
54 
55 // If the change in scale for a single touch event is out of this range,
56 // we consider it to be spurious.
57 static const qreal kSingleStepScaleMax = 2.0;
58 static const qreal kSingleStepScaleMin = 0.1;
59 
create(QObject * target)60 QGesture *QPanGestureRecognizer::create(QObject *target)
61 {
62     if (target && target->isWidgetType()) {
63 #if (defined(Q_OS_MACX) || defined(Q_OS_WIN)) && !defined(QT_NO_NATIVE_GESTURES)
64         // for scroll areas on Windows and OS X we want to use native gestures instead
65         if (!qobject_cast<QAbstractScrollArea *>(target->parent()))
66             static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
67 #else
68         static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
69 #endif
70     }
71     return new QPanGesture;
72 }
73 
panOffset(const QList<QTouchEvent::TouchPoint> & touchPoints,int maxCount)74 static QPointF panOffset(const QList<QTouchEvent::TouchPoint> &touchPoints, int maxCount)
75 {
76     QPointF result;
77     const int count = qMin(touchPoints.size(), maxCount);
78     for (int p = 0; p < count; ++p)
79         result += touchPoints.at(p).pos() - touchPoints.at(p).startPos();
80     return result / qreal(count);
81 }
82 
recognize(QGesture * state,QObject *,QEvent * event)83 QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state,
84                                                             QObject *,
85                                                             QEvent *event)
86 {
87     QPanGesture *q = static_cast<QPanGesture *>(state);
88     QPanGesturePrivate *d = q->d_func();
89 
90     QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
91     switch (event->type()) {
92     case QEvent::TouchBegin: {
93         const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
94         result = QGestureRecognizer::MayBeGesture;
95         QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
96         d->lastOffset = d->offset = QPointF();
97         d->pointCount = m_pointCount;
98         break;
99     }
100     case QEvent::TouchEnd: {
101         if (q->state() != Qt::NoGesture) {
102             const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
103             if (ev->touchPoints().size() == d->pointCount) {
104                 d->lastOffset = d->offset;
105                 d->offset = panOffset(ev->touchPoints(), d->pointCount);
106             }
107             result = QGestureRecognizer::FinishGesture;
108         } else {
109             result = QGestureRecognizer::CancelGesture;
110         }
111         break;
112     }
113     case QEvent::TouchUpdate: {
114         const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
115         if (ev->touchPoints().size() >= d->pointCount) {
116             d->lastOffset = d->offset;
117             d->offset = panOffset(ev->touchPoints(), d->pointCount);
118             if (d->offset.x() > 10  || d->offset.y() > 10 ||
119                 d->offset.x() < -10 || d->offset.y() < -10) {
120                 q->setHotSpot(ev->touchPoints().first().startScreenPos());
121                 result = QGestureRecognizer::TriggerGesture;
122             } else {
123                 result = QGestureRecognizer::MayBeGesture;
124             }
125         }
126         break;
127     }
128     default:
129         break;
130     }
131     return result;
132 }
133 
reset(QGesture * state)134 void QPanGestureRecognizer::reset(QGesture *state)
135 {
136     QPanGesture *pan = static_cast<QPanGesture*>(state);
137     QPanGesturePrivate *d = pan->d_func();
138 
139     d->lastOffset = d->offset = QPointF();
140     d->acceleration = 0;
141 
142     QGestureRecognizer::reset(state);
143 }
144 
145 
146 //
147 // QPinchGestureRecognizer
148 //
149 
QPinchGestureRecognizer()150 QPinchGestureRecognizer::QPinchGestureRecognizer()
151 {
152 }
153 
create(QObject * target)154 QGesture *QPinchGestureRecognizer::create(QObject *target)
155 {
156     if (target && target->isWidgetType()) {
157         static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
158     }
159     return new QPinchGesture;
160 }
161 
recognize(QGesture * state,QObject *,QEvent * event)162 QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state,
163                                                               QObject *,
164                                                               QEvent *event)
165 {
166     QPinchGesture *q = static_cast<QPinchGesture *>(state);
167     QPinchGesturePrivate *d = q->d_func();
168 
169     QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
170 
171     switch (event->type()) {
172     case QEvent::TouchBegin: {
173         result = QGestureRecognizer::MayBeGesture;
174         break;
175     }
176     case QEvent::TouchEnd: {
177         if (q->state() != Qt::NoGesture) {
178             result = QGestureRecognizer::FinishGesture;
179         } else {
180             result = QGestureRecognizer::CancelGesture;
181         }
182         break;
183     }
184     case QEvent::TouchUpdate: {
185         const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
186         d->changeFlags = { };
187         if (ev->touchPoints().size() == 2) {
188             QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
189             QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
190 
191             d->hotSpot = p1.screenPos();
192             d->isHotSpotSet = true;
193 
194             QPointF centerPoint = (p1.screenPos() + p2.screenPos()) / 2.0;
195             if (d->isNewSequence) {
196                 d->startPosition[0] = p1.screenPos();
197                 d->startPosition[1] = p2.screenPos();
198                 d->lastCenterPoint = centerPoint;
199             } else {
200                 d->lastCenterPoint = d->centerPoint;
201             }
202             d->centerPoint = centerPoint;
203 
204             d->changeFlags |= QPinchGesture::CenterPointChanged;
205 
206             if (d->isNewSequence) {
207                 d->scaleFactor = 1.0;
208                 d->lastScaleFactor = 1.0;
209             } else {
210                 d->lastScaleFactor = d->scaleFactor;
211                 QLineF line(p1.screenPos(), p2.screenPos());
212                 QLineF lastLine(p1.lastScreenPos(),  p2.lastScreenPos());
213                 qreal newScaleFactor = line.length() / lastLine.length();
214                 if (newScaleFactor > kSingleStepScaleMax || newScaleFactor < kSingleStepScaleMin)
215                     return QGestureRecognizer::Ignore;
216                 d->scaleFactor = newScaleFactor;
217             }
218             d->totalScaleFactor = d->totalScaleFactor * d->scaleFactor;
219             d->changeFlags |= QPinchGesture::ScaleFactorChanged;
220 
221             qreal angle = QLineF(p1.screenPos(), p2.screenPos()).angle();
222             if (angle > 180)
223                 angle -= 360;
224             qreal startAngle = QLineF(p1.startScreenPos(), p2.startScreenPos()).angle();
225             if (startAngle > 180)
226                 startAngle -= 360;
227             const qreal rotationAngle = startAngle - angle;
228             if (d->isNewSequence)
229                 d->lastRotationAngle = 0.0;
230             else
231                 d->lastRotationAngle = d->rotationAngle;
232             d->rotationAngle = rotationAngle;
233             d->totalRotationAngle += d->rotationAngle - d->lastRotationAngle;
234             d->changeFlags |= QPinchGesture::RotationAngleChanged;
235 
236             d->totalChangeFlags |= d->changeFlags;
237             d->isNewSequence = false;
238             result = QGestureRecognizer::TriggerGesture;
239         } else {
240             d->isNewSequence = true;
241             if (q->state() == Qt::NoGesture)
242                 result = QGestureRecognizer::Ignore;
243             else
244                 result = QGestureRecognizer::FinishGesture;
245         }
246         break;
247     }
248     default:
249         break;
250     }
251     return result;
252 }
253 
reset(QGesture * state)254 void QPinchGestureRecognizer::reset(QGesture *state)
255 {
256     QPinchGesture *pinch = static_cast<QPinchGesture *>(state);
257     QPinchGesturePrivate *d = pinch->d_func();
258 
259     d->totalChangeFlags = d->changeFlags = { };
260 
261     d->startCenterPoint = d->lastCenterPoint = d->centerPoint = QPointF();
262     d->totalScaleFactor = d->lastScaleFactor = d->scaleFactor = 1;
263     d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0;
264 
265     d->isNewSequence = true;
266     d->startPosition[0] = d->startPosition[1] = QPointF();
267 
268     QGestureRecognizer::reset(state);
269 }
270 
271 //
272 // QSwipeGestureRecognizer
273 //
274 
QSwipeGestureRecognizer()275 QSwipeGestureRecognizer::QSwipeGestureRecognizer()
276 {
277 }
278 
create(QObject * target)279 QGesture *QSwipeGestureRecognizer::create(QObject *target)
280 {
281     if (target && target->isWidgetType()) {
282         static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
283     }
284     return new QSwipeGesture;
285 }
286 
recognize(QGesture * state,QObject *,QEvent * event)287 QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state,
288                                                               QObject *,
289                                                               QEvent *event)
290 {
291     QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
292     QSwipeGesturePrivate *d = q->d_func();
293 
294     QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
295 
296     switch (event->type()) {
297     case QEvent::TouchBegin: {
298         d->velocityValue = 1;
299         d->time.start();
300         d->state = QSwipeGesturePrivate::Started;
301         result = QGestureRecognizer::MayBeGesture;
302         break;
303     }
304     case QEvent::TouchEnd: {
305         if (q->state() != Qt::NoGesture) {
306             result = QGestureRecognizer::FinishGesture;
307         } else {
308             result = QGestureRecognizer::CancelGesture;
309         }
310         break;
311     }
312     case QEvent::TouchUpdate: {
313         const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
314         if (d->state == QSwipeGesturePrivate::NoGesture)
315             result = QGestureRecognizer::CancelGesture;
316         else if (ev->touchPoints().size() == 3) {
317             d->state = QSwipeGesturePrivate::ThreePointsReached;
318             QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0);
319             QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1);
320             QTouchEvent::TouchPoint p3 = ev->touchPoints().at(2);
321 
322             if (d->lastPositions[0].isNull()) {
323                 d->lastPositions[0] = p1.startScreenPos().toPoint();
324                 d->lastPositions[1] = p2.startScreenPos().toPoint();
325                 d->lastPositions[2] = p3.startScreenPos().toPoint();
326             }
327             d->hotSpot = p1.screenPos();
328             d->isHotSpotSet = true;
329 
330             int xDistance = (p1.screenPos().x() - d->lastPositions[0].x() +
331                              p2.screenPos().x() - d->lastPositions[1].x() +
332                              p3.screenPos().x() - d->lastPositions[2].x()) / 3;
333             int yDistance = (p1.screenPos().y() - d->lastPositions[0].y() +
334                              p2.screenPos().y() - d->lastPositions[1].y() +
335                              p3.screenPos().y() - d->lastPositions[2].y()) / 3;
336 
337             const int distance = xDistance >= yDistance ? xDistance : yDistance;
338             int elapsedTime = d->time.restart();
339             if (!elapsedTime)
340                 elapsedTime = 1;
341             d->velocityValue = 0.9 * d->velocityValue + (qreal) distance / elapsedTime;
342             d->swipeAngle = QLineF(p1.startScreenPos(), p1.screenPos()).angle();
343 
344             static const int MoveThreshold = 50;
345             static const int directionChangeThreshold = MoveThreshold / 8;
346             if (qAbs(xDistance) > MoveThreshold || qAbs(yDistance) > MoveThreshold) {
347                 // measure the distance to check if the direction changed
348                 d->lastPositions[0] = p1.screenPos().toPoint();
349                 d->lastPositions[1] = p2.screenPos().toPoint();
350                 d->lastPositions[2] = p3.screenPos().toPoint();
351                 result = QGestureRecognizer::TriggerGesture;
352                 // QTBUG-46195, small changes in direction should not cause the gesture to be canceled.
353                 if (d->verticalDirection == QSwipeGesture::NoDirection || qAbs(yDistance) > directionChangeThreshold) {
354                     const QSwipeGesture::SwipeDirection vertical = yDistance > 0
355                         ? QSwipeGesture::Down : QSwipeGesture::Up;
356                     if (d->verticalDirection != QSwipeGesture::NoDirection && d->verticalDirection != vertical)
357                         result = QGestureRecognizer::CancelGesture;
358                     d->verticalDirection = vertical;
359                 }
360                 if (d->horizontalDirection == QSwipeGesture::NoDirection || qAbs(xDistance) > directionChangeThreshold) {
361                     const QSwipeGesture::SwipeDirection horizontal = xDistance > 0
362                         ? QSwipeGesture::Right : QSwipeGesture::Left;
363                     if (d->horizontalDirection != QSwipeGesture::NoDirection && d->horizontalDirection != horizontal)
364                         result = QGestureRecognizer::CancelGesture;
365                     d->horizontalDirection = horizontal;
366                 }
367             } else {
368                 if (q->state() != Qt::NoGesture)
369                     result = QGestureRecognizer::TriggerGesture;
370                 else
371                     result = QGestureRecognizer::MayBeGesture;
372             }
373         } else if (ev->touchPoints().size() > 3) {
374             result = QGestureRecognizer::CancelGesture;
375         } else { // less than 3 touch points
376             switch (d->state) {
377             case QSwipeGesturePrivate::NoGesture:
378                 result = QGestureRecognizer::MayBeGesture;
379                 break;
380             case QSwipeGesturePrivate::Started:
381                 result = QGestureRecognizer::Ignore;
382                 break;
383             case QSwipeGesturePrivate::ThreePointsReached:
384                 result = (ev->touchPointStates() & Qt::TouchPointPressed)
385                     ? QGestureRecognizer::CancelGesture : QGestureRecognizer::Ignore;
386                 break;
387             }
388         }
389         break;
390     }
391     default:
392         break;
393     }
394     return result;
395 }
396 
reset(QGesture * state)397 void QSwipeGestureRecognizer::reset(QGesture *state)
398 {
399     QSwipeGesture *q = static_cast<QSwipeGesture *>(state);
400     QSwipeGesturePrivate *d = q->d_func();
401 
402     d->verticalDirection = d->horizontalDirection = QSwipeGesture::NoDirection;
403     d->swipeAngle = 0;
404 
405     d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint();
406     d->state = QSwipeGesturePrivate::NoGesture;
407     d->velocityValue = 0;
408     d->time.invalidate();
409 
410     QGestureRecognizer::reset(state);
411 }
412 
413 //
414 // QTapGestureRecognizer
415 //
416 
QTapGestureRecognizer()417 QTapGestureRecognizer::QTapGestureRecognizer()
418 {
419 }
420 
create(QObject * target)421 QGesture *QTapGestureRecognizer::create(QObject *target)
422 {
423     if (target && target->isWidgetType()) {
424         static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
425     }
426     return new QTapGesture;
427 }
428 
recognize(QGesture * state,QObject *,QEvent * event)429 QGestureRecognizer::Result QTapGestureRecognizer::recognize(QGesture *state,
430                                                             QObject *,
431                                                             QEvent *event)
432 {
433     QTapGesture *q = static_cast<QTapGesture *>(state);
434     QTapGesturePrivate *d = q->d_func();
435 
436     const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
437 
438     QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
439 
440     switch (event->type()) {
441     case QEvent::TouchBegin: {
442         d->position = ev->touchPoints().at(0).pos();
443         q->setHotSpot(ev->touchPoints().at(0).screenPos());
444         result = QGestureRecognizer::TriggerGesture;
445         break;
446     }
447     case QEvent::TouchUpdate:
448     case QEvent::TouchEnd: {
449         if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) {
450             QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
451             QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
452             enum { TapRadius = 40 };
453             if (delta.manhattanLength() <= TapRadius) {
454                 if (event->type() == QEvent::TouchEnd)
455                     result = QGestureRecognizer::FinishGesture;
456                 else
457                     result = QGestureRecognizer::TriggerGesture;
458             }
459         }
460         break;
461     }
462     case QEvent::MouseButtonPress:
463     case QEvent::MouseMove:
464     case QEvent::MouseButtonRelease:
465         result = QGestureRecognizer::Ignore;
466         break;
467     default:
468         result = QGestureRecognizer::Ignore;
469         break;
470     }
471     return result;
472 }
473 
reset(QGesture * state)474 void QTapGestureRecognizer::reset(QGesture *state)
475 {
476     QTapGesture *q = static_cast<QTapGesture *>(state);
477     QTapGesturePrivate *d = q->d_func();
478 
479     d->position = QPointF();
480 
481     QGestureRecognizer::reset(state);
482 }
483 
484 //
485 // QTapAndHoldGestureRecognizer
486 //
487 
QTapAndHoldGestureRecognizer()488 QTapAndHoldGestureRecognizer::QTapAndHoldGestureRecognizer()
489 {
490 }
491 
create(QObject * target)492 QGesture *QTapAndHoldGestureRecognizer::create(QObject *target)
493 {
494     if (target && target->isWidgetType()) {
495         static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
496     }
497     return new QTapAndHoldGesture;
498 }
499 
500 QGestureRecognizer::Result
recognize(QGesture * state,QObject * object,QEvent * event)501 QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object,
502                                         QEvent *event)
503 {
504     QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
505     QTapAndHoldGesturePrivate *d = q->d_func();
506 
507     if (object == state && event->type() == QEvent::Timer) {
508         q->killTimer(d->timerId);
509         d->timerId = 0;
510         return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
511     }
512 
513     enum { TapRadius = 40 };
514 
515     switch (event->type()) {
516 #if QT_CONFIG(graphicsview)
517     case QEvent::GraphicsSceneMousePress: {
518         const QGraphicsSceneMouseEvent *gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
519         d->position = gsme->screenPos();
520         q->setHotSpot(d->position);
521         if (d->timerId)
522             q->killTimer(d->timerId);
523         d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
524         return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
525     }
526 #endif
527     case QEvent::MouseButtonPress: {
528         const QMouseEvent *me = static_cast<const QMouseEvent *>(event);
529         d->position = me->globalPos();
530         q->setHotSpot(d->position);
531         if (d->timerId)
532             q->killTimer(d->timerId);
533         d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
534         return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
535     }
536     case QEvent::TouchBegin: {
537         const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
538         d->position = ev->touchPoints().at(0).startScreenPos();
539         q->setHotSpot(d->position);
540         if (d->timerId)
541             q->killTimer(d->timerId);
542         d->timerId = q->startTimer(QTapAndHoldGesturePrivate::Timeout);
543         return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
544     }
545 #if QT_CONFIG(graphicsview)
546     case QEvent::GraphicsSceneMouseRelease:
547 #endif
548     case QEvent::MouseButtonRelease:
549     case QEvent::TouchEnd:
550         return QGestureRecognizer::CancelGesture; // get out of the MayBeGesture state
551     case QEvent::TouchUpdate: {
552         const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
553         if (d->timerId && ev->touchPoints().size() == 1) {
554             QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
555             QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
556             if (delta.manhattanLength() <= TapRadius)
557                 return QGestureRecognizer::MayBeGesture;
558         }
559         return QGestureRecognizer::CancelGesture;
560     }
561     case QEvent::MouseMove: {
562         const QMouseEvent *me = static_cast<const QMouseEvent *>(event);
563         QPoint delta = me->globalPos() - d->position.toPoint();
564         if (d->timerId && delta.manhattanLength() <= TapRadius)
565             return QGestureRecognizer::MayBeGesture;
566         return QGestureRecognizer::CancelGesture;
567     }
568 #if QT_CONFIG(graphicsview)
569     case QEvent::GraphicsSceneMouseMove: {
570         const QGraphicsSceneMouseEvent *gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
571         QPoint delta = gsme->screenPos() - d->position.toPoint();
572         if (d->timerId && delta.manhattanLength() <= TapRadius)
573             return QGestureRecognizer::MayBeGesture;
574         return QGestureRecognizer::CancelGesture;
575     }
576 #endif
577     default:
578         return QGestureRecognizer::Ignore;
579     }
580 }
581 
reset(QGesture * state)582 void QTapAndHoldGestureRecognizer::reset(QGesture *state)
583 {
584     QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state);
585     QTapAndHoldGesturePrivate *d = q->d_func();
586 
587     d->position = QPointF();
588     if (d->timerId)
589         q->killTimer(d->timerId);
590     d->timerId = 0;
591 
592     QGestureRecognizer::reset(state);
593 }
594 
595 QT_END_NAMESPACE
596 
597 #endif // QT_NO_GESTURES
598