1/****************************************************************************
2**
3** Copyright (C) 2016 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 "qquickpointerdevicehandler_p_p.h"
41#include <private/qquickitem_p.h>
42#include <QMouseEvent>
43#include <QDebug>
44
45QT_BEGIN_NAMESPACE
46
47/*!
48 \qmltype PointerDeviceHandler
49 \qmlabstract
50 \since 5.10
51 \preliminary
52 \instantiates QQuickPointerDeviceHandler
53 \inherits PointerHandler
54 \inqmlmodule QtQuick
55 \brief Abstract handler for pointer events with device-specific constraints.
56
57 An intermediate class (not registered as a QML type) for handlers which
58 allow filtering based on device type, pointer type, or keyboard modifiers.
59*/
60QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QQuickItem *parent)
61 : QQuickPointerHandler(*(new QQuickPointerDeviceHandlerPrivate), parent)
62{
63}
64
65QQuickPointerDeviceHandler::QQuickPointerDeviceHandler(QQuickPointerDeviceHandlerPrivate &dd, QQuickItem *parent)
66 : QQuickPointerHandler(dd, parent)
67{
68}
69
70QQuickPointerDevice::DeviceTypes QQuickPointerDeviceHandler::acceptedDevices() const
71{
72 Q_D(const QQuickPointerDeviceHandler);
73 return d->acceptedDevices;
74}
75
76QQuickPointerDevice::PointerTypes QQuickPointerDeviceHandler::acceptedPointerTypes() const
77{
78 Q_D(const QQuickPointerDeviceHandler);
79 return d->acceptedPointerTypes;
80}
81
82/*!
83 \qmlproperty flags QtQuick::PointerDeviceHandler::acceptedButtons
84
85 The mouse buttons which can activate this Pointer Handler.
86
87 By default, this property is set to \l {QtQuick::MouseEvent::button} {Qt.LeftButton}.
88 It can be set to an OR combination of mouse buttons, and will ignore events
89 from other buttons.
90
91 For example, a control could be made to respond to left and right clicks
92 in different ways, with two handlers:
93
94 \qml
95 Item {
96 TapHandler {
97 onTapped: console.log("left clicked")
98 }
99 TapHandler {
100 acceptedButtons: Qt.RightButton
101 onTapped: console.log("right clicked")
102 }
103 }
104 \endqml
105
106 \note Tapping on a touchscreen or tapping the stylus on a graphics tablet
107 emulates clicking the left mouse button. This behavior can be altered via
108 \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices} or
109 \l {PointerDeviceHandler::acceptedPointerTypes}{acceptedPointerTypes}.
110*/
111Qt::MouseButtons QQuickPointerDeviceHandler::acceptedButtons() const
112{
113 Q_D(const QQuickPointerDeviceHandler);
114 return d->acceptedButtons;
115}
116
117void QQuickPointerDeviceHandler::setAcceptedButtons(Qt::MouseButtons buttons)
118{
119 Q_D(QQuickPointerDeviceHandler);
120 if (d->acceptedButtons == buttons)
121 return;
122
123 d->acceptedButtons = buttons;
124 emit acceptedButtonsChanged();
125}
126
127Qt::KeyboardModifiers QQuickPointerDeviceHandler::acceptedModifiers() const
128{
129 Q_D(const QQuickPointerDeviceHandler);
130 return d->acceptedModifiers;
131}
132
133/*!
134 \qmlproperty flags PointerDeviceHandler::acceptedDevices
135
136 The types of pointing devices that can activate this Pointer Handler.
137
138 By default, this property is set to
139 \l{QtQuick::PointerDevice::type} {PointerDevice.AllDevices}.
140 If you set it to an OR combination of device types, it will ignore events
141 from non-matching devices.
142
143 For example, a control could be made to respond to mouse and stylus clicks
144 in one way, and touchscreen taps in another way, with two handlers:
145
146 \qml
147 Item {
148 TapHandler {
149 acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
150 onTapped: console.log("clicked")
151 }
152 TapHandler {
153 acceptedDevices: PointerDevice.TouchScreen
154 onTapped: console.log("tapped")
155 }
156 }
157 \endqml
158*/
159void QQuickPointerDeviceHandler::setAcceptedDevices(QQuickPointerDevice::DeviceTypes acceptedDevices)
160{
161 Q_D(QQuickPointerDeviceHandler);
162 if (d->acceptedDevices == acceptedDevices)
163 return;
164
165 d->acceptedDevices = acceptedDevices;
166 emit acceptedDevicesChanged();
167}
168
169/*!
170 \qmlproperty flags PointerDeviceHandler::acceptedPointerTypes
171
172 The types of pointing instruments (finger, stylus, eraser, etc.)
173 that can activate this Pointer Handler.
174
175 By default, this property is set to
176 \l {QtQuick::PointerDevice::pointerType} {PointerDevice.AllPointerTypes}.
177 If you set it to an OR combination of device types, it will ignore events
178 from non-matching events.
179
180 For example, a control could be made to respond to mouse, touch, and stylus clicks
181 in some way, but delete itself if tapped with an eraser tool on a graphics tablet,
182 with two handlers:
183
184 \qml
185 Rectangle {
186 id: rect
187 TapHandler {
188 acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Finger | PointerDevice.Pen
189 onTapped: console.log("clicked")
190 }
191 TapHandler {
192 acceptedPointerTypes: PointerDevice.Eraser
193 onTapped: rect.destroy()
194 }
195 }
196 \endqml
197*/
198void QQuickPointerDeviceHandler::setAcceptedPointerTypes(QQuickPointerDevice::PointerTypes acceptedPointerTypes)
199{
200 Q_D(QQuickPointerDeviceHandler);
201 if (d->acceptedPointerTypes == acceptedPointerTypes)
202 return;
203
204 d->acceptedPointerTypes = acceptedPointerTypes;
205 emit acceptedPointerTypesChanged();
206}
207
208/*!
209 \qmlproperty flags PointerDeviceHandler::acceptedModifiers
210
211 If this property is set, it will require the given keyboard modifiers to
212 be pressed in order to react to pointer events, and otherwise ignore them.
213
214 If this property is set to \c Qt.KeyboardModifierMask (the default value),
215 then the PointerHandler ignores the modifier keys.
216
217 For example, an \l [QML] Item could have two handlers of the same type,
218 one of which is enabled only if the required keyboard modifiers are
219 pressed:
220
221 \qml
222 Item {
223 TapHandler {
224 acceptedModifiers: Qt.ControlModifier
225 onTapped: console.log("control-tapped")
226 }
227 TapHandler {
228 acceptedModifiers: Qt.NoModifier
229 onTapped: console.log("tapped")
230 }
231 }
232 \endqml
233*/
234void QQuickPointerDeviceHandler::setAcceptedModifiers(Qt::KeyboardModifiers acceptedModifiers)
235{
236 Q_D(QQuickPointerDeviceHandler);
237 if (d->acceptedModifiers == acceptedModifiers)
238 return;
239
240 d->acceptedModifiers = acceptedModifiers;
241 emit acceptedModifiersChanged();
242}
243
244bool QQuickPointerDeviceHandler::wantsPointerEvent(QQuickPointerEvent *event)
245{
246 Q_D(QQuickPointerDeviceHandler);
247 if (!QQuickPointerHandler::wantsPointerEvent(event))
248 return false;
249 qCDebug(lcPointerHandlerDispatch) << objectName()
250 << "checking device type" << d->acceptedDevices
251 << "pointer type" << d->acceptedPointerTypes
252 << "modifiers" << d->acceptedModifiers;
253 if ((event->device()->type() & d->acceptedDevices) == 0)
254 return false;
255 if ((event->device()->pointerType() & d->acceptedPointerTypes) == 0)
256 return false;
257 if (d->acceptedModifiers != Qt::KeyboardModifierMask && event->modifiers() != d->acceptedModifiers)
258 return false;
259 // HoverHandler sets acceptedButtons to Qt::NoButton to indicate that button state is irrelevant.
260 if (event->device()->pointerType() != QQuickPointerDevice::Finger && acceptedButtons() != Qt::NoButton &&
261 (event->buttons() & acceptedButtons()) == 0 && (event->button() & acceptedButtons()) == 0
262 && !event->asPointerScrollEvent())
263 return false;
264 return true;
265}
266
267QT_END_NAMESPACE
268