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