Fix drag-to-refile: ListView stole the grip's drag

The grip used a bare MouseArea for the drag. Inside the ListView (a
Flickable), once the pointer moved past the drag threshold the ListView
stole the gesture for flicking, so the grip's positionChanged stopped
firing: the drop target was never resolved and release did nothing.

Replace the MouseArea with a DragHandler (target: null — it tracks, it
doesn't move the item) whose grabPermissions take the pointer grab and
refuse to yield it to the Flickable, so the drag is no longer stolen. It
reports centroid.scenePosition continuously, mapped to ListView content
coordinates via contentItem.mapFromScene, driving the same updateDrop/
commitDrop path. A HoverHandler keeps the hover affordance, and the grip
gets a slightly larger hit target.

QML compiles (AOT cache build of OutlineView). The drop resolution and
refile commit paths were already verified; this restores the gesture
that feeds them.
This commit is contained in:
Levi Neely 2026-10-02 16:57:18 +02:00
parent 1033820229
commit 0a06ca60bf
1 changed files with 34 additions and 18 deletions

View File

@ -520,33 +520,49 @@ ListView {
// Drag grip: drag a section (and its subtree) to restructure. // Drag grip: drag a section (and its subtree) to restructure.
// A live indicator shows the resolved drop target; releasing // A live indicator shows the resolved drop target; releasing
// commits a refile. Horizontal position chooses the depth, // commits a refile. Horizontal position chooses the depth,
// vertical position chooses the gap. // vertical position chooses the gap. A DragHandler is used
// (not a MouseArea) so the enclosing ListView cannot steal the
// drag for flicking.
Label { Label {
id: gripLabel
text: "⠿" text: "⠿"
color: theme.placeholderTextColor color: theme.placeholderTextColor
// A slightly larger hit target than the bare glyph.
Layout.preferredWidth: outline.baseFontSize + 6
horizontalAlignment: Text.AlignHCenter
font.pointSize: outline.baseFontSize - 1 font.pointSize: outline.baseFontSize - 1
opacity: gripMouse.containsMouse || outline.dragRow === del.index ? 1.0 : 0.3 opacity: gripHover.hovered || outline.dragRow === del.index ? 1.0 : 0.3
MouseArea { HoverHandler {
id: gripMouse id: gripHover
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.SizeAllCursor cursorShape: Qt.SizeAllCursor
preventStealing: true }
onPressed: {
outline.dragRow = del.index DragHandler {
id: gripDrag
target: null // we track, we don't move the item
dragThreshold: 3
// Take the grab and refuse to yield it to the ListView
// (a Flickable), which would otherwise steal the drag.
grabPermissions: PointerHandler.CanTakeOverFromItems
| PointerHandler.CanTakeOverFromHandlersOfDifferentType
onActiveChanged: {
if (active) {
outline.dragRow = del.index
} else {
outline.commitDrop()
}
} }
onPositionChanged: (mouse) => { onCentroidChanged: {
if (outline.dragRow < 0) return if (!active || outline.dragRow < 0) return
// Map the pointer to ListView content coordinates. // Map the scene pointer position to ListView content
var p = mapToItem(outline.contentItem, mouse.x, mouse.y) // coordinates and resolve the drop.
var p = outline.contentItem.mapFromScene(
centroid.scenePosition.x,
centroid.scenePosition.y)
outline.updateDrop(p.x, p.y) outline.updateDrop(p.x, p.y)
} }
onReleased: outline.commitDrop()
onCanceled: {
outline.dragRow = -1
outline.dropInfo = null
}
} }
} }