mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
269 lines
7.8 KiB
GDScript3
269 lines
7.8 KiB
GDScript3
|
# (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 PanelContainer
|
||
|
class_name Sidebar
|
||
|
|
||
|
@onready var deck_menu: AccordionMenu = %Deck
|
||
|
@onready var node_menu: AccordionMenu = %Node
|
||
|
@onready var node_list_menu: AccordionMenu = %"Node List"
|
||
|
|
||
|
const SYSTEM_CODE_FONT = preload("res://graph_node_renderer/system_code_font.tres")
|
||
|
|
||
|
var edited_deck_id: String
|
||
|
var edited_node_id: String
|
||
|
|
||
|
var deck_inspector: DeckInspector
|
||
|
var node_inspector: NodeInspector
|
||
|
|
||
|
signal go_to_node_requested(node_id: String)
|
||
|
|
||
|
|
||
|
func _ready() -> void:
|
||
|
set_edited_deck()
|
||
|
|
||
|
|
||
|
func set_edited_deck(id: String = "") -> void:
|
||
|
if edited_deck_id == id and not id.is_empty():
|
||
|
return
|
||
|
|
||
|
edited_deck_id = id
|
||
|
set_edited_node("")
|
||
|
|
||
|
for i in deck_menu.get_children():
|
||
|
i.queue_free()
|
||
|
|
||
|
if id.is_empty():
|
||
|
var label := Label.new()
|
||
|
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||
|
label.text = "There is no open Deck. Open or create one to edit its properties."
|
||
|
deck_menu.add_child(label)
|
||
|
deck_inspector = null
|
||
|
return
|
||
|
|
||
|
deck_inspector = DeckInspector.new(id)
|
||
|
for i in deck_inspector.nodes:
|
||
|
deck_menu.add_child(i)
|
||
|
|
||
|
|
||
|
func refresh_node_list(_unused = null) -> void:
|
||
|
for i in node_list_menu.get_children():
|
||
|
i.queue_free()
|
||
|
|
||
|
for node_id: String in DeckHolder.get_deck(edited_deck_id).nodes:
|
||
|
var node := DeckHolder.get_deck(edited_deck_id).get_node(node_id)
|
||
|
var b := Button.new()
|
||
|
b.flat = true
|
||
|
b.text = "\"%s\"" % node.name
|
||
|
b.pressed.connect(
|
||
|
func():
|
||
|
go_to_node_requested.emit(node._id)
|
||
|
)
|
||
|
b.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
b.tooltip_text = "Click to focus this node in the graph"
|
||
|
b.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||
|
b.clip_text = true
|
||
|
|
||
|
var cb := Button.new()
|
||
|
cb.text = "Copy ID"
|
||
|
cb.pressed.connect(
|
||
|
func():
|
||
|
DisplayServer.clipboard_set(node._id)
|
||
|
)
|
||
|
#Util.safe_connect(node.renamed,
|
||
|
#func(new_name: String):
|
||
|
# TODO: bad. if the node (deck node or button, whichever)
|
||
|
# gets removed the captures get invalidated.
|
||
|
# maybe dont use lambda here
|
||
|
#b.text = "\"%s\"" % node.name
|
||
|
#)
|
||
|
#Util.safe_connect(node.renamed, _set_button_text.bind(b))
|
||
|
# this is probably bad too, but its the only one that worked so far.
|
||
|
Util.safe_connect(node.renamed, refresh_node_list)
|
||
|
var hb := HBoxContainer.new()
|
||
|
hb.add_child(b)
|
||
|
hb.add_child(cb)
|
||
|
node_list_menu.add_child(hb)
|
||
|
|
||
|
|
||
|
#func _set_button_text(new_text: String, button: Button) -> void:
|
||
|
# this was also bad. "Cannot convert argument 2 from Object to Object" 🙃
|
||
|
#button.text = "\"%s\"" % new_text
|
||
|
|
||
|
|
||
|
func set_edited_node(id: String = "") -> void:
|
||
|
if edited_node_id == id and not id.is_empty():
|
||
|
return
|
||
|
|
||
|
edited_node_id = id
|
||
|
|
||
|
for i in node_menu.get_children():
|
||
|
i.queue_free()
|
||
|
|
||
|
if id.is_empty():
|
||
|
var label := Label.new()
|
||
|
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||
|
label.text = "There is no Node selected (or multiple are selected). Select a single Node to edit its properties."
|
||
|
node_menu.add_child(label)
|
||
|
node_inspector = null
|
||
|
return
|
||
|
|
||
|
await get_tree().process_frame
|
||
|
|
||
|
node_inspector = NodeInspector.new(edited_deck_id, id)
|
||
|
node_inspector.go_to_node_requested.connect(
|
||
|
func():
|
||
|
go_to_node_requested.emit(edited_node_id)
|
||
|
)
|
||
|
for i in node_inspector.nodes:
|
||
|
node_menu.add_child(i)
|
||
|
|
||
|
DeckHolder.get_deck(edited_deck_id).node_removed.connect(
|
||
|
func(node: DeckNode):
|
||
|
if node._id == edited_node_id:
|
||
|
set_edited_node()
|
||
|
)
|
||
|
|
||
|
|
||
|
class Inspector extends HBoxContainer:
|
||
|
func _init(text: String, editor: Control = null) -> void:
|
||
|
var _label = Label.new()
|
||
|
_label.text = text
|
||
|
_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
|
||
|
add_child(_label)
|
||
|
if editor:
|
||
|
editor.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
add_child(editor)
|
||
|
|
||
|
|
||
|
class DeckInspector:
|
||
|
var ref: WeakRef
|
||
|
var nodes: Array[Control]
|
||
|
|
||
|
|
||
|
func add_inspector(text: String, control: Control = null) -> void:
|
||
|
nodes.append(Inspector.new(text, control))
|
||
|
|
||
|
|
||
|
func _init(id: String) -> void:
|
||
|
ref = weakref(DeckHolder.get_deck(id))
|
||
|
var deck: Deck = ref.get_ref() as Deck
|
||
|
if deck.is_group:
|
||
|
add_inspector("This deck is a group.")
|
||
|
|
||
|
|
||
|
class NodeInspector:
|
||
|
var ref: WeakRef
|
||
|
var nodes: Array[Control]
|
||
|
|
||
|
signal go_to_node_requested()
|
||
|
|
||
|
var DESCRIPTOR_SCENES := {
|
||
|
"button": load("res://graph_node_renderer/descriptors/button_descriptor.tscn"),
|
||
|
"field": load("res://graph_node_renderer/descriptors/field_descriptor.tscn"),
|
||
|
"singlechoice": load("res://graph_node_renderer/descriptors/single_choice_descriptor.tscn"),
|
||
|
"codeblock": load("res://graph_node_renderer/descriptors/codeblock_descriptor.tscn"),
|
||
|
"checkbox": load("res://graph_node_renderer/descriptors/check_box_descriptor.tscn"),
|
||
|
"spinbox": load("res://graph_node_renderer/descriptors/spin_box_descriptor.tscn"),
|
||
|
"label": load("res://graph_node_renderer/descriptors/label_descriptor.tscn"),
|
||
|
}
|
||
|
|
||
|
|
||
|
func add_inspector(text: String, control: Control = null) -> void:
|
||
|
nodes.append(Inspector.new(text, control))
|
||
|
|
||
|
|
||
|
func create_label(text: String) -> Label:
|
||
|
var l := Label.new()
|
||
|
l.text = text
|
||
|
l.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
return l
|
||
|
|
||
|
|
||
|
func _init(deck_id: String, id: String) -> void:
|
||
|
ref = weakref(DeckHolder.get_deck(deck_id).get_node(id))
|
||
|
var node: DeckNode = ref.get_ref() as DeckNode
|
||
|
|
||
|
var type_label := create_label(node.node_type)
|
||
|
var type_label_settings := LabelSettings.new()
|
||
|
type_label_settings.font = SYSTEM_CODE_FONT
|
||
|
type_label_settings.font_size = 14
|
||
|
type_label.label_settings = type_label_settings
|
||
|
var copy_button := Button.new()
|
||
|
copy_button.text = "Copy"
|
||
|
copy_button.pressed.connect(
|
||
|
func():
|
||
|
DisplayServer.clipboard_set(node.node_type)
|
||
|
)
|
||
|
var hb := HBoxContainer.new()
|
||
|
hb.add_child(type_label)
|
||
|
hb.add_child(copy_button)
|
||
|
add_inspector("Node Type:", hb)
|
||
|
|
||
|
var name_field := LineEdit.new()
|
||
|
name_field.placeholder_text = "Node name"
|
||
|
name_field.text = node.name
|
||
|
name_field.text_changed.connect(node.rename)
|
||
|
node.renamed.connect(
|
||
|
func(new_name: String) -> void:
|
||
|
if name_field.has_focus():
|
||
|
return
|
||
|
|
||
|
name_field.text = new_name
|
||
|
)
|
||
|
add_inspector("Node name:", name_field)
|
||
|
|
||
|
var focus_button := Button.new()
|
||
|
focus_button.text = "Focus node"
|
||
|
focus_button.pressed.connect(
|
||
|
func():
|
||
|
go_to_node_requested.emit()
|
||
|
)
|
||
|
focus_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
|
nodes.append(focus_button)
|
||
|
|
||
|
add_port_menu(node.get_input_ports(), node)
|
||
|
add_port_menu(node.get_output_ports(), node)
|
||
|
|
||
|
|
||
|
func add_port_menu(ports: Array[Port], node: DeckNode) -> void:
|
||
|
if ports.is_empty():
|
||
|
return
|
||
|
var ports_menu := AccordionMenu.new()
|
||
|
ports_menu.draw_background = true
|
||
|
var is_output := ports[0].port_type == DeckNode.PortType.OUTPUT
|
||
|
ports_menu.set_name.call_deferred("Output Ports" if is_output else "Input Ports")
|
||
|
for port in ports:
|
||
|
var acc := AccordionMenu.new()
|
||
|
acc.draw_background = true
|
||
|
acc.name = "Port %s" % port.index_of_type
|
||
|
|
||
|
var label_label := create_label("Name: %s" % port.label)
|
||
|
acc.add_child(label_label)
|
||
|
var type_label := create_label("Type: %s" % DeckType.type_str(port.type).to_lower())
|
||
|
acc.add_child(type_label)
|
||
|
var usage_is_both := port.usage_type == Port.UsageType.BOTH
|
||
|
var usage_text = "Both (Value Request or Trigger)" if usage_is_both else Port.UsageType.keys()[port.usage_type].capitalize()
|
||
|
var usage_label := create_label("Usage: %s" % usage_text)
|
||
|
acc.add_child(usage_label)
|
||
|
|
||
|
var descriptor_split := port.descriptor.split(":")
|
||
|
if DESCRIPTOR_SCENES.has(descriptor_split[0]):
|
||
|
var port_hb := HBoxContainer.new()
|
||
|
var value_label := create_label("Value:")
|
||
|
port_hb.add_child(value_label)
|
||
|
var desc: DescriptorContainer = DESCRIPTOR_SCENES[descriptor_split[0]].instantiate()
|
||
|
|
||
|
desc.ready.connect(
|
||
|
func():
|
||
|
desc.set_up_from_port(port, node, false)
|
||
|
)
|
||
|
port_hb.add_child(desc)
|
||
|
|
||
|
acc.add_child(port_hb)
|
||
|
|
||
|
ports_menu.add_child(acc)
|
||
|
ports_menu.collapsed = true
|
||
|
nodes.append(ports_menu)
|