diff --git a/core/nodeslicer/nodes.py b/core/nodeslicer/nodes.py index ba28ad1..a4f061d 100644 --- a/core/nodeslicer/nodes.py +++ b/core/nodeslicer/nodes.py @@ -61,6 +61,118 @@ class SLICENODE_InputObject(InputNode): input_type = "Object" bl_icon = "OBJECT_DATA" +@register_class +class SLICENODE_PrusaslicerConf(SliceNode): + bl_label = "PrusaSlicer Config" + bl_icon = "PROPERTIES" + + _cache = None + + @classmethod + def get_cache(cls): + if cls._cache is None: + from ...infra.prusaslicer_profiles import LocalCache + cls._cache = LocalCache() + return cls._cache + + def update_profiles(self, context): + cache = self.get_cache() + if not cache.profiles and self.config_path: + abs_path = bpy.path.abspath(self.config_path) + if os.path.isdir(abs_path): + cache.load([abs_path]) + + if self.printer_enum != 'NONE': + cache.evaluate_compatibility({self.printer_enum}, set(cache.vendors)) + + def get_printers(self, context): + cache = self.get_cache() + items = [('NONE', "None", "No printer selected")] + for k, p in cache.printer_profiles.items(): + items.append((k, p.id, p.path.name)) + return items + + def get_filaments(self, context): + cache = self.get_cache() + items = [('NONE', "None", "No filament selected")] + + printer_id = self.printer_enum + if printer_id == 'NONE': + return items + + printer = cache.printer_profiles.get(printer_id) + if not printer: + return items + + for k in printer.compatible_profiles: + if k.startswith("filament:"): + p = cache.profiles[k] + items.append((k, p.id, p.path.name)) + return items + + def get_prints(self, context): + cache = self.get_cache() + items = [('NONE', "None", "No print selected")] + + printer_id = self.printer_enum + if printer_id == 'NONE': + return items + + printer = cache.printer_profiles.get(printer_id) + if not printer: + return items + + for k in printer.compatible_profiles: + if k.startswith("print:"): + p = cache.profiles[k] + items.append((k, p.id, p.path.name)) + return items + + config_path: StringProperty( + name="Profiles", + subtype='DIR_PATH', + update=update_profiles + ) # pyright: ignore[reportInvalidTypeForm] + + printer_enum: EnumProperty( + name="Printer", + items=get_printers, + update=update_profiles + ) # pyright: ignore[reportInvalidTypeForm] + + filament_enum: EnumProperty( + name="Filament", + items=get_filaments + ) # pyright: ignore[reportInvalidTypeForm] + + print_enum: EnumProperty( + name="Print", + items=get_prints + ) # pyright: ignore[reportInvalidTypeForm] + + def init(self, context): + self.add_output("SLICESOCK_PrusaslicerConf", "Config") + + def draw_buttons(self, context, layout): + assert layout + layout.prop(self, "config_path") + layout.prop(self, "printer_enum") + if self.printer_enum != 'NONE': + layout.prop(self, "filament_enum") + layout.prop(self, "print_enum") + + def evaluate_output(self, socket_name: str, **_kwargs) -> Any: + if self.printer_enum == 'NONE' or self.filament_enum == 'NONE' or self.print_enum == 'NONE': + return None + + cache = self.get_cache() + return { + 'printer': self.printer_enum, + 'filament': [self.filament_enum], + 'print': self.print_enum, + 'cache': cache + } + @register_class class SLICENODE_InputPrinter(SliceNode): bl_label = "Printer" diff --git a/core/nodeslicer/sockets.py b/core/nodeslicer/sockets.py index 845edfa..f128cae 100644 --- a/core/nodeslicer/sockets.py +++ b/core/nodeslicer/sockets.py @@ -39,14 +39,14 @@ class SLICESOCK_Object(InputNodeSocket): name="Object", type=bpy.types.Object, ) # pyright: ignore[reportInvalidTypeForm] - color = (0.9, 0.7, 0.2, 1.0) + bl_color = (0.9, 0.7, 0.2, 1.0) class SLICESOCK_Float_Common(InputNodeSocket): bl_label = "Float" value: FloatProperty(name="Float", default=0) # pyright: ignore[reportInvalidTypeForm] - color = (161/255, 161/255, 161/255, 1.0) + bl_color = (161/255, 161/255, 161/255, 1.0) @register_class class SLICESOCK_FloatRo(ReadonlySocket, SLICESOCK_Float_Common): ... @@ -58,7 +58,7 @@ class SLICESOCK_Int_Common(InputNodeSocket): bl_label = "Integer" value: IntProperty(name="Int", default=0) # pyright: ignore[reportInvalidTypeForm] - color = (161/255, 161/255, 161/255, 1.0) + bl_color = (161/255, 161/255, 161/255, 1.0) @register_class class SLICESOCK_Int(SLICESOCK_Int_Common): ... @@ -71,21 +71,21 @@ class SLICESOCK_String(InputNodeSocket): bl_label = "String" value: StringProperty(name="String", default="") # pyright: ignore[reportInvalidTypeForm] - color = (0.4, 0.7, 1.0, 1.0) + bl_color = (0.4, 0.7, 1.0, 1.0) @register_class class SLICESOCK_FilePath(InputNodeSocket): bl_label = "Filepath" value: StringProperty(name="Filepath", default="", subtype='FILE_PATH') # pyright: ignore[reportInvalidTypeForm] - color = (0.4, 0.7, 1.0, 1.0) + bl_color = (0.4, 0.7, 1.0, 1.0) @register_class class SLICESOCK_VectorRotation_Common(InputNodeSocket): bl_label = "VectorRotation" value: bpy.props.FloatVectorProperty(name="Vector", size=3, default=(0.0, 0.0, 0.0), subtype='EULER') # pyright: ignore[reportInvalidTypeForm] - color = (0.39, 0.39, 0.78, 1.0) + bl_color = (0.39, 0.39, 0.78, 1.0) @register_class class SLICESOCK_VectorRotation(SLICESOCK_VectorRotation_Common): ... @register_class @@ -95,31 +95,37 @@ class SLICESOCK_VectorRotationRo(ReadonlySocket, SLICESOCK_VectorRotation_Common class SLICESOCK_Mesh(LabelNodeSocket): bl_label = "Mesh" default = None - color = (0, 214/255, 163/255, 1.0) + bl_color = (0, 214/255, 163/255, 1.0) @register_class class SLICESOCK_Paths(LabelNodeSocket): bl_label = "Paths" default = SlicePaths() - color = (214/255, 0, 120/255, 1.0) + bl_color = (214/255, 0, 120/255, 1.0) @register_class class SLICESOCK_Gcode(LabelNodeSocket): bl_label = "Gcode" default = "" - color = (1., 1., 1., 1.) + bl_color = (1., 1., 1., 1.) @register_class class SLICESOCK_Intrinsics(LabelNodeSocket): bl_label = "Intrinsics" default = None - color = (0.2, 0.2, 0.2, 1.0) + bl_color = (0.2, 0.2, 0.2, 1.0) + +@register_class +class SLICESOCK_PrusaslicerConf(LabelNodeSocket): + bl_label = "PrusaSlicer Config" + default = None + bl_color = (0.95, 0.42, 0.13, 1.0) # #F26C21 @register_class class SLICESOCK_ExecutionLink(LabelNodeSocket): bl_label = "Execution Link" default = None - color = (0.5, 0.0, 0.5, 1.0) # Purple + bl_color = (0.5, 0.0, 0.5, 1.0) # Purple @register_class class SLICESOCK_Printer(InputNodeSocket): @@ -142,7 +148,7 @@ class SLICESOCK_Printer(InputNodeSocket): default='PRUSALINK' ) # pyright: ignore[reportInvalidTypeForm] - color = (1.0, 0.45, 0.1, 1.0) # Orange + bl_color = (1.0, 0.45, 0.1, 1.0) # Orange def draw(self, context, layout, node, text): if self.is_output or self.is_linked: diff --git a/core/nodeslicer/tree.py b/core/nodeslicer/tree.py index 7bcea9d..4eb68ed 100644 --- a/core/nodeslicer/tree.py +++ b/core/nodeslicer/tree.py @@ -122,6 +122,7 @@ class SLICENODE_MT_Menu(Menu): layout.operator("node.add_node", text="Integer Math").type = "SLICENODE_IntMath" layout.operator("node.add_node", text="Object").type = "SLICENODE_InputObject" layout.operator("node.add_node", text="Printer").type = "SLICENODE_InputPrinter" + layout.operator("node.add_node", text="PrusaSlicer Config").type = "SLICENODE_PrusaslicerConf" layout.operator("node.add_node", text="Printer List").type = "SLICENODE_PrinterList" layout.operator("node.add_node", text="Printer Intrinsics").type = "SLICENODE_InputIntrinsics" layout.operator("node.add_node", text="Test").type = "SLICENODE_Test" diff --git a/infra/blender_slice_nodes_generic.py b/infra/blender_slice_nodes_generic.py index 20cc53f..0ae8142 100644 --- a/infra/blender_slice_nodes_generic.py +++ b/infra/blender_slice_nodes_generic.py @@ -16,9 +16,10 @@ class AutoBlIdName: class SliceNodeSocket(NodeSocket, AutoBlIdName): default: Any = None - color = (1., 1., 1., 1.) + bl_color = (1.0, 1.0, 1.0, 1.0) - def draw_color(self, context, node) -> tuple[float, float, float, float]: return self.color # pyright: ignore[reportIncompatibleMethodOverride] + def draw_color(self, context, node) -> tuple[float, float, float, float]: # pyright: ignore[reportIncompatibleMethodOverride] + return self.bl_color class SliceNode(Node, AutoBlIdName): def evaluate_output(self, socket_name: str, **_kwargs) -> Any: ... diff --git a/infra/prusaslicer_profiles/models.py b/infra/prusaslicer_profiles/models.py index 020a634..c968ab9 100644 --- a/infra/prusaslicer_profiles/models.py +++ b/infra/prusaslicer_profiles/models.py @@ -66,7 +66,7 @@ class ConfigWriter: for key, val in dict(sorted(self.config_dict.items())).items(): file.write(f"; {key} = {val}\n") - def get(self, key: str, default: Any = None) -> str | list[str]: + def get(self, key: str, default: str = "") -> str | list[str]: return self.config_dict.get(key, default) @property