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 "qquickhandlerpoint_p.h"
5#include "private/qquickevents_p_p.h"
6#include "private/qquickdeliveryagent_p_p.h"
7
8QT_BEGIN_NAMESPACE
9Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
10
11/*!
12 \qmltype handlerPoint
13 \instantiates QQuickHandlerPoint
14 \inqmlmodule QtQuick
15 \brief An event point.
16
17 A handler-owned QML representation of a QEventPoint.
18
19 It's possible to make bindings to properties of a handler's current
20 \l {SinglePointHandler::point}{point} or
21 \l {MultiPointHandler::centroid}{centroid}. For example:
22
23 \snippet pointerHandlers/dragHandlerNullTarget.qml 0
24
25 The point is kept up-to-date when the DragHandler is actively responding to
26 an \l eventPoint; but after the point is released, or when the current point is
27 being handled by a different handler, \c position.x and \c position.y are 0.
28
29 \note This is practically identical to \l eventPoint; however an eventPoint
30 is a short-lived copy of a long-lived Q_GADGET which is invalidated between
31 gestures and reused for subsequent event deliveries. Continuous bindings to its
32 properties are not possible, and an individual handler cannot rely on it
33 outside the period when that point is part of an active gesture which that
34 handler is handling. handlerPoint is a Q_GADGET that the handler owns.
35 This allows you to make lifetime bindings to its properties.
36
37 \sa SinglePointHandler::point, MultiPointHandler::centroid
38*/
39
40QQuickHandlerPoint::QQuickHandlerPoint()
41{}
42
43void QQuickHandlerPoint::localize(QQuickItem *item)
44{
45 m_pressPosition = item->mapFromScene(point: m_scenePressPosition);
46}
47
48void QQuickHandlerPoint::reset()
49{
50 m_id = -1;
51 m_device = QPointingDevice::primaryPointingDevice();
52 m_uniqueId = QPointingDeviceUniqueId();
53 m_position = QPointF();
54 m_scenePosition = QPointF();
55 m_pressPosition = QPointF();
56 m_scenePressPosition = QPointF();
57 m_sceneGrabPosition = QPointF();
58 m_velocity = QVector2D();
59 m_rotation = 0;
60 m_pressure = 0;
61 m_ellipseDiameters = QSizeF();
62 m_pressedButtons = Qt::NoButton;
63 m_pressedModifiers = Qt::NoModifier;
64}
65
66void QQuickHandlerPoint::reset(const QPointerEvent *event, const QEventPoint &point)
67{
68 const bool isTouch = QQuickDeliveryAgentPrivate::isTouchEvent(ev: event);
69 m_id = point.id();
70 m_device = event->pointingDevice();
71 const auto state = (isTouch ? static_cast<const QTouchEvent *>(event)->touchPointStates() : point.state());
72 if (state.testFlag(flag: QEventPoint::Pressed)) {
73 m_pressPosition = point.position();
74 m_scenePressPosition = point.scenePosition();
75 }
76 if (!isTouch)
77 m_pressedButtons = static_cast<const QSinglePointEvent *>(event)->buttons();
78 m_pressedModifiers = event->modifiers();
79 if (isTouch) {
80 m_uniqueId = point.uniqueId();
81 m_rotation = point.rotation();
82 m_pressure = point.pressure();
83 m_ellipseDiameters = point.ellipseDiameters();
84#if QT_CONFIG(tabletevent)
85 } else if (QQuickDeliveryAgentPrivate::isTabletEvent(ev: event)) {
86 m_uniqueId = event->pointingDevice()->uniqueId();
87 m_rotation = point.rotation();
88 m_pressure = point.pressure();
89 m_ellipseDiameters = QSizeF();
90#endif
91 } else {
92 m_uniqueId = event->pointingDevice()->uniqueId();
93 m_rotation = 0;
94 m_pressure = m_pressedButtons ? 1 : 0;
95 m_ellipseDiameters = QSizeF();
96 }
97 m_position = point.position();
98 m_scenePosition = point.scenePosition();
99 if (point.state() == QEventPoint::Updated)
100 m_velocity = point.velocity();
101}
102
103void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
104{
105 if (points.isEmpty()) {
106 qWarning(msg: "reset: no points");
107 return;
108 }
109 if (points.size() == 1) {
110 *this = points.first(); // copy all values
111 return;
112 }
113 // all points are required to be from the same event
114 QPointF posSum;
115 QPointF scenePosSum;
116 QPointF pressPosSum;
117 QPointF scenePressPosSum;
118 QVector2D velocitySum;
119 qreal pressureSum = 0;
120 QSizeF ellipseDiameterSum;
121 for (const QQuickHandlerPoint &point : points) {
122 posSum += point.position();
123 scenePosSum += point.scenePosition();
124 pressPosSum += point.pressPosition();
125 scenePressPosSum += point.scenePressPosition();
126 velocitySum += point.velocity();
127 pressureSum += point.pressure();
128 ellipseDiameterSum += point.ellipseDiameters();
129 }
130 m_id = -1;
131 m_device = nullptr;
132 m_uniqueId = QPointingDeviceUniqueId();
133 // all points are required to be from the same event, so pressed buttons and modifiers should be the same
134 m_pressedButtons = points.first().pressedButtons();
135 m_pressedModifiers = points.first().modifiers();
136 m_position = posSum / points.size();
137 m_scenePosition = scenePosSum / points.size();
138 m_pressPosition = pressPosSum / points.size();
139 m_scenePressPosition = scenePressPosSum / points.size();
140 m_velocity = velocitySum / points.size();
141 m_rotation = 0; // averaging the rotations of all the points isn't very sensible
142 m_pressure = pressureSum / points.size();
143 m_ellipseDiameters = ellipseDiameterSum / points.size();
144}
145
146/*!
147 \readonly
148 \qmlproperty int QtQuick::handlerPoint::id
149 \brief The ID number of the point
150
151 During a touch gesture, from the time that the first finger is pressed
152 until the last finger is released, each touchpoint will have a unique ID
153 number. Likewise, if input from multiple devices occurs (for example
154 simultaneous mouse and touch presses), all the current \l{eventPoint}{eventPoints} from
155 all the devices will have unique IDs.
156
157 \note Do not assume that id numbers start at zero or that they are
158 sequential. Such an assumption is often false due to the way the underlying
159 drivers work.
160
161 \sa QEventPoint::id
162*/
163
164/*!
165 \readonly
166 \qmlproperty pointingDeviceUniqueId QtQuick::handlerPoint::uniqueId
167 \brief The unique ID of the point, if any
168
169 This is normally empty, because touchscreens cannot uniquely identify fingers.
170
171 On some types of touchscreens, especially those using TUIO drivers,
172 it's possible to use recognizable physical tokens (fiducial objects)
173 in addition to fingers. So if this point is a touch point, and
174 uniqueId is set, it is the identifier for such an object.
175
176 On a graphics tablet, each type of stylus or other tool often has a unique
177 ID or serial number, which can be useful to respond in different ways to
178 different tools.
179
180 Interpreting the contents of this ID requires knowledge of the hardware and
181 drivers in use.
182
183 \sa QTabletEvent::uniqueId, QtQuick::TouchPoint::uniqueId
184*/
185
186/*!
187 \readonly
188 \qmlproperty QPointF QtQuick::handlerPoint::position
189 \brief The position within the \c parent Item
190
191 This is the position of the \l eventPoint relative to the bounds of
192 the \l {PointerHandler::parent} {parent}.
193*/
194
195/*!
196 \readonly
197 \qmlproperty QPointF QtQuick::handlerPoint::scenePosition
198 \brief The position within the scene
199
200 This is the position of the \l eventPoint relative to the bounds of the Qt
201 Quick scene (typically the whole window).
202*/
203
204/*!
205 \readonly
206 \qmlproperty QPointF QtQuick::handlerPoint::pressPosition
207 \brief The pressed position within the \c parent Item
208
209 This is the position at which this point was pressed, relative to the
210 bounds of the \l {PointerHandler::parent} {parent}.
211*/
212
213/*!
214 \readonly
215 \qmlproperty QPointF QtQuick::handlerPoint::scenePressPosition
216 \brief The pressed position within the scene
217
218 This is the position at which this point was pressed, in the coordinate
219 system of the \l {Qt Quick Scene Graph}{scene graph}.
220*/
221
222/*!
223 \readonly
224 \qmlproperty QPointF QtQuick::handlerPoint::sceneGrabPosition
225 \brief The grabbed position within the scene
226
227 If this point has been grabbed by a Pointer Handler or an Item, it means
228 that object has taken sole responsibility for handling the movement and the
229 release if this point. In that case, this is the position at which the grab
230 occurred, in the coordinate system of the \l {Qt Quick Scene Graph}{scene graph}.
231*/
232
233/*!
234 \readonly
235 \qmlproperty enumeration QtQuick::handlerPoint::pressedButtons
236 \brief Which mouse or stylus buttons are currently pressed
237
238 \sa MouseArea::pressedButtons
239*/
240
241/*!
242 \readonly
243 \qmlproperty enumeration QtQuick::handlerPoint::modifiers
244 \brief Which modifier keys are currently pressed
245
246 This property holds the keyboard modifiers that were pressed at the time
247 the event occurred.
248*/
249
250/*!
251 \readonly
252 \qmlproperty QVector2D QtQuick::handlerPoint::velocity
253 \brief A vector representing the average speed and direction of movement
254
255 This is a velocity vector pointing in the direction of movement, in logical
256 pixels per second. It has x and y components, at least one of which will be
257 nonzero when this point is in motion. It holds the average recent velocity:
258 how fast and in which direction the \l eventPoint has been moving recently.
259
260 \sa QtQuick::TouchPoint::velocity, QEventPoint::velocity
261*/
262
263/*!
264 \readonly
265 \qmlproperty qreal QtQuick::handlerPoint::rotation
266
267 This property holds the rotation angle of the stylus on a graphics tablet
268 or the contact patch of a touchpoint on a touchscreen.
269
270 It is valid only with certain tablet stylus devices and touchscreens that
271 can measure the rotation angle. Otherwise, it will be zero.
272*/
273
274/*!
275 \readonly
276 \qmlproperty qreal QtQuick::handlerPoint::pressure
277
278 This property tells how hard the user is pressing the stylus on a graphics
279 tablet or the finger against a touchscreen, in the range from \c 0 (no
280 measurable pressure) to \c 1.0 (maximum pressure which the device can
281 measure).
282
283 It is valid only with certain tablets and touchscreens that can measure
284 pressure. Otherwise, it will be zero.
285*/
286
287/*!
288 \readonly
289 \qmlproperty size QtQuick::handlerPoint::ellipseDiameters
290
291 This property holds the diameters of the contact patch, if the event
292 comes from a touchpoint and the device provides this information.
293
294 A touchpoint is modeled as an elliptical area where the finger is pressed
295 against the touchscreen. (In fact, it could also be modeled as a bitmap;
296 but in that case we expect an elliptical bounding estimate to be fitted to
297 the contact patch before the event is sent.) The harder the user presses,
298 the larger the contact patch; so, these diameters provide an alternate way
299 of detecting pressure, in case the device does not include a separate
300 pressure sensor. The ellipse is centered on \l scenePosition (\l position
301 in the PointerHandler's Item's local coordinates). The \l rotation property
302 provides the rotation of the ellipse, if known. It is expected that if the
303 \l rotation is zero, the \l {QSize::height}{height} is the larger dimension
304 (the major axis), because of the usual hand position, reaching upward or
305 outward across the surface.
306
307 If the contact patch is unknown, or the device is not a touchscreen,
308 these values will be zero.
309
310 \sa QtQuick::TouchPoint::ellipseDiameters, QEventPoint::ellipseDiameters
311*/
312
313/*!
314 \readonly
315 \qmlproperty PointerDevice QtQuick::handlerPoint::device
316
317 This property holds the device that the point (and its event) came from.
318*/
319
320QT_END_NAMESPACE
321
322#include "moc_qquickhandlerpoint_p.cpp"
323

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