mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
group descriptors (#156)
closes #93 Reviewed-on: https://codeberg.org/StreamGraph/StreamGraph/pulls/156 Co-authored-by: Lera Elvoé <yagich@poto.cafe> Co-committed-by: Lera Elvoé <yagich@poto.cafe>
This commit is contained in:
parent
ba2dd6a837
commit
8156e4769f
12 changed files with 478 additions and 44 deletions
|
@ -25,6 +25,8 @@ var is_group: bool = false
|
|||
## Whether this deck is a library. Implies [member is_group].
|
||||
var is_library: bool = false
|
||||
|
||||
var group_descriptors := GroupDescriptors.new()
|
||||
|
||||
#region library group props
|
||||
## The initial name of the library. Displayed by the group node and [SearchProvider].
|
||||
var lib_name: String
|
||||
|
@ -73,11 +75,16 @@ signal node_moved_to_deck(node: DeckNode, other: Deck)
|
|||
signal node_added_to_group(node: DeckNode, assign_id: String, assign_to_self: bool, deck: Deck)
|
||||
signal node_removed_from_group(node_id: String, remove_connections: bool, deck: Deck)
|
||||
signal node_port_value_updated(node_id: String, port_idx: int, new_value: Variant, deck: Deck)
|
||||
signal node_ports_updated(node_id: String, deck: Deck)
|
||||
signal node_renamed(node_id: String, new_name: String, deck: Deck)
|
||||
signal node_moved(node_id: String, new_position: Dictionary, deck: Deck)
|
||||
#endregion
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
group_descriptors.deck = self
|
||||
|
||||
|
||||
## Instantiate a node by its' [member DeckNode.node_type] and add it to this deck.[br]
|
||||
## See [method add_node_inst] for parameter descriptions.
|
||||
func add_node_type(type: String, assign_id: String = "", assign_to_self: bool = true) -> DeckNode:
|
||||
|
@ -104,6 +111,12 @@ func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool
|
|||
nodes[assign_id] = node
|
||||
node._id = assign_id
|
||||
|
||||
if node.node_type == "group_input":
|
||||
group_input_node = node._id
|
||||
|
||||
if node.node_type == "group_output":
|
||||
group_output_node = node._id
|
||||
|
||||
if emit_node_added_signal:
|
||||
node_added.emit(node)
|
||||
|
||||
|
@ -128,6 +141,12 @@ func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool
|
|||
node_moved.emit(node._id, new_position, self)
|
||||
)
|
||||
|
||||
node.ports_updated.connect(
|
||||
func():
|
||||
if is_group and emit_group_signals:
|
||||
node_ports_updated.emit(node._id, self)
|
||||
)
|
||||
|
||||
print_verbose("Deck %s::%s: added node %s, id %s" % [id, instance_id, node.node_type, node.get_instance_id()])
|
||||
|
||||
return node
|
||||
|
@ -479,6 +498,7 @@ func paste_nodes_from_dict(nodes_to_paste: Dictionary, position: Vector2 = Vecto
|
|||
node.group_instance_id = group.instance_id
|
||||
group.get_node(group.group_input_node).group_node = node
|
||||
group.get_node(group.group_output_node).group_node = node
|
||||
|
||||
node.input_node = group.get_node(group.group_input_node)
|
||||
node.output_node = group.get_node(group.group_output_node)
|
||||
node.init_io()
|
||||
|
@ -598,6 +618,9 @@ func to_dict(with_meta: bool = true, group_ids: Array = []) -> Dictionary:
|
|||
"connections": connections.to_dict(),
|
||||
}
|
||||
|
||||
if not group_descriptors.is_empty():
|
||||
inner["group_descriptors"] = group_descriptors.to_dict()
|
||||
|
||||
for node_id: String in nodes.keys():
|
||||
inner["nodes"][node_id] = nodes[node_id].to_dict(with_meta)
|
||||
if get_node(node_id).node_type == "group_node" and not get_node(node_id).is_library:
|
||||
|
@ -645,6 +668,10 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
|||
deck.lib_description = lib_data.get("lib_description", "")
|
||||
# deck.lib_aliases = lib_data.get("lib_aliases", [])
|
||||
|
||||
if data.deck.has("group_descriptors"):
|
||||
deck.group_descriptors = GroupDescriptors.from_dict(data.deck.group_descriptors)
|
||||
deck.group_descriptors.deck = deck
|
||||
|
||||
for key in data.meta:
|
||||
deck.set_meta(key, str_to_var(data.meta[key]))
|
||||
|
||||
|
@ -653,6 +680,7 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
|||
for node_id in nodes_data:
|
||||
var node := DeckNode.from_dict(nodes_data[node_id], deck.connections)
|
||||
deck.add_node_inst(node, node_id)
|
||||
node._post_deck_load()
|
||||
|
||||
var groups_data: Dictionary = data.deck.groups as Dictionary
|
||||
|
||||
|
@ -986,3 +1014,172 @@ class OutgoingConnection:
|
|||
|
||||
func to_dict() -> Dictionary:
|
||||
return {"to_node": to_node, "to_port": to_port}
|
||||
|
||||
|
||||
class GroupDescriptors:
|
||||
var input_ports: Dictionary = {} # Dictionary[int -> input port idx, GroupPort]
|
||||
var output_ports: Dictionary = {} # Dictionary[int -> output port idx, GroupPort]
|
||||
var deck: Deck
|
||||
|
||||
|
||||
func is_empty() -> bool:
|
||||
if input_ports.is_empty() and output_ports.is_empty():
|
||||
return true
|
||||
|
||||
var test := func(e: GroupPort) -> bool:
|
||||
return not e.is_empty()
|
||||
|
||||
var has_inputs = input_ports.values().any(test)
|
||||
var has_outputs = output_ports.values().any(test)
|
||||
|
||||
if has_inputs or has_outputs:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _on_input_updated(port_idx: int) -> void:
|
||||
var node := deck.get_node(deck.group_input_node)
|
||||
var port := node.get_output_ports()[port_idx]
|
||||
var port_override := get_input_port(port_idx)
|
||||
|
||||
if port_override.label.is_empty():
|
||||
port.label = "Input %s" % port_idx
|
||||
else:
|
||||
port.label = port_override.label
|
||||
|
||||
port.type = port_override.type
|
||||
port.descriptor = port_override.descriptor
|
||||
port.usage_type = port_override.usage_type
|
||||
|
||||
node.ports_updated.emit()
|
||||
|
||||
|
||||
func _on_output_updated(port_idx: int) -> void:
|
||||
var node := deck.get_node(deck.group_output_node)
|
||||
var port := node.get_input_ports()[port_idx]
|
||||
var port_override := get_output_port(port_idx)
|
||||
if port_override.label.is_empty():
|
||||
port.label = "Output %s" % port_idx
|
||||
else:
|
||||
port.label = port_override.label
|
||||
|
||||
port.type = port_override.type
|
||||
port.descriptor = port_override.descriptor
|
||||
port.usage_type = port_override.usage_type
|
||||
|
||||
node.ports_updated.emit()
|
||||
|
||||
|
||||
func _get_or_create_input(port_idx: int) -> GroupPort:
|
||||
var res := input_ports.get(port_idx, null) as GroupPort
|
||||
if res == null:
|
||||
var gr := GroupPort.new()
|
||||
input_ports[port_idx] = gr
|
||||
res = gr
|
||||
|
||||
Util.safe_connect(res.updated, _on_input_updated.bind(port_idx))
|
||||
|
||||
return res
|
||||
|
||||
|
||||
func _get_or_create_output(port_idx: int) -> GroupPort:
|
||||
var res := output_ports.get(port_idx, null) as GroupPort
|
||||
if res == null:
|
||||
var gr := GroupPort.new()
|
||||
output_ports[port_idx] = gr
|
||||
res = gr
|
||||
|
||||
Util.safe_connect(res.updated, _on_output_updated.bind(port_idx))
|
||||
|
||||
return res
|
||||
|
||||
|
||||
func get_input_port(port_idx: int) -> GroupPort:
|
||||
return _get_or_create_input(port_idx)
|
||||
|
||||
|
||||
func get_output_port(port_idx: int) -> GroupPort:
|
||||
return _get_or_create_output(port_idx)
|
||||
|
||||
|
||||
func to_dict() -> Dictionary:
|
||||
var res := {
|
||||
"input_ports": {},
|
||||
"output_ports": {},
|
||||
}
|
||||
|
||||
for port_idx: int in input_ports:
|
||||
var gp := input_ports[port_idx] as GroupPort
|
||||
if gp.is_empty():
|
||||
continue
|
||||
res["input_ports"][port_idx] = gp.to_dict()
|
||||
|
||||
for port_idx: int in output_ports:
|
||||
var gp := output_ports[port_idx] as GroupPort
|
||||
if gp.is_empty():
|
||||
continue
|
||||
res["output_ports"][port_idx] = gp.to_dict()
|
||||
|
||||
return res
|
||||
|
||||
|
||||
static func from_dict(d: Dictionary) -> GroupDescriptors:
|
||||
var res := GroupDescriptors.new()
|
||||
|
||||
for port_idx in d.input_ports:
|
||||
res.input_ports[int(port_idx)] = GroupPort.from_dict(d.input_ports[port_idx])
|
||||
|
||||
for port_idx in d.output_ports:
|
||||
res.output_ports[int(port_idx)] = GroupPort.from_dict(d.output_ports[port_idx])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class GroupPort:
|
||||
var type: DeckType.Types = DeckType.Types.ANY:
|
||||
set(v):
|
||||
type = v
|
||||
updated.emit()
|
||||
var label: String:
|
||||
set(v):
|
||||
label = v
|
||||
updated.emit()
|
||||
var descriptor: String:
|
||||
set(v):
|
||||
descriptor = v
|
||||
updated.emit()
|
||||
var usage_type: Port.UsageType = Port.UsageType.BOTH:
|
||||
set(v):
|
||||
usage_type = v
|
||||
updated.emit()
|
||||
|
||||
signal updated()
|
||||
|
||||
|
||||
func is_empty() -> bool:
|
||||
return\
|
||||
type == DeckType.Types.ANY and\
|
||||
label.is_empty() and\
|
||||
descriptor.is_empty() and\
|
||||
usage_type == Port.UsageType.BOTH
|
||||
|
||||
|
||||
func to_dict() -> Dictionary:
|
||||
var res := {
|
||||
"type": type,
|
||||
"label": label,
|
||||
"descriptor": descriptor,
|
||||
"usage_type": usage_type,
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
|
||||
static func from_dict(d: Dictionary) -> GroupPort:
|
||||
var res := GroupPort.new()
|
||||
res.type = d.type as DeckType.Types
|
||||
res.label = d.label
|
||||
res.descriptor = d.descriptor
|
||||
res.usage_type = d.usage_type as Port.UsageType
|
||||
return res
|
||||
|
|
|
@ -185,6 +185,7 @@ static func connect_group_signals(group: Deck) -> void:
|
|||
group.node_added_to_group.connect(DeckHolder._on_node_added_to_group)
|
||||
group.node_removed_from_group.connect(DeckHolder._on_node_removed_from_group)
|
||||
group.node_port_value_updated.connect(DeckHolder._on_node_port_value_updated)
|
||||
group.node_ports_updated.connect(DeckHolder._on_node_ports_updated)
|
||||
group.node_renamed.connect(DeckHolder._on_node_renamed)
|
||||
group.node_moved.connect(DeckHolder._on_node_moved)
|
||||
|
||||
|
@ -343,6 +344,29 @@ static func _on_node_port_value_updated(node_id: String, port_idx: int, new_valu
|
|||
instance.emit_group_signals = true
|
||||
|
||||
|
||||
static func _on_node_ports_updated(node_id: String, deck: Deck) -> void:
|
||||
var group_id := deck.id
|
||||
var original_node := deck.get_node(node_id)
|
||||
for instance_id: String in decks[group_id]:
|
||||
if instance_id == deck.instance_id:
|
||||
continue
|
||||
|
||||
var instance: Deck = get_group_instance(group_id, instance_id)
|
||||
instance.emit_group_signals = false
|
||||
var node := instance.get_node(node_id)
|
||||
node.ports.clear()
|
||||
for port in original_node.ports:
|
||||
node.add_port(
|
||||
port.type,
|
||||
port.label,
|
||||
port.port_type,
|
||||
port.index_of_type,
|
||||
port.descriptor,
|
||||
port.usage_type,
|
||||
)
|
||||
instance.emit_group_signals = true
|
||||
|
||||
|
||||
static func _on_node_renamed(node_id: String, new_name: String, deck: Deck) -> void:
|
||||
var group_id := deck.id
|
||||
for instance_id: String in decks[group_id]:
|
||||
|
|
|
@ -250,6 +250,12 @@ func _post_load(connections: Deck.NodeConnections) -> void:
|
|||
pass
|
||||
|
||||
|
||||
## Virtual function that's called by the parent [Deck] after the node has been deserialized, and after
|
||||
## [method _post_load].
|
||||
func _post_deck_load() -> void:
|
||||
pass
|
||||
|
||||
|
||||
## A helper function to get a value on an input port. Returns the best match in the following
|
||||
## order of priority:[br]
|
||||
## 1. The direct result of [method request value], called asynchronously. [br]
|
||||
|
|
|
@ -55,21 +55,25 @@ func _on_outgoing_connection_removed(port_idx: int) -> void:
|
|||
|
||||
|
||||
func _pre_port_load() -> void:
|
||||
ports.clear()
|
||||
for i in output_count:
|
||||
add_output_port(
|
||||
DeckType.Types.ANY,
|
||||
"Input %s" % (i + 1)
|
||||
"Input %s" % i
|
||||
)
|
||||
output_count = 0
|
||||
|
||||
|
||||
func _post_load(connections: Deck.NodeConnections) -> void:
|
||||
# ensure we have enough ports after connections
|
||||
var last_connected_port := 0
|
||||
var last_connected_port := -1
|
||||
var outgoing_connections = connections.get_all_outgoing_connections(_id)
|
||||
for port: int in outgoing_connections:
|
||||
last_connected_port = port if outgoing_connections.has(port) else last_connected_port
|
||||
|
||||
if last_connected_port == -1:
|
||||
return
|
||||
|
||||
if ports.size() <= last_connected_port:
|
||||
for i in last_connected_port:
|
||||
add_output_port(
|
||||
|
@ -78,6 +82,17 @@ func _post_load(connections: Deck.NodeConnections) -> void:
|
|||
)
|
||||
|
||||
|
||||
func _post_deck_load() -> void:
|
||||
for port in get_output_ports():
|
||||
var gp := _belonging_to.group_descriptors.get_input_port(port.index_of_type)
|
||||
if gp.is_empty():
|
||||
continue
|
||||
port.label = gp.label
|
||||
port.descriptor = gp.descriptor
|
||||
port.type = gp.type
|
||||
port.usage_type = gp.usage_type
|
||||
|
||||
|
||||
func _value_request(from_port: int) -> Variant:
|
||||
if group_node:
|
||||
return await group_node.request_value_async(group_node.get_input_ports()[from_port].index_of_type)
|
||||
|
|
|
@ -23,13 +23,13 @@ func _init() -> void:
|
|||
appears_in_search = false
|
||||
|
||||
|
||||
func _pre_port_load() -> void:
|
||||
for port_type: PortType in extra_ports:
|
||||
match port_type:
|
||||
PortType.OUTPUT:
|
||||
add_output_port(DeckType.Types.ANY, "Output %s" % get_output_ports().size())
|
||||
PortType.INPUT:
|
||||
add_input_port(DeckType.Types.ANY, "Input %s" % get_input_ports().size())
|
||||
#func _pre_port_load() -> void:
|
||||
#for port_type: PortType in extra_ports:
|
||||
#match port_type:
|
||||
#PortType.OUTPUT:
|
||||
#add_output_port(DeckType.Types.ANY, "Output %s" % get_output_ports().size())
|
||||
#PortType.INPUT:
|
||||
#add_input_port(DeckType.Types.ANY, "Input %s" % get_input_ports().size())
|
||||
|
||||
|
||||
func init_io() -> void:
|
||||
|
@ -64,14 +64,18 @@ func recalculate_ports() -> void:
|
|||
|
||||
for output_port: Port in output_node.get_input_ports():
|
||||
add_output_port(
|
||||
DeckType.Types.ANY,
|
||||
"Output %s" % output_port.index
|
||||
output_port.type,
|
||||
output_port.label,
|
||||
output_port.descriptor,
|
||||
output_port.usage_type,
|
||||
)
|
||||
|
||||
for input_port: Port in input_node.get_output_ports():
|
||||
add_input_port(
|
||||
DeckType.Types.ANY,
|
||||
"Input %s" % input_port.index
|
||||
input_port.type,
|
||||
input_port.label,
|
||||
input_port.descriptor,
|
||||
input_port.usage_type,
|
||||
)
|
||||
|
||||
extra_ports.clear()
|
||||
|
|
|
@ -56,10 +56,11 @@ func _on_incoming_connection_removed(port_idx: int) -> void:
|
|||
|
||||
|
||||
func _pre_port_load() -> void:
|
||||
ports.clear()
|
||||
for i in input_count:
|
||||
add_input_port(
|
||||
DeckType.Types.ANY,
|
||||
"Output %s" % (i + 1)
|
||||
"Output %s" % i
|
||||
)
|
||||
input_count = 0
|
||||
|
||||
|
@ -79,6 +80,17 @@ func _post_load(connections: Deck.NodeConnections) -> void:
|
|||
)
|
||||
|
||||
|
||||
func _post_deck_load() -> void:
|
||||
for port in get_input_ports():
|
||||
var gp := _belonging_to.group_descriptors.get_output_port(port.index_of_type)
|
||||
if gp.is_empty():
|
||||
continue
|
||||
port.label = gp.label
|
||||
port.descriptor = gp.descriptor
|
||||
port.type = gp.type
|
||||
port.usage_type = gp.usage_type
|
||||
|
||||
|
||||
func _receive(to_input_port: int, data: Variant) -> void:
|
||||
if group_node:
|
||||
group_node.send(group_node.get_output_ports()[to_input_port].index_of_type, data)
|
||||
|
|
|
@ -9,13 +9,13 @@ static var _batches: Dictionary # Dictionary[StringName, BatchConnection]
|
|||
|
||||
## Connects the [param p_func] to [param p_signal] if that connection doesn't already exist.
|
||||
static func safe_connect(p_signal: Signal, p_func: Callable) -> void:
|
||||
if not p_signal.is_null() and p_func.is_valid() and not p_signal.is_connected(p_func):
|
||||
if is_instance_valid(p_signal.get_object()) and is_instance_valid(p_func.get_object()) and not p_signal.is_null() and p_func.is_valid() and not p_signal.is_connected(p_func):
|
||||
p_signal.connect(p_func)
|
||||
|
||||
|
||||
## Disconnects the [param p_func] from [param p_signal] if that connection exists.
|
||||
static func safe_disconnect(p_signal: Signal, p_func: Callable) -> void:
|
||||
if not p_signal.is_null() and p_func.is_valid() and p_signal.is_connected(p_func):
|
||||
if is_instance_valid(p_signal.get_object()) and is_instance_valid(p_func.get_object()) and not p_signal.is_null() and p_func.is_valid() and p_signal.is_connected(p_func):
|
||||
p_signal.disconnect(p_func)
|
||||
|
||||
|
||||
|
|
|
@ -112,14 +112,7 @@ func _ready() -> void:
|
|||
|
||||
add_recents_to_menu()
|
||||
|
||||
tab_container.tab_close_requested.connect(
|
||||
func(tab: int):
|
||||
if tab_container.get_tab_metadata(tab, "dirty") and not tab_container.get_tab_metadata(tab, "group"):
|
||||
unsaved_changes_dialog_single_deck.set_meta("tab", tab)
|
||||
unsaved_changes_dialog_single_deck.show()
|
||||
return
|
||||
await close_tab(tab)
|
||||
)
|
||||
tab_container.tab_close_requested.connect(request_tab_close)
|
||||
|
||||
file_dialog.canceled.connect(disconnect_file_dialog_signals)
|
||||
Connections.obs_websocket = no_obsws
|
||||
|
@ -184,6 +177,7 @@ func _notification(what: int) -> void:
|
|||
func _on_tab_container_tab_about_to_change(previous_tab: int) -> void:
|
||||
var deck := get_deck_at_tab(previous_tab)
|
||||
if deck == null:
|
||||
sidebar.set_edited_deck()
|
||||
return
|
||||
|
||||
Util.safe_disconnect(deck.variables_updated, bottom_dock.rebuild_variable_tree)
|
||||
|
@ -198,6 +192,7 @@ func _on_tab_container_tab_about_to_change(previous_tab: int) -> void:
|
|||
func _on_tab_container_tab_changed(tab: int) -> void:
|
||||
var deck := get_active_deck()
|
||||
if deck == null:
|
||||
sidebar.set_edited_deck()
|
||||
return
|
||||
var is_group = tab_container.get_tab_metadata(tab, "group", false)
|
||||
file_popup_menu.set_item_disabled(FileMenuId.SAVE, is_group)
|
||||
|
@ -245,7 +240,7 @@ func _on_file_id_pressed(id: int) -> void:
|
|||
FileMenuId.SAVE_AS when tab_container.get_tab_count() > 0:
|
||||
open_save_dialog(tab_container.get_tab_metadata(tab_container.get_current_tab(), "path"))
|
||||
FileMenuId.CLOSE:
|
||||
close_current_tab()
|
||||
request_tab_close(tab_container.get_current_tab())
|
||||
_ when id in range(FileMenuId.RECENTS, FileMenuId.RECENTS + max_recents + 1):
|
||||
open_deck_at_path(recent_files[id - FileMenuId.RECENTS - 1])
|
||||
|
||||
|
@ -299,6 +294,14 @@ func close_current_tab() -> void:
|
|||
tab_container.close_tab(tab_container.get_current_tab())
|
||||
|
||||
|
||||
func request_tab_close(tab: int):
|
||||
if tab_container.get_tab_metadata(tab, "dirty") and not tab_container.get_tab_metadata(tab, "group"):
|
||||
unsaved_changes_dialog_single_deck.set_meta("tab", tab)
|
||||
unsaved_changes_dialog_single_deck.show()
|
||||
return
|
||||
await close_tab(tab)
|
||||
|
||||
|
||||
func close_tab(tab: int) -> void:
|
||||
if not tab_container.get_tab_metadata(tab, "group"):
|
||||
var groups := DeckHolder.close_deck(tab_container.get_tab_metadata(tab, "id"))
|
||||
|
@ -310,8 +313,10 @@ func close_tab(tab: int) -> void:
|
|||
await get_tree().process_frame
|
||||
|
||||
tab_container.close_tab(tab)
|
||||
var tc = tab_container.get_tab_count()
|
||||
if tab_container.get_tab_count() == 0:
|
||||
bottom_dock.variable_viewer.disable_new_button()
|
||||
sidebar.set_edited_deck()
|
||||
|
||||
|
||||
## Opens [member file_dialog] with the mode [member FileDialog.FILE_MODE_SAVE_FILE]
|
||||
|
|
|
@ -19,11 +19,11 @@ func _setup(port: Port, node: DeckNode) -> void:
|
|||
else:
|
||||
spin_box.step = 1.0
|
||||
else:
|
||||
spin_box.min_value = float(descriptor[2])
|
||||
spin_box.min_value = float(descriptor[1])
|
||||
if descriptor.size() > 2:
|
||||
spin_box.max_value = float(descriptor[3])
|
||||
spin_box.max_value = float(descriptor[2])
|
||||
if descriptor.size() > 3:
|
||||
spin_box.step = float(descriptor[4])
|
||||
spin_box.step = float(descriptor[3])
|
||||
port.value_callback = spin_box.get_value
|
||||
spin_box.value_changed.connect(port.set_value)
|
||||
spin_box.editable = not node._belonging_to.is_library
|
||||
|
|
|
@ -40,6 +40,8 @@ var _title: String
|
|||
var _renamed_lambda = func():
|
||||
_set_title(name)
|
||||
|
||||
signal menu_collapsed(is_visible: bool)
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if get_child_count(true) > 0 and get_child(0, true) is CollapseButton:
|
||||
|
@ -92,6 +94,7 @@ func collapse() -> void:
|
|||
for child in get_children(false):
|
||||
child.visible = false
|
||||
if is_inside_tree():
|
||||
menu_collapsed.emit(true)
|
||||
await get_tree().process_frame
|
||||
update_minimum_size()
|
||||
|
||||
|
@ -103,6 +106,7 @@ func uncollapse() -> void:
|
|||
for child in get_children(false):
|
||||
child.visible = true
|
||||
if is_inside_tree():
|
||||
menu_collapsed.emit(false)
|
||||
await get_tree().process_frame
|
||||
update_minimum_size()
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ var edited_node_id: String
|
|||
var deck_inspector: DeckInspector
|
||||
var node_inspector: NodeInspector
|
||||
|
||||
static var collapsed_menus: Dictionary # Dictionary[String -> id, bool -> collapsed]
|
||||
|
||||
signal go_to_node_requested(node_id: String)
|
||||
|
||||
|
||||
|
@ -133,6 +135,18 @@ func set_edited_node(id: String = "") -> void:
|
|||
#)
|
||||
|
||||
|
||||
static func create_menu(title: String, id: String, default_collapsed: bool = false) -> AccordionMenu:
|
||||
var res := AccordionMenu.new()
|
||||
res.set_title(title)
|
||||
res.collapsed = collapsed_menus.get(id, default_collapsed)
|
||||
res.menu_collapsed.connect(
|
||||
func(p_is_visible: bool) -> void:
|
||||
collapsed_menus[id] = p_is_visible
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
class Inspector extends HBoxContainer:
|
||||
func _init(text: String, editor: Control = null) -> void:
|
||||
var _label = Label.new()
|
||||
|
@ -148,13 +162,14 @@ class Inspector extends HBoxContainer:
|
|||
class DeckInspector:
|
||||
var ref: WeakRef
|
||||
var nodes: Array[Control]
|
||||
var group_descriptors_inspector: GroupDescriptorsInspector
|
||||
|
||||
|
||||
func add_inspector(text: String, control: Control = null) -> void:
|
||||
nodes.append(Inspector.new(text, control))
|
||||
|
||||
|
||||
func create_label(text: String) -> Label:
|
||||
static func create_label(text: String) -> Label:
|
||||
var l := Label.new()
|
||||
l.text = text
|
||||
l.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
|
@ -165,7 +180,7 @@ class DeckInspector:
|
|||
var hb := HBoxContainer.new()
|
||||
|
||||
control.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
hb.add_child(create_label(text))
|
||||
hb.add_child(DeckInspector.create_label(text))
|
||||
hb.add_child(control)
|
||||
|
||||
return hb
|
||||
|
@ -186,7 +201,7 @@ class DeckInspector:
|
|||
else:
|
||||
lib_group_text = "This deck is a group."
|
||||
|
||||
var l := create_label(lib_group_text)
|
||||
var l := DeckInspector.create_label(lib_group_text)
|
||||
l.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||
l.custom_minimum_size.x = 40
|
||||
lib_menu.add_child(l)
|
||||
|
@ -215,7 +230,166 @@ class DeckInspector:
|
|||
desc_field.custom_minimum_size.x = 100
|
||||
lib_menu.add_child(create_hb_label("Library description:", desc_field))
|
||||
|
||||
group_descriptors_inspector = GroupDescriptorsInspector.new(deck)
|
||||
|
||||
nodes.append(lib_menu)
|
||||
nodes.append(group_descriptors_inspector.menu)
|
||||
|
||||
|
||||
class GroupDescriptorsInspector:
|
||||
var menu: AccordionMenu
|
||||
|
||||
var inputs_menu: AccordionMenu
|
||||
var outputs_menu: AccordionMenu
|
||||
var deck: Deck
|
||||
|
||||
|
||||
func _init(p_deck: Deck) -> void:
|
||||
deck = p_deck
|
||||
|
||||
menu = AccordionMenu.new()
|
||||
menu.set_title("Group Inputs/Outputs")
|
||||
|
||||
inputs_menu = Sidebar.create_menu("Inputs", "group_inputs", true)
|
||||
outputs_menu = Sidebar.create_menu("Outputs", "group_outputs", true)
|
||||
|
||||
deck.node_added.connect(_on_deck_node_added)
|
||||
|
||||
create_inputs()
|
||||
create_outputs()
|
||||
|
||||
menu.add_child(inputs_menu)
|
||||
menu.add_child(outputs_menu)
|
||||
|
||||
|
||||
func _on_deck_node_added(node: DeckNode) -> void:
|
||||
if node.node_type == "group_input":
|
||||
Util.safe_connect(node.ports_updated, refresh_inputs.bind(node))
|
||||
create_inputs(node)
|
||||
if node.node_type == "group_output":
|
||||
Util.safe_connect(node.ports_updated, refresh_outputs.bind(node))
|
||||
create_outputs(node)
|
||||
|
||||
|
||||
func refresh_inputs(node: DeckNode) -> void:
|
||||
# oh boy
|
||||
var root := menu.get_tree().get_root()
|
||||
var fo := root.gui_get_focus_owner()
|
||||
if inputs_menu.is_ancestor_of(fo):
|
||||
return
|
||||
|
||||
create_inputs(node)
|
||||
|
||||
|
||||
func refresh_outputs(node: DeckNode) -> void:
|
||||
# oh boy
|
||||
var root := menu.get_tree().get_root()
|
||||
var fo := root.gui_get_focus_owner()
|
||||
if outputs_menu.is_ancestor_of(fo):
|
||||
return
|
||||
|
||||
create_outputs(node)
|
||||
|
||||
|
||||
func create_inputs(node: DeckNode = null) -> void:
|
||||
create_io(true, node)
|
||||
|
||||
|
||||
func create_outputs(node: DeckNode = null) -> void:
|
||||
create_io(false, node)
|
||||
|
||||
|
||||
func create_io(input: bool = true, node: DeckNode = null) -> void:
|
||||
var io_menu := inputs_menu if input else outputs_menu
|
||||
for i in io_menu.get_children(false):
|
||||
i.queue_free()
|
||||
|
||||
if node == null:
|
||||
if input and deck.get_node(deck.group_input_node) == null:
|
||||
var l := DeckInspector.create_label("No input node")
|
||||
io_menu.add_child(l)
|
||||
return
|
||||
if not input and deck.get_node(deck.group_output_node) == null:
|
||||
var l := DeckInspector.create_label("No output node")
|
||||
io_menu.add_child(l)
|
||||
return
|
||||
|
||||
if input:
|
||||
node = deck.get_node(deck.group_input_node)
|
||||
else:
|
||||
node = deck.get_node(deck.group_output_node)
|
||||
|
||||
var refresh_func := refresh_inputs if input else refresh_outputs
|
||||
Util.safe_connect(node.ports_updated, refresh_func.bind(node))
|
||||
|
||||
var ports := node.get_output_ports() if input else node.get_input_ports()
|
||||
var get_port := func(index: int) -> Deck.GroupPort:
|
||||
if input:
|
||||
return deck.group_descriptors.get_input_port(index)
|
||||
else:
|
||||
return deck.group_descriptors.get_output_port(index)
|
||||
|
||||
|
||||
for i in ports.size():
|
||||
var port_override: Deck.GroupPort = get_port.call(i)
|
||||
var menu_title := "Input %s" if input else "Output %s"
|
||||
var menu_id := "group_input_%s" if input else "group_output_%s"
|
||||
var _menu := Sidebar.create_menu(menu_title % i, menu_id % i, true)
|
||||
#input_menu.set_title("Input %s" % i)
|
||||
|
||||
var port_label_field := LineEdit.new()
|
||||
#port_label_field.placeholder_text = ports[i].label
|
||||
port_label_field.placeholder_text = menu_title % i
|
||||
|
||||
port_label_field.text = port_override.label
|
||||
|
||||
port_label_field.text_changed.connect(
|
||||
func(new_text: String) -> void:
|
||||
port_override.label = new_text
|
||||
)
|
||||
|
||||
_menu.add_child(Inspector.new("Label:", port_label_field))
|
||||
|
||||
var type_combo := OptionButton.new()
|
||||
for type in DeckType.Types.size():
|
||||
type_combo.add_item(DeckType.type_str(type).capitalize())
|
||||
|
||||
type_combo.selected = port_override.type
|
||||
|
||||
type_combo.item_selected.connect(
|
||||
func(idx: int) -> void:
|
||||
port_override.type = idx as DeckType.Types
|
||||
)
|
||||
|
||||
_menu.add_child(Inspector.new("Type:", type_combo))
|
||||
|
||||
var usage_combo := OptionButton.new()
|
||||
for usage in Port.UsageType.size():
|
||||
usage_combo.add_item(Port.UsageType.keys()[usage].capitalize())
|
||||
|
||||
usage_combo.selected = port_override.usage_type
|
||||
|
||||
usage_combo.item_selected.connect(
|
||||
func(idx: int) -> void:
|
||||
port_override.usage_type = idx as Port.UsageType
|
||||
)
|
||||
|
||||
_menu.add_child(Inspector.new("Usage:", usage_combo))
|
||||
|
||||
var descriptor_field := LineEdit.new()
|
||||
descriptor_field.placeholder_text = "Descriptor (advanced)"
|
||||
descriptor_field.tooltip_text = "Advanced use only.\nSeparate arguments with colon (:).\nPress Enter to confirm."
|
||||
|
||||
descriptor_field.text = port_override.descriptor
|
||||
|
||||
descriptor_field.text_submitted.connect(
|
||||
func(new_text: String) -> void:
|
||||
port_override.descriptor = new_text
|
||||
)
|
||||
|
||||
_menu.add_child(Inspector.new("Descriptor:", descriptor_field))
|
||||
|
||||
io_menu.add_child(_menu)
|
||||
|
||||
|
||||
class NodeInspector:
|
||||
|
@ -241,13 +415,6 @@ class NodeInspector:
|
|||
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 _name_field_rename(new_name: String) -> void:
|
||||
if _name_field.has_focus():
|
||||
return
|
||||
|
@ -259,7 +426,7 @@ class NodeInspector:
|
|||
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 := DeckInspector.create_label(node.node_type)
|
||||
var type_label_settings := LabelSettings.new()
|
||||
type_label_settings.font = SYSTEM_CODE_FONT
|
||||
type_label_settings.font_size = 14
|
||||
|
@ -310,19 +477,19 @@ class NodeInspector:
|
|||
acc.draw_background = true
|
||||
acc.set_title("Port %s" % port.index_of_type)
|
||||
|
||||
var label_label := create_label("Name: %s" % port.label)
|
||||
var label_label := DeckInspector.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())
|
||||
var type_label := DeckInspector.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)
|
||||
var usage_label := DeckInspector.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:")
|
||||
var value_label := DeckInspector.create_label("Value:")
|
||||
port_hb.add_child(value_label)
|
||||
var desc: DescriptorContainer = DESCRIPTOR_SCENES[descriptor_split[0]].instantiate()
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ class_name TabContainerCustom
|
|||
signal add_button_pressed
|
||||
## Emitted when the current tab in [member tab_bar] is changed.
|
||||
signal tab_changed(tab: int)
|
||||
## Emitted just before the current tab in [member tab_bar] is changed.s
|
||||
## Emitted just before the current tab in [member tab_bar] is changed.
|
||||
signal tab_about_to_change(previous_tab: int)
|
||||
## Emitted when a tab in [member tab_bar] has been closed.
|
||||
## See [signal TabBar.tab_close_requested]
|
||||
|
|
Loading…
Reference in a new issue