mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-04-29 10:17:27 +02:00
[core] Handle attribute valueChanged callback at the Node level
Move the attributeChanged callback logic within Node, as this is a Node level mecanism (callbacks being declared on the node desc). This commit also moves the attribute valueChanged signal outside of the Attribute's constructor. This seems to be the root cause to undesired side-effects breaking Qt's evaluation system, data model access and consequently Meshroom's UI.
This commit is contained in:
parent
e73e8f2fd7
commit
7fdb5cc734
2 changed files with 35 additions and 15 deletions
|
@ -25,11 +25,14 @@ def attributeFactory(description, value, isOutput, node, root=None, parent=None)
|
||||||
root: (optional) parent Attribute (must be ListAttribute or GroupAttribute)
|
root: (optional) parent Attribute (must be ListAttribute or GroupAttribute)
|
||||||
parent (BaseObject): (optional) the parent BaseObject if any
|
parent (BaseObject): (optional) the parent BaseObject if any
|
||||||
"""
|
"""
|
||||||
attr = description.instanceType(node, description, isOutput, root, parent)
|
attr: Attribute = description.instanceType(node, description, isOutput, root, parent)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
attr._set_value(value, emitSignals=False)
|
attr._set_value(value, emitSignals=False)
|
||||||
else:
|
else:
|
||||||
attr.resetToDefaultValue(emitSignals=False)
|
attr.resetToDefaultValue(emitSignals=False)
|
||||||
|
|
||||||
|
attr.valueChanged.connect(lambda attr=attr: node._onAttributeChanged(attr))
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,7 +70,6 @@ class Attribute(BaseObject):
|
||||||
self._value = None
|
self._value = None
|
||||||
self.initValue()
|
self.initValue()
|
||||||
|
|
||||||
self.valueChanged.connect(self.onChanged)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def node(self):
|
def node(self):
|
||||||
|
|
|
@ -14,6 +14,7 @@ import types
|
||||||
import uuid
|
import uuid
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from typing import Callable, Optional
|
||||||
|
|
||||||
import meshroom
|
import meshroom
|
||||||
from meshroom.common import Signal, Variant, Property, BaseObject, Slot, ListModel, DictModel
|
from meshroom.common import Signal, Variant, Property, BaseObject, Slot, ListModel, DictModel
|
||||||
|
@ -929,25 +930,42 @@ class BaseNode(BaseObject):
|
||||||
def _updateChunks(self):
|
def _updateChunks(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def onAttributeChanged(self, attr):
|
def _getAttributeChangedCallback(self, attr: Attribute) -> Optional[Callable]:
|
||||||
""" When an attribute changed, a specific function can be defined in the descriptor and be called.
|
"""Get the node descriptor-defined value changed callback associated to `attr` if any."""
|
||||||
|
|
||||||
|
attrCapitalizedName = attr.name[:1].upper() + attr.name[1:]
|
||||||
|
callbackName = f"on{attrCapitalizedName}Changed"
|
||||||
|
|
||||||
|
callback = getattr(self.nodeDesc, callbackName, None)
|
||||||
|
return callback if callback and callable(callback) else None
|
||||||
|
|
||||||
|
def _onAttributeChanged(self, attr: Attribute):
|
||||||
|
"""
|
||||||
|
When an attribute value has changed, a specific function can be defined in the descriptor and be called.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
attr (Attribute): attribute that has changed
|
attr: The Attribute that has changed.
|
||||||
"""
|
"""
|
||||||
# Call the specific function if it exists in the node implementation
|
|
||||||
paramName = attr.name[:1].upper() + attr.name[1:]
|
if self.isCompatibilityNode:
|
||||||
methodName = f'on{paramName}Changed'
|
# Compatibility nodes are not meant to be updated.
|
||||||
if hasattr(self.nodeDesc, methodName):
|
return
|
||||||
m = getattr(self.nodeDesc, methodName)
|
|
||||||
if callable(m):
|
if attr.isOutput and not self.isInputNode:
|
||||||
m(self)
|
# Ignore changes on output attributes for non-input nodes
|
||||||
|
# as they are updated during the node's computation.
|
||||||
|
# And we do not want notifications during the graph processing.
|
||||||
|
return
|
||||||
|
|
||||||
|
callback = self._getAttributeChangedCallback(attr)
|
||||||
|
|
||||||
|
if callback:
|
||||||
|
callback(self)
|
||||||
|
|
||||||
if self.graph:
|
if self.graph:
|
||||||
# If we are in a graph, propagate the notification to the connected output attributes
|
# If we are in a graph, propagate the notification to the connected output attributes
|
||||||
outEdges = self.graph.outEdges(attr)
|
for edge in self.graph.outEdges(attr):
|
||||||
for edge in outEdges:
|
edge.dst.node._onAttributeChanged(edge.dst)
|
||||||
edge.dst.onChanged()
|
|
||||||
|
|
||||||
def onAttributeClicked(self, attr):
|
def onAttributeClicked(self, attr):
|
||||||
""" When an attribute is clicked, a specific function can be defined in the descriptor and be called.
|
""" When an attribute is clicked, a specific function can be defined in the descriptor and be called.
|
||||||
|
|
Loading…
Add table
Reference in a new issue