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 "qgesture.h"
41#include "qapplication.h"
42#include "qevent.h"
43#include "qwidget.h"
44#if QT_CONFIG(graphicsview)
45#include "qgraphicsitem.h"
46#include "qgraphicsscene.h"
47#include "qgraphicssceneevent.h"
48#include "qgraphicsview.h"
49#endif
50#include "qscroller.h"
51#include <QtGui/qpointingdevice.h>
52#include "private/qapplication_p.h"
53#include "private/qevent_p.h"
54#include "private/qflickgesture_p.h"
55#include "qdebug.h"
56
57#ifndef QT_NO_GESTURES
58
59QT_BEGIN_NAMESPACE
60
61//#define QFLICKGESTURE_DEBUG
62
63#ifdef QFLICKGESTURE_DEBUG
64# define qFGDebug qDebug
65#else
66# define qFGDebug while (false) qDebug
67#endif
68
69extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
70
71static QMouseEvent *copyMouseEvent(QEvent *e)
72{
73 switch (e->type()) {
74 case QEvent::MouseButtonPress:
75 case QEvent::MouseButtonRelease:
76 case QEvent::MouseMove: {
77 QMouseEvent *me = static_cast<QMouseEvent *>(e);
78 QMouseEvent *cme = new QMouseEvent(me->type(), QPoint(0, 0), me->scenePosition(), me->globalPosition(),
79 me->button(), me->buttons(), me->modifiers(), me->source());
80 return cme;
81 }
82#if QT_CONFIG(graphicsview)
83 case QEvent::GraphicsSceneMousePress:
84 case QEvent::GraphicsSceneMouseRelease:
85 case QEvent::GraphicsSceneMouseMove: {
86 QGraphicsSceneMouseEvent *me = static_cast<QGraphicsSceneMouseEvent *>(e);
87#if 1
88 QEvent::Type met = me->type() == QEvent::GraphicsSceneMousePress ? QEvent::MouseButtonPress :
89 (me->type() == QEvent::GraphicsSceneMouseRelease ? QEvent::MouseButtonRelease : QEvent::MouseMove);
90 QMouseEvent *cme = new QMouseEvent(met, QPoint(0, 0), QPoint(0, 0), me->screenPos(),
91 me->button(), me->buttons(), me->modifiers(), me->source());
92 return cme;
93#else
94 QGraphicsSceneMouseEvent *copy = new QGraphicsSceneMouseEvent(me->type());
95 copy->setPos(me->pos());
96 copy->setScenePos(me->scenePos());
97 copy->setScreenPos(me->screenPos());
98 for (int i = 0x1; i <= 0x10; i <<= 1) {
99 Qt::MouseButton button = Qt::MouseButton(i);
100 copy->setButtonDownPos(button, me->buttonDownPos(button));
101 copy->setButtonDownScenePos(button, me->buttonDownScenePos(button));
102 copy->setButtonDownScreenPos(button, me->buttonDownScreenPos(button));
103 }
104 copy->setLastPos(me->lastPos());
105 copy->setLastScenePos(me->lastScenePos());
106 copy->setLastScreenPos(me->lastScreenPos());
107 copy->setButtons(me->buttons());
108 copy->setButton(me->button());
109 copy->setModifiers(me->modifiers());
110 copy->setSource(me->source());
111 copy->setFlags(me->flags());
112 return copy;
113#endif
114 }
115#endif // QT_CONFIG(graphicsview)
116 default:
117 return nullptr;
118 }
119}
120
121class PressDelayHandler : public QObject
122{
123private:
124 PressDelayHandler(QObject *parent = nullptr)
125 : QObject(parent)
126 , pressDelayTimer(0)
127 , sendingEvent(false)
128 , mouseButton(Qt::NoButton)
129 , mouseTarget(nullptr)
130 , mouseEventSource(Qt::MouseEventNotSynthesized)
131 { }
132
133public:
134 enum {
135 UngrabMouseBefore = 1,
136 RegrabMouseAfterwards = 2
137 };
138
139 static PressDelayHandler *instance()
140 {
141 static PressDelayHandler *inst = nullptr;
142 if (!inst)
143 inst = new PressDelayHandler(QCoreApplication::instance());
144 return inst;
145 }
146
147 bool shouldEventBeIgnored(QEvent *) const
148 {
149 return sendingEvent;
150 }
151
152 bool isDelaying() const
153 {
154 return !pressDelayEvent.isNull();
155 }
156
157 void pressed(QEvent *e, int delay)
158 {
159 if (!pressDelayEvent) {
160 pressDelayEvent.reset(copyMouseEvent(e));
161 pressDelayTimer = startTimer(delay);
162 mouseTarget = QApplication::widgetAt(pressDelayEvent->globalPosition().toPoint());
163 mouseButton = pressDelayEvent->button();
164 mouseEventSource = pressDelayEvent->source();
165 qFGDebug("QFG: consuming/delaying mouse press");
166 } else {
167 qFGDebug("QFG: NOT consuming/delaying mouse press");
168 }
169 e->setAccepted(true);
170 }
171
172 bool released(QEvent *e, bool scrollerWasActive, bool scrollerIsActive)
173 {
174 // consume this event if the scroller was or is active
175 bool result = scrollerWasActive || scrollerIsActive;
176
177 // stop the timer
178 if (pressDelayTimer) {
179 killTimer(pressDelayTimer);
180 pressDelayTimer = 0;
181 }
182 // we still haven't even sent the press, so do it now
183 if (pressDelayEvent && mouseTarget && !scrollerIsActive) {
184 QScopedPointer<QMouseEvent> releaseEvent(copyMouseEvent(e));
185
186 qFGDebug() << "QFG: re-sending mouse press (due to release) for " << mouseTarget;
187 sendMouseEvent(pressDelayEvent.data(), UngrabMouseBefore);
188
189 qFGDebug() << "QFG: faking mouse release (due to release) for " << mouseTarget;
190 sendMouseEvent(releaseEvent.data());
191
192 result = true; // consume this event
193 } else if (mouseTarget && scrollerIsActive) {
194 // we grabbed the mouse expicitly when the scroller became active, so undo that now
195 sendMouseEvent(nullptr, UngrabMouseBefore);
196 }
197 pressDelayEvent.reset(nullptr);
198 mouseTarget = nullptr;
199 return result;
200 }
201
202 void scrollerWasIntercepted()
203 {
204 qFGDebug("QFG: deleting delayed mouse press, since scroller was only intercepted");
205 if (pressDelayEvent) {
206 // we still haven't even sent the press, so just throw it away now
207 if (pressDelayTimer) {
208 killTimer(pressDelayTimer);
209 pressDelayTimer = 0;
210 }
211 pressDelayEvent.reset(nullptr);
212 }
213 mouseTarget = nullptr;
214 }
215
216 void scrollerBecameActive(Qt::KeyboardModifiers eventModifiers, Qt::MouseButtons eventButtons)
217 {
218 if (pressDelayEvent) {
219 // we still haven't even sent the press, so just throw it away now
220 qFGDebug("QFG: deleting delayed mouse press, since scroller is active now");
221 if (pressDelayTimer) {
222 killTimer(pressDelayTimer);
223 pressDelayTimer = 0;
224 }
225 pressDelayEvent.reset(nullptr);
226 mouseTarget = nullptr;
227 } else if (mouseTarget) {
228 // we did send a press, so we need to fake a release now
229
230 // release all pressed mouse buttons
231 /* Qt::MouseButtons mouseButtons = QGuiApplication::mouseButtons();
232 for (int i = 0; i < 32; ++i) {
233 if (mouseButtons & (1 << i)) {
234 Qt::MouseButton b = static_cast<Qt::MouseButton>(1 << i);
235 mouseButtons &= ~b;
236 QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
237
238 qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
239 QMouseEvent re(QEvent::MouseButtonRelease, QPoint(), farFarAway,
240 b, mouseButtons, QGuiApplication::keyboardModifiers());
241 sendMouseEvent(&re);
242 }
243 }*/
244
245 QPoint farFarAway(-QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
246
247 qFGDebug() << "QFG: sending a fake mouse release at far-far-away to " << mouseTarget;
248 QMouseEvent re(QEvent::MouseButtonRelease, QPoint(), farFarAway, farFarAway,
249 mouseButton, eventButtons & ~mouseButton,
250 eventModifiers, mouseEventSource);
251 sendMouseEvent(&re, RegrabMouseAfterwards);
252 // don't clear the mouseTarget just yet, since we need to explicitly ungrab the mouse on release!
253 }
254 }
255
256protected:
257 void timerEvent(QTimerEvent *e) override
258 {
259 if (e->timerId() == pressDelayTimer) {
260 if (pressDelayEvent && mouseTarget) {
261 qFGDebug() << "QFG: timer event: re-sending mouse press to " << mouseTarget;
262 sendMouseEvent(pressDelayEvent.data(), UngrabMouseBefore);
263 }
264 pressDelayEvent.reset(nullptr);
265
266 if (pressDelayTimer) {
267 killTimer(pressDelayTimer);
268 pressDelayTimer = 0;
269 }
270 }
271 }
272
273 void sendMouseEvent(QMouseEvent *me, int flags = 0)
274 {
275 if (mouseTarget) {
276 sendingEvent = true;
277
278#if QT_CONFIG(graphicsview)
279 QGraphicsItem *grabber = nullptr;
280 if (mouseTarget->parentWidget()) {
281 if (QGraphicsView *gv = qobject_cast<QGraphicsView *>(mouseTarget->parentWidget())) {
282 if (gv->scene())
283 grabber = gv->scene()->mouseGrabberItem();
284 }
285 }
286
287 if (grabber && (flags & UngrabMouseBefore)) {
288 // GraphicsView Mouse Handling Workaround #1:
289 // we need to ungrab the mouse before re-sending the press,
290 // since the scene had already set the mouse grabber to the
291 // original (and consumed) event's receiver
292 qFGDebug() << "QFG: ungrabbing" << grabber;
293 grabber->ungrabMouse();
294 }
295#else
296 Q_UNUSED(flags);
297#endif // QT_CONFIG(graphicsview)
298
299 if (me) {
300 QMouseEvent copy(me->type(), mouseTarget->mapFromGlobal(me->globalPosition()),
301 mouseTarget->topLevelWidget()->mapFromGlobal(me->globalPosition()), me->globalPosition(),
302 me->button(), me->buttons(), me->modifiers(), me->source());
303 qt_sendSpontaneousEvent(mouseTarget, &copy);
304 }
305
306#if QT_CONFIG(graphicsview)
307 if (grabber && (flags & RegrabMouseAfterwards)) {
308 // GraphicsView Mouse Handling Workaround #2:
309 // we need to re-grab the mouse after sending a faked mouse
310 // release, since we still need the mouse moves for the gesture
311 // (the scene will clear the item's mouse grabber status on
312 // release).
313 qFGDebug() << "QFG: re-grabbing" << grabber;
314 grabber->grabMouse();
315 }
316#endif
317 sendingEvent = false;
318 }
319 }
320
321
322private:
323 int pressDelayTimer;
324 QScopedPointer<QMouseEvent> pressDelayEvent;
325 bool sendingEvent;
326 Qt::MouseButton mouseButton;
327 QPointer<QWidget> mouseTarget;
328 Qt::MouseEventSource mouseEventSource;
329};
330
331
332/*!
333 \internal
334 \class QFlickGesture
335 \since 4.8
336 \brief The QFlickGesture class describes a flicking gesture made by the user.
337 \ingroup gestures
338 The QFlickGesture is more complex than the QPanGesture that uses QScroller and QScrollerProperties
339 to decide if it is triggered.
340 This gesture is reacting on touch event as compared to the QMouseFlickGesture.
341
342 \sa {Gestures in Widgets and Graphics View}, QScroller, QScrollerProperties, QMouseFlickGesture
343*/
344
345/*!
346 \internal
347*/
348QFlickGesture::QFlickGesture(QObject *receiver, Qt::MouseButton button, QObject *parent)
349 : QGesture(*new QFlickGesturePrivate, parent)
350{
351 d_func()->q_ptr = this;
352 d_func()->receiver = receiver;
353 d_func()->receiverScroller = (receiver && QScroller::hasScroller(receiver)) ? QScroller::scroller(receiver) : nullptr;
354 d_func()->button = button;
355}
356
357QFlickGesture::~QFlickGesture()
358{ }
359
360QFlickGesturePrivate::QFlickGesturePrivate()
361 : receiverScroller(nullptr), button(Qt::NoButton), macIgnoreWheel(false)
362{ }
363
364
365//
366// QFlickGestureRecognizer
367//
368
369
370QFlickGestureRecognizer::QFlickGestureRecognizer(Qt::MouseButton button)
371{
372 this->button = button;
373}
374
375/*! \reimp
376 */
377QGesture *QFlickGestureRecognizer::create(QObject *target)
378{
379#if QT_CONFIG(graphicsview)
380 QGraphicsObject *go = qobject_cast<QGraphicsObject*>(target);
381 if (go && button == Qt::NoButton) {
382 go->setAcceptTouchEvents(true);
383 }
384#endif
385 return new QFlickGesture(target, button);
386}
387
388/*! \internal
389 The recognize function detects a touch event suitable to start the attached QScroller.
390 The QFlickGesture will be triggered as soon as the scroller is no longer in the state
391 QScroller::Inactive or QScroller::Pressed. It will be finished or canceled
392 at the next QEvent::TouchEnd.
393 Note that the QScroller might continue scrolling (kinetically) at this point.
394 */
395QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state,
396 QObject *watched,
397 QEvent *event)
398{
399 Q_UNUSED(watched);
400
401 static QElapsedTimer monotonicTimer;
402 if (!monotonicTimer.isValid())
403 monotonicTimer.start();
404
405 QFlickGesture *q = static_cast<QFlickGesture *>(state);
406 QFlickGesturePrivate *d = q->d_func();
407
408 QScroller *scroller = d->receiverScroller;
409 if (!scroller)
410 return Ignore; // nothing to do without a scroller?
411
412 QWidget *receiverWidget = qobject_cast<QWidget *>(d->receiver);
413#if QT_CONFIG(graphicsview)
414 QGraphicsObject *receiverGraphicsObject = qobject_cast<QGraphicsObject *>(d->receiver);
415#endif
416
417 // this is only set for events that we inject into the event loop via sendEvent()
418 if (PressDelayHandler::instance()->shouldEventBeIgnored(event)) {
419 //qFGDebug() << state << "QFG: ignored event: " << event->type();
420 return Ignore;
421 }
422
423 const QMouseEvent *me = nullptr;
424#if QT_CONFIG(graphicsview)
425 const QGraphicsSceneMouseEvent *gsme = nullptr;
426#endif
427 const QTouchEvent *te = nullptr;
428 QPoint globalPos;
429
430 // qFGDebug() << "FlickGesture "<<state<<"watched:"<<watched<<"receiver"<<d->receiver<<"event"<<event->type()<<"button"<<button;
431
432 Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier;
433 Qt::MouseButtons mouseButtons = Qt::NoButton;
434 switch (event->type()) {
435 case QEvent::MouseButtonPress:
436 case QEvent::MouseButtonRelease:
437 case QEvent::MouseMove:
438 if (!receiverWidget)
439 return Ignore;
440 if (button != Qt::NoButton) {
441 me = static_cast<const QMouseEvent *>(event);
442 keyboardModifiers = me->modifiers();
443 mouseButtons = me->buttons();
444 globalPos = me->globalPosition().toPoint();
445 }
446 break;
447#if QT_CONFIG(graphicsview)
448 case QEvent::GraphicsSceneMousePress:
449 case QEvent::GraphicsSceneMouseRelease:
450 case QEvent::GraphicsSceneMouseMove:
451 if (!receiverGraphicsObject)
452 return Ignore;
453 if (button != Qt::NoButton) {
454 gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
455 keyboardModifiers = gsme->modifiers();
456 mouseButtons = gsme->buttons();
457 globalPos = gsme->screenPos();
458 }
459 break;
460#endif
461 case QEvent::TouchBegin:
462 case QEvent::TouchEnd:
463 case QEvent::TouchUpdate:
464 if (button == Qt::NoButton) {
465 te = static_cast<const QTouchEvent *>(event);
466 keyboardModifiers = te->modifiers();
467 if (!te->points().isEmpty())
468 globalPos = te->points().at(0).globalPosition().toPoint();
469 }
470 break;
471
472 // consume all wheel events if the scroller is active
473 case QEvent::Wheel:
474 if (d->macIgnoreWheel || (scroller->state() != QScroller::Inactive))
475 return Ignore | ConsumeEventHint;
476 break;
477
478 // consume all dbl click events if the scroller is active
479 case QEvent::MouseButtonDblClick:
480 if (scroller->state() != QScroller::Inactive)
481 return Ignore | ConsumeEventHint;
482 break;
483
484 default:
485 break;
486 }
487
488 if (!me
489#if QT_CONFIG(graphicsview)
490 && !gsme
491#endif
492 && !te) // Neither mouse nor touch
493 return Ignore;
494
495 // get the current pointer position in local coordinates.
496 QPointF point;
497 QScroller::Input inputType = (QScroller::Input) 0;
498
499 switch (event->type()) {
500 case QEvent::MouseButtonPress:
501 if (me && me->button() == button && me->buttons() == button) {
502 point = me->globalPosition().toPoint();
503 inputType = QScroller::InputPress;
504 } else if (me) {
505 scroller->stop();
506 return CancelGesture;
507 }
508 break;
509 case QEvent::MouseButtonRelease:
510 if (me && me->button() == button) {
511 point = me->globalPosition().toPoint();
512 inputType = QScroller::InputRelease;
513 }
514 break;
515 case QEvent::MouseMove:
516 if (me && me->buttons() == button) {
517 point = me->globalPosition().toPoint();
518 inputType = QScroller::InputMove;
519 }
520 break;
521
522#if QT_CONFIG(graphicsview)
523 case QEvent::GraphicsSceneMousePress:
524 if (gsme && gsme->button() == button && gsme->buttons() == button) {
525 point = gsme->scenePos();
526 inputType = QScroller::InputPress;
527 } else if (gsme) {
528 scroller->stop();
529 return CancelGesture;
530 }
531 break;
532 case QEvent::GraphicsSceneMouseRelease:
533 if (gsme && gsme->button() == button) {
534 point = gsme->scenePos();
535 inputType = QScroller::InputRelease;
536 }
537 break;
538 case QEvent::GraphicsSceneMouseMove:
539 if (gsme && gsme->buttons() == button) {
540 point = gsme->scenePos();
541 inputType = QScroller::InputMove;
542 }
543 break;
544#endif
545
546 case QEvent::TouchBegin:
547 inputType = QScroller::InputPress;
548 Q_FALLTHROUGH();
549 case QEvent::TouchEnd:
550 if (!inputType)
551 inputType = QScroller::InputRelease;
552 Q_FALLTHROUGH();
553 case QEvent::TouchUpdate:
554 if (!inputType)
555 inputType = QScroller::InputMove;
556
557 if (te->pointingDevice()->type() == QInputDevice::DeviceType::TouchPad) {
558 if (te->points().count() != 2) // 2 fingers on pad
559 return Ignore;
560
561 point = te->points().at(0).scenePressPosition() +
562 ((te->points().at(0).scenePosition() - te->points().at(0).scenePressPosition()) +
563 (te->points().at(1).scenePosition() - te->points().at(1).scenePressPosition())) / 2;
564 } else { // TouchScreen
565 if (te->points().count() != 1) // 1 finger on screen
566 return Ignore;
567
568 point = te->points().at(0).scenePosition();
569 }
570 break;
571
572 default:
573 break;
574 }
575
576 // Check for an active scroller at globalPos
577 if (inputType == QScroller::InputPress) {
578 const auto activeScrollers = QScroller::activeScrollers();
579 for (QScroller *as : activeScrollers) {
580 if (as != scroller) {
581 QRegion scrollerRegion;
582
583 if (QWidget *w = qobject_cast<QWidget *>(as->target())) {
584 scrollerRegion = QRect(w->mapToGlobal(QPoint(0, 0)), w->size());
585#if QT_CONFIG(graphicsview)
586 } else if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(as->target())) {
587 if (const auto *scene = go->scene()) {
588 const auto goBoundingRectMappedToScene = go->mapToScene(go->boundingRect());
589 const auto views = scene->views();
590 for (QGraphicsView *gv : views) {
591 scrollerRegion |= gv->mapFromScene(goBoundingRectMappedToScene)
592 .translated(gv->mapToGlobal(QPoint(0, 0)));
593 }
594 }
595#endif
596 }
597 // active scrollers always have priority
598 if (scrollerRegion.contains(globalPos))
599 return Ignore;
600 }
601 }
602 }
603
604 bool scrollerWasDragging = (scroller->state() == QScroller::Dragging);
605 bool scrollerWasScrolling = (scroller->state() == QScroller::Scrolling);
606
607 if (inputType) {
608 if (QWidget *w = qobject_cast<QWidget *>(d->receiver))
609 point = w->mapFromGlobal(point.toPoint());
610#if QT_CONFIG(graphicsview)
611 else if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(d->receiver))
612 point = go->mapFromScene(point);
613#endif
614
615 // inform the scroller about the new event
616 scroller->handleInput(inputType, point, monotonicTimer.elapsed());
617 }
618
619 // depending on the scroller state return the gesture state
620 Result result;
621 bool scrollerIsActive = (scroller->state() == QScroller::Dragging ||
622 scroller->state() == QScroller::Scrolling);
623
624 // Consume all mouse events while dragging or scrolling to avoid nasty
625 // side effects with Qt's standard widgets.
626 if ((me
627#if QT_CONFIG(graphicsview)
628 || gsme
629#endif
630 ) && scrollerIsActive)
631 result |= ConsumeEventHint;
632
633 // The only problem with this approach is that we consume the
634 // MouseRelease when we start the scrolling with a flick gesture, so we
635 // have to fake a MouseRelease "somewhere" to not mess with the internal
636 // states of Qt's widgets (a QPushButton would stay in 'pressed' state
637 // forever, if it doesn't receive a MouseRelease).
638 if (me
639#if QT_CONFIG(graphicsview)
640 || gsme
641#endif
642 ) {
643 if (!scrollerWasDragging && !scrollerWasScrolling && scrollerIsActive)
644 PressDelayHandler::instance()->scrollerBecameActive(keyboardModifiers, mouseButtons);
645 else if (scrollerWasScrolling && (scroller->state() == QScroller::Dragging || scroller->state() == QScroller::Inactive))
646 PressDelayHandler::instance()->scrollerWasIntercepted();
647 }
648
649 if (!inputType) {
650 result |= Ignore;
651 } else {
652 switch (event->type()) {
653 case QEvent::MouseButtonPress:
654#if QT_CONFIG(graphicsview)
655 case QEvent::GraphicsSceneMousePress:
656#endif
657 if (scroller->state() == QScroller::Pressed) {
658 int pressDelay = int(1000 * scroller->scrollerProperties().scrollMetric(QScrollerProperties::MousePressEventDelay).toReal());
659 if (pressDelay > 0) {
660 result |= ConsumeEventHint;
661
662 PressDelayHandler::instance()->pressed(event, pressDelay);
663 event->accept();
664 }
665 }
666 Q_FALLTHROUGH();
667 case QEvent::TouchBegin:
668 q->setHotSpot(globalPos);
669 result |= scrollerIsActive ? TriggerGesture : MayBeGesture;
670 break;
671
672 case QEvent::MouseMove:
673#if QT_CONFIG(graphicsview)
674 case QEvent::GraphicsSceneMouseMove:
675#endif
676 if (PressDelayHandler::instance()->isDelaying())
677 result |= ConsumeEventHint;
678 Q_FALLTHROUGH();
679 case QEvent::TouchUpdate:
680 result |= scrollerIsActive ? TriggerGesture : Ignore;
681 break;
682
683#if QT_CONFIG(graphicsview)
684 case QEvent::GraphicsSceneMouseRelease:
685#endif
686 case QEvent::MouseButtonRelease:
687 if (PressDelayHandler::instance()->released(event, scrollerWasDragging || scrollerWasScrolling, scrollerIsActive))
688 result |= ConsumeEventHint;
689 Q_FALLTHROUGH();
690 case QEvent::TouchEnd:
691 result |= scrollerIsActive ? FinishGesture : CancelGesture;
692 break;
693
694 default:
695 result |= Ignore;
696 break;
697 }
698 }
699 return result;
700}
701
702
703/*! \reimp
704 */
705void QFlickGestureRecognizer::reset(QGesture *state)
706{
707 QGestureRecognizer::reset(state);
708}
709
710QT_END_NAMESPACE
711
712#include "moc_qflickgesture_p.cpp"
713
714#endif // QT_NO_GESTURES
715