Make the drag grip own its gesture; fix scene mapping
Two drag fixes: - The gutter grip still fought the ListView (a Flickable) for the drag. Make it a dedicated control: pressing the grip sets outline.interactive = false for the duration of the press (via a TapHandler), so the Flickable cannot scroll and the grip's DragHandler takes the grab cleanly. Flicking is restored on release. Drops the earlier press-and-hold arming (and the now-unused dragArmed property); a plain press on the grip starts the drag. - Fix a runtime TypeError on every drag move: Item has no mapFromScene(). Use contentItem.mapFromItem(null, x, y), where a null source item means scene coordinates, to convert the DragHandler centroid to ListView content coordinates. GUI builds clean.
This commit is contained in:
parent
ed65235940
commit
614378ffa4
|
|
@ -26,10 +26,6 @@ ListView {
|
||||||
property var dropInfo: null // {valid, level, parentId, parentTitle, beforeId}
|
property var dropInfo: null // {valid, level, parentId, parentTitle, beforeId}
|
||||||
property real dropIndicatorY: 0 // content-y of the insertion bar
|
property real dropIndicatorY: 0 // content-y of the insertion bar
|
||||||
property int dropGapAbove: -2 // visible row above the gap (-1 = top)
|
property int dropGapAbove: -2 // visible row above the gap (-1 = top)
|
||||||
// Row whose grip has been "armed" by a press-and-hold, so its DragHandler
|
|
||||||
// may start a structural drag. This gates the drag behind a hold so a
|
|
||||||
// quick press-drag still scrolls the ListView (Flickable) instead.
|
|
||||||
property int dragArmed: -1
|
|
||||||
|
|
||||||
// Recompute the drop target from a pointer position in content coords.
|
// Recompute the drop target from a pointer position in content coords.
|
||||||
function updateDrop(contentX, contentY) {
|
function updateDrop(contentX, contentY) {
|
||||||
|
|
@ -521,53 +517,49 @@ ListView {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
// Drag grip (left gutter): press-and-hold to arm, then drag to
|
// Drag grip (left gutter): a dedicated drag control. Pressing
|
||||||
// restructure the section (and its subtree). A live indicator
|
// it disables ListView flicking for the duration of the press,
|
||||||
// shows the resolved drop target; releasing commits a refile.
|
// so the grip — not the enclosing Flickable — owns the gesture;
|
||||||
// Horizontal position chooses the depth, vertical the gap.
|
// dragging then restructures the section (and its subtree) and
|
||||||
//
|
// releasing commits a refile. Horizontal position chooses the
|
||||||
// Gating the drag behind a hold resolves the conflict with the
|
// depth, vertical the gap. Flicking is restored on release.
|
||||||
// ListView (a Flickable): a quick press-drag scrolls the list;
|
|
||||||
// a hold arms the grip so its DragHandler takes the grab.
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: gripLabel
|
id: gripLabel
|
||||||
Layout.preferredWidth: outline.baseFontSize + 8
|
Layout.preferredWidth: outline.baseFontSize + 8
|
||||||
Layout.preferredHeight: outline.baseFontSize + 8
|
Layout.preferredHeight: outline.baseFontSize + 8
|
||||||
radius: 3
|
radius: 3
|
||||||
readonly property bool armed: outline.dragArmed === del.index
|
readonly property bool active: outline.dragRow === del.index
|
||||||
|| outline.dragRow === del.index
|
|| gripPress.pressed
|
||||||
color: armed ? theme.highlightColor
|
color: active ? theme.highlightColor
|
||||||
: (gripHover.hovered ? theme.alternateBaseColor : "transparent")
|
: (gripHover.hovered ? theme.alternateBaseColor : "transparent")
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "⠿"
|
text: "⠿"
|
||||||
color: gripLabel.armed ? theme.highlightedTextColor
|
color: gripLabel.active ? theme.highlightedTextColor
|
||||||
: theme.placeholderTextColor
|
: theme.placeholderTextColor
|
||||||
font.pointSize: outline.baseFontSize - 1
|
font.pointSize: outline.baseFontSize - 1
|
||||||
opacity: gripHover.hovered || gripLabel.armed ? 1.0 : 0.4
|
opacity: gripHover.hovered || gripLabel.active ? 1.0 : 0.4
|
||||||
}
|
}
|
||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
id: gripHover
|
id: gripHover
|
||||||
cursorShape: gripLabel.armed ? Qt.SizeAllCursor : Qt.OpenHandCursor
|
cursorShape: gripLabel.active ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
||||||
}
|
}
|
||||||
|
|
||||||
// Press-and-hold to arm the drag without moving.
|
// Own the gesture: while the grip is pressed, the ListView
|
||||||
|
// must not flick. This is what makes the gutter behave as a
|
||||||
|
// separate control rather than fighting the Flickable.
|
||||||
TapHandler {
|
TapHandler {
|
||||||
id: gripHold
|
id: gripPress
|
||||||
longPressThreshold: 0.35 // seconds
|
onPressedChanged: outline.interactive = !pressed
|
||||||
onLongPressed: outline.dragArmed = del.index
|
|
||||||
// A plain tap (no hold) shouldn't arm anything.
|
|
||||||
onTapped: outline.dragArmed = -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The structural drag itself. Only grabs once armed, so the
|
// The structural drag. The Flickable is non-interactive
|
||||||
// Flickable keeps scrolling for un-armed press-drags.
|
// while pressed, so the handler takes the grab cleanly.
|
||||||
DragHandler {
|
DragHandler {
|
||||||
id: gripDrag
|
id: gripDrag
|
||||||
target: null // track only; don't move the item
|
target: null // track only; don't move the item
|
||||||
enabled: gripLabel.armed
|
|
||||||
dragThreshold: 3
|
dragThreshold: 3
|
||||||
grabPermissions: PointerHandler.CanTakeOverFromItems
|
grabPermissions: PointerHandler.CanTakeOverFromItems
|
||||||
| PointerHandler.CanTakeOverFromHandlersOfDifferentType
|
| PointerHandler.CanTakeOverFromHandlersOfDifferentType
|
||||||
|
|
@ -577,14 +569,16 @@ ListView {
|
||||||
outline.dragRow = del.index
|
outline.dragRow = del.index
|
||||||
} else {
|
} else {
|
||||||
outline.commitDrop()
|
outline.commitDrop()
|
||||||
outline.dragArmed = -1
|
outline.interactive = true // belt-and-suspenders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onCentroidChanged: {
|
onCentroidChanged: {
|
||||||
if (!active || outline.dragRow < 0) return
|
if (!active || outline.dragRow < 0) return
|
||||||
// Map the scene pointer position to ListView content
|
// Map the scene pointer position to ListView content
|
||||||
// coordinates and resolve the drop.
|
// coordinates. mapFromItem(null, ...) treats the
|
||||||
var p = outline.contentItem.mapFromScene(
|
// source coordinates as scene coordinates.
|
||||||
|
var p = outline.contentItem.mapFromItem(
|
||||||
|
null,
|
||||||
centroid.scenePosition.x,
|
centroid.scenePosition.x,
|
||||||
centroid.scenePosition.y)
|
centroid.scenePosition.y)
|
||||||
outline.updateDrop(p.x, p.y)
|
outline.updateDrop(p.x, p.y)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue