@@ -1017,10 +1017,11 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1017
1017
accepted, recursion stops. Returns \c true in that case, or \c false if the
1018
1018
event is rejected.
1019
1019
1020
- All items that have hover enabled (either explicitly, from
1021
- setAcceptHoverEvents(), or implicitly by having HoverHandlers) will have
1022
- the QQuickItemPrivate::hoverEnabled flag set. And all their anchestors will
1023
- have the QQuickItemPrivate::subtreeHoverEnabledset. This function will
1020
+ Each item that has hover enabled (from setAcceptHoverEvents()) has the
1021
+ QQuickItemPrivate::hoverEnabled flag set. This only controls whether we
1022
+ should send hover events to the item itself. (HoverHandlers no longer set
1023
+ this flag.) When an item has hoverEnabled set, all its ancestors have the
1024
+ QQuickItemPrivate::subtreeHoverEnabled set. This function will
1024
1025
follow the subtrees that have subtreeHoverEnabled by recursing into each
1025
1026
child with that flag set. And for each child (in addition to the item
1026
1027
itself) that also has hoverEnabled set, we call deliverHoverEventToItem()
@@ -1032,10 +1033,19 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1032
1033
of an item that is stacked underneath, will not. Note that since siblings
1033
1034
can overlap, there can be more than one leaf item under the mouse.
1034
1035
1036
+ Note that HoverHandler doesn't set the hoverEnabled flag on the parent item.
1037
+ But still, adding a HoverHandler to an item will set its subtreeHoverEnabled flag.
1038
+ So all the propagation logic described above will otherwise be the same.
1039
+ But the hoverEnabled flag can be used to resolve if subtreeHoverEnabled is on
1040
+ because the application explicitly requested it (setAcceptHoverEvents()), or
1041
+ indirectly, because the item has HoverHandlers.
1042
+
1035
1043
For legacy reasons (Qt 6.1), as soon as we find a leaf item that has hover
1036
1044
enabled, and therefore receives the event, we stop recursing into the remaining
1037
1045
siblings (even if the event was ignored). This means that we only allow hover
1038
1046
events to propagate up the direct parent-child hierarchy, and not to siblings.
1047
+ However, if the first candidate HoverHandler is disabled, delivery continues
1048
+ to the next one, which may be a sibling (QTBUG-106548).
1039
1049
*/
1040
1050
bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive (
1041
1051
QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
@@ -1073,8 +1083,7 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
1073
1083
1074
1084
// All decendants have been visited.
1075
1085
// Now deliver the event to the item
1076
- if (itemPrivate->hoverEnabled )
1077
- return deliverHoverEventToItem (item, scenePos, lastScenePos, modifiers, timestamp, false );
1086
+ return deliverHoverEventToItem (item, scenePos, lastScenePos, modifiers, timestamp, false );
1078
1087
1079
1088
// Continue propagation / recursion
1080
1089
return false ;
@@ -1101,14 +1110,17 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1101
1110
qCDebug (lcHoverTrace) << " item:" << item << " scene pos:" << scenePos << " localPos:" << localPos
1102
1111
<< " wasHovering:" << wasHovering << " isHovering:" << isHovering;
1103
1112
1104
- if (isHovering)
1105
- hoveredLeafItemFound = true ;
1106
-
1107
- // Send enter/move/leave event to the item
1108
1113
bool accepted = false ;
1109
- if (isHovering && !clearHover) {
1114
+
1115
+ // Start by sending out enter/move/leave events to the item.
1116
+ // Note that hoverEnabled only controls if we should send out hover events to the
1117
+ // item itself. HoverHandlers are not included, and are dealt with separately below.
1118
+ if (itemPrivate->hoverEnabled && isHovering && !clearHover) {
1110
1119
// Add the item to the list of hovered items (if it doesn't exist there
1111
1120
// from before), and update hoverId to mark that it's (still) hovered.
1121
+ // Also set hoveredLeafItemFound, so that only propagate in a straight
1122
+ // line towards the root from now on.
1123
+ hoveredLeafItemFound = true ;
1112
1124
hoverItems[item] = currentHoverId;
1113
1125
if (wasHovering)
1114
1126
accepted = sendHoverEvent (QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp);
@@ -1123,6 +1135,7 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1123
1135
if (!itemPrivate->hasPointerHandlers ())
1124
1136
return accepted;
1125
1137
1138
+ // Next, send out hover events to the hover handlers.
1126
1139
// If the item didn't accept the hover event, 'accepted' is now false.
1127
1140
// Otherwise it's true, and then it should stay the way regardless of
1128
1141
// whether or not the hoverhandlers themselves are hovered.
@@ -1136,6 +1149,8 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1136
1149
1137
1150
for (QQuickPointerHandler *h : itemPrivate->extra ->pointerHandlers ) {
1138
1151
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1152
+ if (!hh->isHovered ())
1153
+ continue ;
1139
1154
hoverEvent.setAccepted (true );
1140
1155
QCoreApplication::sendEvent (hh, &hoverEvent);
1141
1156
}
@@ -1146,11 +1161,14 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1146
1161
1147
1162
for (QQuickPointerHandler *h : itemPrivate->extra ->pointerHandlers ) {
1148
1163
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1164
+ if (!hh->enabled ())
1165
+ continue ;
1149
1166
hoverEvent.setAccepted (true );
1150
1167
hh->handlePointerEvent (&hoverEvent);
1151
1168
if (hh->isHovered ()) {
1152
1169
// Mark the whole item as updated, even if only the handler is
1153
1170
// actually in a hovered state (because of HoverHandler.margins)
1171
+ hoveredLeafItemFound = true ;
1154
1172
hoverItems[item] = currentHoverId;
1155
1173
if (hh->isBlocking ()) {
1156
1174
qCDebug (lcHoverTrace) << " skipping rest of hover delivery due to blocking" << hh;
0 commit comments