# (c) 2023-present Eroax # (c) 2023-present Yagich # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) extends GraphNode class_name DeckNodeRendererGraphNode ## [GraphNode] based renderer of [DeckNode] ## Stores the data container [DeckNode] that the visuals of this [DeckNodeRendererGraphNode] ## are based off. var node: DeckNode const TYPE_COLORS := { DeckType.Types.BOOL: Color("#7048e0"), DeckType.Types.STRING: Color("#dbe048"), DeckType.Types.NUMERIC: Color("#68e36c"), DeckType.Types.ARRAY: Color("#e36868"), DeckType.Types.DICTIONARY: Color("#79ede3"), DeckType.Types.ANY: Color.WHITE, } ## Setups up all the properties based off [member node]. Including looping through ## [method DeckNode.get_all_ports()] and setting up all the descriptors. func _ready() -> void: title = node.name node.position_updated.connect(_on_node_position_updated) resize_request.connect(_on_resize_request) #node.port_added.connect(_on_node_port_added) #node.port_removed.connect(_on_node_port_removed) node.ports_updated.connect(_on_node_ports_updated) for port in node.get_all_ports(): update_port(port) position_offset_changed.connect(_on_position_offset_changed) node.renamed.connect(_on_node_renamed) if node.node_type == "group_node": get_titlebar_hbox().tooltip_text = "Group %s" % node.group_id.left(8) size = node.get_meta("size", Vector2()) ## Connected to [signal GraphElement.position_offset_updated] and updates the ## [member node]s properties func _on_position_offset_changed() -> void: node.position.x = position_offset.x node.position.y = position_offset.y node.position_updated.emit(node.position) (get_parent() as DeckRendererGraphEdit).dirty = true ## Connected to [member node]s [signal position_updated] to keep parity with the ## data position. func _on_node_position_updated(new_position: Dictionary) -> void: position_offset_changed.disconnect(_on_position_offset_changed) position_offset.x = new_position.x position_offset.y = new_position.y position_offset_changed.connect(_on_position_offset_changed) (get_parent() as DeckRendererGraphEdit).dirty = true func _on_resize_request(new_minsize: Vector2) -> void: node.set_meta(&"size", new_minsize) (get_parent() as DeckRendererGraphEdit).dirty = true ## Connected to [member node]s [signal port_added] handles setting up the specified ## [member Port.descriptor] with it's required nodes/signals etc. + adding the port ## using [method GraphNode.set_slot] func _on_node_port_added(port_idx: int) -> void: var port := node.get_all_ports()[port_idx] update_port(port) ## Connected to [member node]s [signal port_removed], queue_frees the [Node] ## used for the descriptor, as well as using [method GraphNode.set_slot] to remove the slot. func _on_node_port_removed(port_idx: int) -> void: set_slot( port_idx, false, 0, Color.WHITE, false, 0, Color.WHITE, ) get_child(port_idx).queue_free() ## Connected to [member node]s [signal ports_updated]. Remakes all of the ports ## + their descriptors whenever this is received to allow keeping the Renderers ports up to date. func _on_node_ports_updated() -> void: clear_all_slots() for c in get_children(): c.queue_free() for port in node.get_all_ports(): update_port(port) await get_tree().process_frame size = Vector2() func _on_node_renamed(new_name: String) -> void: title = new_name func update_port(port: Port) -> void: var descriptor_split := port.descriptor.split(":") match descriptor_split[0]: "button": var button := Button.new() add_child(button) button.text = port.label if port.port_type == DeckNode.PortType.OUTPUT: button.pressed.connect( func(): node.send(port.index_of_type, true) ) #elif port.port_type == DeckNode.PortType.INPUT: else: button.pressed.connect( func(): node._receive(port.index_of_type, true) ) "field": var line_edit := LineEdit.new() add_child(line_edit) if port.value: line_edit.text = str(port.value) line_edit.placeholder_text = port.label port.value_callback = line_edit.get_text line_edit.text_changed.connect(port.set_value) "singlechoice": var box := OptionButton.new() if descriptor_split.slice(1).is_empty(): if port.value: box.add_item(port.value) else: box.add_item(port.label) else: for item in descriptor_split.slice(1): box.add_item(item) add_child(box) port.value_callback = func(): return box.get_item_text(box.get_selected_id()) if port.type == DeckType.Types.STRING: box.item_selected.connect( func(id: int): port.set_value.call(box.get_item_text(box.get_selected_id())) ) "codeblock": var code_edit = CodeEdit.new() add_child(code_edit) if port.value: code_edit.text = str(port.value) code_edit.placeholder_text = port.label port.value_callback = code_edit.get_text code_edit.text_changed.connect(port.set_value.bind(code_edit.get_text)) code_edit.custom_minimum_size = Vector2(200, 100) code_edit.size_flags_vertical = SIZE_EXPAND_FILL "checkbox": var cb := CheckBox.new() add_child(cb) if descriptor_split.size() > 1: cb.button_pressed = true if port.value is bool: cb.button_pressed = port.value cb.text = port.label port.value_callback = cb.is_pressed cb.toggled.connect(port.set_value) "spinbox": var sb := SpinBox.new() add_child(sb) if port.value != null: sb.value = float(port.value) if "unbounded" in descriptor_split: sb.max_value = 99999 sb.allow_greater = true sb.allow_lesser = true if descriptor_split.size() > 2: sb.step = float(descriptor_split[1]) else: sb.step = 1.0 else: sb.min_value = float(descriptor_split[1]) if descriptor_split.size() > 2: sb.max_value = float(descriptor_split[2]) if descriptor_split.size() > 3: sb.step = float(descriptor_split[3]) port.value_callback = sb.get_value sb.value_changed.connect(port.set_value) _: var label := Label.new() add_child(label) label.text = port.label if port.port_type == DeckNode.PortType.OUTPUT: label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT set_slot( port.index, port.port_type == DeckNode.PortType.INPUT, port.type, TYPE_COLORS[port.type], port.port_type == DeckNode.PortType.OUTPUT, port.type, TYPE_COLORS[port.type], )