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 real dropIndicatorY: 0 // content-y of the insertion bar
|
||||
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.
|
||||
function updateDrop(contentX, contentY) {
|
||||
|
|
@ -521,53 +517,49 @@ ListView {
|
|||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
// Drag grip (left gutter): press-and-hold to arm, then drag to
|
||||
// restructure the section (and its subtree). A live indicator
|
||||
// shows the resolved drop target; releasing commits a refile.
|
||||
// Horizontal position chooses the depth, vertical the gap.
|
||||
//
|
||||
// Gating the drag behind a hold resolves the conflict with the
|
||||
// ListView (a Flickable): a quick press-drag scrolls the list;
|
||||
// a hold arms the grip so its DragHandler takes the grab.
|
||||
// Drag grip (left gutter): a dedicated drag control. Pressing
|
||||
// it disables ListView flicking for the duration of the press,
|
||||
// so the grip — not the enclosing Flickable — owns the gesture;
|
||||
// dragging then restructures the section (and its subtree) and
|
||||
// releasing commits a refile. Horizontal position chooses the
|
||||
// depth, vertical the gap. Flicking is restored on release.
|
||||
Rectangle {
|
||||
id: gripLabel
|
||||
Layout.preferredWidth: outline.baseFontSize + 8
|
||||
Layout.preferredHeight: outline.baseFontSize + 8
|
||||
radius: 3
|
||||
readonly property bool armed: outline.dragArmed === del.index
|
||||
|| outline.dragRow === del.index
|
||||
color: armed ? theme.highlightColor
|
||||
readonly property bool active: outline.dragRow === del.index
|
||||
|| gripPress.pressed
|
||||
color: active ? theme.highlightColor
|
||||
: (gripHover.hovered ? theme.alternateBaseColor : "transparent")
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: "⠿"
|
||||
color: gripLabel.armed ? theme.highlightedTextColor
|
||||
color: gripLabel.active ? theme.highlightedTextColor
|
||||
: theme.placeholderTextColor
|
||||
font.pointSize: outline.baseFontSize - 1
|
||||
opacity: gripHover.hovered || gripLabel.armed ? 1.0 : 0.4
|
||||
opacity: gripHover.hovered || gripLabel.active ? 1.0 : 0.4
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
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 {
|
||||
id: gripHold
|
||||
longPressThreshold: 0.35 // seconds
|
||||
onLongPressed: outline.dragArmed = del.index
|
||||
// A plain tap (no hold) shouldn't arm anything.
|
||||
onTapped: outline.dragArmed = -1
|
||||
id: gripPress
|
||||
onPressedChanged: outline.interactive = !pressed
|
||||
}
|
||||
|
||||
// The structural drag itself. Only grabs once armed, so the
|
||||
// Flickable keeps scrolling for un-armed press-drags.
|
||||
// The structural drag. The Flickable is non-interactive
|
||||
// while pressed, so the handler takes the grab cleanly.
|
||||
DragHandler {
|
||||
id: gripDrag
|
||||
target: null // track only; don't move the item
|
||||
enabled: gripLabel.armed
|
||||
dragThreshold: 3
|
||||
grabPermissions: PointerHandler.CanTakeOverFromItems
|
||||
| PointerHandler.CanTakeOverFromHandlersOfDifferentType
|
||||
|
|
@ -577,14 +569,16 @@ ListView {
|
|||
outline.dragRow = del.index
|
||||
} else {
|
||||
outline.commitDrop()
|
||||
outline.dragArmed = -1
|
||||
outline.interactive = true // belt-and-suspenders
|
||||
}
|
||||
}
|
||||
onCentroidChanged: {
|
||||
if (!active || outline.dragRow < 0) return
|
||||
// Map the scene pointer position to ListView content
|
||||
// coordinates and resolve the drop.
|
||||
var p = outline.contentItem.mapFromScene(
|
||||
// coordinates. mapFromItem(null, ...) treats the
|
||||
// source coordinates as scene coordinates.
|
||||
var p = outline.contentItem.mapFromItem(
|
||||
null,
|
||||
centroid.scenePosition.x,
|
||||
centroid.scenePosition.y)
|
||||
outline.updateDrop(p.x, p.y)
|
||||
|
|
|
|||
Loading…
Reference in New Issue