[ui] GraphEditor: highlight the edge that will be deleted when it is replaced with another edge

This commit is contained in:
ChemicalXandco 2021-06-04 19:59:49 +01:00
parent d3cb164316
commit ecb1662b6b
3 changed files with 50 additions and 3 deletions

View file

@ -29,6 +29,7 @@ RowLayout {
signal childPinDeleted(var childAttribute, var pin) signal childPinDeleted(var childAttribute, var pin)
signal pressed(var mouse) signal pressed(var mouse)
signal edgeAboutToBeRemoved(var input)
objectName: attribute ? attribute.name + "." : "" objectName: attribute ? attribute.name + "." : ""
layoutDirection: Qt.LeftToRight layoutDirection: Qt.LeftToRight
@ -95,14 +96,21 @@ RowLayout {
// Refuse attributes connection // Refuse attributes connection
drag.accepted = false drag.accepted = false
} }
else if (inputDragTarget.attribute.isLink) { // already connected attribute
root.edgeAboutToBeRemoved(inputDragTarget.attribute)
}
inputDropArea.acceptableDrop = drag.accepted inputDropArea.acceptableDrop = drag.accepted
} }
onExited: { onExited: {
if (inputDragTarget.attribute.isLink) { // already connected attribute
root.edgeAboutToBeRemoved(undefined)
}
acceptableDrop = false acceptableDrop = false
drag.source.dropAccepted = false drag.source.dropAccepted = false
} }
onDropped: { onDropped: {
root.edgeAboutToBeRemoved(undefined)
_reconstruction.addEdge(drag.source.attribute, inputDragTarget.attribute) _reconstruction.addEdge(drag.source.attribute, inputDragTarget.attribute)
} }
} }
@ -129,8 +137,7 @@ RowLayout {
MouseArea { MouseArea {
id: inputConnectMA id: inputConnectMA
// If an input attribute is connected (isLink), we disable drag&drop drag.target: attribute.isReadOnly ? undefined : inputDragTarget
drag.target: (attribute.isReadOnly) ? undefined : inputDragTarget
drag.threshold: 0 drag.threshold: 0
enabled: !root.readOnly enabled: !root.readOnly
anchors.fill: parent anchors.fill: parent
@ -234,13 +241,18 @@ RowLayout {
// Refuse attributes connection // Refuse attributes connection
drag.accepted = false drag.accepted = false
} }
else if (drag.source.attribute.isLink) { // already connected attribute
root.edgeAboutToBeRemoved(drag.source.attribute)
}
outputDropArea.acceptableDrop = drag.accepted outputDropArea.acceptableDrop = drag.accepted
} }
onExited: { onExited: {
root.edgeAboutToBeRemoved(undefined)
acceptableDrop = false acceptableDrop = false
} }
onDropped: { onDropped: {
root.edgeAboutToBeRemoved(undefined)
_reconstruction.addEdge(outputDragTarget.attribute, drag.source.attribute) _reconstruction.addEdge(outputDragTarget.attribute, drag.source.attribute)
} }
} }

View file

@ -15,6 +15,8 @@ Item {
readonly property variant graph: uigraph ? uigraph.graph : null /// core graph contained in ui graph readonly property variant graph: uigraph ? uigraph.graph : null /// core graph contained in ui graph
property variant nodeTypesModel: null /// the list of node types that can be instantiated property variant nodeTypesModel: null /// the list of node types that can be instantiated
property var edgeAboutToBeRemoved: undefined
property var _attributeToDelegate: ({}) property var _attributeToDelegate: ({})
// signals // signals
@ -314,7 +316,7 @@ Item {
property bool inFocus: containsMouse || (edgeMenu.opened && edgeMenu.currentEdge == edge) property bool inFocus: containsMouse || (edgeMenu.opened && edgeMenu.currentEdge == edge)
edge: object edge: object
color: inFocus ? activePalette.highlight : activePalette.text color: edge.dst === root.edgeAboutToBeRemoved ? "red" : inFocus ? activePalette.highlight : activePalette.text
thickness: inFocus ? 2 : 1 thickness: inFocus ? 2 : 1
opacity: 0.7 opacity: 0.7
point1x: isValidEdge ? src.globalX + src.outputAnchorPos.x : 0 point1x: isValidEdge ? src.globalX + src.outputAnchorPos.x : 0
@ -479,8 +481,10 @@ Item {
id: nodeRepeater id: nodeRepeater
model: root.graph ? root.graph.nodes : undefined model: root.graph ? root.graph.nodes : undefined
property bool loaded: model ? count === model.count : false property bool loaded: model ? count === model.count : false
property bool dragging: false property bool dragging: false
property var temporaryEdgeAboutToBeRemoved: undefined
delegate: Node { delegate: Node {
id: nodeDelegate id: nodeDelegate
@ -530,6 +534,30 @@ Item {
onEntered: uigraph.hoveredNode = node onEntered: uigraph.hoveredNode = node
onExited: uigraph.hoveredNode = null onExited: uigraph.hoveredNode = null
onEdgeAboutToBeRemoved: {
/*
Sometimes the signals are not in the right order
because of weird Qt/QML update order (next DropArea
entered signal before previous DropArea exited signal)
so edgeAboutToBeRemoved must be set to undefined before
it can be set to another attribute object.
*/
if (input === undefined) {
if (nodeRepeater.temporaryEdgeAboutToBeRemoved === undefined) {
root.edgeAboutToBeRemoved = input
} else {
root.edgeAboutToBeRemoved = nodeRepeater.temporaryEdgeAboutToBeRemoved
nodeRepeater.temporaryEdgeAboutToBeRemoved = undefined
}
} else {
if (root.edgeAboutToBeRemoved === undefined) {
root.edgeAboutToBeRemoved = input
} else {
nodeRepeater.temporaryEdgeAboutToBeRemoved = input
}
}
}
onPositionChanged: { onPositionChanged: {
if (dragging && uigraph.selectedNodes.contains(node)) { if (dragging && uigraph.selectedNodes.contains(node)) {
// update all selected nodes positions with this node that is being dragged // update all selected nodes positions with this node that is being dragged

View file

@ -43,6 +43,9 @@ Item {
signal entered() signal entered()
signal exited() signal exited()
// Already connected attribute with another edge in DropArea
signal edgeAboutToBeRemoved(var input)
/// Emitted when child attribute pins are created /// Emitted when child attribute pins are created
signal attributePinCreated(var attribute, var pin) signal attributePinCreated(var attribute, var pin)
/// Emitted when child attribute pins are deleted /// Emitted when child attribute pins are deleted
@ -303,6 +306,8 @@ Item {
property real globalY: root.y + nodeAttributes.y + outputs.y + outputLoader.y + outPin.y property real globalY: root.y + nodeAttributes.y + outputs.y + outputLoader.y + outPin.y
onPressed: root.pressed(mouse) onPressed: root.pressed(mouse)
onEdgeAboutToBeRemoved: root.edgeAboutToBeRemoved(input)
Component.onCompleted: attributePinCreated(object, outPin) Component.onCompleted: attributePinCreated(object, outPin)
Component.onDestruction: attributePinDeleted(attribute, outPin) Component.onDestruction: attributePinDeleted(attribute, outPin)
} }
@ -334,6 +339,7 @@ Item {
Component.onCompleted: attributePinCreated(attribute, inPin) Component.onCompleted: attributePinCreated(attribute, inPin)
Component.onDestruction: attributePinDeleted(attribute, inPin) Component.onDestruction: attributePinDeleted(attribute, inPin)
onPressed: root.pressed(mouse) onPressed: root.pressed(mouse)
onEdgeAboutToBeRemoved: root.edgeAboutToBeRemoved(input)
onChildPinCreated: attributePinCreated(childAttribute, inPin) onChildPinCreated: attributePinCreated(childAttribute, inPin)
onChildPinDeleted: attributePinDeleted(childAttribute, inPin) onChildPinDeleted: attributePinDeleted(childAttribute, inPin)
} }
@ -395,6 +401,7 @@ Item {
Component.onCompleted: attributePinCreated(attribute, inPin) Component.onCompleted: attributePinCreated(attribute, inPin)
Component.onDestruction: attributePinDeleted(attribute, inPin) Component.onDestruction: attributePinDeleted(attribute, inPin)
onPressed: root.pressed(mouse) onPressed: root.pressed(mouse)
onEdgeAboutToBeRemoved: root.edgeAboutToBeRemoved(input)
onChildPinCreated: attributePinCreated(childAttribute, inPin) onChildPinCreated: attributePinCreated(childAttribute, inPin)
onChildPinDeleted: attributePinDeleted(childAttribute, inPin) onChildPinDeleted: attributePinDeleted(childAttribute, inPin)
} }