1// Copyright (C) 2018 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
4#include "qquicksinglepointhandler_p.h"
5#include "qquicksinglepointhandler_p_p.h"
6#include <private/qquickdeliveryagent_p_p.h>
7
8QT_BEGIN_NAMESPACE
9Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
10
11/*!
12 \qmltype SinglePointHandler
13 \qmlabstract
14 \preliminary
15 \nativetype QQuickSinglePointHandler
16 \inherits PointerDeviceHandler
17 \inqmlmodule QtQuick
18 \brief Abstract handler for single-point Pointer Events.
19
20 An intermediate class (not registered as a QML type)
21 for the most common handlers: those which expect only a single point.
22 wantsPointerEvent() will choose the first point which is inside the
23 \l target item, and return true as long as the event contains that point.
24 Override handleEventPoint() to implement a single-point handler.
25*/
26
27QQuickSinglePointHandler::QQuickSinglePointHandler(QQuickItem *parent)
28 : QQuickPointerDeviceHandler(*(new QQuickSinglePointHandlerPrivate), parent)
29{
30}
31
32QQuickSinglePointHandler::QQuickSinglePointHandler(QQuickSinglePointHandlerPrivate &dd, QQuickItem *parent)
33 : QQuickPointerDeviceHandler(dd, parent)
34{
35}
36
37bool QQuickSinglePointHandler::wantsPointerEvent(QPointerEvent *event)
38{
39 Q_D(QQuickSinglePointHandler);
40 if (!QQuickPointerDeviceHandler::wantsPointerEvent(event))
41 return false;
42
43 if (d->pointInfo.id() != -1) {
44 // We already know which one we want, so check whether it's there.
45 // It's expected to be an update or a release.
46 // If we no longer want it, cancel the grab.
47 int candidatePointCount = 0;
48 bool missing = true;
49 QEventPoint *point = nullptr;
50 for (int i = 0; i < event->pointCount(); ++i) {
51 auto &p = event->point(i);
52 const bool found = (p.id() == d->pointInfo.id());
53 if (found)
54 missing = false;
55 if (wantsEventPoint(event, point: p)) {
56 ++candidatePointCount;
57 if (found)
58 point = &p;
59 }
60 }
61 if (missing) {
62 // Received a stray touch begin event => reset and start over.
63 if (event->type() == QEvent::TouchBegin && event->points().count() == 1) {
64 const QEventPoint &point = event->point(i: 0);
65 qCDebug(lcTouchTarget) << this << "pointId" << Qt::hex << point.id()
66 << "was received as a stray TouchBegin event. Canceling existing gesture"
67 " and starting over.";
68 d->pointInfo.reset(event, point);
69 return true;
70 } else {
71 qCWarning(lcTouchTarget) << this << "pointId" << Qt::hex << d->pointInfo.id()
72 << "is missing from current event, but was neither canceled nor released."
73 " Ignoring:" << event->type();
74 }
75 }
76 if (point) {
77 if (candidatePointCount == 1 || (candidatePointCount > 1 && d->ignoreAdditionalPoints)) {
78 point->setAccepted();
79 return true;
80 } else {
81 cancelAllGrabs(event, point&: *point);
82 }
83 } else {
84 return false;
85 }
86 } else {
87 // We have not yet chosen a point; choose the first one for which wantsEventPoint() returns true.
88 int candidatePointCount = 0;
89 QEventPoint *chosen = nullptr;
90 for (int i = 0; i < event->pointCount(); ++i) {
91 auto &p = event->point(i);
92 if (!event->exclusiveGrabber(point: p) && wantsEventPoint(event, point: p)) {
93 ++candidatePointCount;
94 if (!chosen) {
95 chosen = &p;
96 break;
97 }
98 }
99 }
100 if (chosen && candidatePointCount == 1) {
101 setPointId(chosen->id());
102 chosen->setAccepted();
103 }
104 }
105 return d->pointInfo.id() != -1;
106}
107
108void QQuickSinglePointHandler::handlePointerEventImpl(QPointerEvent *event)
109{
110 Q_D(QQuickSinglePointHandler);
111 QQuickPointerDeviceHandler::handlePointerEventImpl(event);
112 QEventPoint *currentPoint = const_cast<QEventPoint *>(event->pointById(id: d->pointInfo.id()));
113 Q_ASSERT(currentPoint);
114 if (!QQuickDeliveryAgentPrivate::isSynthMouse(ev: event))
115 d->pointInfo.reset(event, point: *currentPoint);
116 handleEventPoint(event, point&: *currentPoint);
117 emit pointChanged();
118}
119
120void QQuickSinglePointHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
121{
122 if (point.state() == QEventPoint::Released) {
123 // If it's a mouse or tablet event, with buttons,
124 // do not deactivate unless all acceptable buttons are released.
125 if (event->isSinglePointEvent()) {
126 const Qt::MouseButtons releasedButtons = static_cast<QSinglePointEvent *>(event)->buttons();
127 if ((releasedButtons & acceptedButtons()) != Qt::NoButton)
128 return;
129 }
130
131 // Deactivate this handler on release
132 setExclusiveGrab(ev: event, point, grab: false);
133 d_func()->reset();
134 }
135}
136
137void QQuickSinglePointHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point)
138{
139 Q_D(QQuickSinglePointHandler);
140 if (grabber != this)
141 return;
142 switch (transition) {
143 case QPointingDevice::GrabExclusive:
144 d->pointInfo.m_sceneGrabPosition = point.sceneGrabPosition();
145 setActive(true);
146 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
147 break;
148 case QPointingDevice::GrabPassive:
149 d->pointInfo.m_sceneGrabPosition = point.sceneGrabPosition();
150 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
151 break;
152 case QPointingDevice::OverrideGrabPassive:
153 return; // don't emit
154 case QPointingDevice::UngrabPassive:
155 case QPointingDevice::UngrabExclusive:
156 case QPointingDevice::CancelGrabPassive:
157 case QPointingDevice::CancelGrabExclusive:
158 // the grab is lost or relinquished, so the point is no longer relevant
159 QQuickPointerHandler::onGrabChanged(grabber, transition, event, point);
160 d->reset();
161 break;
162 }
163}
164
165void QQuickSinglePointHandler::setIgnoreAdditionalPoints(bool v)
166{
167 Q_D(QQuickSinglePointHandler);
168 d->ignoreAdditionalPoints = v;
169}
170
171void QQuickSinglePointHandler::moveTarget(QPointF pos, QEventPoint &point)
172{
173 Q_D(QQuickSinglePointHandler);
174 target()->setPosition(pos);
175 d->pointInfo.m_scenePosition = point.scenePosition();
176 d->pointInfo.m_position = target()->mapFromScene(point: d->pointInfo.m_scenePosition);
177}
178
179void QQuickSinglePointHandler::setPointId(int id)
180{
181 Q_D(QQuickSinglePointHandler);
182 d->pointInfo.m_id = id;
183}
184
185QQuickHandlerPoint QQuickSinglePointHandler::point() const
186{
187 Q_D(const QQuickSinglePointHandler);
188 return d->pointInfo;
189}
190
191/*!
192 \readonly
193 \qmlproperty handlerPoint QtQuick::SinglePointHandler::point
194
195 The \l eventPoint currently being handled. When no point is currently being
196 handled, this object is reset to default values (all coordinates are 0).
197*/
198
199QQuickSinglePointHandlerPrivate::QQuickSinglePointHandlerPrivate()
200 : QQuickPointerDeviceHandlerPrivate()
201{
202}
203
204void QQuickSinglePointHandlerPrivate::reset()
205{
206 Q_Q(QQuickSinglePointHandler);
207 q->setActive(false);
208 pointInfo.reset();
209}
210
211QT_END_NAMESPACE
212
213#include "moc_qquicksinglepointhandler_p.cpp"
214

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/quick/handlers/qquicksinglepointhandler.cpp