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

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