realtime also when changing parameters
This commit is contained in:
parent
e69a92c9a3
commit
3b6f996724
3 changed files with 80 additions and 45 deletions
|
|
@ -17,6 +17,7 @@ from .. import slice
|
||||||
from ..slice import Pather, slice_at_range, SlicePaths
|
from ..slice import Pather, slice_at_range, SlicePaths
|
||||||
from ...infra.blender_mesh_capture import SlicingObject, capture_mesh_edges, SlicingGroup
|
from ...infra.blender_mesh_capture import SlicingObject, capture_mesh_edges, SlicingGroup
|
||||||
from ...infra.blender_slice_nodes_generic import SliceNode, resolve_input
|
from ...infra.blender_slice_nodes_generic import SliceNode, resolve_input
|
||||||
|
from .tree import notify_tree_changed
|
||||||
from ...infra._3mf_writer._3mf import prepare_3mf
|
from ...infra._3mf_writer._3mf import prepare_3mf
|
||||||
|
|
||||||
class SliceIntrinsics:
|
class SliceIntrinsics:
|
||||||
|
|
@ -90,6 +91,8 @@ class SLICENODE_PrusaslicerConf(SliceNode):
|
||||||
|
|
||||||
if self.printer_enum != 'NONE':
|
if self.printer_enum != 'NONE':
|
||||||
cache.evaluate_compatibility({self.printer_enum}, set(cache.vendors))
|
cache.evaluate_compatibility({self.printer_enum}, set(cache.vendors))
|
||||||
|
|
||||||
|
notify_tree_changed(self, context)
|
||||||
|
|
||||||
def get_printers(self, context):
|
def get_printers(self, context):
|
||||||
cache = self.get_cache()
|
cache = self.get_cache()
|
||||||
|
|
@ -148,12 +151,14 @@ class SLICENODE_PrusaslicerConf(SliceNode):
|
||||||
|
|
||||||
filament_enum: EnumProperty(
|
filament_enum: EnumProperty(
|
||||||
name="Filament",
|
name="Filament",
|
||||||
items=get_filaments
|
items=get_filaments,
|
||||||
|
update=notify_tree_changed
|
||||||
) # pyright: ignore[reportInvalidTypeForm]
|
) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
print_enum: EnumProperty(
|
print_enum: EnumProperty(
|
||||||
name="Print",
|
name="Print",
|
||||||
items=get_prints
|
items=get_prints,
|
||||||
|
update=notify_tree_changed
|
||||||
) # pyright: ignore[reportInvalidTypeForm]
|
) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
|
|
@ -186,6 +191,7 @@ class SLICENODE_InputPrinter(SliceNode):
|
||||||
|
|
||||||
def update_label(self, context):
|
def update_label(self, context):
|
||||||
self.label = self.printer_label
|
self.label = self.printer_label
|
||||||
|
notify_tree_changed(self, context)
|
||||||
|
|
||||||
printer_label: StringProperty(name="Label", default="Printer", update=update_label) # pyright: ignore[reportInvalidTypeForm]
|
printer_label: StringProperty(name="Label", default="Printer", update=update_label) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
|
|
@ -196,7 +202,8 @@ class SLICENODE_InputPrinter(SliceNode):
|
||||||
('CREALITY', "Creality", "Creality Cloud API"),
|
('CREALITY', "Creality", "Creality Cloud API"),
|
||||||
('MOONRAKER', "Moonraker", "Moonraker (Klipper) API"),
|
('MOONRAKER', "Moonraker", "Moonraker (Klipper) API"),
|
||||||
],
|
],
|
||||||
default='PRUSALINK'
|
default='PRUSALINK',
|
||||||
|
update=notify_tree_changed
|
||||||
) # pyright: ignore[reportInvalidTypeForm]
|
) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
|
|
@ -503,14 +510,16 @@ class SLICENODE_Infill(SliceNode):
|
||||||
bl_label = "Infill"
|
bl_label = "Infill"
|
||||||
|
|
||||||
infill_type: EnumProperty(
|
infill_type: EnumProperty(
|
||||||
name="Infill Type",
|
name="Type",
|
||||||
items=[
|
items=[
|
||||||
('GRID', "Grid", "Cross-hatch grid infill"),
|
('GRID', "Grid", "Cross-hatch grid"),
|
||||||
('RECTILINEAR', "Rectilinear", "Alternating parallel lines"),
|
('RECTILINEAR', "Rectilinear", "Alternating parallel lines"),
|
||||||
],
|
],
|
||||||
default='GRID'
|
default='GRID',
|
||||||
|
update=notify_tree_changed
|
||||||
) # pyright: ignore[reportInvalidTypeForm]
|
) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_input("SLICESOCK_Paths")
|
self.add_input("SLICESOCK_Paths")
|
||||||
self.add_input("SLICESOCK_Float", "Density").value = 2.0
|
self.add_input("SLICESOCK_Float", "Density").value = 2.0
|
||||||
|
|
@ -562,12 +571,12 @@ class SLICENODE_Infill(SliceNode):
|
||||||
class SLICENODE_PathsToGcode(SliceNode):
|
class SLICENODE_PathsToGcode(SliceNode):
|
||||||
bl_label = "Paths to Gcode"
|
bl_label = "Paths to Gcode"
|
||||||
|
|
||||||
use_header: BoolProperty(name="Header", default=True) # pyright: ignore[reportInvalidTypeForm]
|
use_header: BoolProperty(name="Header", default=True, update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_input("SLICESOCK_Paths")
|
self.add_input("SLICESOCK_Paths")
|
||||||
self.add_input("SLICESOCK_Intrinsics")
|
self.add_input("SLICESOCK_Intrinsics")
|
||||||
self.add_output("SLICESOCK_Gcode")
|
self.add_output("SLICESOCK_GcodeRo")
|
||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
def draw_buttons(self, context, layout):
|
||||||
assert layout
|
assert layout
|
||||||
|
|
@ -593,17 +602,11 @@ class SLICENODE_PathsToGcode(SliceNode):
|
||||||
class SLICENODE_GcodeBlock(SliceNode):
|
class SLICENODE_GcodeBlock(SliceNode):
|
||||||
bl_label = "Gcode Block"
|
bl_label = "Gcode Block"
|
||||||
|
|
||||||
gcode: StringProperty(name="Gcode", default="") # pyright: ignore[reportInvalidTypeForm]
|
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_output("SLICESOCK_Gcode")
|
self.add_output("SLICESOCK_Gcode", "Gcode")
|
||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
|
||||||
assert layout
|
|
||||||
layout.prop(self, "gcode", text="")
|
|
||||||
|
|
||||||
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
||||||
return self.gcode
|
return self.outputs['Gcode'].value
|
||||||
|
|
||||||
@register_class
|
@register_class
|
||||||
class SLICENODE_GcodeHelper(SliceNode):
|
class SLICENODE_GcodeHelper(SliceNode):
|
||||||
|
|
@ -644,7 +647,7 @@ class SLICENODE_GcodeHelper(SliceNode):
|
||||||
parameters: StringProperty(name="Params", default="") # pyright: ignore[reportInvalidTypeForm]
|
parameters: StringProperty(name="Params", default="") # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_output("SLICESOCK_Gcode")
|
self.add_output("SLICESOCK_GcodeRo")
|
||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
def draw_buttons(self, context, layout):
|
||||||
assert layout
|
assert layout
|
||||||
|
|
@ -675,7 +678,9 @@ class SliceNodeJoiner(SliceNode):
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
def is_active(input) -> bool:
|
def is_active(input) -> bool:
|
||||||
return input.is_linked or getattr(input, 'value', False)
|
a: bool = input.is_linked or getattr(input, 'value', False)
|
||||||
|
b: bool = getattr(self.inputs[-1], 'value', False)
|
||||||
|
return a or b
|
||||||
|
|
||||||
if len(self.inputs) == 0:
|
if len(self.inputs) == 0:
|
||||||
self.add_input(self.socket_type)
|
self.add_input(self.socket_type)
|
||||||
|
|
@ -695,6 +700,7 @@ class SliceNodeJoiner(SliceNode):
|
||||||
class SLICENODE_JoinGcode(SliceNodeJoiner):
|
class SLICENODE_JoinGcode(SliceNodeJoiner):
|
||||||
bl_label = "Join Gcode"
|
bl_label = "Join Gcode"
|
||||||
socket_type = "SLICESOCK_Gcode"
|
socket_type = "SLICESOCK_Gcode"
|
||||||
|
output_socket_type = "SLICESOCK_GcodeRo"
|
||||||
|
|
||||||
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
||||||
gcode_input: list[str] = []
|
gcode_input: list[str] = []
|
||||||
|
|
@ -841,7 +847,7 @@ class SLICENODE_LoadGcode(SliceNode):
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self.add_input("SLICESOCK_FilePath", "Filepath")
|
self.add_input("SLICESOCK_FilePath", "Filepath")
|
||||||
self.add_output("SLICESOCK_Gcode")
|
self.add_output("SLICESOCK_GcodeRo")
|
||||||
|
|
||||||
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
||||||
path = resolve_input(self.inputs.get("Filepath"))
|
path = resolve_input(self.inputs.get("Filepath"))
|
||||||
|
|
@ -1053,14 +1059,14 @@ class SLICENODE_PrusaslicerSlice(ExecSliceNode):
|
||||||
bl_label = "PrusaSlicer Slice"
|
bl_label = "PrusaSlicer Slice"
|
||||||
button_label = "Slice with PrusaSlicer"
|
button_label = "Slice with PrusaSlicer"
|
||||||
|
|
||||||
prusaslicer_executable: StringProperty(name="PrusaSlicer Path", subtype='FILE_PATH') # pyright: ignore[reportInvalidTypeForm]
|
prusaslicer_executable: StringProperty(name="PrusaSlicer Path", subtype='FILE_PATH', update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
gcode_result: StringProperty(name="Gcode Result", default="") # pyright: ignore[reportInvalidTypeForm]
|
gcode_result: StringProperty(name="Gcode Result", default="") # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self._init_exec()
|
self._init_exec()
|
||||||
self.add_input("SLICESOCK_Object", "Object")
|
self.add_input("SLICESOCK_Object", "Object")
|
||||||
self.add_input("SLICESOCK_PrusaslicerConf", "Config")
|
self.add_input("SLICESOCK_PrusaslicerConf", "Config")
|
||||||
self.add_output("SLICESOCK_Gcode")
|
self.add_output("SLICESOCK_GcodeRo")
|
||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
def draw_buttons(self, context, layout):
|
||||||
super().draw_buttons(context, layout)
|
super().draw_buttons(context, layout)
|
||||||
|
|
@ -1186,10 +1192,13 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self._init_exec()
|
self._init_exec()
|
||||||
self.add_input("SLICESOCK_Gcode")
|
self.add_input("SLICESOCK_Gcode", "Gcode")
|
||||||
|
self.add_input("SLICESOCK_String", "Name")
|
||||||
|
|
||||||
def evaluate(self, operator=None):
|
def evaluate(self, operator=None):
|
||||||
gcode: str = resolve_input(self.inputs.get("Gcode"))
|
gcode: str = self.resolve("Gcode")
|
||||||
|
mesh_name: str = self.resolve("Name")
|
||||||
|
|
||||||
if not gcode:
|
if not gcode:
|
||||||
return 'empty'
|
return 'empty'
|
||||||
|
|
||||||
|
|
@ -1247,7 +1256,6 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
|
||||||
return 'no segments'
|
return 'no segments'
|
||||||
|
|
||||||
# Create or find "Debug" mesh object
|
# Create or find "Debug" mesh object
|
||||||
mesh_name = "Debug"
|
|
||||||
if mesh_name in bpy.data.objects:
|
if mesh_name in bpy.data.objects:
|
||||||
obj = bpy.data.objects[mesh_name]
|
obj = bpy.data.objects[mesh_name]
|
||||||
mesh = obj.data
|
mesh = obj.data
|
||||||
|
|
@ -1290,7 +1298,7 @@ class SLICENODE_Executor(ExecSliceNode, SliceNodeJoiner):
|
||||||
button_label = "Execute All"
|
button_label = "Execute All"
|
||||||
socket_type = "SLICESOCK_ExecutionLink"
|
socket_type = "SLICESOCK_ExecutionLink"
|
||||||
|
|
||||||
auto_refresh: bpy.props.BoolProperty(name="Auto-refresh", default=False) # pyright: ignore[reportInvalidTypeForm]
|
auto_refresh: bpy.props.BoolProperty(name="Auto-refresh", default=False, update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
def init(self, context):
|
def init(self, context):
|
||||||
self._init_exec()
|
self._init_exec()
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ from ...registry import register_class
|
||||||
from ...infra.blender_slice_nodes_generic import SliceNodeSocket
|
from ...infra.blender_slice_nodes_generic import SliceNodeSocket
|
||||||
from ..slice import SlicePaths
|
from ..slice import SlicePaths
|
||||||
|
|
||||||
|
from .tree import notify_tree_changed
|
||||||
|
|
||||||
class LabelNodeSocket(SliceNodeSocket):
|
class LabelNodeSocket(SliceNodeSocket):
|
||||||
default = ""
|
default = ""
|
||||||
def draw(self, context: Any, layout: Any, node: Any, text: str | None):
|
def draw(self, context: Any, layout: Any, node: Any, text: str | None):
|
||||||
|
|
@ -38,6 +40,7 @@ class SLICESOCK_Object(InputNodeSocket):
|
||||||
value: PointerProperty(
|
value: PointerProperty(
|
||||||
name="Object",
|
name="Object",
|
||||||
type=bpy.types.Object,
|
type=bpy.types.Object,
|
||||||
|
update=notify_tree_changed
|
||||||
) # pyright: ignore[reportInvalidTypeForm]
|
) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_color = (0.9, 0.7, 0.2, 1.0)
|
bl_color = (0.9, 0.7, 0.2, 1.0)
|
||||||
|
|
||||||
|
|
@ -45,7 +48,7 @@ class SLICESOCK_Object(InputNodeSocket):
|
||||||
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, update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_color = (161/255, 161/255, 161/255, 1.0)
|
bl_color = (161/255, 161/255, 161/255, 1.0)
|
||||||
|
|
||||||
@register_class
|
@register_class
|
||||||
|
|
@ -57,7 +60,7 @@ class SLICESOCK_Float(SLICESOCK_Float_Common): ...
|
||||||
class SLICESOCK_Int_Common(InputNodeSocket):
|
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, update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_color = (161/255, 161/255, 161/255, 1.0)
|
bl_color = (161/255, 161/255, 161/255, 1.0)
|
||||||
|
|
||||||
@register_class
|
@register_class
|
||||||
|
|
@ -70,21 +73,21 @@ class SLICESOCK_IntRo(ReadonlySocket, SLICESOCK_Int_Common): ...
|
||||||
class SLICESOCK_String(InputNodeSocket):
|
class SLICESOCK_String(InputNodeSocket):
|
||||||
bl_label = "String"
|
bl_label = "String"
|
||||||
|
|
||||||
value: StringProperty(name="String", default="") # pyright: ignore[reportInvalidTypeForm]
|
value: StringProperty(name="String", default="", update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_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', update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_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', update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_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): ...
|
||||||
|
|
@ -103,12 +106,16 @@ class SLICESOCK_Paths(LabelNodeSocket):
|
||||||
default = SlicePaths()
|
default = SlicePaths()
|
||||||
bl_color = (214/255, 0, 120/255, 1.0)
|
bl_color = (214/255, 0, 120/255, 1.0)
|
||||||
|
|
||||||
@register_class
|
class SLICESOCK_Gcode_Common(InputNodeSocket):
|
||||||
class SLICESOCK_Gcode(LabelNodeSocket):
|
|
||||||
bl_label = "Gcode"
|
bl_label = "Gcode"
|
||||||
default = ""
|
value: StringProperty(name="Gcode", default="", update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
bl_color = (1., 1., 1., 1.)
|
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
|
@register_class
|
||||||
class SLICESOCK_Intrinsics(LabelNodeSocket):
|
class SLICESOCK_Intrinsics(LabelNodeSocket):
|
||||||
bl_label = "Intrinsics"
|
bl_label = "Intrinsics"
|
||||||
|
|
@ -131,12 +138,12 @@ class SLICESOCK_ExecutionLink(LabelNodeSocket):
|
||||||
class SLICESOCK_Printer(InputNodeSocket):
|
class SLICESOCK_Printer(InputNodeSocket):
|
||||||
bl_label = "Printer"
|
bl_label = "Printer"
|
||||||
|
|
||||||
host: StringProperty(name="Host", default="localhost") # pyright: ignore[reportInvalidTypeForm]
|
host: StringProperty(name="Host", default="localhost", update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
port: IntProperty(name="Port", default=80, min=1, max=65535) # pyright: ignore[reportInvalidTypeForm]
|
port: IntProperty(name="Port", default=80, min=1, max=65535, update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
prefix: StringProperty(name="Prefix", default="") # pyright: ignore[reportInvalidTypeForm]
|
prefix: StringProperty(name="Prefix", default="", update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
label: StringProperty(name="Label", default="Printer") # pyright: ignore[reportInvalidTypeForm]
|
label: StringProperty(name="Label", default="Printer", update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
username: StringProperty(name="Username", default="") # pyright: ignore[reportInvalidTypeForm]
|
username: StringProperty(name="Username", default="", update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
password: StringProperty(name="Password", default="", subtype='PASSWORD') # pyright: ignore[reportInvalidTypeForm]
|
password: StringProperty(name="Password", default="", subtype='PASSWORD', update=notify_tree_changed) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
host_type: EnumProperty(
|
host_type: EnumProperty(
|
||||||
name="Type",
|
name="Type",
|
||||||
|
|
@ -145,7 +152,8 @@ class SLICESOCK_Printer(InputNodeSocket):
|
||||||
('CREALITY', "Creality", "Creality Cloud API"),
|
('CREALITY', "Creality", "Creality Cloud API"),
|
||||||
('MOONRAKER', "Moonraker", "Moonraker (Klipper) API"),
|
('MOONRAKER', "Moonraker", "Moonraker (Klipper) API"),
|
||||||
],
|
],
|
||||||
default='PRUSALINK'
|
default='PRUSALINK',
|
||||||
|
update=notify_tree_changed
|
||||||
) # pyright: ignore[reportInvalidTypeForm]
|
) # pyright: ignore[reportInvalidTypeForm]
|
||||||
|
|
||||||
bl_color = (1.0, 0.45, 0.1, 1.0) # Orange
|
bl_color = (1.0, 0.45, 0.1, 1.0) # Orange
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,15 @@ def get_referenced_objects(node, visited=None):
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
_is_updating = False
|
_is_updating = False
|
||||||
|
_tree_changed = False
|
||||||
|
|
||||||
|
def notify_tree_changed(self, context):
|
||||||
|
global _tree_changed
|
||||||
|
_tree_changed = True
|
||||||
|
|
||||||
@persistent
|
@persistent
|
||||||
def depsgraph_update_handler(scene, depsgraph):
|
def depsgraph_update_handler(scene, depsgraph):
|
||||||
global _is_updating
|
global _is_updating, _tree_changed
|
||||||
if _is_updating:
|
if _is_updating:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -55,18 +61,31 @@ def depsgraph_update_handler(scene, depsgraph):
|
||||||
if obj.type == 'MESH' and obj.data in updated_meshes:
|
if obj.type == 'MESH' and obj.data in updated_meshes:
|
||||||
updated_object_names.add(obj.name)
|
updated_object_names.add(obj.name)
|
||||||
|
|
||||||
if not updated_object_names:
|
# Note: custom NodeTree updates often don't appear in depsgraph.updates
|
||||||
|
# so we rely on _tree_changed flag set by property update callbacks.
|
||||||
|
|
||||||
|
if not updated_object_names and not _tree_changed:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
tree_needs_refresh = _tree_changed
|
||||||
|
_tree_changed = False # reset for next run
|
||||||
|
|
||||||
for tree in bpy.data.node_groups:
|
for tree in bpy.data.node_groups:
|
||||||
if tree.bl_idname != "SLICETREE_NodeTree":
|
if tree.bl_idname != "SLICETREE_NodeTree":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for node in tree.nodes:
|
for node in tree.nodes:
|
||||||
if node.bl_idname == "SLICENODE_Executor" and getattr(node, "auto_refresh", False):
|
if node.bl_idname == "SLICENODE_Executor" and getattr(node, "auto_refresh", False):
|
||||||
referenced = get_referenced_objects(node)
|
# Trigger if the tree changed OR if a referenced object changed
|
||||||
referenced_names = {obj.name for obj in referenced if obj}
|
should_refresh = tree_needs_refresh
|
||||||
if updated_object_names & referenced_names:
|
|
||||||
|
if not should_refresh:
|
||||||
|
referenced = get_referenced_objects(node)
|
||||||
|
referenced_names = {obj.name for obj in referenced if obj}
|
||||||
|
if updated_object_names & referenced_names:
|
||||||
|
should_refresh = True
|
||||||
|
|
||||||
|
if should_refresh:
|
||||||
_is_updating = True
|
_is_updating = True
|
||||||
try:
|
try:
|
||||||
node.evaluate()
|
node.evaluate()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue