From eb1a0faf97d211842adbf3dd86c48fbefcc772e4 Mon Sep 17 00:00:00 2001 From: Aurore LAFAURIE Date: Wed, 24 Apr 2024 15:29:08 +0200 Subject: [PATCH 1/5] [core] PushButton attribute implemented Add PushButtonParam class and implement onAttributeClicked method --- meshroom/core/attribute.py | 9 +++++++++ meshroom/core/desc.py | 9 +++++++++ meshroom/core/node.py | 13 +++++++++++++ 3 files changed, 31 insertions(+) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index 43d7b4c7..5d205d87 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -31,6 +31,8 @@ def attributeFactory(description, value, isOutput, node, root=None, parent=None) cls = ListAttribute elif isinstance(description, desc.ChoiceParam): cls = ChoiceParam + elif isinstance(description, desc.PushButtonParam): + cls = PushButtonParam else: cls = Attribute attr = cls(node, description, isOutput, root, parent) @@ -398,6 +400,13 @@ def raiseIfLink(func): return func(attr, *args, **kwargs) return wrapper +class PushButtonParam(Attribute): + def __init__(self, node, attributeDesc, isOutput, root=None, parent=None): + super(PushButtonParam, self).__init__(node, attributeDesc, isOutput, root, parent) + + @Slot() + def clicked(self): + self.node.onAttributeClicked(self) class ChoiceParam(Attribute): diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index 359377e9..e0c1bba8 100644 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -301,6 +301,15 @@ class FloatParam(Param): range = Property(VariantList, lambda self: self._range, constant=True) +class PushButtonParam(Param): + """ + """ + def __init__(self, name, label, description, uid, group='allParams', advanced=False, semantic='', enabled=True, visible=True): + super(PushButtonParam, self).__init__(name=name, label=label, description=description, value="", uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled, visible=visible) + def validateValue(self, value): + pass + def checkValueTypes(self): + pass class ChoiceParam(Param): """ diff --git a/meshroom/core/node.py b/meshroom/core/node.py index c7287a23..8f782e07 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -892,6 +892,19 @@ class BaseNode(BaseObject): if callable(m): m(self) + def onAttributeClicked(self, attr): + """ When an attribute is clicked, a specific function can be defined in the descriptor and be called. + + Args: + attr (Attribute): attribute that has been clicked + """ + paramName = attr.name[:1].upper() + attr.name[1:] + methodName = f'on{paramName}Clicked' + if hasattr(self.nodeDesc, methodName): + m = getattr(self.nodeDesc, methodName) + if callable(m): + m(self) + def updateInternals(self, cacheDir=None): """ Update Node's internal parameters and output attributes. From c5f440b8a8275321d6ef964e37ac18cb2c910f6d Mon Sep 17 00:00:00 2001 From: Aurore LAFAURIE Date: Wed, 24 Apr 2024 15:29:45 +0200 Subject: [PATCH 2/5] [ui] Add PushButton component to AttributeItemDelegate --- .../ui/qml/GraphEditor/AttributeItemDelegate.qml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml index 8a86b4b2..c77ff71f 100644 --- a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml +++ b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml @@ -179,6 +179,8 @@ RowLayout { sourceComponent: { switch (attribute.type) { + case "PushButtonParam": + return pushButton_component case "ChoiceParam": return attribute.desc.exclusive ? comboBox_component : multiChoice_component case "IntParam": return slider_component @@ -203,6 +205,17 @@ RowLayout { } } + Component { + id: pushButton_component + Button { + text: attribute.desc.label + enabled: root.editable + onClicked: { + attribute.clicked() + } + } + } + Component { id: textField_component TextField { From bb8b54455057ce66000fcb30c649db431abef216 Mon Sep 17 00:00:00 2001 From: Aurore LAFAURIE Date: Thu, 25 Apr 2024 17:01:54 +0200 Subject: [PATCH 3/5] [core] PushButton Description Conflict handled for function descripted --- meshroom/core/attribute.py | 9 +++++++++ meshroom/core/desc.py | 2 +- meshroom/core/node.py | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index 5d205d87..47d725be 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -6,6 +6,7 @@ import re import weakref import types import logging +import inspect from collections.abc import Iterable, Sequence from string import Template @@ -404,6 +405,14 @@ class PushButtonParam(Attribute): def __init__(self, node, attributeDesc, isOutput, root=None, parent=None): super(PushButtonParam, self).__init__(node, attributeDesc, isOutput, root, parent) + def getExportValue(self): + """ Return the function defined of the PushButtonParam """ + paramName = self.name[:1].upper() + self.name[1:] + methodName = f'on{paramName}Clicked' + if hasattr(self.node.nodeDesc, methodName): + return inspect.getsource(getattr(self.node.nodeDesc, methodName)) + return f'def {methodName}:\n pass' + @Slot() def clicked(self): self.node.onAttributeClicked(self) diff --git a/meshroom/core/desc.py b/meshroom/core/desc.py index e0c1bba8..14ddd80b 100644 --- a/meshroom/core/desc.py +++ b/meshroom/core/desc.py @@ -305,7 +305,7 @@ class PushButtonParam(Param): """ """ def __init__(self, name, label, description, uid, group='allParams', advanced=False, semantic='', enabled=True, visible=True): - super(PushButtonParam, self).__init__(name=name, label=label, description=description, value="", uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled, visible=visible) + super(PushButtonParam, self).__init__(name=name, label=label, description=description, value=None, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled, visible=visible) def validateValue(self, value): pass def checkValueTypes(self): diff --git a/meshroom/core/node.py b/meshroom/core/node.py index 8f782e07..e725c363 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -14,6 +14,7 @@ import types import uuid from collections import defaultdict, namedtuple from enum import Enum +import inspect import meshroom from meshroom.common import Signal, Variant, Property, BaseObject, Slot, ListModel, DictModel @@ -1704,6 +1705,13 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False): # verify that all inputs match their descriptions for attrName, value in inputs.items(): + paramName = attrName[:1].upper() + attrName[1:] + functionName = f'on{paramName}Clicked' + if hasattr(nodeDesc, functionName): + m = inspect.getsource(getattr(nodeDesc, functionName)) + if value != m: + compatibilityIssue = CompatibilityIssue.DescriptionConflict + break if not CompatibilityNode.attributeDescFromName(nodeDesc.inputs, attrName, value): compatibilityIssue = CompatibilityIssue.DescriptionConflict break From 55c657dc1dec06ab9851bbfbe01fa82b2b9233cc Mon Sep 17 00:00:00 2001 From: Aurore LAFAURIE Date: Thu, 25 Apr 2024 17:03:33 +0200 Subject: [PATCH 4/5] [core/ui] Modifiable label and description of node available --- meshroom/core/attribute.py | 26 ++++++++++++++++++- .../qml/GraphEditor/AttributeItemDelegate.qml | 4 +-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index 47d725be..aa03f8d9 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -68,6 +68,7 @@ class Attribute(BaseObject): self._label = attributeDesc.label self._enabled = True self._validValue = True + self._description = attributeDesc.description # invalidation value for output attributes self._invalidationValue = "" @@ -212,6 +213,21 @@ class Attribute(BaseObject): self.valueChanged.emit() self.validValueChanged.emit() + def _set_label(self, label): + if self._label == label: + return + self._label = label + self.labelChanged.emit() + + def _get_description(self): + return self._description + + def _set_description(self, desc): + if self._description == desc: + return + self._description = desc + self.descriptionChanged.emit() + def upgradeValue(self, exportedValue): self._set_value(exportedValue) @@ -364,14 +380,22 @@ class Attribute(BaseObject): fullName = Property(str, getFullName, constant=True) fullNameToNode = Property(str, getFullNameToNode, constant=True) fullNameToGraph = Property(str, getFullNameToGraph, constant=True) - label = Property(str, getLabel, constant=True) + labelChanged = Signal() + label = Property(str, getLabel, _set_label, notify=labelChanged) fullLabel = Property(str, getFullLabel, constant=True) fullLabelToNode = Property(str, getFullLabelToNode, constant=True) fullLabelToGraph = Property(str, getFullLabelToGraph, constant=True) type = Property(str, getType, constant=True) baseType = Property(str, getType, constant=True) isReadOnly = Property(bool, _isReadOnly, constant=True) + + # description of the attribute + descriptionChanged = Signal() + description = Property(str, _get_description, _set_description, notify=descriptionChanged) + + # definition of the attribute desc = Property(desc.Attribute, lambda self: self.attributeDesc, constant=True) + valueChanged = Signal() value = Property(Variant, _get_value, _set_value, notify=valueChanged) valueStr = Property(Variant, getValueStr, notify=valueChanged) diff --git a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml index c77ff71f..f7634886 100644 --- a/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml +++ b/meshroom/ui/qml/GraphEditor/AttributeItemDelegate.qml @@ -78,7 +78,7 @@ RowLayout { var tooltip = "" if (!object.validValue && object.desc.errorMessage !== "") tooltip += "Error: " + Format.plainToHtml(object.desc.errorMessage) + "

" - tooltip += "" + object.desc.name + "
" + Format.plainToHtml(object.desc.description) + tooltip += "" + object.desc.name + "
" + Format.plainToHtml(object.description) return tooltip } visible: parameterMA.containsMouse @@ -208,7 +208,7 @@ RowLayout { Component { id: pushButton_component Button { - text: attribute.desc.label + text: attribute.label enabled: root.editable onClicked: { attribute.clicked() From 862c5506a98ed21f7b7c2e79b8e2b5d9e1cc5791 Mon Sep 17 00:00:00 2001 From: Aurore LAFAURIE Date: Mon, 13 May 2024 15:11:27 +0200 Subject: [PATCH 5/5] [core] Remove of saving PushButton behavior --- meshroom/core/attribute.py | 9 --------- meshroom/core/node.py | 10 +--------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/meshroom/core/attribute.py b/meshroom/core/attribute.py index aa03f8d9..8ad92892 100644 --- a/meshroom/core/attribute.py +++ b/meshroom/core/attribute.py @@ -6,7 +6,6 @@ import re import weakref import types import logging -import inspect from collections.abc import Iterable, Sequence from string import Template @@ -428,14 +427,6 @@ def raiseIfLink(func): class PushButtonParam(Attribute): def __init__(self, node, attributeDesc, isOutput, root=None, parent=None): super(PushButtonParam, self).__init__(node, attributeDesc, isOutput, root, parent) - - def getExportValue(self): - """ Return the function defined of the PushButtonParam """ - paramName = self.name[:1].upper() + self.name[1:] - methodName = f'on{paramName}Clicked' - if hasattr(self.node.nodeDesc, methodName): - return inspect.getsource(getattr(self.node.nodeDesc, methodName)) - return f'def {methodName}:\n pass' @Slot() def clicked(self): diff --git a/meshroom/core/node.py b/meshroom/core/node.py index e725c363..c56b5b3a 100644 --- a/meshroom/core/node.py +++ b/meshroom/core/node.py @@ -14,7 +14,6 @@ import types import uuid from collections import defaultdict, namedtuple from enum import Enum -import inspect import meshroom from meshroom.common import Signal, Variant, Property, BaseObject, Slot, ListModel, DictModel @@ -1686,7 +1685,7 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False): # do not perform that check for internal attributes because there is no point in # raising compatibility issues if their number differs: in that case, it is only useful # if some internal attributes do not exist or are invalid - if not template and (sorted([attr.name for attr in nodeDesc.inputs]) != sorted(inputs.keys()) or \ + if not template and (sorted([attr.name for attr in nodeDesc.inputs if not isinstance(attr, desc.PushButtonParam)]) != sorted(inputs.keys()) or \ sorted([attr.name for attr in nodeDesc.outputs]) != sorted(outputs.keys())): compatibilityIssue = CompatibilityIssue.DescriptionConflict @@ -1705,13 +1704,6 @@ def nodeFactory(nodeDict, name=None, template=False, uidConflict=False): # verify that all inputs match their descriptions for attrName, value in inputs.items(): - paramName = attrName[:1].upper() + attrName[1:] - functionName = f'on{paramName}Clicked' - if hasattr(nodeDesc, functionName): - m = inspect.getsource(getattr(nodeDesc, functionName)) - if value != m: - compatibilityIssue = CompatibilityIssue.DescriptionConflict - break if not CompatibilityNode.attributeDescFromName(nodeDesc.inputs, attrName, value): compatibilityIssue = CompatibilityIssue.DescriptionConflict break