armory/blender/arm/logicnode/arm_sockets.py
2021-08-19 21:58:43 +02:00

310 lines
8.8 KiB
Python

import bpy
from bpy.props import *
from bpy.types import NodeSocket
import arm.utils
if arm.is_reload(__name__):
arm.utils = arm.reload_module(arm.utils)
else:
arm.enable_reload(__name__)
def _on_update_socket(self, context):
self.node.on_socket_val_update(context, self)
class ArmCustomSocket(NodeSocket):
"""
A custom socket that can be used to define more socket types for
logic node packs. Do not use this type directly (it is not
registered)!
"""
bl_idname = 'ArmCustomSocket'
bl_label = 'Custom Socket'
# note: trying to use the `type` property will fail. All custom nodes will have "VALUE" as a type, because it is the default.
arm_socket_type = 'NONE'
# please also declare a property named "default_value_raw" of arm_socket_type isn't "NONE"
def get_default_value(self):
"""Override this for values of unconnected input sockets."""
return None
class ArmActionSocket(ArmCustomSocket):
bl_idname = 'ArmNodeSocketAction'
bl_label = 'Action Socket'
arm_socket_type = 'NONE'
def draw(self, context, layout, node, text):
layout.label(text=self.name)
def draw_color(self, context, node):
return 0.8, 0.3, 0.3, 1
class ArmAnimActionSocket(ArmCustomSocket):
bl_idname = 'ArmNodeSocketAnimAction'
bl_label = 'Action Socket'
arm_socket_type = 'STRING'
default_value_get: PointerProperty(name='Action', type=bpy.types.Action) # legacy version of the line after this one
default_value_raw: PointerProperty(name='Action', type=bpy.types.Action, update=_on_update_socket)
def __init__(self):
super().__init__()
if self.default_value_get is not None:
self.default_value_raw = self.default_value_get
self.default_value_get = None
def get_default_value(self):
if self.default_value_raw is None:
return ''
if self.default_value_raw.name not in bpy.data.actions:
return self.default_value_raw.name
name = arm.utils.asset_name(bpy.data.actions[self.default_value_raw.name])
return arm.utils.safestr(name)
def draw(self, context, layout, node, text):
if self.is_output:
layout.label(text=self.name)
elif self.is_linked:
layout.label(text=self.name)
else:
layout.prop_search(self, 'default_value_raw', bpy.data, 'actions', icon='NONE', text='')
def draw_color(self, context, node):
return 0.8, 0.8, 0.8, 1
class ArmArraySocket(ArmCustomSocket):
bl_idname = 'ArmNodeSocketArray'
bl_label = 'Array Socket'
arm_socket_type = 'NONE'
def draw(self, context, layout, node, text):
layout.label(text=self.name)
def draw_color(self, context, node):
return 0.8, 0.4, 0.0, 1
class ArmBoolSocket(ArmCustomSocket):
bl_idname = 'ArmBoolSocket'
bl_label = 'Boolean Socket'
arm_socket_type = 'BOOLEAN'
default_value_raw: BoolProperty(
name='Value',
description='Input value used for unconnected socket',
update=_on_update_socket
)
def draw(self, context, layout, node, text):
draw_socket_layout(self, layout)
def draw_color(self, context, node):
return 0.8, 0.651, 0.839, 1
def get_default_value(self):
return self.default_value_raw
class ArmColorSocket(ArmCustomSocket):
bl_idname = 'ArmColorSocket'
bl_label = 'Color Socket'
arm_socket_type = 'RGBA'
default_value_raw: FloatVectorProperty(
name='Value',
size=4,
subtype='COLOR',
min=0.0,
max=1.0,
default=[0.0, 0.0, 0.0, 1.0],
description='Input value used for unconnected socket',
update=_on_update_socket
)
def draw(self, context, layout, node, text):
draw_socket_layout_split(self, layout)
def draw_color(self, context, node):
return 0.78, 0.78, 0.161, 1
def get_default_value(self):
return self.default_value_raw
class ArmDynamicSocket(ArmCustomSocket):
bl_idname = 'ArmDynamicSocket'
bl_label = 'Dynamic Socket'
arm_socket_type = 'NONE'
def draw(self, context, layout, node, text):
layout.label(text=self.name)
def draw_color(self, context, node):
return 0.388, 0.78, 0.388, 1
class ArmFloatSocket(ArmCustomSocket):
bl_idname = 'ArmFloatSocket'
bl_label = 'Float Socket'
arm_socket_type = 'VALUE'
default_value_raw: FloatProperty(
name='Value',
description='Input value used for unconnected socket',
precision=3,
update=_on_update_socket
)
def draw(self, context, layout, node, text):
draw_socket_layout(self, layout)
def draw_color(self, context, node):
return 0.631, 0.631, 0.631, 1
def get_default_value(self):
return self.default_value_raw
class ArmIntSocket(ArmCustomSocket):
bl_idname = 'ArmIntSocket'
bl_label = 'Integer Socket'
arm_socket_type = 'INT'
default_value_raw: IntProperty(
name='Value',
description='Input value used for unconnected socket',
update=_on_update_socket
)
def draw(self, context, layout, node, text):
draw_socket_layout(self, layout)
def draw_color(self, context, node):
return 0.059, 0.522, 0.149, 1
def get_default_value(self):
return self.default_value_raw
class ArmObjectSocket(ArmCustomSocket):
bl_idname = 'ArmNodeSocketObject'
bl_label = 'Object Socket'
arm_socket_type = 'OBJECT'
default_value_get: PointerProperty(name='Object', type=bpy.types.Object) # legacy version of the line after this one
default_value_raw: PointerProperty(name='Object', type=bpy.types.Object, update=_on_update_socket)
def __init__(self):
super().__init__()
if self.default_value_get is not None:
self.default_value_raw = self.default_value_get
self.default_value_get = None
def get_default_value(self):
if self.default_value_raw is None:
return ''
if self.default_value_raw.name not in bpy.data.objects:
return self.default_value_raw.name
return arm.utils.asset_name(bpy.data.objects[self.default_value_raw.name])
def draw(self, context, layout, node, text):
if self.is_output:
layout.label(text=self.name)
elif self.is_linked:
layout.label(text=self.name)
else:
row = layout.row(align=True)
row.prop_search(self, 'default_value_raw', context.scene, 'objects', icon='NONE', text=self.name)
def draw_color(self, context, node):
return 0.15, 0.55, 0.75, 1
class ArmStringSocket(ArmCustomSocket):
bl_idname = 'ArmStringSocket'
bl_label = 'String Socket'
arm_socket_type = 'STRING'
default_value_raw: StringProperty(
name='Value',
description='Input value used for unconnected socket',
update=_on_update_socket
)
def draw(self, context, layout, node, text):
draw_socket_layout_split(self, layout)
def draw_color(self, context, node):
return 0.439, 0.698, 1, 1
def get_default_value(self):
return self.default_value_raw
class ArmVectorSocket(ArmCustomSocket):
bl_idname = 'ArmVectorSocket'
bl_label = 'Vector Socket'
arm_socket_type = 'VECTOR'
default_value_raw: FloatVectorProperty(
name='Value',
size=3,
precision=3,
description='Input value used for unconnected socket',
update=_on_update_socket
)
def draw(self, context, layout, node, text):
if not self.is_output and not self.is_linked:
col = layout.column(align=True)
col.label(text=self.name + ":")
col.prop(self, 'default_value_raw', text='')
else:
layout.label(text=self.name)
def draw_color(self, context, node):
return 0.388, 0.388, 0.78, 1
def get_default_value(self):
return self.default_value_raw
def draw_socket_layout(socket: bpy.types.NodeSocket, layout: bpy.types.UILayout, prop_name='default_value_raw'):
if not socket.is_output and not socket.is_linked:
layout.prop(socket, prop_name, text=socket.name)
else:
layout.label(text=socket.name)
def draw_socket_layout_split(socket: bpy.types.NodeSocket, layout: bpy.types.UILayout, prop_name='default_value_raw'):
if not socket.is_output and not socket.is_linked:
# Blender layouts use 0.4 splits
layout = layout.split(factor=0.4, align=True)
layout.label(text=socket.name)
if not socket.is_output and not socket.is_linked:
layout.prop(socket, prop_name, text='')
REG_CLASSES = (
ArmActionSocket,
ArmAnimActionSocket,
ArmArraySocket,
ArmBoolSocket,
ArmColorSocket,
ArmDynamicSocket,
ArmFloatSocket,
ArmIntSocket,
ArmObjectSocket,
ArmStringSocket,
ArmVectorSocket,
)
register, unregister = bpy.utils.register_classes_factory(REG_CLASSES)