106 lines
2.3 KiB
Python
106 lines
2.3 KiB
Python
|
import typing as typ
|
||
|
import bpy
|
||
|
|
||
|
from .. import contracts
|
||
|
|
||
|
class BLSocket(bpy.types.NodeSocket):
|
||
|
"""A base type for nodes that greatly simplifies the implementation of
|
||
|
reliable, powerful nodes.
|
||
|
|
||
|
Should be used together with `contracts.BLSocketProtocol`.
|
||
|
"""
|
||
|
def __init_subclass__(cls, **kwargs: typ.Any):
|
||
|
super().__init_subclass__(**kwargs) ## Yucky superclass setup.
|
||
|
|
||
|
# Set bl_idname
|
||
|
cls.bl_idname = cls.socket_type.value
|
||
|
|
||
|
# Declare Node Property: 'preset' EnumProperty
|
||
|
if hasattr(cls, "draw_preview"):
|
||
|
cls.__annotations__["preview_active"] = bpy.props.BoolProperty(
|
||
|
name="Preview",
|
||
|
description="Preview the socket value",
|
||
|
default=False,
|
||
|
)
|
||
|
|
||
|
####################
|
||
|
# - Methods
|
||
|
####################
|
||
|
def is_compatible(self, value: typ.Any) -> bool:
|
||
|
for compatible_type, checks in self.compatible_types.items():
|
||
|
if (
|
||
|
compatible_type is typ.Any or
|
||
|
isinstance(value, compatible_type)
|
||
|
):
|
||
|
return all(check(value) for check in checks)
|
||
|
|
||
|
return False
|
||
|
|
||
|
####################
|
||
|
# - UI
|
||
|
####################
|
||
|
@classmethod
|
||
|
def draw_color_simple(cls) -> contracts.BlenderColorRGB:
|
||
|
return cls.socket_color
|
||
|
|
||
|
def draw(
|
||
|
self,
|
||
|
context: bpy.types.Context,
|
||
|
layout: bpy.types.UILayout,
|
||
|
node: bpy.types.Node,
|
||
|
text: str,
|
||
|
) -> None:
|
||
|
if self.is_output:
|
||
|
self.draw_output(context, layout, node, text)
|
||
|
else:
|
||
|
self.draw_input(context, layout, node, text)
|
||
|
|
||
|
def draw_input(
|
||
|
self,
|
||
|
context: bpy.types.Context,
|
||
|
layout: bpy.types.UILayout,
|
||
|
node: bpy.types.Node,
|
||
|
text: str,
|
||
|
) -> None:
|
||
|
if self.is_linked:
|
||
|
layout.label(text=text)
|
||
|
return
|
||
|
|
||
|
# Column
|
||
|
col = layout.column(align=True)
|
||
|
|
||
|
# Row: Label & Preview Toggle
|
||
|
label_col_row = col.row(align=True)
|
||
|
if hasattr(self, "draw_label_row"):
|
||
|
self.draw_label_row(label_col_row, text)
|
||
|
else:
|
||
|
label_col_row.label(text=text)
|
||
|
|
||
|
if hasattr(self, "draw_preview"):
|
||
|
label_col_row.prop(
|
||
|
self,
|
||
|
"preview_active",
|
||
|
toggle=True,
|
||
|
text="",
|
||
|
icon="SEQ_PREVIEW",
|
||
|
)
|
||
|
|
||
|
# Row: Preview (in Box)
|
||
|
if hasattr(self, "draw_preview"):
|
||
|
if self.preview_active:
|
||
|
col_box = col.box()
|
||
|
self.draw_preview(col_box)
|
||
|
|
||
|
# Row(s): Value
|
||
|
if hasattr(self, "draw_value"):
|
||
|
self.draw_value(col)
|
||
|
|
||
|
def draw_output(
|
||
|
self,
|
||
|
context: bpy.types.Context,
|
||
|
layout: bpy.types.UILayout,
|
||
|
node: bpy.types.Node,
|
||
|
text: str,
|
||
|
) -> None:
|
||
|
layout.label(text=text)
|