Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquicktaphandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7#include <QtQuick/private/qquickdeliveryagent_p_p.h>
8#include <QtQuick/qquickwindow.h>
9#include <qpa/qplatformtheme.h>
10#include <private/qguiapplication_p.h>
11#include <QtGui/qstylehints.h>
12
14
15Q_STATIC_LOGGING_CATEGORY(lcTapHandler, "qt.quick.handler.tap")
16
17quint64 QQuickTapHandler::m_multiTapInterval(0);
18// single tap distance is the same as the drag threshold
19int QQuickTapHandler::m_mouseMultiClickDistanceSquared(-1);
20int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1);
21
22/*!
23 \qmltype TapHandler
24 \nativetype QQuickTapHandler
25 \inherits SinglePointHandler
26 \inqmlmodule QtQuick
27 \ingroup qtquick-input-handlers
28 \brief Handler for taps and clicks.
29
30 TapHandler is a handler for taps on a touchscreen or clicks on a mouse.
31
32 Detection of a valid tap gesture depends on \l gesturePolicy. The default
33 value is DragThreshold, which requires the press and release to be close
34 together in both space and time. In this case, DragHandler is able to
35 function using only a passive grab, and therefore does not interfere with
36 event delivery to any other Items or Input Handlers. So the default
37 gesturePolicy is useful when you want to modify behavior of an existing
38 control or Item by adding a TapHandler with bindings and/or JavaScript
39 callbacks.
40
41 Note that buttons (such as QPushButton) are often implemented not to care
42 whether the press and release occur close together: if you press the button
43 and then change your mind, you need to drag all the way off the edge of the
44 button in order to cancel the click. For this use case, set the
45 \l gesturePolicy to \c TapHandler.ReleaseWithinBounds.
46
47 \snippet pointerHandlers/tapHandlerButton.qml 0
48
49 For multi-tap gestures (double-tap, triple-tap etc.), the distance moved
50 must not exceed QStyleHints::mouseDoubleClickDistance() with mouse and
51 QStyleHints::touchDoubleTapDistance() with touch, and the time between
52 taps must not exceed QStyleHints::mouseDoubleClickInterval().
53
54 \sa MouseArea, {Qt Quick Examples - Pointer Handlers}
55*/
56
57QQuickTapHandler::QQuickTapHandler(QQuickItem *parent)
58 : QQuickSinglePointHandler(parent)
59 , m_longPressThreshold(QGuiApplication::styleHints()->mousePressAndHoldInterval())
60{
61 if (m_mouseMultiClickDistanceSquared < 0) {
62 m_multiTapInterval = qApp->styleHints()->mouseDoubleClickInterval();
63 m_mouseMultiClickDistanceSquared = qApp->styleHints()->mouseDoubleClickDistance();
64 m_mouseMultiClickDistanceSquared *= m_mouseMultiClickDistanceSquared;
65 m_touchMultiTapDistanceSquared = qApp->styleHints()->touchDoubleTapDistance();
66 m_touchMultiTapDistanceSquared *= m_touchMultiTapDistanceSquared;
67 }
68}
69
70bool QQuickTapHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point)
71{
72 if (!QQuickDeliveryAgentPrivate::isMouseEvent(event) &&
73 !QQuickDeliveryAgentPrivate::isTouchEvent(event) &&
74 !QQuickDeliveryAgentPrivate::isTabletEvent(event))
75 return false;
76 // If the user has not violated any constraint, it could be a tap.
77 // Otherwise we want to give up the grab so that a competing handler
78 // (e.g. DragHandler) gets a chance to take over.
79 // Don't forget to emit released in case of a cancel.
80 bool ret = false;
81 bool overThreshold = d_func()->dragOverThreshold(point);
82 if (overThreshold && m_gesturePolicy != DragWithinBounds) {
83 if (m_longPressTimer.isActive())
84 qCDebug(lcTapHandler) << objectName() << "drag threshold exceeded";
85 m_longPressTimer.stop();
86 m_holdTimer.invalidate();
87 }
88 switch (point.state()) {
89 case QEventPoint::Pressed:
90 case QEventPoint::Released:
91 ret = parentContains(point);
92 break;
93 case QEventPoint::Updated:
94 ret = point.id() == this->point().id();
95 switch (m_gesturePolicy) {
96 case DragThreshold:
97 ret = ret && !overThreshold && parentContains(point);
98 break;
99 case WithinBounds:
100 case DragWithinBounds:
101 ret = ret && parentContains(point);
102 break;
103 case ReleaseWithinBounds:
104 // no change to ret: depends only whether it's the already-tracking point ID
105 break;
106 }
107 break;
108 case QEventPoint::Stationary:
109 // If the point hasn't moved since last time, the return value should be the same as last time.
110 // If we return false here, QQuickPointerHandler::handlePointerEvent() will call setActive(false).
111 ret = point.id() == this->point().id();
112 break;
113 case QEventPoint::Unknown:
114 break;
115 }
116 // If this is the grabber, returning false from this function will cancel the grab,
117 // so onGrabChanged(this, CancelGrabExclusive, point) and setPressed(false) will be called.
118 // But when m_gesturePolicy is DragThreshold, we don't get an exclusive grab, but
119 // we still don't want to be pressed anymore.
120 if (!ret && point.id() == this->point().id())
121 setPressed(false, true, const_cast<QPointerEvent *>(event), const_cast<QEventPoint &>(point));
122 return ret;
123}
124
125void QQuickTapHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
126{
127 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(event);
128 switch (point.state()) {
129 case QEventPoint::Pressed:
130 setPressed(true, false, event, point);
131 break;
132 case QEventPoint::Released: {
133 if (isTouch || (static_cast<const QSinglePointEvent *>(event)->buttons() & acceptedButtons()) == Qt::NoButton)
134 setPressed(false, false, event, point);
135 break;
136 }
137 default:
138 break;
139 }
140
141 QQuickSinglePointHandler::handleEventPoint(event, point);
142
143 // If TapHandler only needs a passive grab, it should not block other items and handlers from reacting.
144 // If the point is accepted, QQuickItemPrivate::localizedTouchEvent() would skip it.
145 if (isTouch && m_gesturePolicy == DragThreshold)
146 point.setAccepted(false);
147}
148
149/*!
150 \qmlproperty real QtQuick::TapHandler::longPressThreshold
151
152 The time in seconds that an \l eventPoint must be pressed in order to
153 trigger a long press gesture and emit the \l longPressed() signal, if the
154 value is greater than \c 0. If the point is released before this time
155 limit, a tap can be detected if the \l gesturePolicy constraint is
156 satisfied. If \c longPressThreshold is \c 0, the timer is disabled and the
157 signal will not be emitted. If \c longPressThreshold is set to \c undefined,
158 the default value is used instead, and can be read back from this property.
159
160 The default value is QStyleHints::mousePressAndHoldInterval() converted to
161 seconds.
162*/
163qreal QQuickTapHandler::longPressThreshold() const
164{
165 return m_longPressThreshold / qreal(1000);
166}
167
168void QQuickTapHandler::setLongPressThreshold(qreal longPressThreshold)
169{
170 if (longPressThreshold < 0) {
171 resetLongPressThreshold();
172 return;
173 }
174 int ms = qRound(longPressThreshold * 1000);
175 if (m_longPressThreshold == ms)
176 return;
177
178 m_longPressThreshold = ms;
179 emit longPressThresholdChanged();
180}
181
182void QQuickTapHandler::resetLongPressThreshold()
183{
184 int ms = QGuiApplication::styleHints()->mousePressAndHoldInterval();
185 if (m_longPressThreshold == ms)
186 return;
187
188 m_longPressThreshold = ms;
189 emit longPressThresholdChanged();
190}
191
192void QQuickTapHandler::timerEvent(QTimerEvent *event)
193{
194 if (event->timerId() == m_longPressTimer.timerId()) {
195 m_longPressTimer.stop();
196 qCDebug(lcTapHandler) << objectName() << "longPressed";
197 m_longPressed = true;
198 emit longPressed();
199 } else if (event->timerId() == m_doubleTapTimer.timerId()) {
200 m_doubleTapTimer.stop();
201 qCDebug(lcTapHandler) << objectName() << "double-tap timer expired; taps:" << m_tapCount;
202 Q_ASSERT(m_exclusiveSignals == (SingleTap | DoubleTap));
203 if (m_tapCount == 1)
204 emit singleTapped(m_singleTapReleasedPoint, m_singleTapReleasedButton);
205 else if (m_tapCount == 2)
206 emit doubleTapped(m_singleTapReleasedPoint, m_singleTapReleasedButton);
207 }
208}
209
210/*!
211 \qmlproperty enumeration QtQuick::TapHandler::gesturePolicy
212
213 The spatial constraint for a tap or long press gesture to be recognized,
214 in addition to the constraint that the release must occur before
215 \l longPressThreshold has elapsed. If these constraints are not satisfied,
216 the \l tapped signal is not emitted, and \l tapCount is not incremented.
217 If the spatial constraint is violated, \l pressed transitions immediately
218 from true to false, regardless of the time held.
219
220 The \c gesturePolicy also affects grab behavior as described below.
221
222 \table
223 \header
224 \li Constant
225 \li Description
226 \row
227 \li \c TapHandler.DragThreshold
228 \image pointerHandlers/tapHandlerOverlappingButtons.webp
229 Grab on press: \e passive
230 \li (the default value) The \l eventPoint must not move significantly.
231 If the mouse, finger or stylus moves past the system-wide drag
232 threshold (QStyleHints::startDragDistance), the tap gesture is
233 canceled, even if the device or finger is still pressed. This policy
234 can be useful whenever TapHandler needs to cooperate with other
235 input handlers (for example \l DragHandler) or event-handling Items
236 (for example \l {Qt Quick Controls}), because in this case TapHandler
237 will not take the exclusive grab, but merely a
238 \l {QPointerEvent::addPassiveGrabber()}{passive grab}.
239 That is, \c DragThreshold is especially useful to \e augment
240 existing behavior: it reacts to tap/click/long-press even when
241 another item or handler is already reacting, perhaps even in a
242 different layer of the UI. The following snippet shows one
243 TapHandler as used in one component; but if we stack up two
244 instances of the component, you will see the handlers in both of them
245 react simultaneously when a press occurs over both of them, because
246 the passive grab does not stop event propagation:
247 \quotefromfile pointerHandlers/tapHandlerOverlappingButtons.qml
248 \skipto Item
249 \printuntil component Button
250 \skipto TapHandler
251 \printuntil }
252 \skipuntil Text {
253 \skipuntil }
254 \printuntil Button
255 \printuntil Button
256 \printuntil }
257
258 \row
259 \li \c TapHandler.WithinBounds
260 \image pointerHandlers/tapHandlerButtonWithinBounds.webp
261 Grab on press: \e exclusive
262 \li If the \l eventPoint leaves the bounds of the \c parent Item, the tap
263 gesture is canceled. The TapHandler will take the
264 \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on
265 press, but will release the grab as soon as the boundary constraint
266 is no longer satisfied.
267 \snippet pointerHandlers/tapHandlerButtonWithinBounds.qml 1
268
269 \row
270 \li \c TapHandler.ReleaseWithinBounds
271 \image pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
272 Grab on press: \e exclusive
273 \li At the time of release (the mouse button is released or the finger
274 is lifted), if the \l eventPoint is outside the bounds of the
275 \c parent Item, a tap gesture is not recognized. This corresponds to
276 typical behavior for button widgets: you can cancel a click by
277 dragging outside the button, and you can also change your mind by
278 dragging back inside the button before release. Note that it's
279 necessary for TapHandler to take the
280 \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press
281 and retain it until release in order to detect this gesture.
282 \snippet pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml 1
283
284 \row
285 \li \c TapHandler.DragWithinBounds
286 \image pointerHandlers/dragReleaseMenu.webp
287 Grab on press: \e exclusive
288 \li On press, TapHandler takes the
289 \l {QPointerEvent::setExclusiveGrabber}{exclusive grab}; after that,
290 the \l eventPoint can be dragged within the bounds of the \c parent
291 item, while the \l timeHeld property keeps counting, and the
292 \l longPressed() signal will be emitted regardless of drag distance.
293 However, like \c WithinBounds, if the point leaves the bounds,
294 the tap gesture is \l {PointerHandler::}{canceled()}, \l active()
295 becomes \c false, and \l timeHeld stops counting. This is suitable
296 for implementing press-drag-release components, such as menus, in
297 which a single TapHandler detects press, \c timeHeld drives an
298 "opening" animation, and then the user can drag to a menu item and
299 release, while never leaving the bounds of the parent scene containing
300 the menu. This value was added in Qt 6.3.
301 \snippet pointerHandlers/dragReleaseMenu.qml 1
302 \endtable
303
304 The \l {Qt Quick Examples - Pointer Handlers} demonstrates some use cases for these.
305
306 \note If you find that TapHandler is reacting in cases that conflict with
307 some other behavior, the first thing you should try is to think about which
308 \c gesturePolicy is appropriate. If you cannot fix it by changing \c gesturePolicy,
309 some cases are better served by adjusting \l {PointerHandler::}{grabPermissions},
310 either in this handler, or in another handler that should \e prevent TapHandler
311 from reacting.
312*/
313void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gesturePolicy)
314{
315 if (m_gesturePolicy == gesturePolicy)
316 return;
317
318 m_gesturePolicy = gesturePolicy;
319 emit gesturePolicyChanged();
320}
321
322/*!
323 \qmlproperty enumeration QtQuick::TapHandler::exclusiveSignals
324 \since 6.5
325
326 Determines the exclusivity of the singleTapped() and doubleTapped() signals.
327
328 \value NotExclusive (the default) singleTapped() and doubleTapped() are
329 emitted immediately when the user taps once or twice, respectively.
330
331 \value SingleTap singleTapped() is emitted immediately when the user taps
332 once, and doubleTapped() is never emitted.
333
334 \value DoubleTap doubleTapped() is emitted immediately when the user taps
335 twice, and singleTapped() is never emitted.
336
337 \value (SingleTap | DoubleTap) Both signals are delayed until
338 QStyleHints::mouseDoubleClickInterval(), such that either singleTapped()
339 or doubleTapped() can be emitted, but not both. But if 3 or more taps
340 occur within \c mouseDoubleClickInterval, neither signal is emitted.
341
342 \note The remaining signals such as tapped() and tapCountChanged() are
343 always emitted immediately, regardless of this property.
344*/
345void QQuickTapHandler::setExclusiveSignals(QQuickTapHandler::ExclusiveSignals exc)
346{
347 if (m_exclusiveSignals == exc)
348 return;
349
350 m_exclusiveSignals = exc;
351 emit exclusiveSignalsChanged();
352}
353
354/*!
355 \qmlproperty bool QtQuick::TapHandler::pressed
356 \readonly
357
358 Holds true whenever the mouse or touch point is pressed,
359 and any movement since the press is compliant with the current
360 \l gesturePolicy. When the \l eventPoint is released or the policy is
361 violated, \e pressed will change to false.
362*/
363void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event, QEventPoint &point)
364{
365 if (m_pressed != press) {
366 qCDebug(lcTapHandler) << objectName() << "pressed" << m_pressed << "->" << press
367 << (cancel ? "CANCEL" : "") << point << "gp" << m_gesturePolicy;
368 m_pressed = press;
369 connectPreRenderSignal(press);
370 updateTimeHeld();
371 if (press) {
372 if (m_longPressThreshold > 0)
373 m_longPressTimer.start(m_longPressThreshold, this);
374 m_holdTimer.start();
375 } else {
376 m_longPressTimer.stop();
377 m_holdTimer.invalidate();
378 }
379 if (press) {
380 // on press, grab before emitting changed signals
381 if (m_gesturePolicy == DragThreshold)
382 setPassiveGrab(event, point, press);
383 else
384 setExclusiveGrab(event, point, press);
385 }
386 if (!cancel && !press && parentContains(point)) {
387 if (m_longPressed) {
388 qCDebug(lcTapHandler) << objectName() << "long press threshold" << longPressThreshold() << "exceeded:" << point.timeHeld();
389 } else if (event) {
390 // Assuming here that pointerEvent()->timestamp() is in ms.
391 const quint64 ts = event->timestamp();
392 const quint64 interval = ts - m_lastTapTimestamp;
393 const auto distanceSquared = QVector2D(point.scenePosition() - m_lastTapPos).lengthSquared();
394 const auto singleTapReleasedButton = event->isSinglePointEvent() ? static_cast<QSinglePointEvent *>(event)->button() : Qt::NoButton;
395 if ((interval < m_multiTapInterval && distanceSquared <
396 (event->device()->type() == QInputDevice::DeviceType::Mouse ?
397 m_mouseMultiClickDistanceSquared : m_touchMultiTapDistanceSquared))
398 && m_singleTapReleasedButton == singleTapReleasedButton) {
399 ++m_tapCount;
400 } else {
401 m_singleTapReleasedButton = singleTapReleasedButton;
402 m_singleTapReleasedPoint = point;
403 m_tapCount = 1;
404 }
405 qCDebug(lcTapHandler) << objectName() << "tapped" << m_tapCount << "times; interval since last:" << interval
406 << "sec; distance since last:" << qSqrt(distanceSquared);
407 auto button = event->isSinglePointEvent() ? static_cast<QSinglePointEvent *>(event)->button() : Qt::NoButton;
408 emit tapped(point, button);
409 emit tapCountChanged();
410 switch (m_exclusiveSignals) {
411 case NotExclusive:
412 if (m_tapCount == 1)
413 emit singleTapped(point, button);
414 else if (m_tapCount == 2)
415 emit doubleTapped(point, button);
416 break;
417 case SingleTap:
418 if (m_tapCount == 1)
419 emit singleTapped(point, button);
420 break;
421 case DoubleTap:
422 if (m_tapCount == 2)
423 emit doubleTapped(point, button);
424 break;
425 case (SingleTap | DoubleTap):
426 if (m_tapCount == 1) {
427 qCDebug(lcTapHandler) << objectName() << "waiting to emit singleTapped:" << m_multiTapInterval << "ms";
428 m_doubleTapTimer.start(m_multiTapInterval, this);
429 }
430 }
431 qCDebug(lcTapHandler) << objectName() << "tap" << m_tapCount << "after" << event->timestamp() - m_lastTapTimestamp << "ms";
432
433 m_lastTapTimestamp = ts;
434 m_lastTapPos = point.scenePosition();
435 }
436 }
437 m_longPressed = false;
438 emit pressedChanged();
439 if (!press && m_gesturePolicy != DragThreshold) {
440 // on release, ungrab after emitting changed signals
441 setExclusiveGrab(event, point, press);
442 }
443 if (cancel) {
444 emit canceled(point);
445 if (event)
446 setExclusiveGrab(event, point, false);
447 // In case there is a filtering parent (Flickable), we should not give up the passive grab,
448 // so that it can continue to filter future events.
449 d_func()->reset();
450 emit pointChanged();
451 }
452 }
453}
454
455void QQuickTapHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition,
456 QPointerEvent *ev, QEventPoint &point)
457{
458 // QQuickPointerHandler::onGrabChanged() calls setActive(false) in many cases.
459 QQuickSinglePointHandler::onGrabChanged(grabber, transition, ev, point);
460 // We don't override onActiveChanged(): we could not call setPressed(false) from there anyway.
461 // But ensure that if the TapHandler just got deactivated, it's no longer pressed either.
462 const bool isCanceled = transition == QPointingDevice::CancelGrabExclusive || transition == QPointingDevice::CancelGrabPassive;
463 // But passive grab/ungrab does not change the active state, so that's not a reason to change pressed state either
464 // (i.e. when gesturePolicy == DragThreshold, TapHandler does not become active).
465 const bool passiveGrab = transition == QPointingDevice::GrabPassive || transition == QPointingDevice::UngrabPassive;
466 if (grabber == this && (isCanceled || point.state() == QEventPoint::Released || (!active() && !passiveGrab)))
467 setPressed(false, isCanceled, ev, point);
468}
469
470void QQuickTapHandler::connectPreRenderSignal(bool conn)
471{
472 // disconnect pre-existing connection, if any
473 disconnect(m_preRenderSignalConnection);
474
475 auto par = parentItem();
476 if (!par || !par->window())
477 return;
478
479 /*
480 Note: beforeSynchronizing is emitted from the SG thread, and the
481 timeHeldChanged signal can be used to do arbitrary things in user QML.
482
483 But the docs say the GUI thread is blockd, and "Therefore, it is safe
484 to access GUI thread thread data in a slot or lambda that is connected
485 with Qt::DirectConnection." We use the default AutoConnection just in case.
486 */
487 if (conn) {
488 m_preRenderSignalConnection = connect(par->window(), &QQuickWindow::beforeSynchronizing,
489 this, &QQuickTapHandler::updateTimeHeld);
490 }
491}
492
493void QQuickTapHandler::updateTimeHeld()
494{
495 emit timeHeldChanged();
496}
497
498/*!
499 \qmlproperty int QtQuick::TapHandler::tapCount
500 \readonly
501
502 The number of taps which have occurred within the time and space
503 constraints to be considered a single gesture. The counter is reset to 1
504 if the button changed. For example, to detect a triple-tap, you can write:
505
506 \qml
507 Rectangle {
508 width: 100; height: 30
509 signal tripleTap
510 TapHandler {
511 acceptedButtons: Qt.AllButtons
512 onTapped: if (tapCount == 3) tripleTap()
513 }
514 }
515 \endqml
516*/
517
518/*!
519 \qmlproperty real QtQuick::TapHandler::timeHeld
520 \readonly
521
522 The amount of time in seconds that a pressed point has been held, without
523 moving beyond the drag threshold. It will be updated at least once per
524 frame rendered, which enables rendering an animation showing the progress
525 towards an action which will be triggered by a long-press. It is also
526 possible to trigger one of a series of actions depending on how long the
527 press is held.
528
529 A value of less than zero means no point is being held within this
530 handler's \l [QML] Item.
531
532 \note If \l gesturePolicy is set to \c TapHandler.DragWithinBounds,
533 \c timeHeld does not stop counting even when the pressed point is moved
534 beyond the drag threshold, but only when the point leaves the \l {Item::}
535 {parent} item's \l {QtQuick::Item::contains()}{bounds}.
536*/
537
538/*!
539 \qmlsignal QtQuick::TapHandler::tapped(eventPoint eventPoint, Qt::MouseButton button)
540
541 This signal is emitted each time the \c parent Item is tapped.
542
543 That is, if you press and release a touchpoint or button within a time
544 period less than \l longPressThreshold, while any movement does not exceed
545 the drag threshold, then the \c tapped signal will be emitted at the time
546 of release. The \a eventPoint signal parameter contains information
547 from the release event about the point that was tapped, and \a button
548 is the \l {Qt::MouseButton}{mouse button} that was clicked, or \c NoButton
549 on a touchscreen.
550
551 \snippet pointerHandlers/tapHandlerOnTapped.qml 0
552*/
553
554/*!
555 \qmlsignal QtQuick::TapHandler::singleTapped(eventPoint eventPoint, Qt::MouseButton button)
556 \since 5.11
557
558 This signal is emitted when the \c parent Item is tapped once.
559 After an amount of time greater than QStyleHints::mouseDoubleClickInterval,
560 it can be tapped again; but if the time until the next tap is less,
561 \l tapCount will increase. The \a eventPoint signal parameter contains
562 information from the release event about the point that was tapped, and
563 \a button is the \l {Qt::MouseButton}{mouse button} that was clicked, or
564 \c NoButton on a touchscreen.
565*/
566
567/*!
568 \qmlsignal QtQuick::TapHandler::doubleTapped(eventPoint eventPoint, Qt::MouseButton button)
569 \since 5.11
570
571 This signal is emitted when the \c parent Item is tapped twice within a
572 short span of time (QStyleHints::mouseDoubleClickInterval()) and distance
573 (QStyleHints::mouseDoubleClickDistance() or
574 QStyleHints::touchDoubleTapDistance()). This signal always occurs after
575 \l singleTapped, \l tapped, and \l tapCountChanged. The \a eventPoint
576 signal parameter contains information from the release event about the
577 point that was tapped, and \a button is the
578 \l {Qt::MouseButton}{mouse button} that was clicked, or \c NoButton
579 on a touchscreen.
580*/
581
582/*!
583 \qmlsignal QtQuick::TapHandler::longPressed()
584
585 This signal is emitted when the \c parent Item is pressed and held for a
586 time period greater than \l longPressThreshold. That is, if you press and
587 hold a touchpoint or button, while any movement does not exceed the drag
588 threshold, then the \c longPressed signal will be emitted at the time that
589 \l timeHeld exceeds \l longPressThreshold.
590*/
591
592/*!
593 \qmlsignal QtQuick::TapHandler::tapCountChanged()
594
595 This signal is emitted when the \c parent Item is tapped once or more (within
596 a specified time and distance span) and when the present \c tapCount differs
597 from the previous \c tapCount.
598*/
599QT_END_NAMESPACE
600
601#include "moc_qquicktaphandler_p.cpp"