armory/blender/arm/logicnode/logic/LN_select.py
Moritz Brückner 20f9f8a5f4 Add Select node
Implements feature requests #2200 and #2201
2021-06-05 20:35:21 +02:00

123 lines
4.2 KiB
Python

from bpy.types import NodeSocketInterfaceInt
from arm.logicnode.arm_nodes import *
class SelectNode(ArmLogicTreeNode):
"""Selects one of multiple values (of arbitrary types) based on some
input state. The exact behaviour of this node is specified by the
`Execution Mode` option (see below).
@output Out: [*Available if Execution Mode is set to From Input*]
Activated after the node was executed.
@output Value: The last selected value. This value is not reset
until the next execution of this node.
@option Execution Mode: Specifies the condition that determines
what value to choose.
- `From Index`: Select the value at the given index. If there is
no value at that index, the value plugged in to the
`Default` input is used instead (`null` if unconnected).
- `From Input`: This mode uses input pairs of one action socket
and one value socket. Depending on which action socket is
activated, the associated value socket (the value with the
same index as the activated action input) is forwarded to
the `Value` output.
@option New: Add a new value to the list of values.
@option X Button: Remove the value with the highest index."""
bl_idname = 'LNSelectNode'
bl_label = 'Select'
arm_version = 1
min_inputs = 2
def update_exec_mode(self, context):
self.set_mode()
property0: EnumProperty(
name='Execution Mode',
description="The node's behaviour.",
items=[
('from_index', 'From Index', 'Choose the value from the given index'),
('from_input', 'From Input', 'Choose the value with the same position as the active input')],
default='from_index',
update=update_exec_mode,
)
# The number of choices, NOT of individual inputs. This needs to be
# a property in order to be saved with each individual node
num_choices: IntProperty(default=1, min=0)
def __init__(self):
super().__init__()
array_nodes[str(id(self))] = self
def init(self, context):
super().init(context)
self.set_mode()
def set_mode(self):
self.inputs.clear()
self.outputs.clear()
if self.property0 == 'from_index':
self.add_input('NodeSocketInt', 'Index')
self.add_input('NodeSocketShader', 'Default')
self.num_choices = 0
# from_input
else:
# We could also start with index 1 here, but we need to use
# 0 for the "from_index" mode and it makes the code simpler
# if we stick to the same convention for both exec modes
self.add_input('ArmNodeSocketAction', 'Input 0')
self.add_input('NodeSocketShader', 'Value 0')
self.num_choices = 1
self.add_output('ArmNodeSocketAction', 'Out')
self.add_output('NodeSocketShader', 'Value')
def draw_buttons(self, context, layout):
layout.prop(self, 'property0', text='')
row = layout.row(align=True)
op = row.operator('arm.node_call_func', text='New', icon='PLUS', emboss=True)
op.node_index = str(id(self))
op.callback_name = 'add_input_func'
op = row.operator('arm.node_call_func', text='', icon='X', emboss=True)
op.node_index = str(id(self))
op.callback_name = 'remove_input_func'
def add_input_func(self):
if self.property0 == 'from_input':
self.add_input('ArmNodeSocketAction', f'Input {self.num_choices}')
# Move new action input up to the end of all other action inputs
self.inputs.move(from_index=len(self.inputs) - 1, to_index=self.num_choices)
self.add_input('NodeSocketShader', f'Value {self.num_choices}')
self.num_choices += 1
def remove_input_func(self):
if self.property0 == 'from_input':
if len(self.inputs) > self.min_inputs:
self.inputs.remove(self.inputs[self.num_choices - 1])
if len(self.inputs) > self.min_inputs:
self.inputs.remove(self.inputs[-1])
self.num_choices -= 1
def draw_label(self) -> str:
if self.num_choices == 0:
return self.bl_label
return f'{self.bl_label}: [{self.num_choices}]'