forked from qt-creator/qt-creator
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:
@@ -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)
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user