nodeslicer/core/nodeslicer/nodes/inputs.py

177 lines
5.9 KiB
Python

from __future__ import annotations
from typing import Any
import bpy
import os
import numpy as np
from ..bpy_ns_types import NfStringProperty, notify_tree_changed, NfEnumProperty, NfPointerProperty
from ....registry import register_class
from .base import InputNode, SliceNode, SliceIntrinsics
@register_class
class SLICENODE_InputString(InputNode):
bl_label = "String"
socket_type = "NodeSocketString"
@register_class
class SLICENODE_InputFloat(InputNode):
bl_label = "Float"
socket_type = "NodeSocketFloat"
@register_class
class SLICENODE_InputInt(InputNode):
bl_label = "Integer"
socket_type = "NodeSocketInt"
@register_class
class SLICENODE_InputVectorRotation(InputNode):
bl_label = "Vector Rotation"
socket_type = "NodeSocketRotation"
@register_class
class SLICENODE_InputVector(InputNode):
bl_label = "Vector"
socket_type = "NodeSocketVector"
@register_class
class SLICENODE_InputObject(InputNode):
bl_label = "Object"
socket_type = "NodeSocketObject"
bl_icon = "OBJECT_DATA"
@register_class
class SLICENODE_CollectionObjects(SliceNode):
bl_label = "Collection Objects"
collection: bpy.types.Collection | None = NfPointerProperty(
name="Collection",
type=bpy.types.Collection,
update=notify_tree_changed
)
def init(self, context):
self._update_outputs()
def update(self):
super().update()
self._update_outputs()
def draw_buttons(self, context, layout):
assert layout
layout.prop(self, "collection", text="")
def _update_outputs(self):
col = getattr(self, "collection", None)
if not col or not hasattr(col, "objects"):
self.outputs.clear()
return
objs = [obj for obj in col.objects if getattr(obj, "type", "") == 'MESH']
expected_names = sorted([obj.name for obj in objs])
# Remove outputs that are no longer in the collection
to_remove = [o for o in self.outputs if o.name not in expected_names]
for o in to_remove:
self.outputs.remove(o)
# Add new outputs
for name in expected_names:
if name not in self.outputs:
self.add_output("NodeSocketObject", name, identifier=name)
# Re-order to match sorted alphabetical order
if hasattr(self.outputs, "find") and hasattr(self.outputs, "move"):
for i, name in enumerate(expected_names):
current_index = self.outputs.find(name)
if current_index != -1 and current_index != i:
self.outputs.move(current_index, i)
def evaluate_output(self, socket_name: str, **kwargs) -> Any:
if self.collection and socket_name in bpy.data.objects:
return bpy.data.objects[socket_name]
return None
@register_class
class SLICENODE_InputSettings(InputNode):
input_type = "Settings"
bl_icon = "OBJECT_DATA"
@register_class
class SLICENODE_InputPrinter(SliceNode):
bl_label = "Printer"
bl_icon = "OUTPUT"
def update_label(self, context):
self.label = self.printer_label
notify_tree_changed(self, context)
printer_label: str = NfStringProperty(name="Label", default="Printer", update=update_label)
host_type: str = NfEnumProperty(
name="Type",
items=[
('PRUSALINK', "PrusaLink", "PrusaLink API"),
('CREALITY', "Creality", "Creality Cloud API"),
('MOONRAKER', "Moonraker", "Moonraker (Klipper) API"),
],
default='PRUSALINK'
)
def init(self, context):
self.add_output("SLICESOCK_Printer")
self.add_input("NodeSocketString", "Host").value = "localhost"
self.add_input("NodeSocketInt", "Port").value = 80
self.add_input("NodeSocketString", "Prefix")
self.add_input("NodeSocketString", "Username")
self.add_input("NodeSocketString", "Password")
def draw_buttons(self, context, layout):
layout.prop(self, "printer_label") # pyright: ignore[reportOptionalMemberAccess]
layout.prop(self, "host_type") # pyright: ignore[reportOptionalMemberAccess]
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
from ....infra.networking.printer_backends import PrinterConfig
return PrinterConfig(
host=self.resolve("Host"),
port=self.resolve("Port"),
prefix=self.resolve("Prefix"),
label=self.printer_label,
username=self.resolve("Username"),
password=self.resolve("Password"),
host_type=self.host_type
)
@register_class
class SLICENODE_InputIntrinsics(SliceNode):
bl_label = "Printer Intrinsics"
def init(self, context):
self.add_output("SLICESOCK_Intrinsics")
self.add_input("NodeSocketFloat", "Bed X").value = 250.0
self.add_input("NodeSocketFloat", "Bed Y").value = 210.0
self.add_input("NodeSocketFloat", "Feedrate").value = 1200.0
self.add_input("NodeSocketFloat", "Travel Feedrate").value = 2400.0
self.add_input("NodeSocketFloat", "Extrusion Rate").value = 0.035
self.add_input("NodeSocketFloat", "Retraction").value = 0.0
self.add_input("NodeSocketFloat", "Retraction Feedrate").value = 0.0
self.add_input("NodeSocketFloat", "Lift").value = 0.0
def evaluate_output(self, socket_name: str, **_kwargs) -> SliceIntrinsics:
ret_fr = 0.0
try:
ret_fr = self.resolve("Retraction Feedrate") or 0.0
except Exception:
ret_fr = 0.0
return SliceIntrinsics(
bed_x=self.resolve("Bed X"),
bed_y=self.resolve("Bed Y"),
feedrate=self.resolve("Feedrate"),
travel_feedrate=self.resolve("Travel Feedrate"),
extrusion_rate=self.resolve("Extrusion Rate"),
retraction=self.resolve("Retraction"),
lift=self.resolve("Lift"),
retraction_feedrate=ret_fr
)