[ui] GraphEditor: Added Loader for Node Delegate

The Loader allows loading Backdrop Component for backdrop nodes and Standard Node component for other nodes
This commit is contained in:
waaake 2024-12-18 12:20:15 +05:30
parent fce662b7f0
commit ce25d0087b

View file

@ -827,141 +827,303 @@ Item {
property bool updateSelectionOnClick: false
property var temporaryEdgeAboutToBeRemoved: undefined
delegate: Node {
id: nodeDelegate
delegate: Loader {
id: nodeLoader
Component {
id: nodeComponent
Node {
id: nodeDelegate
node: object
width: uigraph.layout.nodeWidth
node: object
width: uigraph.layout.nodeWidth
mainSelected: uigraph.selectedNode === node
hovered: uigraph.hoveredNode === node
mainSelected: uigraph.selectedNode === node
hovered: uigraph.hoveredNode === node
// ItemSelectionModel.hasSelection triggers updates anytime the selectionChanged() signal is emitted.
selected: uigraph.nodeSelection.hasSelection ? uigraph.nodeSelection.isRowSelected(index) : false
// ItemSelectionModel.hasSelection triggers updates anytime the selectionChanged() signal is emitted.
selected: uigraph.nodeSelection.hasSelection ? uigraph.nodeSelection.isRowSelected(index) : false
onAttributePinCreated: function(attribute, pin) { registerAttributePin(attribute, pin) }
onAttributePinDeleted: function(attribute, pin) { unregisterAttributePin(attribute, pin) }
onAttributePinCreated: function(attribute, pin) { registerAttributePin(attribute, pin) }
onAttributePinDeleted: function(attribute, pin) { unregisterAttributePin(attribute, pin) }
onPressed: function(mouse) {
nodeRepeater.updateSelectionOnClick = true;
nodeRepeater.ongoingDrag = true;
onPressed: function(mouse) {
nodeRepeater.updateSelectionOnClick = true;
nodeRepeater.ongoingDrag = true;
let selectionMode = ItemSelectionModel.NoUpdate;
let selectionMode = ItemSelectionModel.NoUpdate;
if(!selected) {
selectionMode = ItemSelectionModel.ClearAndSelect;
}
if (mouse.button === Qt.LeftButton) {
if(mouse.modifiers & Qt.ShiftModifier) {
selectionMode = ItemSelectionModel.Select;
}
if(mouse.modifiers & Qt.ControlModifier) {
selectionMode = ItemSelectionModel.Toggle;
}
if(mouse.modifiers & Qt.AltModifier) {
let selectFollowingMode = ItemSelectionModel.ClearAndSelect;
if(mouse.modifiers & Qt.ShiftModifier) {
selectFollowingMode = ItemSelectionModel.Select;
if(!selected) {
selectionMode = ItemSelectionModel.ClearAndSelect;
}
uigraph.selectFollowing(node, selectFollowingMode);
// Indicate selection has been dealt with by setting conservative Select mode.
selectionMode = ItemSelectionModel.Select;
if (mouse.button === Qt.LeftButton) {
if(mouse.modifiers & Qt.ShiftModifier) {
selectionMode = ItemSelectionModel.Select;
}
if(mouse.modifiers & Qt.ControlModifier) {
selectionMode = ItemSelectionModel.Toggle;
}
if(mouse.modifiers & Qt.AltModifier) {
let selectFollowingMode = ItemSelectionModel.ClearAndSelect;
if(mouse.modifiers & Qt.ShiftModifier) {
selectFollowingMode = ItemSelectionModel.Select;
}
uigraph.selectFollowing(node, selectFollowingMode);
// Indicate selection has been dealt with by setting conservative Select mode.
selectionMode = ItemSelectionModel.Select;
}
}
else if (mouse.button === Qt.RightButton) {
if(selected) {
// Keep the full selection when right-clicking on an already selected node.
nodeRepeater.updateSelectionOnClick = false;
}
}
if(selectionMode != ItemSelectionModel.NoUpdate) {
nodeRepeater.updateSelectionOnClick = false;
uigraph.selectNodeByIndex(index, selectionMode);
}
// If the node is selected after this, make it the active selected node.
if(selected) {
uigraph.selectedNode = node;
}
// Open the node context menu once selection has been updated.
if(mouse.button == Qt.RightButton) {
nodeMenuLoader.load(node)
}
}
}
else if (mouse.button === Qt.RightButton) {
if(selected) {
// Keep the full selection when right-clicking on an already selected node.
nodeRepeater.updateSelectionOnClick = false;
onReleased: function(mouse, wasDragged) {
nodeRepeater.ongoingDrag = false;
}
}
if(selectionMode != ItemSelectionModel.NoUpdate) {
nodeRepeater.updateSelectionOnClick = false;
uigraph.selectNodeByIndex(index, selectionMode);
}
// If the node is selected after this, make it the active selected node.
if(selected) {
uigraph.selectedNode = node;
}
// Open the node context menu once selection has been updated.
if(mouse.button == Qt.RightButton) {
nodeMenuLoader.load(node)
}
}
onReleased: function(mouse, wasDragged) {
nodeRepeater.ongoingDrag = false;
}
// Only called when the node has not been dragged.
onClicked: function(mouse) {
if(!nodeRepeater.updateSelectionOnClick) {
return;
}
uigraph.selectNodeByIndex(index);
}
onDoubleClicked: function(mouse) { root.nodeDoubleClicked(mouse, node) }
onEntered: uigraph.hoveredNode = node
onExited: uigraph.hoveredNode = null
onEdgeAboutToBeRemoved: function(input) {
/*
* 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
// Only called when the node has not been dragged.
onClicked: function(mouse) {
if(!nodeRepeater.updateSelectionOnClick) {
return;
}
uigraph.selectNodeByIndex(index);
}
} else {
if (root.edgeAboutToBeRemoved === undefined) {
root.edgeAboutToBeRemoved = input
} else {
nodeRepeater.temporaryEdgeAboutToBeRemoved = input
onDoubleClicked: function(mouse) { root.nodeDoubleClicked(mouse, node) }
onEntered: uigraph.hoveredNode = node
onExited: uigraph.hoveredNode = null
onEdgeAboutToBeRemoved: function(input) {
/*
* 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
}
}
}
// Interactive dragging: move the visual delegates
onPositionChanged: {
if(!selected || !dragging) {
return;
}
// Compute offset between the delegate and the stored node position.
const offset = Qt.point(x - node.x, y - node.y);
uigraph.nodeSelection.selectedIndexes.forEach(function(idx) {
if(idx != index) {
const delegate = nodeRepeater.itemAt(idx.row).item;
delegate.x = delegate.node.x + offset.x;
delegate.y = delegate.node.y + offset.y;
}
});
}
// After drag: apply the final offset to all selected nodes
onMoved: function(position) {
const offset = Qt.point(position.x - node.x, position.y - node.y);
uigraph.moveSelectedNodesBy(offset);
}
Behavior on x {
enabled: !nodeRepeater.ongoingDrag
NumberAnimation { duration: 100 }
}
Behavior on y {
enabled: !nodeRepeater.ongoingDrag
NumberAnimation { duration: 100 }
}
}
}
// Interactive dragging: move the visual delegates
onPositionChanged: {
if(!selected || !dragging) {
return;
}
// Compute offset between the delegate and the stored node position.
const offset = Qt.point(x - node.x, y - node.y);
Component {
id: backdropComponent
Backdrop {
id: backdropDelegate
uigraph.nodeSelection.selectedIndexes.forEach(function(idx) {
if(idx != index) {
const delegate = nodeRepeater.itemAt(idx.row);
delegate.x = delegate.node.x + offset.x;
delegate.y = delegate.node.y + offset.y;
node: object
// The Item instantiating the delegates.
modelInstantiator: nodeRepeater
property var nodes: []
width: uigraph.layout.nodeWidth
mainSelected: uigraph.selectedNode === node
hovered: uigraph.hoveredNode === node
// ItemSelectionModel.hasSelection triggers updates anytime the selectionChanged() signal is emitted.
selected: uigraph.nodeSelection.hasSelection ? uigraph.nodeSelection.isRowSelected(index) : false
onPressed: function(mouse) {
nodeRepeater.updateSelectionOnClick = true;
nodeRepeater.ongoingDrag = true;
let selectionMode = ItemSelectionModel.NoUpdate;
if(!selected) {
selectionMode = ItemSelectionModel.ClearAndSelect;
}
if (mouse.button === Qt.LeftButton) {
if(mouse.modifiers & Qt.ShiftModifier) {
selectionMode = ItemSelectionModel.Select;
}
if(mouse.modifiers & Qt.ControlModifier) {
selectionMode = ItemSelectionModel.Toggle;
}
if(mouse.modifiers & Qt.AltModifier) {
let selectFollowingMode = ItemSelectionModel.ClearAndSelect;
if(mouse.modifiers & Qt.ShiftModifier) {
selectFollowingMode = ItemSelectionModel.Select;
}
uigraph.selectFollowing(node, selectFollowingMode);
// Indicate selection has been dealt with by setting conservative Select mode.
selectionMode = ItemSelectionModel.Select;
}
}
else if (mouse.button === Qt.RightButton) {
if(selected) {
// Keep the full selection when right-clicking on an already selected node.
nodeRepeater.updateSelectionOnClick = false;
}
}
if(selectionMode != ItemSelectionModel.NoUpdate) {
nodeRepeater.updateSelectionOnClick = false;
uigraph.selectNodeByIndex(index, selectionMode);
}
// If the node is selected after this, make it the active selected node.
if(selected) {
uigraph.selectedNode = node;
}
// Open the node context menu once selection has been updated.
if(mouse.button == Qt.RightButton) {
nodeMenuLoader.load(node)
}
}
});
onReleased: function(mouse, wasDragged) {
nodeRepeater.ongoingDrag = false;
}
// Only called when the node has not been dragged.
onClicked: function(mouse) {
if(!nodeRepeater.updateSelectionOnClick) {
return;
}
uigraph.selectNodeByIndex(index);
}
onDoubleClicked: function(mouse) { root.nodeDoubleClicked(mouse, node) }
onResized: function(width, height) {
uigraph.resizeNode(node, width, height);
}
onEntered: uigraph.hoveredNode = node
onExited: uigraph.hoveredNode = null
// Interactive dragging: move the visual delegates
onPositionChanged: {
if(!selected || !dragging) {
return;
}
// Compute offset between the delegate and the stored node position.
const offset = Qt.point(x - node.x, y - node.y);
nodes = []
// Get all of the current children for the backdrop
let children = getChildrenNodes();
for (var i = 0; i < children.length; i++) {
const delegate = children[i];
// Ignore the selected delegates as they will be iterated upon separately
if (delegate.selected)
continue;
delegate.x = delegate.node.x + offset.x;
delegate.y = delegate.node.y + offset.y;
// If the delegate is not the current Node
if (delegate !== node)
nodes.push(delegate.node);
}
uigraph.nodeSelection.selectedIndexes.forEach(function(idx) {
if(idx != index) {
const delegate = nodeRepeater.itemAt(idx.row).item;
delegate.x = delegate.node.x + offset.x;
delegate.y = delegate.node.y + offset.y;
// If the delegate is not the current Node
if (delegate !== node)
nodes.push(delegate.node);
}
});
}
// After drag: apply the final offset to all selected nodes
onMoved: function(position) {
const offset = Qt.point(position.x - node.x, position.y - node.y);
uigraph.moveNodesBy(nodes, offset);
}
Behavior on x {
enabled: !nodeRepeater.ongoingDrag && !resizing
NumberAnimation { duration: 100 }
}
Behavior on y {
enabled: !nodeRepeater.ongoingDrag
NumberAnimation { duration: 100 }
}
}
}
// After drag: apply the final offset to all selected nodes
onMoved: function(position) {
const offset = Qt.point(position.x - node.x, position.y - node.y);
uigraph.moveSelectedNodesBy(offset);
}
// Source Component for the delegate
sourceComponent: object.isBackdrop ? backdropComponent : nodeComponent;
Behavior on x {
enabled: !nodeRepeater.ongoingDrag
NumberAnimation { duration: 100 }
}
Behavior on y {
enabled: !nodeRepeater.ongoingDrag
NumberAnimation { duration: 100 }
onLoaded: {
// Node's Z-Ordering
nodeLoader.z = nodeLoader.item.z;
}
}
}