From 5fb6a5fb0f0907aa4bceff29cb044bf4aa832647 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Mon, 28 Dec 2020 15:29:10 +0100 Subject: [PATCH] [ui] GraphEditor: only connect compatible attributes --- meshroom/core/attribute.py | 8 ++++ meshroom/ui/commands.py | 3 ++ meshroom/ui/qml/GraphEditor/AttributePin.qml | 42 +++++++++++--------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index 1257b81d2c..c0651de274 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -93,6 +93,9 @@ def getName(self): def getType(self): return self.attributeDesc.__class__.__name__ + def getBaseType(self): + return self.getType() + def getLabel(self): return self._label @@ -258,6 +261,7 @@ def updateInternals(self): fullName = Property(str, getFullName, constant=True) label = Property(str, getLabel, constant=True) type = Property(str, getType, constant=True) + baseType = Property(str, getType, constant=True) desc = Property(desc.Attribute, lambda self: self.attributeDesc, constant=True) valueChanged = Signal() value = Property(Variant, _get_value, _set_value, notify=valueChanged) @@ -292,6 +296,9 @@ def __init__(self, node, attributeDesc, isOutput, root=None, parent=None): def __len__(self): return len(self._value) + def getBaseType(self): + return self.attributeDesc.elementDesc.__class__.__name__ + def at(self, idx): """ Returns child attribute at index 'idx' """ # implement 'at' rather than '__getitem__' @@ -396,6 +403,7 @@ def updateInternals(self): # Override value property setter value = Property(Variant, Attribute._get_value, _set_value, notify=Attribute.valueChanged) isDefault = Property(bool, _isDefault, notify=Attribute.valueChanged) + baseType = Property(str, getBaseType, constant=True) class GroupAttribute(Attribute): diff --git a/meshroom/ui/commands.py b/meshroom/ui/commands.py index 32cf85df6c..f5429c0ea0 100755 --- a/meshroom/ui/commands.py +++ b/meshroom/ui/commands.py @@ -227,6 +227,9 @@ def __init__(self, graph, src, dst, parent=None): self.dstAttr = dst.getFullName() self.setText("Connect '{}'->'{}'".format(self.srcAttr, self.dstAttr)) + if src.baseType != dst.baseType: + raise ValueError("Attribute types are not compatible and cannot be connected: '{}'({})->'{}'({})".format(self.srcAttr, src.baseType, self.dstAttr, dst.baseType)) + def redoImpl(self): self.graph.addEdge(self.graph.attribute(self.srcAttr), self.graph.attribute(self.dstAttr)) return True diff --git a/meshroom/ui/qml/GraphEditor/AttributePin.qml b/meshroom/ui/qml/GraphEditor/AttributePin.qml index a51c8ac5e2..0e87ba4177 100755 --- a/meshroom/ui/qml/GraphEditor/AttributePin.qml +++ b/meshroom/ui/qml/GraphEditor/AttributePin.qml @@ -82,16 +82,18 @@ RowLayout { keys: [inputDragTarget.objectName] onEntered: { - // Filter drops: - if( root.readOnly - || drag.source.objectName != inputDragTarget.objectName // not an edge connector - || drag.source.nodeItem == inputDragTarget.nodeItem // connection between attributes of the same node - || inputDragTarget.attribute.isLink // already connected attribute - || (drag.source.isList && !inputDragTarget.isList) // connection between a list and a simple attribute - || (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children - || drag.source.connectorType == "input" - ) + // Check if attributes are compatible to create a valid connection + if( root.readOnly // cannot connect on a read-only attribute + || drag.source.objectName != inputDragTarget.objectName // not an edge connector + || drag.source.baseType != inputDragTarget.baseType // not the same base type + || drag.source.nodeItem == inputDragTarget.nodeItem // connection between attributes of the same node + || inputDragTarget.attribute.isLink // already connected attribute + || (drag.source.isList && !inputDragTarget.isList) // connection between a list and a simple attribute + || (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children + || drag.source.connectorType == "input" // refuse to connect an "input pin" on another one (input attr can be connected to input attr, but not the graphical pin) + ) { + // Refuse attributes connection drag.accepted = false } inputDropArea.acceptableDrop = drag.accepted @@ -112,7 +114,8 @@ RowLayout { readonly property string connectorType: "input" readonly property alias attribute: root.attribute readonly property alias nodeItem: root.nodeItem - readonly property bool isOutput: attribute && attribute.isOutput + readonly property bool isOutput: attribute.isOutput + readonly property string baseType: attribute.baseType readonly property alias isList: root.isList property bool dragAccepted: false anchors.verticalCenter: parent.verticalCenter @@ -219,15 +222,17 @@ RowLayout { keys: [outputDragTarget.objectName] onEntered: { - // Filter drops: - if( drag.source.objectName != outputDragTarget.objectName // not an edge connector - || drag.source.nodeItem == outputDragTarget.nodeItem // connection between attributes of the same node - || drag.source.attribute.isLink // already connected attribute - || (!drag.source.isList && outputDragTarget.isList) // connection between a list and a simple attribute - || (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children - || drag.source.connectorType == "output" - ) + // Check if attributes are compatible to create a valid connection + if( drag.source.objectName != outputDragTarget.objectName // not an edge connector + || drag.source.baseType != outputDragTarget.baseType // not the same base type + || drag.source.nodeItem == outputDragTarget.nodeItem // connection between attributes of the same node + || drag.source.attribute.isLink // already connected attribute + || (!drag.source.isList && outputDragTarget.isList) // connection between a list and a simple attribute + || (drag.source.isList && childrenRepeater.count) // source/target are lists but target already has children + || drag.source.connectorType == "output" // refuse to connect an output pin on another one + ) { + // Refuse attributes connection drag.accepted = false } outputDropArea.acceptableDrop = drag.accepted @@ -249,6 +254,7 @@ RowLayout { readonly property alias nodeItem: root.nodeItem readonly property bool isOutput: attribute.isOutput readonly property alias isList: root.isList + readonly property string baseType: attribute.baseType property bool dropAccepted: false anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter