EffectComposer: Improve reordering nodes via drag

The dragged effect is collapsed when dragging start, which helps with
large nodes. Autoscrolling content was added when dragging nodes to
the top/bottom of the scrollview.

Fixes: QDS-10857
Change-Id: I5027324918a200746356704e36a6d99cb98aa04e
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2024-02-15 17:27:05 +02:00
parent 12ad750d16
commit 788d4c0040
2 changed files with 95 additions and 44 deletions

View File

@@ -191,17 +191,12 @@ ColumnLayout {
HelperWidgets.ScrollView {
id: scrollView
readonly property int dragScrollMargin: 50
anchors.fill: parent
clip: true
interactive: !HelperWidgets.Controller.contextMenuOpened
onContentHeightChanged: {
if (scrollView.contentItem.height > scrollView.height) {
let lastItemH = repeater.itemAt(repeater.count - 1).height
scrollView.contentY = scrollView.contentItem.height - lastItemH
}
}
Column {
id: nodesCol
width: scrollView.width
@@ -221,7 +216,10 @@ ColumnLayout {
width: parent.width
modelIndex: index
property bool wasExpanded: false
Behavior on y {
id: dragAnimation
PropertyAnimation {
duration: 300
easing.type: Easing.InOutQuad
@@ -231,54 +229,29 @@ ColumnLayout {
onStartDrag: (section) => {
root.draggedSec = section
root.moveFromIdx = index
// We only need to animate non-dragged sections
dragAnimation.enabled = false
wasExpanded = expanded
expanded = false
highlightBorder = true
root.secsY = []
for (let i = 0; i < repeater.count; ++i)
root.secsY[i] = repeater.itemAt(i).y
}
onStopDrag: {
if (root.moveFromIdx === root.moveToIdx)
root.draggedSec.y = root.secsY[root.moveFromIdx]
else
root.backendModel.moveNode(root.moveFromIdx, root.moveToIdx)
if (root.secsY.length !== 0) {
if (root.moveFromIdx === root.moveToIdx)
root.draggedSec.y = root.secsY[root.moveFromIdx]
else
root.backendModel.moveNode(root.moveFromIdx, root.moveToIdx)
}
highlightBorder = false
root.draggedSec = null
expanded = wasExpanded
dragAnimation.enabled = true
}
}
} // Repeater
Timer {
running: root.draggedSec
interval: 50
repeat: true
onTriggered: {
root.moveToIdx = root.moveFromIdx
for (let i = 0; i < repeater.count; ++i) {
let currItem = repeater.itemAt(i)
if (i > root.moveFromIdx) {
if (root.draggedSec.y > currItem.y + (currItem.height - root.draggedSec.height) * .5) {
currItem.y = root.secsY[i] - root.draggedSec.height - nodesCol.spacing
root.moveToIdx = i
} else {
currItem.y = root.secsY[i]
}
} else if (i < root.moveFromIdx) {
if (!repeater.model.isDependencyNode(i)
&& root.draggedSec.y < currItem.y + (currItem.height - root.draggedSec.height) * .5) {
currItem.y = root.secsY[i] + root.draggedSec.height + nodesCol.spacing
root.moveToIdx = Math.min(root.moveToIdx, i)
} else {
currItem.y = root.secsY[i]
}
}
}
}
} // Timer
} // Column
} // ScrollView
@@ -295,4 +268,77 @@ ColumnLayout {
} // Item
} // Column
} // SplitView
function handleDragMove() {
dragTimer.stop()
if (root.secsY.length === 0) {
for (let i = 0; i < repeater.count; ++i)
root.secsY[i] = repeater.itemAt(i).y
}
let oldContentY = scrollView.contentY
if (root.draggedSec.y < scrollView.dragScrollMargin + scrollView.contentY
&& scrollView.contentY > 0) {
scrollView.contentY -= scrollView.dragScrollMargin / 2
} else if (root.draggedSec.y > scrollView.contentY + scrollView.height - scrollView.dragScrollMargin
&& scrollView.contentY < scrollView.contentHeight - scrollView.height) {
scrollView.contentY += scrollView.dragScrollMargin / 2
if (scrollView.contentY > scrollView.contentHeight - scrollView.height)
scrollView.contentY = scrollView.contentHeight - scrollView.height
}
if (scrollView.contentY < 0)
scrollView.contentY = 0
if (oldContentY !== scrollView.contentY) {
// Changing dragged section position in drag handler doesn't seem to stick
// when triggered by mouse move, so do it again async
dragTimer.targetY = root.draggedSec.y - oldContentY + scrollView.contentY
dragTimer.restart()
dragConnection.enabled = false
root.draggedSec.y = dragTimer.targetY
dragConnection.enabled = true
}
root.moveToIdx = root.moveFromIdx
for (let i = 0; i < repeater.count; ++i) {
let currItem = repeater.itemAt(i)
if (i > root.moveFromIdx) {
if (root.draggedSec.y > currItem.y) {
currItem.y = root.secsY[i] - root.draggedSec.height - nodesCol.spacing
root.moveToIdx = i
} else {
currItem.y = root.secsY[i]
}
} else if (i < root.moveFromIdx) {
if (!repeater.model.isDependencyNode(i) && root.draggedSec.y < currItem.y) {
currItem.y = root.secsY[i] + root.draggedSec.height + nodesCol.spacing
root.moveToIdx = Math.min(root.moveToIdx, i)
} else {
currItem.y = root.secsY[i]
}
}
}
}
Connections {
id: dragConnection
target: root.draggedSec
onYChanged: root.handleDragMove()
}
Timer {
id: dragTimer
running: false
interval: 16
repeat: false
property real targetY: -1
onTriggered: {
// Ensure we get position change triggers even if user holds mouse still to
// make scrolling smooth
root.draggedSec.y = targetY
root.handleDragMove()
}
} // Timer
}

View File

@@ -318,5 +318,10 @@ Item {
duration: 120
easing.type: Easing.OutCubic
}
onRunningChanged: {
if (!running)
enabled = false
}
}
}