1/****************************************************************************
2**
3** Copyright (C) 2019 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 "qquickhoverhandler_p.h"
41#include <private/qquicksinglepointhandler_p_p.h>
42
43QT_BEGIN_NAMESPACE
44
45Q_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
46
47/*!
48 \qmltype HoverHandler
49 \instantiates QQuickHoverHandler
50 \inherits SinglePointHandler
51 \inqmlmodule QtQuick
52 \ingroup qtquick-input-handlers
53 \brief Handler for mouse and tablet hover.
54
55 HoverHandler detects a hovering mouse or tablet stylus cursor.
56
57 A binding to the \l hovered property is the easiest way to react when the
58 cursor enters or leaves the \l {PointerHandler::parent}{parent} Item.
59 The \l {SinglePointHandler::point}{point} property provides more detail,
60 including the cursor position. The
61 \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices},
62 \l {PointerDeviceHandler::acceptedPointerTypes}{acceptedPointerTypes},
63 and \l {PointerDeviceHandler::acceptedModifiers}{acceptedModifiers}
64 properties can be used to narrow the behavior to detect hovering of
65 specific kinds of devices or while holding a modifier key.
66
67 The \l cursorShape property allows changing the cursor whenever
68 \l hovered changes to \c true.
69
70 \sa MouseArea, PointHandler
71*/
72
73QQuickHoverHandler::QQuickHoverHandler(QQuickItem *parent)
74 : QQuickSinglePointHandler(parent)
75{
76 // Tell QQuickPointerDeviceHandler::wantsPointerEvent() to ignore button state
77 d_func()->acceptedButtons = Qt::NoButton;
78}
79
80QQuickHoverHandler::~QQuickHoverHandler()
81{
82 if (auto parent = parentItem())
83 QQuickItemPrivate::get(item: parent)->setHasHoverInChild(false);
84}
85
86void QQuickHoverHandler::componentComplete()
87{
88 QQuickSinglePointHandler::componentComplete();
89 if (auto par = parentItem()) {
90 par->setAcceptHoverEvents(true);
91 QQuickItemPrivate::get(item: par)->setHasHoverInChild(true);
92 }
93}
94
95bool QQuickHoverHandler::wantsPointerEvent(QQuickPointerEvent *event)
96{
97 QQuickEventPoint *point = event->point(i: 0);
98 if (QQuickPointerDeviceHandler::wantsPointerEvent(event) && wantsEventPoint(point) && parentContains(point)) {
99 // assume this is a mouse or tablet event, so there's only one point
100 setPointId(point->pointId());
101 return true;
102 }
103
104 // Some hover events come from QQuickWindow::tabletEvent(). In between,
105 // some hover events come from QQWindowPrivate::flushFrameSynchronousEvents(),
106 // but those look like mouse events. If a particular HoverHandler instance
107 // is filtering for tablet events only (e.g. by setting
108 // acceptedDevices:PointerDevice.Stylus), those events should not cause
109 // the hovered property to transition to false prematurely.
110 // If a QQuickPointerTabletEvent caused the hovered property to become true,
111 // then only another QQuickPointerTabletEvent can make it become false.
112 if (!(m_hoveredTablet && event->asPointerMouseEvent()))
113 setHovered(false);
114
115 return false;
116}
117
118void QQuickHoverHandler::handleEventPoint(QQuickEventPoint *point)
119{
120 bool hovered = true;
121 if (point->state() == QQuickEventPoint::Released &&
122 point->pointerEvent()->device()->pointerType() == QQuickPointerDevice::Finger)
123 hovered = false;
124 else if (point->pointerEvent()->asPointerTabletEvent())
125 m_hoveredTablet = true;
126 setHovered(hovered);
127 setPassiveGrab(point);
128}
129
130void QQuickHoverHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point)
131{
132 QQuickSinglePointHandler::onGrabChanged(grabber, transition, point);
133 if (grabber == this && transition == QQuickEventPoint::CancelGrabPassive)
134 setHovered(false);
135}
136
137/*!
138 \qmlproperty bool QtQuick::HoverHandler::hovered
139 \readonly
140
141 Holds true whenever any pointing device cursor (mouse or tablet) is within
142 the bounds of the \c parent Item, extended by the
143 \l {PointerHandler::margin}{margin}, if any.
144*/
145void QQuickHoverHandler::setHovered(bool hovered)
146{
147 if (m_hovered != hovered) {
148 qCDebug(lcHoverHandler) << objectName() << "hovered" << m_hovered << "->" << hovered;
149 m_hovered = hovered;
150 if (!hovered)
151 m_hoveredTablet = false;
152 emit hoveredChanged();
153 }
154}
155
156/*!
157 \since 5.15
158 \qmlproperty Qt::CursorShape QtQuick::HoverHandler::cursorShape
159 This property holds the cursor shape that will appear whenever
160 \l hovered is \c true and no other handler is overriding it.
161
162 The available cursor shapes are:
163 \list
164 \li Qt.ArrowCursor
165 \li Qt.UpArrowCursor
166 \li Qt.CrossCursor
167 \li Qt.WaitCursor
168 \li Qt.IBeamCursor
169 \li Qt.SizeVerCursor
170 \li Qt.SizeHorCursor
171 \li Qt.SizeBDiagCursor
172 \li Qt.SizeFDiagCursor
173 \li Qt.SizeAllCursor
174 \li Qt.BlankCursor
175 \li Qt.SplitVCursor
176 \li Qt.SplitHCursor
177 \li Qt.PointingHandCursor
178 \li Qt.ForbiddenCursor
179 \li Qt.WhatsThisCursor
180 \li Qt.BusyCursor
181 \li Qt.OpenHandCursor
182 \li Qt.ClosedHandCursor
183 \li Qt.DragCopyCursor
184 \li Qt.DragMoveCursor
185 \li Qt.DragLinkCursor
186 \endlist
187
188 The default value of this property is not set, which allows any active
189 handler on the same \l parentItem to determine the cursor shape.
190 This property can be reset to the initial condition by setting it to
191 \c undefined.
192
193 If any handler with defined \c cursorShape is
194 \l {PointerHandler::active}{active}, that cursor will appear.
195 Else if the HoverHandler has a defined \c cursorShape, that cursor will appear.
196 Otherwise, the \l {QQuickItem::cursor()}{cursor} of \l parentItem will appear.
197
198 \note When this property has not been set, or has been set to \c undefined,
199 if you read the value it will return \c Qt.ArrowCursor.
200
201 \sa Qt::CursorShape, QQuickItem::cursor()
202*/
203
204QT_END_NAMESPACE
205

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