QmlDesigner: Implement effect maker node drag to reorder

Also small relevant tweaks

Fixes: QDS-10411
Change-Id: I332482d4726c79786edbc0a5fa1e8f6489d77f11
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Amr Elsayed <amr.elsayed@qt.io>
Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Mahmoud Badri
2023-09-04 14:17:01 +03:00
parent 6251730f8f
commit 9bbe78df8b
7 changed files with 147 additions and 19 deletions

View File

@@ -15,8 +15,11 @@ HelperWidgets.Section {
caption: nodeName caption: nodeName
category: "EffectMaker" category: "EffectMaker"
draggable: true
fillBackground: true
showCloseButton: true showCloseButton: true
closeButtonToolTip: qsTr("Remove") closeButtonToolTip: qsTr("Remove")
onCloseButtonClicked: { onCloseButtonClicked: {
EffectMakerBackend.effectMakerModel.removeNode(index) EffectMakerBackend.effectMakerModel.removeNode(index)
} }

View File

@@ -10,6 +10,11 @@ import EffectMakerBackend
Item { Item {
id: root id: root
property var draggedSec: null
property var secsY: []
property int moveFromIdx: 0
property int moveToIdx: 0
Column { Column {
id: col id: col
anchors.fill: parent anchors.fill: parent
@@ -47,7 +52,6 @@ Item {
} }
} }
HelperWidgets.ScrollView { HelperWidgets.ScrollView {
id: scrollView id: scrollView
@@ -55,29 +59,77 @@ Item {
height: parent.height - y height: parent.height - y
clip: true clip: true
Behavior on contentY {
id: contentYBehavior
PropertyAnimation {
id: scrollViewAnim
easing.type: Easing.InOutQuad
}
}
Column { Column {
width: scrollView.width width: scrollView.width
spacing: 1 spacing: 1
Repeater { Repeater {
id: compositionRepeater id: repeater
width: root.width width: root.width
model: EffectMakerBackend.effectMakerModel model: EffectMakerBackend.effectMakerModel
delegate: EffectCompositionNode { delegate: EffectCompositionNode {
width: root.width width: root.width
Behavior on y {
PropertyAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
onStartDrag: (section) => {
root.draggedSec = section
root.moveFromIdx = index
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
EffectMakerBackend.effectMakerModel.moveNode(root.moveFromIdx, root.moveToIdx)
highlightBorder = false
root.draggedSec = null
}
} }
} } // 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
root.moveToIdx = i
} else {
currItem.y = root.secsY[i]
}
} else if (i < root.moveFromIdx) {
if (root.draggedSec.y < currItem.y + (currItem.height - root.draggedSec.height) * .5) {
currItem.y = root.secsY[i] + root.draggedSec.height
root.moveToIdx = Math.min(root.moveToIdx, i)
} else {
currItem.y = root.secsY[i]
}
}
}
}
} // Timer
} // Column
} // ScrollView
} }
} }

View File

@@ -13,7 +13,7 @@ Rectangle {
id: root id: root
width: 140 width: 140
height: 22 height: 32
color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundInteraction color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundInteraction
: "transparent" : "transparent"
@@ -38,8 +38,8 @@ Rectangle {
IconImage { IconImage {
id: nodeIcon id: nodeIcon
width: 22 width: 32
height: 22 height: 32
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
source: modelData.nodeIcon source: modelData.nodeIcon

View File

@@ -10,6 +10,8 @@ Rectangle {
id: root id: root
signal clicked() signal clicked()
signal pressed()
signal released()
property alias icon: icon.text property alias icon: icon.text
property alias tooltip: toolTip.text property alias tooltip: toolTip.text
@@ -20,6 +22,7 @@ Rectangle {
property alias iconStyleColor: icon.styleColor property alias iconStyleColor: icon.styleColor
property alias containsMouse: mouseArea.containsMouse property alias containsMouse: mouseArea.containsMouse
property alias drag: mouseArea.drag
property bool enabled: true property bool enabled: true
property bool transparentBg: false property bool transparentBg: false
@@ -55,12 +58,22 @@ Rectangle {
if (root.enabled) if (root.enabled)
root.clicked() root.clicked()
} }
onPressed: {
if (root.enabled)
root.pressed()
}
onReleased: {
if (root.enabled)
root.released()
}
} }
ToolTip { ToolTip {
id: toolTip id: toolTip
visible: mouseArea.containsMouse visible: mouseArea.containsMouse && text !== ""
delay: 1000 delay: 1000
} }
} }

View File

@@ -21,6 +21,9 @@ Item {
property alias showCloseButton: closeButton.visible property alias showCloseButton: closeButton.visible
property alias closeButtonToolTip: closeButton.tooltip property alias closeButtonToolTip: closeButton.tooltip
property alias spacing: column.spacing property alias spacing: column.spacing
property alias draggable: dragButton.visible
property alias fillBackground: sectionBackground.visible
property alias highlightBorder: sectionBorder.visible
property int leftPadding: StudioTheme.Values.sectionLeftPadding property int leftPadding: StudioTheme.Values.sectionLeftPadding
property int rightPadding: 0 property int rightPadding: 0
@@ -82,6 +85,8 @@ Item {
signal expand() signal expand()
signal collapse() signal collapse()
signal closeButtonClicked() signal closeButtonClicked()
signal startDrag(var section)
signal stopDrag()
DropArea { DropArea {
id: dropArea id: dropArea
@@ -128,7 +133,7 @@ Item {
height: 4 height: 4
source: "image://icons/down-arrow" source: "image://icons/down-arrow"
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 4 + (section.level * section.levelShift) anchors.leftMargin: 4 + (section.level * section.levelShift) + (section.draggable ? 20 : 0)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@@ -136,7 +141,7 @@ Item {
id: label id: label
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
x: 22 + (section.level * section.levelShift) x: arrow.x + 18
font.pixelSize: StudioTheme.Values.myFontSize font.pixelSize: StudioTheme.Values.myFontSize
font.capitalization: Font.AllUppercase font.capitalization: Font.AllUppercase
} }
@@ -174,8 +179,34 @@ Item {
onClicked: root.closeButtonClicked() onClicked: root.closeButtonClicked()
} }
IconButton {
id: dragButton
icon: StudioTheme.Constants.dragmarks
buttonSize: 22
iconScale: containsMouse ? 1.2 : 1
transparentBg: true
visible: false
drag.target: section
drag.axis: Drag.YAxis
onPressed: {
section.startDrag(section)
section.z = ++section.parent.z // put the dragged section on top
}
onReleased: {
section.stopDrag()
}
}
} }
Drag.active: dragButton.drag.active
Drag.source: dragButton
Rectangle { Rectangle {
id: topSeparator id: topSeparator
height: 1 height: 1
@@ -193,6 +224,23 @@ Item {
implicitHeight: Math.round(column.height + header.height + topSpacer.height + bottomSpacer.height) implicitHeight: Math.round(column.height + header.height + topSpacer.height + bottomSpacer.height)
Rectangle {
id: sectionBackground
anchors.top: header.bottom
width: section.width
height: topSpacer.height + column.height + bottomSpacer.height
color: StudioTheme.Values.themePanelBackground
visible: false
}
Rectangle {
id: sectionBorder
anchors.fill: parent
color: "transparent"
border.color: StudioTheme.Values.themeInteraction
border.width: 1
visible: false
}
Item { Item {
id: topSpacer id: topSpacer
height: section.addTopPadding && column.height > 0 ? section.topPadding : 0 height: section.addTopPadding && column.height > 0 ? section.topPadding : 0

View File

@@ -49,6 +49,17 @@ void EffectMakerModel::addNode(const QString &nodeQenPath)
endInsertRows(); endInsertRows();
} }
void EffectMakerModel::moveNode(int fromIdx, int toIdx)
{
if (fromIdx == toIdx)
return;
int toIdxAdjusted = fromIdx < toIdx ? toIdx + 1 : toIdx; // otherwise beginMoveRows() crashes
beginMoveRows({}, fromIdx, fromIdx, {}, toIdxAdjusted);
m_nodes.move(fromIdx, toIdx);
endMoveRows();
}
void EffectMakerModel::removeNode(int idx) void EffectMakerModel::removeNode(int idx)
{ {
beginRemoveRows({}, idx, idx); beginRemoveRows({}, idx, idx);

View File

@@ -44,6 +44,7 @@ public:
void addNode(const QString &nodeQenPath); void addNode(const QString &nodeQenPath);
Q_INVOKABLE void moveNode(int fromIdx, int toIdx);
Q_INVOKABLE void removeNode(int idx); Q_INVOKABLE void removeNode(int idx);
bool shadersUpToDate() const; bool shadersUpToDate() const;