miggor-StreamGraph/graph_node_renderer/sidebar/sidebar.gd

269 lines
7.8 KiB
GDScript3
Raw Normal View History

# (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)