Prusaslicerconf node

This commit is contained in:
Nicolas Predella 2026-05-15 15:23:40 +03:00
parent 4bfc351189
commit d49f89ec43
5 changed files with 135 additions and 15 deletions

View file

@ -61,6 +61,118 @@ class SLICENODE_InputObject(InputNode):
input_type = "Object" input_type = "Object"
bl_icon = "OBJECT_DATA" 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 @register_class
class SLICENODE_InputPrinter(SliceNode): class SLICENODE_InputPrinter(SliceNode):
bl_label = "Printer" bl_label = "Printer"

View file

@ -39,14 +39,14 @@ class SLICESOCK_Object(InputNodeSocket):
name="Object", name="Object",
type=bpy.types.Object, type=bpy.types.Object,
) # pyright: ignore[reportInvalidTypeForm] ) # 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): class SLICESOCK_Float_Common(InputNodeSocket):
bl_label = "Float" bl_label = "Float"
value: FloatProperty(name="Float", default=0) # pyright: ignore[reportInvalidTypeForm] 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 @register_class
class SLICESOCK_FloatRo(ReadonlySocket, SLICESOCK_Float_Common): ... class SLICESOCK_FloatRo(ReadonlySocket, SLICESOCK_Float_Common): ...
@ -58,7 +58,7 @@ class SLICESOCK_Int_Common(InputNodeSocket):
bl_label = "Integer" bl_label = "Integer"
value: IntProperty(name="Int", default=0) # pyright: ignore[reportInvalidTypeForm] 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 @register_class
class SLICESOCK_Int(SLICESOCK_Int_Common): ... class SLICESOCK_Int(SLICESOCK_Int_Common): ...
@ -71,21 +71,21 @@ class SLICESOCK_String(InputNodeSocket):
bl_label = "String" bl_label = "String"
value: StringProperty(name="String", default="") # pyright: ignore[reportInvalidTypeForm] 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 @register_class
class SLICESOCK_FilePath(InputNodeSocket): class SLICESOCK_FilePath(InputNodeSocket):
bl_label = "Filepath" bl_label = "Filepath"
value: StringProperty(name="Filepath", default="", subtype='FILE_PATH') # pyright: ignore[reportInvalidTypeForm] 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 @register_class
class SLICESOCK_VectorRotation_Common(InputNodeSocket): class SLICESOCK_VectorRotation_Common(InputNodeSocket):
bl_label = "VectorRotation" bl_label = "VectorRotation"
value: bpy.props.FloatVectorProperty(name="Vector", size=3, default=(0.0, 0.0, 0.0), subtype='EULER') # pyright: ignore[reportInvalidTypeForm] 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 @register_class
class SLICESOCK_VectorRotation(SLICESOCK_VectorRotation_Common): ... class SLICESOCK_VectorRotation(SLICESOCK_VectorRotation_Common): ...
@register_class @register_class
@ -95,31 +95,37 @@ class SLICESOCK_VectorRotationRo(ReadonlySocket, SLICESOCK_VectorRotation_Common
class SLICESOCK_Mesh(LabelNodeSocket): class SLICESOCK_Mesh(LabelNodeSocket):
bl_label = "Mesh" bl_label = "Mesh"
default = None default = None
color = (0, 214/255, 163/255, 1.0) bl_color = (0, 214/255, 163/255, 1.0)
@register_class @register_class
class SLICESOCK_Paths(LabelNodeSocket): class SLICESOCK_Paths(LabelNodeSocket):
bl_label = "Paths" bl_label = "Paths"
default = SlicePaths() default = SlicePaths()
color = (214/255, 0, 120/255, 1.0) bl_color = (214/255, 0, 120/255, 1.0)
@register_class @register_class
class SLICESOCK_Gcode(LabelNodeSocket): class SLICESOCK_Gcode(LabelNodeSocket):
bl_label = "Gcode" bl_label = "Gcode"
default = "" default = ""
color = (1., 1., 1., 1.) bl_color = (1., 1., 1., 1.)
@register_class @register_class
class SLICESOCK_Intrinsics(LabelNodeSocket): class SLICESOCK_Intrinsics(LabelNodeSocket):
bl_label = "Intrinsics" bl_label = "Intrinsics"
default = None 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 @register_class
class SLICESOCK_ExecutionLink(LabelNodeSocket): class SLICESOCK_ExecutionLink(LabelNodeSocket):
bl_label = "Execution Link" bl_label = "Execution Link"
default = None 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 @register_class
class SLICESOCK_Printer(InputNodeSocket): class SLICESOCK_Printer(InputNodeSocket):
@ -142,7 +148,7 @@ class SLICESOCK_Printer(InputNodeSocket):
default='PRUSALINK' default='PRUSALINK'
) # pyright: ignore[reportInvalidTypeForm] ) # 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): def draw(self, context, layout, node, text):
if self.is_output or self.is_linked: if self.is_output or self.is_linked:

View file

@ -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="Integer Math").type = "SLICENODE_IntMath"
layout.operator("node.add_node", text="Object").type = "SLICENODE_InputObject" 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="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 List").type = "SLICENODE_PrinterList"
layout.operator("node.add_node", text="Printer Intrinsics").type = "SLICENODE_InputIntrinsics" layout.operator("node.add_node", text="Printer Intrinsics").type = "SLICENODE_InputIntrinsics"
layout.operator("node.add_node", text="Test").type = "SLICENODE_Test" layout.operator("node.add_node", text="Test").type = "SLICENODE_Test"

View file

@ -16,9 +16,10 @@ class AutoBlIdName:
class SliceNodeSocket(NodeSocket, AutoBlIdName): class SliceNodeSocket(NodeSocket, AutoBlIdName):
default: Any = None 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): class SliceNode(Node, AutoBlIdName):
def evaluate_output(self, socket_name: str, **_kwargs) -> Any: ... def evaluate_output(self, socket_name: str, **_kwargs) -> Any: ...

View file

@ -66,7 +66,7 @@ class ConfigWriter:
for key, val in dict(sorted(self.config_dict.items())).items(): for key, val in dict(sorted(self.config_dict.items())).items():
file.write(f"; {key} = {val}\n") 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) return self.config_dict.get(key, default)
@property @property