Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
04a9fd5
[desc] Add classes to manage internal attributes based on a node's type
cbentejac Jan 13, 2026
98f18ba
[tests] test_compatibility: Update test case for `InputNode` with no …
cbentejac Jan 19, 2026
35de24d
[core] node: Add properties for new internal attributes
cbentejac Jan 13, 2026
888c5f7
[core] node: Add new `BackdropNode` class
cbentejac Jan 13, 2026
2058ca5
[core] node: `MrNodeType.BACKDROP` is incomputable
cbentejac Jan 14, 2026
732c8b5
[core] nodeFactory: Add method to choose correct node constructor
cbentejac Jan 13, 2026
092c321
[core] Use method to select correct node constructor
cbentejac Jan 13, 2026
3a36c4e
[nodes] Add `Backdrop` node
cbentejac Jan 13, 2026
d32025b
[components] geom2D: Add `rectRectFullIntersect` slot
cbentejac Jan 14, 2026
adf6d1d
[GraphEditor] Add component for Backdrop nodes
cbentejac Jan 13, 2026
f2a6085
[GraphEditor] GraphEditor: Add loader for node delegate and `Backdrop…
cbentejac Jan 13, 2026
f16b42e
[GraphEditor] Node: Add `isBackdropNode` property
cbentejac Jan 14, 2026
91fe325
[Controls] DelegateSelectionBox: Handle backdrops and use correct acc…
cbentejac Jan 14, 2026
7a481ed
[GraphEditor] NodeEditor: Correctly handle tab index for backdrops
cbentejac Jan 14, 2026
e77931b
[ui] graph: Add slots to resize `Backdrop` nodes
cbentejac Jan 14, 2026
b47e476
[GraphEditor] Backdrop: Harmonize code and comments
cbentejac Jan 14, 2026
2bf58f8
[GraphEditor] GraphEditor: Stop using semicolons for the `Node` compo…
cbentejac Jan 14, 2026
f4ab2aa
[GraphEditor] Backdrop: Wrap comments to the backdrop's size
cbentejac Jan 19, 2026
c84cbee
[GraphEditor] Backdrop: Add actual resizing support
cbentejac Jan 19, 2026
5f39011
[GraphEditor] Backdrop: Handle animations and backdrop attachment to …
cbentejac Jan 19, 2026
f05d1df
[GraphEditor] GraphEditor: Stop using semicolons and harmonize the file
cbentejac Jan 19, 2026
66eba60
[Controls] DelegateSelectionBox: Ensure a child node cannot be pushed…
cbentejac Jan 19, 2026
8c3e751
[GraphEditor] Clean-up backdrop-related code
cbentejac Jan 19, 2026
796d5a7
[Controls] NodeActions: Use correct accessor to items in `nodeRepeater`
cbentejac Jan 27, 2026
378b913
[graph] Exclude non-computable from the list of nodes to compute
cbentejac Jan 28, 2026
cbfa385
[GraphEditor] Use correct accessors for `nodeRepeaters` and clean-up
cbentejac Jan 29, 2026
71df225
[GraphEditor] Backdrop: Add resize option on the bottom-right corner
cbentejac Jan 29, 2026
9f11044
[core] graphIO: Fix serialization for nodes with no inputs
cbentejac Jan 29, 2026
ee39ee3
[GraphEditor] Backdrop: Add eliding on the backdrop's comment
cbentejac Jan 29, 2026
313a1da
[GraphEditor] Fix the selection mode when `Ctrl + Click` on a backdrop
cbentejac Jan 29, 2026
ef186d9
[tests] test_nodes: Add test for `BackdropNodes`
cbentejac Feb 2, 2026
a4a73fa
[core] Add `fontColor` internal attribute and its associated property
cbentejac Feb 2, 2026
5435e00
[GraphEditor] Backdrop: Use user-set color for the comment's font
cbentejac Feb 2, 2026
81b20e4
[tests] test_nodes: Update tests on `BackdropNodes` to include `fontC…
cbentejac Feb 2, 2026
d1f0f83
[GraphEditor] AttributeItemDelegate: Fix component for `ColorParam`
cbentejac Feb 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion meshroom/core/desc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@
StaticNodeSize,
)
from .node import (
MrNodeType,
AVCommandLineNode,
BaseNode,
BackdropNode,
CommandLineNode,
InitNode,
InputNode,
InternalAttributesFactory,
MrNodeType,
Node,
)
139 changes: 113 additions & 26 deletions meshroom/core/desc/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from meshroom.core.utils import VERBOSE_LEVEL

from .computation import Level, StaticNodeSize
from .attribute import StringParam, ColorParam, ChoiceParam
from .attribute import Attribute, ChoiceParam, ColorParam, IntParam, StringParam

_MESHROOM_ROOT = Path(meshroom.__file__).parent.parent.as_posix()
_MESHROOM_COMPUTE = (Path(_MESHROOM_ROOT) / "bin" / "meshroom_compute").as_posix()
Expand Down Expand Up @@ -56,29 +56,11 @@ class MrNodeType(enum.Enum):
NODE = enum.auto()
COMMANDLINE = enum.auto()
INPUT = enum.auto()
BACKDROP = enum.auto()


class BaseNode(object):
"""
"""
cpu = Level.NORMAL
gpu = Level.NONE
ram = Level.NORMAL
packageName = ""
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
),
class InternalAttributesFactory:
BASIC = [
StringParam(
name="comment",
label="Comments",
Expand Down Expand Up @@ -113,6 +95,84 @@ class BaseNode(object):
invalidate=False,
)
]

INVALIDATION = [
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
),
]

RESIZABLE = [
IntParam(
name="fontSize",
label="Font Size",
description="Size of the font used to display the comments.",
value=12,
range=(6, 100, 1),
invalidate=False,
),
ColorParam(
name="fontColor",
label="Font Color",
description="Color of the font used to display the comments (SVG name or hexadecimal code).",
value="",
invalidate=False,
),
IntParam(
name="nodeWidth",
label="Node Width",
description="Width of the node in the graph editor.",
value=600,
range=None,
invalidate=False,
enabled=False, # Hidden
),
IntParam(
name="nodeHeight",
label="Node Height",
description="Height of the node in the graph editor.",
value=400,
range=None,
invalidate=False,
enabled=False, # Hidden
),
]

@classmethod
def getInternalAttributes(cls, mrNodeType: MrNodeType) -> list[Attribute]:
paramMap = {
MrNodeType.NONE: cls.BASIC,
MrNodeType.BASENODE: cls.INVALIDATION + cls.BASIC,
MrNodeType.NODE: cls.INVALIDATION + cls.BASIC,
MrNodeType.COMMANDLINE: cls.INVALIDATION + cls.BASIC,
MrNodeType.INPUT: cls.BASIC,
MrNodeType.BACKDROP: cls.BASIC + cls.RESIZABLE,
}

return paramMap.get(mrNodeType)


class BaseNode(object):
"""
"""
cpu = Level.NORMAL
gpu = Level.NONE
ram = Level.NORMAL
packageName = ""
_mrNodeType: MrNodeType = MrNodeType.BASENODE

internalInputs = InternalAttributesFactory.getInternalAttributes(_mrNodeType)

inputs = []
outputs = []
size = StaticNodeSize(1)
Expand All @@ -130,7 +190,7 @@ def __init__(self):
self.sourceCodeFolder = Path(getfile(self.__class__)).parent.resolve().as_posix()

def getMrNodeType(self):
return MrNodeType.BASENODE
return self._mrNodeType

def upgradeAttributeValues(self, attrValues, fromVersion):
return attrValues
Expand Down Expand Up @@ -286,24 +346,50 @@ class InputNode(BaseNode):
"""
Node that does not need to be processed, it is just a placeholder for inputs.
"""
_mrNodeType: MrNodeType = MrNodeType.INPUT
internalInputs = InternalAttributesFactory.getInternalAttributes(_mrNodeType)

def __init__(self):
super(InputNode, self).__init__()

def getMrNodeType(self):
return MrNodeType.INPUT
return self._mrNodeType

def processChunk(self, chunk):
pass

def process(self, node):
pass

class BackdropNode(BaseNode):
"""
Node that does not need to be processed, it is just a placeholder for grouping other nodes.
"""
_mrNodeType: MrNodeType = MrNodeType.BACKDROP
internalInputs = InternalAttributesFactory.getInternalAttributes(_mrNodeType)

def __init__(self):
super(BackdropNode, self).__init__()

def getMrNodeType(self):
return self._mrNodeType

def processChunk(self, chunk):
pass

def process(self, node):
pass


class Node(BaseNode):
pythonExecutable = "python"
_mrNodeType: MrNodeType = MrNodeType.NODE

def __init__(self):
super(Node, self).__init__()

def getMrNodeType(self):
return MrNodeType.NODE
return self._mrNodeType

def processChunkInEnvironment(self, chunk):
meshroomComputeCmd = f"{chunk.node.nodeDesc.pythonExecutable} {_MESHROOM_COMPUTE}" + \
Expand All @@ -326,12 +412,13 @@ class CommandLineNode(BaseNode):
commandLine = "" # need to be defined on the node
parallelization = None
commandLineRange = ""
_mrNodeType: MrNodeType = MrNodeType.COMMANDLINE

def __init__(self):
super(CommandLineNode, self).__init__()

def getMrNodeType(self):
return MrNodeType.COMMANDLINE
return self._mrNodeType

def buildCommandLine(self, chunk) -> str:
cmdLineVars = chunk.node.createCmdLineVars()
Expand Down
4 changes: 2 additions & 2 deletions meshroom/core/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from meshroom.core.exception import GraphCompatibilityError, InvalidEdgeError, StopGraphVisit, StopBranchVisit, CyclicDependencyError
from meshroom.core.graphIO import GraphIO, GraphSerializer, TemplateGraphSerializer, PartialGraphSerializer
from meshroom.core.node import BaseNode, Status, Node, CompatibilityNode
from meshroom.core.nodeFactory import nodeFactory
from meshroom.core.nodeFactory import nodeFactory, getNodeConstructor
from meshroom.core.mtyping import PathLike
from meshroom.core.submitter import BaseSubmittedJob, jobManager

Expand Down Expand Up @@ -693,7 +693,7 @@ def addNewNode(
if name and name in self._nodes.keys():
name = self._createUniqueNodeName(name)

node = self.addNode(Node(nodeType, position=position, **kwargs), uniqueName=name)
node = self.addNode(getNodeConstructor(nodeType, position=position, **kwargs), uniqueName=name)
node.updateInternals()
self._triggerNodeCreatedCallback([node])
return node
Expand Down
5 changes: 3 additions & 2 deletions meshroom/core/graphIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,9 @@ def serializeNode(self, node: Node) -> dict:

# Override input attributes with custom serialization logic, to handle attributes
# connected to nodes that are not in the list of nodes to serialize.
for attributeName in nodeData["inputs"]:
nodeData["inputs"][attributeName] = self._serializeAttribute(node.attribute(attributeName))
if nodeData.get("inputs", None):
for attributeName in nodeData["inputs"]:
nodeData["inputs"][attributeName] = self._serializeAttribute(node.attribute(attributeName))

# Clear UID for non-compatibility nodes, as the custom attribute serialization
# can be impacting the UID by removing connections to missing nodes.
Expand Down
Loading
Loading