1/****************************************************************************
2**
3** Copyright (C) 2017 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 "qquickpointhandler_p.h"
41#include <private/qquickwindow_p.h>
42#include <QDebug>
43
44QT_BEGIN_NAMESPACE
45
46/*!
47 \qmltype PointHandler
48 \instantiates QQuickPointHandler
49 \inherits SinglePointHandler
50 \inqmlmodule QtQuick
51 \ingroup qtquick-input-handlers
52 \brief Handler for reacting to a single touchpoint.
53
54 PointHandler can be used to show feedback about a touchpoint or the mouse
55 position, or to otherwise react to pointer events.
56
57 When a press event occurs, each instance of PointHandler chooses a
58 single point which is not yet "taken" at that moment: if the press
59 occurs within the bounds of the \l {PointerHandler::parent}, and
60 no sibling PointHandler within the same \l {PointerHandler::parent}
61 has yet acquired a passive grab on that point, and if the other
62 constraints such as \l {PointerDeviceHandler::acceptedButtons}{acceptedButtons}, \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices} etc.
63 are satisfied, it's
64 eligible, and the PointHandler then acquires a passive grab. In
65 this way, the \l {PointerHandler::parent} acts like an exclusive
66 group: there can be multiple instances of PointHandler, and the
67 set of pressed touchpoints will be distributed among them. Each
68 PointHandler which has chosen a point to track has its \l active
69 property \c true. It then continues to track its chosen point
70 until release: the properties of the \l point will be kept
71 up-to-date. Any Item can bind to these properties, and thereby
72 follow the point's movements.
73
74 By being only a passive grabber, it has the ability to keep independent
75 oversight of all movements. The passive grab cannot be stolen or overridden
76 even when other gestures are detected and exclusive grabs occur.
77
78 If your goal is orthogonal surveillance of eventpoints, an older
79 alternative was QObject::installEventFilter(), but that has never been a
80 built-in QtQuick feature: it requires some C++ code, such as a QQuickItem
81 subclass. PointHandler is more efficient than that, because only pointer
82 events will be delivered to it, during the course of normal event delivery
83 in QQuickWindow; whereas an event filter needs to filter all QEvents of all
84 types, and thus sets itself up as a potential event delivery bottleneck.
85
86 One possible use case is to add this handler to a transparent Item which is
87 on top of the rest of the scene (by having a high \l{Item::z} {z} value),
88 so that when a point is freshly pressed, it will be delivered to that Item
89 and its handlers first, providing the opportunity to take the passive grab
90 as early as possible. Such an item (like a pane of glass over the whole UI)
91 can be a convenient parent for other Items which visualize the kind of reactive
92 feedback which must always be on top; and likewise it can be the parent for
93 popups, popovers, dialogs and so on. If it will be used in that way, it can
94 be helpful for your main.cpp to use QQmlContext::setContextProperty() to
95 make the "glass pane" accessible by ID to the entire UI, so that other
96 Items and PointHandlers can be reparented to it.
97
98 \snippet pointerHandlers/pointHandler.qml 0
99
100 Like all input handlers, a PointHandler has a \l target property, which
101 may be used as a convenient place to put a point-tracking Item; but
102 PointHandler will not automatically manipulate the \c target item in any way.
103 You need to use bindings to make it react to the \l point.
104
105 \note On macOS, PointHandler does not react to the trackpad by default.
106 That is because macOS can provide either native gesture recognition, or raw
107 touchpoints, but not both. We prefer to use the native gesture event in
108 PinchHandler, so we do not want to disable it by enabling touch. However
109 MultiPointTouchArea does enable touch, thus disabling native gesture
110 recognition within the entire window; so it's an alternative if you only
111 want to react to all the touchpoints but do not require the smooth
112 native-gesture experience.
113
114 \sa MultiPointTouchArea
115*/
116
117QQuickPointHandler::QQuickPointHandler(QQuickItem *parent)
118 : QQuickSinglePointHandler(parent)
119{
120 setIgnoreAdditionalPoints();
121}
122
123bool QQuickPointHandler::wantsEventPoint(QQuickEventPoint *pt)
124{
125 // On press, we want it unless a sibling of the same type also does.
126 if (pt->state() == QQuickEventPoint::Pressed && QQuickSinglePointHandler::wantsEventPoint(pt)) {
127 for (const QQuickPointerHandler *grabber : pt->passiveGrabbers()) {
128 if (grabber && grabber->parent() == parent() &&
129 grabber->metaObject()->className() == metaObject()->className())
130 return false;
131 }
132 return true;
133 }
134 // If we've already been interested in a point, stay interested, even if it has strayed outside bounds.
135 return (pt->state() != QQuickEventPoint::Pressed && point().id() == pt->pointId());
136}
137
138void QQuickPointHandler::handleEventPoint(QQuickEventPoint *point)
139{
140 switch (point->state()) {
141 case QQuickEventPoint::Pressed:
142 if (point->pointerEvent()->asPointerTouchEvent() ||
143 (point->pointerEvent()->buttons() & acceptedButtons()) != Qt::NoButton) {
144 setPassiveGrab(point);
145 setActive(true);
146 }
147 break;
148 case QQuickEventPoint::Released:
149 if (point->pointerEvent()->asPointerTouchEvent() ||
150 (point->pointerEvent()->buttons() & acceptedButtons()) == Qt::NoButton)
151 setActive(false);
152 break;
153 default:
154 break;
155 }
156 point->setAccepted(false); // Just lurking... don't interfere with propagation
157 emit translationChanged();
158}
159
160QVector2D QQuickPointHandler::translation() const
161{
162 return QVector2D(point().position() - point().pressPosition());
163}
164
165QT_END_NAMESPACE
166