Merge pull request #2382 from alicevision/dev/pushButtonAttribute

[core/ui] Add support for PushButton attribute
This commit is contained in:
Fabien Castan 2024-05-17 20:11:40 +02:00 committed by GitHub
commit d9b4b26a69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 71 additions and 3 deletions

View file

@ -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)
@ -65,6 +67,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 = ""
@ -210,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)
@ -362,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)
@ -399,6 +425,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):

View file

@ -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=None, uid=uid, group=group, advanced=advanced, semantic=semantic, enabled=enabled, visible=visible)
def validateValue(self, value):
pass
def checkValueTypes(self):
pass
class ChoiceParam(Param):
"""

View file

@ -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.
@ -1685,7 +1698,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

View file

@ -78,7 +78,7 @@ RowLayout {
var tooltip = ""
if (!object.validValue && object.desc.errorMessage !== "")
tooltip += "<i><b>Error: </b>" + Format.plainToHtml(object.desc.errorMessage) + "</i><br><br>"
tooltip += "<b>" + object.desc.name + "</b><br>" + Format.plainToHtml(object.desc.description)
tooltip += "<b>" + object.desc.name + "</b><br>" + Format.plainToHtml(object.description)
return tooltip
}
visible: parameterMA.containsMouse
@ -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.label
enabled: root.editable
onClicked: {
attribute.clicked()
}
}
}
Component {
id: textField_component
TextField {