This commit is contained in:
Nicolas Predella 2026-08-25 14:26:02 +03:00
parent 2bfc1ef781
commit e504e9b88e
9 changed files with 37 additions and 71 deletions

View file

@ -17,7 +17,7 @@ class SLICENODE_PathsToGcode(SliceNode):
def init(self, context):
self.add_input("SLICESOCK_Paths")
self.add_input("SLICESOCK_Intrinsics")
self.add_output("SLICESOCK_GcodeRo")
self.add_output("NodeSocketString")
def draw_buttons(self, context, layout):
assert layout
@ -53,7 +53,7 @@ class SLICENODE_GcodeBlock(SliceNode):
bl_label = "Gcode Block"
def init(self, context):
self.add_output("SLICESOCK_Gcode", "Gcode")
self.add_output("NodeSocketString", "Gcode")
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
return self.outputs['Gcode'].value
@ -66,7 +66,7 @@ class SLICENODE_AssignMetadata(SliceNode):
self.add_input("NodeSocketString", "Name")
self.add_input("NodeSocketString", "Filament Type")
self.add_input("NodeSocketString", "Printer Model")
self.add_output("SLICESOCK_GcodeRo", "Gcode")
self.add_output("NodeSocketString", "Gcode")
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
name = self.resolve("Name")
@ -86,10 +86,10 @@ class SLICENODE_GcodeRegexReplace(SliceNode):
bl_label = "Gcode Regex Replace"
def init(self, context):
self.add_input("SLICESOCK_Gcode", "Gcode")
self.add_input("NodeSocketString", "Gcode")
self.add_input("NodeSocketString", "Find")
self.add_input("NodeSocketString", "Replace")
self.add_output("SLICESOCK_GcodeRo", "Gcode")
self.add_output("NodeSocketString", "Gcode")
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
import re
@ -154,7 +154,7 @@ class SLICENODE_GcodeHelper(SliceNode):
parameters: NfStringProperty(name="Params", default="") # pyright: ignore[reportInvalidTypeForm]
def init(self, context):
self.add_output("SLICESOCK_GcodeRo")
self.add_output("NodeSocketString")
def draw_buttons(self, context, layout):
assert layout
@ -177,8 +177,8 @@ class SLICENODE_GcodeHelper(SliceNode):
@register_class
class SLICENODE_JoinGcode(SliceNodeJoiner):
bl_label = "Join Gcode"
socket_type = "SLICESOCK_Gcode"
output_socket_type = "SLICESOCK_GcodeRo"
socket_type = "NodeSocketString"
output_socket_type = "NodeSocketString"
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
from ....infra.blender.blender_slice_nodes_generic import resolve_input
@ -193,8 +193,8 @@ class SLICENODE_LoadGcode(SliceNode):
bl_label = "Load Gcode File"
def init(self, context):
self.add_input("SLICESOCK_FilePath", "Filepath")
self.add_output("SLICESOCK_GcodeRo")
self.add_input("NodeSocketString", "Filepath")
self.add_output("NodeSocketString")
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
path = self.resolve("Filepath")

View file

@ -590,10 +590,12 @@ class SLICENODE_TransformGeometry(SliceNode):
self.add_output("SLICESOCK_Geometry", "Geometry")
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
if socket_name not in ("Geometry"):
if socket_name not in ("Geometry", "Mesh"):
return None
geom_data: Any = self.resolve("Geometry")
if geom_data is None:
geom_data = self.resolve("Mesh")
if geom_data is None:
return None

View file

@ -19,8 +19,8 @@ class SLICENODE_GcodeToFile(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_input("SLICESOCK_DirPath", "Folder")
self.add_multi_socket_group("SLICESOCK_Gcode", name="Gcode")
self.add_input("NodeSocketString", "Folder")
self.add_multi_socket_group("NodeSocketString", name="Gcode")
def draw_buttons(self, context, layout):
super().draw_buttons(context, layout)
@ -73,7 +73,7 @@ class SLICENODE_GcodeToTextBlock(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_input("SLICESOCK_Gcode")
self.add_input("NodeSocketString")
def draw_buttons(self, context, layout):
super().draw_buttons(context, layout)
@ -109,7 +109,7 @@ class SLICENODE_StartPrint(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_input("SLICESOCK_Gcode")
self.add_input("NodeSocketString")
self.add_input("SLICESOCK_Printer")
def evaluate(self, operator=None):
@ -178,7 +178,7 @@ class ExecSliceNode_DatabaseSubmit(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_multi_socket_group("SLICESOCK_Gcode", name="Gcode")
self.add_multi_socket_group("NodeSocketString", name="Gcode")
def draw_buttons(self, context, layout):
super().draw_buttons(context, layout)

View file

@ -16,7 +16,7 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_input("NodeSocketString", "Name")
self.add_multi_socket_group("SLICESOCK_Gcode", name="Gcode")
self.add_multi_socket_group("NodeSocketString", name="Gcode")
def draw_buttons(self, context, layout):
super().draw_buttons(context, layout)

View file

@ -41,7 +41,7 @@ class SLICENODE_PrinterList(ExecSliceNode):
printer_names.add(name)
sock = self.inputs.get(name)
if not sock:
self.add_input("SLICESOCK_GcodeRo", name)
self.add_input("NodeSocketString", name)
# Remove stale input sockets
for sock in list(self.inputs):
@ -162,7 +162,7 @@ class SLICENODE_PrusaslicerSlice(SliceNode):
def init(self, context):
self.add_input("SLICESOCK_PrusaslicerConf", "Config")
self.add_input("SLICESOCK_Settings", "Settings")
self.add_multi_socket_group("SLICESOCK_Mesh", "SLICESOCK_GcodeRo", name="Slicing Group", in_name="Mesh", out_name="Gcode", in_display_shape='LIST')
self.add_multi_socket_group("SLICESOCK_Mesh", "NodeSocketString", name="Slicing Group", in_name="Mesh", out_name="Gcode", in_display_shape='LIST')
def draw_buttons(self, context, layout):
assert layout
@ -317,7 +317,7 @@ class SLICENODE_PrusaslicerPreview(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_multi_socket_group("SLICESOCK_Gcode", name="Gcode")
self.add_multi_socket_group("NodeSocketString", name="Gcode")
def draw_buttons(self, context, layout):
super().draw_buttons(context, layout)
@ -468,7 +468,7 @@ class SLICENODE_Test(ExecSliceNode):
def init(self, context):
self._init_exec()
self.add_input("SLICESOCK_Gcode")
self.add_input("NodeSocketString")
def evaluate(self, operator=None):
_ = self.resolve("Gcode")

View file

@ -44,18 +44,7 @@ class ReadonlySocket():
def draw(self, context: Any, layout: Any, node: Any, text: str | None):
return self._draw_as_ro(context, layout, node, text) # pyright: ignore[reportAttributeAccessIssue]
# Native Blender socket type aliases
SLICESOCK_Object = "NodeSocketObject"
SLICESOCK_ObjectRo = "NodeSocketObject"
SLICESOCK_Float = "NodeSocketFloat"
SLICESOCK_FloatRo = "NodeSocketFloat"
SLICESOCK_Int = "NodeSocketInt"
SLICESOCK_IntRo = "NodeSocketInt"
SLICESOCK_String = "NodeSocketString"
SLICESOCK_VectorRotation = "NodeSocketRotation"
SLICESOCK_VectorRotationRo = "NodeSocketRotation"
SLICESOCK_Vector = "NodeSocketVector"
SLICESOCK_VectorRo = "NodeSocketVector"
@register_class
class SLICESOCK_Geometry(LabelNodeSocket):
@ -86,20 +75,6 @@ class SLICESOCK_Geometry(LabelNodeSocket):
else:
return _get_upstream_color(self)
@register_class
class SLICESOCK_FilePath(InputNodeSocket):
bl_label = "Filepath"
value: NfStringProperty(name="Filepath", default="", subtype='FILE_PATH') # pyright: ignore[reportInvalidTypeForm]
bl_color = (0.4, 0.7, 1.0, 1.0)
@register_class
class SLICESOCK_DirPath(InputNodeSocket):
bl_label = "Filepath"
value: NfStringProperty(name="Folder", default="", subtype='DIR_PATH') # pyright: ignore[reportInvalidTypeForm]
bl_color = (0.4, 0.7, 1.0, 1.0)
@register_class
class SLICESOCK_Mesh(LabelNodeSocket):
bl_label = "Mesh"
@ -112,18 +87,6 @@ class SLICESOCK_Paths(LabelNodeSocket):
default = SlicePaths()
bl_color = (214/255, 0, 120/255, 1.0)
class SLICESOCK_Gcode_Common(InputNodeSocket):
bl_label = "Gcode"
value: NfStringProperty(name="Gcode", default="") # pyright: ignore[reportInvalidTypeForm]
bl_color = (1., 1., 1., 1.)
@register_class
class SLICESOCK_Gcode(SLICESOCK_Gcode_Common): ...
@register_class
class SLICESOCK_GcodeRo(ReadonlySocket, SLICESOCK_Gcode_Common): ...
@register_class
class SLICESOCK_Intrinsics(LabelNodeSocket):
bl_label = "Intrinsics"

View file

@ -126,6 +126,8 @@ def object_init_handler(scene, depsgraph):
update_collection(pg.modifiers)
@persistent
def depsgraph_update_handler(scene, depsgraph):
global _is_updating, _tree_changed
@ -134,7 +136,7 @@ def depsgraph_update_handler(scene, depsgraph):
tree_update_handler(scene, depsgraph)
object_init_handler(scene, depsgraph)
# Sync SLICENODE_Group sockets if interface changed
# Sync SLICENODE_Group sockets if interface changed and migrate legacy sockets
for tree in bpy.data.node_groups:
if tree.bl_idname == "SLICETREE_NodeTree":
for node in tree.nodes:

View file

@ -7,13 +7,12 @@
| `NodeSocketObject` | `bpy.types.Object` | Blender RNA Object | Reference to a Blender Object |
| `NodeSocketFloat` | `float` | Python float | Numeric value |
| `NodeSocketInt` | `int` | Python int | Integer value |
| `NodeSocketString` | `str` | Python string | Text value |
| `NodeSocketString` | `str` | Python string | Text, G-code, file/folder path value |
| `NodeSocketVector` | `tuple` | Python tuple (3) | XYZ vector value |
| `NodeSocketRotation` | `tuple` | Python tuple (3) | Euler rotation value |
| `NodeSocketGeometry` | `Geometry` | Geometry Data | Generic geometry reference |
| `SLICESOCK_Mesh` | `SlicingObject` | NumPy NDArray (Triangles) | Internal mesh data (Transformed/Scaled) |
| `SLICESOCK_Paths` | `SlicePaths` (list) | List of paths (N, 3) + groups | Generic toolpaths or slice boundaries |
| `SLICESOCK_Gcode` | `str` | Multi-line string | Generated G-code text |
| `SLICESOCK_Settings` | `dict[str, str]` | Python dictionary | Mapping of configuration fields to values |
| `SLICESOCK_SettingsRo` | `dict[str, str]` | Python dictionary | Read-only merged configuration overrides |

View file

@ -436,26 +436,26 @@ class TestTransform(unittest.TestCase):
node.evaluate()
node._process_gcode.assert_called_once_with("GCODE1", "Part", None)
# 2. Three parts - padded to 2 digits (01, 02, 03)
# 2. Three parts - padded to 2 digits (00, 01, 02)
node.resolve_multi_input = MagicMock(return_value=["GC1", "GC2", "GC3"])
node.resolve = MagicMock(return_value="Part")
node._process_gcode = MagicMock()
node.evaluate()
self.assertEqual(node._process_gcode.call_count, 3)
node._process_gcode.assert_any_call("GC1", "Part01", None)
node._process_gcode.assert_any_call("GC2", "Part02", None)
node._process_gcode.assert_any_call("GC3", "Part03", None)
node._process_gcode.assert_any_call("GC1", "Part00", None)
node._process_gcode.assert_any_call("GC2", "Part01", None)
node._process_gcode.assert_any_call("GC3", "Part02", None)
# 3. Fifteen parts - padded to 2 digits (01..15)
# 3. Fifteen parts - padded to 2 digits (00..14)
node.resolve_multi_input = MagicMock(return_value=[f"GC{i}" for i in range(1, 16)])
node.resolve = MagicMock(return_value="Part")
node._process_gcode = MagicMock()
node.evaluate()
self.assertEqual(node._process_gcode.call_count, 15)
node._process_gcode.assert_any_call("GC1", "Part01", None)
node._process_gcode.assert_any_call("GC15", "Part15", None)
node._process_gcode.assert_any_call("GC1", "Part00", None)
node._process_gcode.assert_any_call("GC15", "Part14", None)
# 4. Default base name when empty name provided
node.resolve_multi_input = MagicMock(return_value=["GC1", "GC2"])
@ -463,8 +463,8 @@ class TestTransform(unittest.TestCase):
node._process_gcode = MagicMock()
node.evaluate()
node._process_gcode.assert_any_call("GC1", "GcodePreview01", None)
node._process_gcode.assert_any_call("GC2", "GcodePreview02", None)
node._process_gcode.assert_any_call("GC1", "GcodePreview00", None)
node._process_gcode.assert_any_call("GC2", "GcodePreview01", None)
if __name__ == '__main__':