aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2021-12-08 18:06:35 +0100
committerShawn Rutledge <shawn.rutledge@qt.io>2021-12-09 23:16:36 +0100
commit2b50181be816094325adef6e9610b8dd9a03d6a8 (patch)
treecb4d454938fcf925088d62985de4e7b61507b65a
parent93bdedc1557fe9681a64b9be409bd92e702d54aa (diff)
Add HoverHandler.blocking property
As with WheelHandler, sometimes users want to let the hover events propagate (which has been the default all along), but sometimes it's not appropriate to allow parents of nested items to show hover feedback. [ChangeLog][QtQuick][HoverHandler] HoverHandler now has a property called blocking, which is false by default; but if set to true, it prevents hover events from propagating to items "under" this handler's parent, and their HoverHandlers. Task-number: QTBUG-85926 Change-Id: I26f89482e294c7a6b30a55a7e23ac444a0d1ac7f Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r--examples/quick/pointerhandlers/sidebar.qml26
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp16
-rw-r--r--src/quick/handlers/qquickhoverhandler_p.h6
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp5
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp22
5 files changed, 66 insertions, 9 deletions
diff --git a/examples/quick/pointerhandlers/sidebar.qml b/examples/quick/pointerhandlers/sidebar.qml
index 7406931b28..29727b5684 100644
--- a/examples/quick/pointerhandlers/sidebar.qml
+++ b/examples/quick/pointerhandlers/sidebar.qml
@@ -55,7 +55,7 @@ Rectangle {
id: root
width: 640
height: 480
- color: "#444"
+ color: rootHover.hovered ? "#555" : "#444"
Component {
id: buttonsAndStuff
@@ -64,6 +64,11 @@ Rectangle {
anchors.margins: 8
spacing: 8
+ CheckBox {
+ id: hoverBlockingCB
+ text: "Button hover is blocking"
+ }
+
Rectangle {
objectName: "buttonWithMA"
width: parent.width
@@ -98,6 +103,7 @@ Rectangle {
id: buttonHH
objectName: "buttonHH"
acceptedDevices: PointerDevice.AllDevices
+ blocking: hoverBlockingCB.checked
cursorShape: tapHandler.pressed ? Qt.BusyCursor : Qt.PointingHandCursor
}
@@ -152,9 +158,9 @@ Rectangle {
objectName: "topSidebar"
radius: 5
antialiasing: true
- x: -radius
+ x: -10
y: -radius
- width: 120
+ width: 200
height: 200
border.color: topSidebarHH.hovered ? "cyan" : "black"
color: "#777"
@@ -181,16 +187,21 @@ Rectangle {
sourceComponent: buttonsAndStuff
anchors.fill: parent
}
+
+ Text {
+ anchors { left: parent.left; bottom: parent.bottom; margins: 12 }
+ text: "Hover Handler"
+ }
}
Rectangle {
objectName: "bottomSidebar"
radius: 5
antialiasing: true
- x: -radius
+ x: -10
anchors.bottom: parent.bottom
anchors.bottomMargin: -radius
- width: 120
+ width: 200
height: 200
border.color: bottomSidebarMA.containsMouse ? "cyan" : "black"
color: "#777"
@@ -208,6 +219,11 @@ Rectangle {
sourceComponent: buttonsAndStuff
anchors.fill: parent
}
+
+ Text {
+ anchors { left: parent.left; bottom: parent.bottom; margins: 12 }
+ text: "MouseArea"
+ }
}
HoverHandler {
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index d72123bdcb..989109dfd3 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -83,6 +83,22 @@ QQuickHoverHandler::~QQuickHoverHandler()
QQuickItemPrivate::get(parent)->setHasHoverInChild(false);
}
+/*!
+ \qmlproperty bool QtQuick::HoverHandler::blocking
+ \since 6.3
+
+ Whether this handler prevents other items or handlers behind it from
+ being hovered at the same timee. This property is \c false by default.
+*/
+void QQuickHoverHandler::setBlocking(bool blocking)
+{
+ if (m_blocking == blocking)
+ return;
+
+ m_blocking = blocking;
+ emit blockingChanged();
+}
+
bool QQuickHoverHandler::event(QEvent *event)
{
switch (event->type())
diff --git a/src/quick/handlers/qquickhoverhandler_p.h b/src/quick/handlers/qquickhoverhandler_p.h
index 8d87a36727..e73e7ee71f 100644
--- a/src/quick/handlers/qquickhoverhandler_p.h
+++ b/src/quick/handlers/qquickhoverhandler_p.h
@@ -62,6 +62,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickHoverHandler : public QQuickSinglePointHandle
{
Q_OBJECT
Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged)
+ Q_PROPERTY(bool blocking READ isBlocking WRITE setBlocking NOTIFY blockingChanged REVISION(6, 3))
QML_NAMED_ELEMENT(HoverHandler)
QML_ADDED_IN_VERSION(2, 12)
@@ -73,8 +74,12 @@ public:
bool isHovered() const { return m_hovered; }
+ bool isBlocking() const { return m_blocking; }
+ void setBlocking(bool blocking);
+
Q_SIGNALS:
void hoveredChanged();
+ Q_REVISION(6, 3) void blockingChanged();
protected:
void componentComplete() override;
@@ -87,6 +92,7 @@ private:
private:
bool m_hovered = false;
bool m_hoveredTablet = false;
+ bool m_blocking = false;
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 6c0596c4b3..5eebcfecc1 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -1145,6 +1145,11 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
// Mark the whole item as updated, even if only the handler is
// actually in a hovered state (because of HoverHandler.margins)
hoverItems[item] = currentHoverId;
+ if (hh->isBlocking()) {
+ qCDebug(lcHoverTrace) << "skipping rest of hover delivery due to blocking" << hh;
+ accepted = true;
+ break;
+ }
}
}
}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index 8e92714a84..5cafaf42ea 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -58,6 +58,7 @@ public:
{}
private slots:
+ void hoverHandlerAndUnderlyingHoverHandler_data();
void hoverHandlerAndUnderlyingHoverHandler();
void mouseAreaAndUnderlyingHoverHandler();
void hoverHandlerAndUnderlyingMouseArea();
@@ -82,8 +83,18 @@ void tst_HoverHandler::createView(QScopedPointer<QQuickView> &window, const char
QVERIFY(window->rootObject() != nullptr);
}
+void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler_data()
+{
+ QTest::addColumn<bool>("blocking");
+
+ QTest::newRow("default: nonblocking") << false;
+ QTest::newRow("blocking") << true;
+}
+
void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
{
+ QFETCH(bool, blocking);
+
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "lesHoverables.qml");
QQuickView * window = windowPtr.data();
@@ -96,6 +107,9 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
QQuickHoverHandler *buttonHH = button->findChild<QQuickHoverHandler *>("buttonHH");
QVERIFY(buttonHH);
+ QCOMPARE(buttonHH->isBlocking(), false); // default property value
+ buttonHH->setBlocking(blocking);
+
QPoint buttonCenter(button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint());
QPoint rightOfButton(button->mapToScene(QPointF(button->width() + 2, button->height() / 2)).toPoint());
QPoint outOfSidebar(topSidebar->mapToScene(QPointF(topSidebar->width() + 2, topSidebar->height() / 2)).toPoint());
@@ -121,8 +135,8 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
#endif
QTest::mouseMove(window, buttonCenter);
- QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(topSidebarHH->isHovered(), !blocking);
+ QCOMPARE(sidebarHoveredSpy.count(), blocking ? 2 : 1);
QCOMPARE(buttonHH->isHovered(), true);
QCOMPARE(buttonHoveredSpy.count(), 1);
#if QT_CONFIG(cursor)
@@ -131,7 +145,7 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.count(), blocking ? 3 : 1);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
#if QT_CONFIG(cursor)
@@ -140,7 +154,7 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 2);
+ QCOMPARE(sidebarHoveredSpy.count(), blocking ? 4 : 2);
QCOMPARE(buttonHH->isHovered(), false);
QCOMPARE(buttonHoveredSpy.count(), 2);
#if QT_CONFIG(cursor)