Skip to content

Commit

Permalink
[core] Node: Representation of a Backdrop node
Browse files Browse the repository at this point in the history
The core Node is now able to distinguish a backdrop node which
  • Loading branch information
waaake committed Oct 22, 2024
1 parent 88f9d4b commit a817bbe
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 8 deletions.
78 changes: 78 additions & 0 deletions meshroom/core/desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,22 @@ class Node(object):
value="",
invalidate=False,
),
FloatParam(
name="nodeWidth",
label="Node Width",
description="The Node's Width.",
value=160,
range=None,
enabled=False # Hidden always
),
FloatParam(
name="nodeHeight",
label="Node Height",
description="The Node's Height.",
value=120,
range=None,
enabled=False # Hidden always
),
ColorParam(
name="color",
label="Color",
Expand Down Expand Up @@ -779,6 +795,68 @@ def __init__(self):
def processChunk(self, chunk):
pass

def stopProcess(self, chunk):
pass


class Backdrop(InputNode):
""" A Backdrop for other nodes.
"""

# The internal inputs' of Backdrop Node needs a Integer Field to determine the font size for the comment
internalInputs = [
StringParam(
name="invalidation",
label="Invalidation Message",
description="A message that will invalidate the node's output folder.\n"
"This is useful for development, we can invalidate the output of the node when we modify the code.\n"
"It is displayed in bold font in the invalidation/comment messages tooltip.",
value="",
semantic="multiline",
advanced=True,
uidIgnoreValue="", # If the invalidation string is empty, it does not participate to the node's UID
),
StringParam(
name="comment",
label="Comments",
description="User comments describing this specific node instance.\n"
"It is displayed in regular font in the invalidation/comment messages tooltip.",
value="",
semantic="multiline",
invalidate=False,
),
IntParam(
name="fontSize",
label="Font Size",
description="The Font size for the User Comment on the Backdrop.",
value=12,
range=(6, 100, 1),
),
FloatParam(
name="nodeWidth",
label="Node Width",
description="The Backdrop Node's Width.",
value=600,
range=None,
enabled=False # Hidden always
),
FloatParam(
name="nodeHeight",
label="Node Height",
description="The Backdrop Node's Height.",
value=400,
range=None,
enabled=False # Hidden always
),
ColorParam(
name="color",
label="Color",
description="Custom color for the node (SVG name or hexadecimal code).",
value="",
invalidate=False,
)
]


class CommandLineNode(Node):
"""
Expand Down
86 changes: 81 additions & 5 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class Status(Enum):
SUCCESS = 6
INPUT = 7 # Special status for input nodes

BACKDROP = 8 # Backdrops are just well.. backdrops


class ExecMode(Enum):
NONE = 0
Expand Down Expand Up @@ -570,6 +572,60 @@ def getComment(self):
return self.internalAttribute("comment").value
return ""

def getFontSize(self):
""" Gets the Font Size of the node comment.
Returns:
int: The font size from the node if it exists, else 12 as default.
"""
if self.hasInternalAttribute("fontSize"):
return self.internalAttribute("fontSize").value

# Default to 12
return 12

def getNodeWidth(self):
""" Gets the Width of the node from the internal attribute.
Returns:
int: The Width from the node if the attribute exists, else 160 as default.
"""
if self.hasInternalAttribute("nodeWidth"):
return self.internalAttribute("nodeWidth").value

# Default to 160
return 160

def getNodeHeight(self):
""" Gets the Height of the node from the internal attribute.
Returns:
int: The Height from the node if the attribute exists, else 120 as default.
"""
if self.hasInternalAttribute("nodeHeight"):
return self.internalAttribute("nodeHeight").value

# Default to 120
return 120

def setNodeWidth(self, width):
""" Gets the Width of the node from the internal attribute.
Returns:
int: The Width from the node if the attribute exists, else 160 as default.
"""
if self.hasInternalAttribute("nodeWidth"):
self.internalAttribute("nodeWidth").value = width

def setNodeHeight(self, height):
""" Gets the Height of the node from the internal attribute.
Returns:
int: The Height from the node if the attribute exists, else 120 as default.
"""
if self.hasInternalAttribute("nodeHeight"):
self.internalAttribute("nodeHeight").value = height

@Slot(str, result=str)
def nameToLabel(self, name):
"""
Expand Down Expand Up @@ -817,7 +873,7 @@ def nbParallelizationBlocks(self):

def hasStatus(self, status):
if not self._chunks:
return (status == Status.INPUT)
return (status in (Status.BACKDROP, Status.INPUT))
for chunk in self._chunks:
if chunk.status.status != status:
return False
Expand All @@ -829,7 +885,13 @@ def _isComputed(self):
return self.hasStatus(Status.SUCCESS)

def _isComputable(self):
return self.getGlobalStatus() != Status.INPUT
# A node is not considered computable if it is a Backdrop or an inputNode
return self.getGlobalStatus() not in (Status.BACKDROP, Status.INPUT)

def _isBackdrop(self):
""" If this is a backdrop node?
"""
return self.getGlobalStatus() == Status.BACKDROP

def clearData(self):
""" Delete this Node internal folder.
Expand Down Expand Up @@ -1126,8 +1188,13 @@ def getGlobalStatus(self):
Returns:
Status: the node global status
"""
# A Backdrop Node instance
if isinstance(self.nodeDesc, desc.Backdrop):
return Status.BACKDROP

if isinstance(self.nodeDesc, desc.InputNode):
return Status.INPUT

chunksStatus = [chunk.status.status for chunk in self._chunks]

anyOf = (Status.ERROR, Status.STOPPED, Status.KILLED,
Expand Down Expand Up @@ -1323,7 +1390,7 @@ def hasSequenceOutputAttribute(self):
False otherwise.
"""
for attr in self._attributes:
if attr.enabled and attr.isOutput and (attr.desc.semantic == "sequence" or
if attr.enabled and attr.isOutput and (attr.desc.semantic == "sequence" or
attr.desc.semantic == "imageList"):
return True
return False
Expand Down Expand Up @@ -1356,6 +1423,12 @@ def has3DOutputAttribute(self):
color = Property(str, getColor, notify=internalAttributesChanged)
invalidation = Property(str, getInvalidationMessage, notify=internalAttributesChanged)
comment = Property(str, getComment, notify=internalAttributesChanged)
fontSize = Property(int, getFontSize, notify=internalAttributesChanged)

# Node Dimensions
nodeWidth = Property(float, getNodeWidth, notify=internalAttributesChanged)
nodeHeight = Property(float, getNodeHeight, notify=internalAttributesChanged)

internalFolderChanged = Signal()
internalFolder = Property(str, internalFolder.fget, notify=internalFolderChanged)
valuesFile = Property(str, valuesFile.fget, notify=internalFolderChanged)
Expand All @@ -1381,6 +1454,7 @@ def has3DOutputAttribute(self):
isExternal = Property(bool, isExtern, notify=globalExecModeChanged)
isComputed = Property(bool, _isComputed, notify=globalStatusChanged)
isComputable = Property(bool, _isComputable, notify=globalStatusChanged)
isBackdrop = Property(bool, _isBackdrop, notify=globalStatusChanged)
aliveChanged = Signal()
alive = Property(bool, alive.fget, alive.fset, notify=aliveChanged)
lockedChanged = Signal()
Expand Down Expand Up @@ -1526,8 +1600,10 @@ def toDict(self):

def _updateChunks(self):
""" Update Node's computation task splitting into NodeChunks based on its description """
if isinstance(self.nodeDesc, desc.InputNode):
# No chunks for Input and Backdrop nodes as they don't need any processing
if isinstance(self.nodeDesc, (desc.InputNode, desc.Backdrop)):
return

self.setSize(self.nodeDesc.size.computeSize(self))
if self.isParallelized:
try:
Expand Down Expand Up @@ -1876,7 +1952,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
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 if not attr.isDynamicValue]) !=
sorted(outputs.keys())):
Expand Down
10 changes: 7 additions & 3 deletions meshroom/core/taskManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,14 @@ def checkNodesDependencies(self, graph, toNodes, context):
"""
ready = []
computed = []
inputNodes = []

# The Node which does not have processing functionality
incomputable = []

for node in toNodes:
# Input or Backdrop nodes
if not node.isComputable:
inputNodes.append(node)
incomputable.append(node)
elif context == "COMPUTATION":
if graph.canComputeTopologically(node) and graph.canSubmitOrCompute(node) % 2 == 1:
ready.append(node)
Expand All @@ -353,7 +357,7 @@ def checkNodesDependencies(self, graph, toNodes, context):
else:
raise ValueError("Argument 'context' must be: 'COMPUTATION' or 'SUBMITTING'")

if len(ready) + len(computed) + len(inputNodes) != len(toNodes):
if len(ready) + len(computed) + len(incomputable) != len(toNodes):
toNodes.clear()
toNodes.extend(ready)
return False
Expand Down

0 comments on commit a817bbe

Please sign in to comment.