diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml index 6efa67919d0..ed89ea149bd 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml @@ -15,8 +15,11 @@ HelperWidgets.Section { caption: nodeName category: "EffectMaker" + draggable: true + fillBackground: true showCloseButton: true closeButtonToolTip: qsTr("Remove") + onCloseButtonClicked: { EffectMakerBackend.effectMakerModel.removeNode(index) } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 3e41d32c633..5c32df314a0 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -10,6 +10,11 @@ import EffectMakerBackend Item { id: root + property var draggedSec: null + property var secsY: [] + property int moveFromIdx: 0 + property int moveToIdx: 0 + Column { id: col anchors.fill: parent @@ -47,7 +52,6 @@ Item { } } - HelperWidgets.ScrollView { id: scrollView @@ -55,29 +59,77 @@ Item { height: parent.height - y clip: true - Behavior on contentY { - id: contentYBehavior - PropertyAnimation { - id: scrollViewAnim - easing.type: Easing.InOutQuad - } - } - Column { width: scrollView.width spacing: 1 Repeater { - id: compositionRepeater + id: repeater width: root.width model: EffectMakerBackend.effectMakerModel delegate: EffectCompositionNode { 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 } } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml index 324304e4e45..8ae703adb7e 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml @@ -13,7 +13,7 @@ Rectangle { id: root width: 140 - height: 22 + height: 32 color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundInteraction : "transparent" @@ -38,8 +38,8 @@ Rectangle { IconImage { id: nodeIcon - width: 22 - height: 22 + width: 32 + height: 32 color: StudioTheme.Values.themeTextColor source: modelData.nodeIcon diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml index 08a560baa25..4852b05a98a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml @@ -10,6 +10,8 @@ Rectangle { id: root signal clicked() + signal pressed() + signal released() property alias icon: icon.text property alias tooltip: toolTip.text @@ -20,6 +22,7 @@ Rectangle { property alias iconStyleColor: icon.styleColor property alias containsMouse: mouseArea.containsMouse + property alias drag: mouseArea.drag property bool enabled: true property bool transparentBg: false @@ -55,12 +58,22 @@ Rectangle { if (root.enabled) root.clicked() } + + onPressed: { + if (root.enabled) + root.pressed() + } + + onReleased: { + if (root.enabled) + root.released() + } } ToolTip { id: toolTip - visible: mouseArea.containsMouse + visible: mouseArea.containsMouse && text !== "" delay: 1000 } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml index dd7b750ffaa..b1161147f9a 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml @@ -21,6 +21,9 @@ Item { property alias showCloseButton: closeButton.visible property alias closeButtonToolTip: closeButton.tooltip 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 rightPadding: 0 @@ -82,6 +85,8 @@ Item { signal expand() signal collapse() signal closeButtonClicked() + signal startDrag(var section) + signal stopDrag() DropArea { id: dropArea @@ -128,7 +133,7 @@ Item { height: 4 source: "image://icons/down-arrow" 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 } @@ -136,7 +141,7 @@ Item { id: label anchors.verticalCenter: parent.verticalCenter color: StudioTheme.Values.themeTextColor - x: 22 + (section.level * section.levelShift) + x: arrow.x + 18 font.pixelSize: StudioTheme.Values.myFontSize font.capitalization: Font.AllUppercase } @@ -174,8 +179,34 @@ Item { 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 { id: topSeparator height: 1 @@ -193,6 +224,23 @@ Item { 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 { id: topSpacer height: section.addTopPadding && column.height > 0 ? section.topPadding : 0 diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp index 176678f328f..47e77305e60 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp @@ -49,6 +49,17 @@ void EffectMakerModel::addNode(const QString &nodeQenPath) 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) { beginRemoveRows({}, idx, idx); diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h index 1d00c6dda71..02fb5cec2c9 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h @@ -44,6 +44,7 @@ public: void addNode(const QString &nodeQenPath); + Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); bool shadersUpToDate() const;