mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
store connections inside the deck (#147)
- node/port connections are now stored in the deck they belong to - share the connections object between group instances for free syncing - add compatibility code to allow loading decks made before this change - disabled the ability to open multiple decks in the renderer for now since it'd cause problems when opening multiple decks and one of them is incompatible; to be redesigned later closes #140 Reviewed-on: https://codeberg.org/StreamGraph/StreamGraph/pulls/147 Co-authored-by: Lera Elvoé <yagich@poto.cafe> Co-committed-by: Lera Elvoé <yagich@poto.cafe>
This commit is contained in:
parent
1ce3cd0367
commit
f24906715d
10 changed files with 521 additions and 252 deletions
|
@ -16,6 +16,9 @@ var variable_stack: Dictionary = {}
|
|||
## The path to save this deck on the file system.
|
||||
var save_path: String = ""
|
||||
|
||||
## The connections graph.
|
||||
var connections := NodeConnections.new()
|
||||
|
||||
var is_group: bool = false
|
||||
## List of groups belonging to this deck, in the format of[br]
|
||||
## [code]Dictionary[String -> Deck.id, Deck][/code]
|
||||
|
@ -25,6 +28,7 @@ var id: String = ""
|
|||
## If this is a group, this is the local ID of this instance of the group.
|
||||
var instance_id: String = ""
|
||||
## The parent deck of this deck, if this is a group.
|
||||
@warning_ignore("unused_private_class_variable")
|
||||
var _belonging_to: String = "" # for groups
|
||||
## The ID of this group's input node. Used only if [member is_group] is [code]true[/code].
|
||||
var group_input_node: String
|
||||
|
@ -52,8 +56,6 @@ signal variables_updated()
|
|||
#region group signals
|
||||
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 nodes_connected_in_group(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int, deck: Deck)
|
||||
signal nodes_disconnected_in_group(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int, deck: Deck)
|
||||
signal node_port_value_updated(node_id: String, port_idx: int, new_value: Variant, deck: Deck)
|
||||
signal node_renamed(node_id: String, new_name: String, deck: Deck)
|
||||
signal node_moved(node_id: String, new_position: Dictionary, deck: Deck)
|
||||
|
@ -129,6 +131,10 @@ func get_node(uuid: String) -> DeckNode:
|
|||
return nodes.get(uuid)
|
||||
|
||||
|
||||
func get_connections_dict() -> Dictionary:
|
||||
return connections.data
|
||||
|
||||
|
||||
## Returns [code]true[/code] if the connection between two nodes is legal.
|
||||
func is_valid_connection(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> bool:
|
||||
# do not connect to self
|
||||
|
@ -152,7 +158,7 @@ func is_valid_connection(from_node_id: String, to_node_id: String, from_output_p
|
|||
return false
|
||||
|
||||
# duplicate connection
|
||||
if from_node.has_outgoing_connection_exact(from_output_port, to_node_id, to_input_port):
|
||||
if connections.has_outgoing_connection_exact(from_node_id, from_output_port, to_node_id, to_input_port):
|
||||
return false
|
||||
|
||||
return true
|
||||
|
@ -162,34 +168,30 @@ func is_valid_connection(from_node_id: String, to_node_id: String, from_output_p
|
|||
func connect_nodes(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> bool:
|
||||
if not is_valid_connection(from_node_id, to_node_id, from_output_port, to_input_port):
|
||||
return false
|
||||
|
||||
|
||||
var from_node := get_node(from_node_id)
|
||||
var to_node := get_node(to_node_id)
|
||||
|
||||
if to_node.has_incoming_connection(to_input_port):
|
||||
var connection: Dictionary = to_node.incoming_connections[to_input_port]
|
||||
var node_id: String = connection.keys()[0]
|
||||
var node_out_port: int = connection.values()[0]
|
||||
disconnect_nodes(node_id, to_node_id, node_out_port, to_input_port)
|
||||
if connections.has_incoming_connection(to_node_id, to_input_port):
|
||||
var connection := connections.get_incoming_connection(to_node_id, to_input_port)
|
||||
disconnect_nodes(connection.from_node, to_node_id, connection.from_port, to_input_port)
|
||||
|
||||
if is_group and emit_group_signals:
|
||||
nodes_connected_in_group.emit(from_node_id, to_node_id, from_output_port, to_input_port, self)
|
||||
|
||||
from_node.add_outgoing_connection(from_output_port, to_node._id, to_input_port)
|
||||
connections.add_connection(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
nodes_connected.emit(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
from_node.outgoing_connection_added.emit(from_output_port)
|
||||
to_node.incoming_connection_added.emit(to_input_port)
|
||||
return true
|
||||
|
||||
|
||||
## Remove a connection from two nodes.
|
||||
func disconnect_nodes(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> void:
|
||||
connections.remove_connection(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
nodes_disconnected.emit(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
|
||||
var from_node := get_node(from_node_id)
|
||||
var to_node := get_node(to_node_id)
|
||||
from_node.remove_outgoing_connection(from_output_port, to_node_id, to_input_port)
|
||||
to_node.remove_incoming_connection(to_input_port)
|
||||
if is_group and emit_group_signals:
|
||||
nodes_disconnected_in_group.emit(from_node_id, to_node_id, from_output_port, to_input_port, self)
|
||||
|
||||
nodes_disconnected.emit(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
from_node.outgoing_connection_removed.emit(from_output_port)
|
||||
to_node.incoming_connection_removed.emit(to_input_port)
|
||||
|
||||
|
||||
## Returns true if this deck has no nodes and no variables.
|
||||
|
@ -210,19 +212,17 @@ func remove_node(uuid: String, remove_connections: bool = false, force: bool = f
|
|||
DeckHolder.close_group_instance(node.group_id, node.group_instance_id)
|
||||
|
||||
if remove_connections:
|
||||
var outgoing_connections := node.outgoing_connections.duplicate(true)
|
||||
|
||||
for output_port: int in outgoing_connections:
|
||||
for to_node: String in outgoing_connections[output_port]:
|
||||
for to_port: int in outgoing_connections[output_port][to_node]:
|
||||
disconnect_nodes(uuid, to_node, output_port, to_port)
|
||||
|
||||
var incoming_connections := node.incoming_connections.duplicate(true)
|
||||
|
||||
for input_port: int in incoming_connections:
|
||||
for from_node: String in incoming_connections[input_port]:
|
||||
disconnect_nodes(from_node, uuid, incoming_connections[input_port][from_node], input_port)
|
||||
|
||||
var outgoing_connections := connections.get_all_outgoing_connections(uuid)
|
||||
for from_port: int in outgoing_connections:
|
||||
for outgoing: OutgoingConnection in outgoing_connections[from_port]:
|
||||
var incoming := outgoing.counterpart.get_ref() as IncomingConnection
|
||||
disconnect_nodes(uuid, outgoing.to_node, incoming.from_port, outgoing.to_port)
|
||||
|
||||
var incoming_connections := connections.get_all_incoming_connections(uuid)
|
||||
for to_port: int in incoming_connections:
|
||||
var incoming := connections.get_incoming_connection(uuid, to_port)
|
||||
disconnect_nodes(incoming.from_node, uuid, incoming.from_port, to_port)
|
||||
|
||||
nodes.erase(uuid)
|
||||
|
||||
node_removed.emit(node)
|
||||
|
@ -265,6 +265,10 @@ func group_nodes(nodes_to_group: Array) -> Deck:
|
|||
)
|
||||
|
||||
var group := DeckHolder.add_empty_group(id)
|
||||
var connection_pairs := connections.filter_pairs(node_ids_to_keep)
|
||||
|
||||
for pair in connection_pairs:
|
||||
group.connections.add_pair(pair)
|
||||
|
||||
var midpoint := Vector2()
|
||||
|
||||
|
@ -283,20 +287,31 @@ func group_nodes(nodes_to_group: Array) -> Deck:
|
|||
if node.position.x < leftmost:
|
||||
leftmost = node.position.x
|
||||
|
||||
var outgoing_connections := node.outgoing_connections.duplicate(true)
|
||||
#var outgoing_connections := node.outgoing_connections.duplicate(true)
|
||||
#
|
||||
#for from_port: int in outgoing_connections:
|
||||
#for to_node: String in outgoing_connections[from_port]:
|
||||
#for to_port: int in outgoing_connections[from_port][to_node]:
|
||||
#if to_node not in node_ids_to_keep:
|
||||
#disconnect_nodes(node._id, to_node, from_port, to_port)
|
||||
|
||||
var outgoing_connections := connections.get_all_outgoing_connections(node._id)
|
||||
for from_port: int in outgoing_connections:
|
||||
for to_node: String in outgoing_connections[from_port]:
|
||||
for to_port: int in outgoing_connections[from_port][to_node]:
|
||||
if to_node not in node_ids_to_keep:
|
||||
disconnect_nodes(node._id, to_node, from_port, to_port)
|
||||
|
||||
var incoming_connections := node.incoming_connections.duplicate(true)
|
||||
for outgoing: OutgoingConnection in outgoing_connections[from_port]:
|
||||
var incoming := outgoing.counterpart.get_ref() as IncomingConnection
|
||||
disconnect_nodes(node._id, outgoing.to_node, incoming.from_port, outgoing.to_port)
|
||||
|
||||
#var incoming_connections := node.incoming_connections.duplicate(true)
|
||||
#
|
||||
#for to_port: int in incoming_connections:
|
||||
#for from_node: String in incoming_connections[to_port]:
|
||||
#if from_node not in node_ids_to_keep:
|
||||
#disconnect_nodes(from_node, node._id, incoming_connections[to_port][from_node], to_port)
|
||||
|
||||
var incoming_connections := connections.get_all_incoming_connections(node._id)
|
||||
for to_port: int in incoming_connections:
|
||||
for from_node: String in incoming_connections[to_port]:
|
||||
if from_node not in node_ids_to_keep:
|
||||
disconnect_nodes(from_node, node._id, incoming_connections[to_port][from_node], to_port)
|
||||
var incoming := connections.get_incoming_connection(node._id, to_port)
|
||||
disconnect_nodes(incoming.from_node, node._id, incoming.from_port, to_port)
|
||||
|
||||
midpoint += node.position_as_vector2()
|
||||
remove_node(node._id, false, true)
|
||||
|
@ -344,7 +359,10 @@ func group_nodes(nodes_to_group: Array) -> Deck:
|
|||
|
||||
|
||||
func copy_nodes(nodes_to_copy: Array[String]) -> Dictionary:
|
||||
var d := {"nodes": {}}
|
||||
var d := {
|
||||
"nodes": {},
|
||||
"connections": connections.filter_pairs(nodes_to_copy),
|
||||
}
|
||||
|
||||
for node_id: String in nodes_to_copy:
|
||||
d.nodes[node_id] = get_node(node_id).to_dict()
|
||||
|
@ -392,7 +410,12 @@ func copy_nodes(nodes_to_copy: Array[String]) -> Dictionary:
|
|||
|
||||
|
||||
func copy_nodes_json(nodes_to_copy: Array[String]) -> String:
|
||||
return JSON.stringify(copy_nodes(nodes_to_copy))
|
||||
var res := copy_nodes(nodes_to_copy)
|
||||
res.connections = res.connections.map(
|
||||
func(x: ConnectionPair):
|
||||
return x.to_dict()
|
||||
)
|
||||
return JSON.stringify(res)
|
||||
|
||||
|
||||
func allocate_ids(count: int) -> Array[String]:
|
||||
|
@ -406,35 +429,30 @@ func paste_nodes_from_dict(nodes_to_paste: Dictionary, position: Vector2 = Vecto
|
|||
if not nodes_to_paste.get("nodes"):
|
||||
return
|
||||
|
||||
var pairs = (nodes_to_paste.connections as Array).map(
|
||||
func(x: Dictionary):
|
||||
return ConnectionPair.from_dict(x)
|
||||
)
|
||||
|
||||
var new_ids := allocate_ids(nodes_to_paste.nodes.size())
|
||||
var ids_map := {}
|
||||
for i: int in nodes_to_paste.nodes.keys().size():
|
||||
var node_id: String = nodes_to_paste.nodes.keys()[i]
|
||||
ids_map[node_id] = new_ids[i]
|
||||
|
||||
for old_id: String in ids_map:
|
||||
for pair: ConnectionPair in pairs:
|
||||
pair.remap_id(old_id, ids_map[old_id])
|
||||
|
||||
for pair: ConnectionPair in pairs:
|
||||
connections.add_pair(pair)
|
||||
|
||||
for node_id: String in nodes_to_paste.nodes:
|
||||
nodes_to_paste.nodes[node_id]._id = ids_map[node_id]
|
||||
|
||||
nodes_to_paste.nodes[node_id].position.x += position.x
|
||||
nodes_to_paste.nodes[node_id].position.y += position.y
|
||||
|
||||
var outgoing_connections: Dictionary = nodes_to_paste.nodes[node_id].outgoing_connections as Dictionary
|
||||
var outgoing_connections_res := {}
|
||||
for from_port in outgoing_connections:
|
||||
outgoing_connections_res[from_port] = {}
|
||||
for to_node_id in outgoing_connections[from_port]:
|
||||
outgoing_connections_res[from_port][ids_map[to_node_id]] = outgoing_connections[from_port][to_node_id]
|
||||
|
||||
var incoming_connections: Dictionary = nodes_to_paste.nodes[node_id].incoming_connections as Dictionary
|
||||
var incoming_connections_res := {}
|
||||
for to_port in incoming_connections:
|
||||
incoming_connections_res[to_port] = {}
|
||||
for from_node_id in incoming_connections[to_port]:
|
||||
incoming_connections_res[to_port][ids_map[from_node_id]] = incoming_connections[to_port][from_node_id]
|
||||
|
||||
nodes_to_paste.nodes[node_id].outgoing_connections = outgoing_connections_res
|
||||
nodes_to_paste.nodes[node_id].incoming_connections = incoming_connections_res
|
||||
|
||||
var node := DeckNode.from_dict(nodes_to_paste.nodes[node_id])
|
||||
var group_needs_unique := false
|
||||
if node.node_type == "group_node":
|
||||
|
@ -465,6 +483,29 @@ func duplicate_nodes(nodes_to_copy: Array[String]) -> void:
|
|||
paste_nodes_from_dict(d, position)
|
||||
|
||||
|
||||
## Send [param data] from [param from_node_id] to all outgoing connections on port [param from_output_port].[br]
|
||||
## See [method DeckNode.send].
|
||||
func send(from_node_id: String, from_output_port: int, data: Variant, send_id: String) -> void:
|
||||
var outgoing_connections := connections.get_outgoing_connections(from_node_id, from_output_port)
|
||||
for connection in outgoing_connections:
|
||||
var node := get_node(connection.to_node)
|
||||
node.handle_receive(connection.to_port, data, send_id)
|
||||
|
||||
|
||||
## Asynchronously request a value from an incoming connection on the node at [param node_id]'s input port at [param on_input_port].
|
||||
## Returns [code]null[/code] if no incoming connection exists on that port.
|
||||
## The connected node may also return [code]null[/code].[br]
|
||||
## See [method DeckNode.request_value_async].
|
||||
func request_value_async(node_id: String, on_input_port: int) -> Variant:
|
||||
var connection := connections.get_incoming_connection(node_id, on_input_port)
|
||||
if connection == null:
|
||||
return null
|
||||
|
||||
var other_node := get_node(connection.from_node)
|
||||
|
||||
return await other_node._value_request(connection.from_port)
|
||||
|
||||
|
||||
func send_event(event_name: StringName, event_data: Dictionary = {}) -> void:
|
||||
for node: DeckNode in nodes.values():
|
||||
node._event_received(event_name, event_data)
|
||||
|
@ -512,7 +553,8 @@ func to_dict(with_meta: bool = true, group_ids: Array = []) -> Dictionary:
|
|||
"nodes": {},
|
||||
"variable_stack": variable_stack,
|
||||
"id": id,
|
||||
"groups": {}
|
||||
"groups": {},
|
||||
"connections": connections.to_dict(),
|
||||
}
|
||||
|
||||
for node_id: String in nodes.keys():
|
||||
|
@ -545,6 +587,7 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
|||
deck.save_path = path
|
||||
deck.variable_stack = data.deck.variable_stack
|
||||
deck.id = data.deck.id
|
||||
deck.connections = NodeConnections.from_dict(data.deck.connections)
|
||||
|
||||
for key in data.meta:
|
||||
deck.set_meta(key, str_to_var(data.meta[key]))
|
||||
|
@ -581,3 +624,269 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
|||
|
||||
|
||||
return deck
|
||||
|
||||
|
||||
class NodeConnections:
|
||||
# Dictionary[String -> node id, Dictionary["incoming": Dictionary[int -> input port idx, IncomingConnection], "outgoing": Dictionary[int - > output port idx, Array[OutgoingConnection]]]
|
||||
var data := {}
|
||||
|
||||
|
||||
func add_connection(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> void:
|
||||
var from_connection: Dictionary = data.get(from_node_id, _create_empty_connection())
|
||||
var to_connection: Dictionary = data.get(to_node_id, _create_empty_connection())
|
||||
var pair := ConnectionPair.new(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
|
||||
var out_list: Array = (from_connection.outgoing as Dictionary).get(from_output_port, [])
|
||||
out_list.append(pair.outgoing)
|
||||
(from_connection.outgoing as Dictionary)[from_output_port] = out_list
|
||||
|
||||
(to_connection.incoming as Dictionary)[to_input_port] = pair.incoming
|
||||
|
||||
data[from_node_id] = from_connection
|
||||
data[to_node_id] = to_connection
|
||||
|
||||
|
||||
func remove_connection(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> void:
|
||||
var from_connection: Dictionary = data.get(from_node_id, {})
|
||||
if from_connection.is_empty():
|
||||
return
|
||||
|
||||
var out_list: Array = (from_connection.outgoing as Dictionary).get(from_output_port, [])
|
||||
if out_list.is_empty():
|
||||
return
|
||||
|
||||
var comp := ConnectionPair.new(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
|
||||
for i in out_list.size():
|
||||
var out: OutgoingConnection = out_list[i]
|
||||
var pair := ConnectionPair.from_outgoing(out)
|
||||
if pair.is_equivalent(comp):
|
||||
var to_connection: Dictionary = data.get(to_node_id).incoming
|
||||
to_connection.erase(to_input_port)
|
||||
out_list.erase(out)
|
||||
break
|
||||
|
||||
|
||||
func has_incoming_connection(node_id: String, on_port: int) -> bool:
|
||||
return data.get(node_id, _create_empty_connection()).incoming.has(on_port)
|
||||
|
||||
|
||||
func get_incoming_connection(node_id: String, on_port: int) -> IncomingConnection:
|
||||
return data.get(node_id, _create_empty_connection()).incoming.get(on_port)
|
||||
|
||||
|
||||
func has_outgoing_connection_exact(node_id: String, from_port: int, to_node: String, to_port: int) -> bool:
|
||||
if not data.get(node_id, _create_empty_connection()).outgoing.has(from_port):
|
||||
return false
|
||||
|
||||
var has = false
|
||||
for connection: OutgoingConnection in data.get(node_id, _create_empty_connection()).outgoing.get(from_port):
|
||||
var inc := connection.counterpart.get_ref() as IncomingConnection
|
||||
if connection.to_node == to_node \
|
||||
and connection.to_port == to_port\
|
||||
and inc.from_port == from_port:
|
||||
has = true
|
||||
|
||||
return has
|
||||
|
||||
|
||||
func get_outgoing_connections(node_id: String, from_port: int) -> Array[OutgoingConnection]:
|
||||
if data.get(node_id, _create_empty_connection()).outgoing.is_empty():
|
||||
return []
|
||||
|
||||
var res: Array[OutgoingConnection] = []
|
||||
|
||||
res.assign(data[node_id].outgoing[from_port])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
func get_all_outgoing_connections(node_id: String) -> Dictionary:
|
||||
return data.get(node_id, _create_empty_connection()).outgoing
|
||||
|
||||
|
||||
func get_all_incoming_connections(node_id: String) -> Dictionary:
|
||||
return data.get(node_id, _create_empty_connection()).incoming
|
||||
|
||||
|
||||
func filter_pairs(nodes: Array) -> Array[ConnectionPair]:
|
||||
var res: Array[ConnectionPair] = []
|
||||
|
||||
for node_id: String in nodes:
|
||||
var connections: Dictionary = data.get(node_id, _create_empty_connection())
|
||||
for to_port: int in connections.outgoing:
|
||||
for outgoing: OutgoingConnection in connections.outgoing[to_port]:
|
||||
if outgoing.to_node in nodes:
|
||||
res.append(ConnectionPair.from_outgoing(outgoing))
|
||||
|
||||
return res
|
||||
|
||||
|
||||
func add_pair(pair: ConnectionPair) -> void:
|
||||
var outgoing := pair.outgoing
|
||||
var incoming := pair.incoming
|
||||
add_connection(incoming.from_node, outgoing.to_node, incoming.from_port, outgoing.to_port)
|
||||
|
||||
|
||||
func _create_empty_connection() -> Dictionary:
|
||||
return {
|
||||
"incoming": {},
|
||||
"outgoing": {},
|
||||
}
|
||||
|
||||
|
||||
func to_dict() -> Dictionary:
|
||||
var res := {}
|
||||
for node_id: String in data:
|
||||
res[node_id] = _create_empty_connection()
|
||||
for to_port: int in data[node_id].incoming:
|
||||
res[node_id].incoming[to_port] = (data[node_id].incoming[to_port] as IncomingConnection).to_dict()
|
||||
|
||||
for from_port: int in data[node_id].outgoing:
|
||||
for i: OutgoingConnection in data[node_id].outgoing[from_port]:
|
||||
var arr: Array = res[node_id].outgoing.get(from_port, [])
|
||||
arr.append(i.to_dict())
|
||||
res[node_id].outgoing[from_port] = arr
|
||||
return res
|
||||
|
||||
|
||||
static func from_dict(d: Dictionary) -> NodeConnections:
|
||||
var res := NodeConnections.new()
|
||||
for node_id: String in d:
|
||||
for from_port in d[node_id].outgoing:
|
||||
for connection: Dictionary in d[node_id].outgoing[from_port]:
|
||||
res.add_connection(node_id, connection.to_node, int(from_port), int(connection.to_port))
|
||||
return res
|
||||
|
||||
|
||||
class ConnectionPair:
|
||||
var from_node_id: String
|
||||
var to_node_id: String
|
||||
var from_output_port: int
|
||||
var to_input_port: int
|
||||
|
||||
var incoming: IncomingConnection
|
||||
var outgoing: OutgoingConnection
|
||||
|
||||
|
||||
func _init(
|
||||
p_from_node_id: String,
|
||||
p_to_node_id: String,
|
||||
p_from_output_port: int,
|
||||
p_to_input_port: int,
|
||||
p_outgoing: OutgoingConnection = null,
|
||||
p_incoming: IncomingConnection = null
|
||||
) -> void:
|
||||
from_node_id = p_from_node_id
|
||||
to_node_id = p_to_node_id
|
||||
from_output_port = p_from_output_port
|
||||
to_input_port = p_to_input_port
|
||||
|
||||
if not p_outgoing:
|
||||
outgoing = OutgoingConnection.new()
|
||||
outgoing.to_node = to_node_id
|
||||
outgoing.to_port = to_input_port
|
||||
|
||||
incoming = IncomingConnection.new()
|
||||
incoming.from_port = from_output_port
|
||||
incoming.from_node = from_node_id
|
||||
|
||||
incoming.counterpart = weakref(outgoing)
|
||||
outgoing.counterpart = weakref(incoming)
|
||||
else:
|
||||
outgoing = p_outgoing
|
||||
incoming = p_incoming
|
||||
|
||||
|
||||
func remap_id(old_id: String, new_id: String) -> void:
|
||||
if old_id == from_node_id:
|
||||
from_node_id = new_id
|
||||
incoming.from_node = new_id
|
||||
elif old_id == to_node_id:
|
||||
to_node_id = new_id
|
||||
outgoing.to_node = new_id
|
||||
|
||||
|
||||
func is_equivalent(other: ConnectionPair) -> bool:
|
||||
if from_node_id == other.from_node_id and \
|
||||
to_node_id == other.to_node_id and \
|
||||
from_output_port == other.from_output_port and \
|
||||
to_input_port == other.to_input_port:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func to_dict() -> Dictionary:
|
||||
return {
|
||||
"incoming": incoming.to_dict(),
|
||||
"outgoing": outgoing.to_dict(),
|
||||
}
|
||||
|
||||
|
||||
static func from_incoming(p_incoming: IncomingConnection) -> ConnectionPair:
|
||||
@warning_ignore("shadowed_variable")
|
||||
var outgoing := p_incoming.counterpart.get_ref() as OutgoingConnection
|
||||
|
||||
return ConnectionPair.new(
|
||||
p_incoming.from_node, outgoing.to_node,
|
||||
p_incoming.from_port, outgoing.to_port,
|
||||
outgoing, p_incoming
|
||||
)
|
||||
|
||||
|
||||
static func from_outgoing(p_outgoing: OutgoingConnection) -> ConnectionPair:
|
||||
@warning_ignore("shadowed_variable")
|
||||
var incoming := p_outgoing.counterpart.get_ref() as IncomingConnection
|
||||
|
||||
return ConnectionPair.new(
|
||||
incoming.from_node, p_outgoing.to_node,
|
||||
incoming.from_port, p_outgoing.to_port,
|
||||
p_outgoing, incoming
|
||||
)
|
||||
|
||||
|
||||
static func from_dict(d: Dictionary) -> ConnectionPair:
|
||||
@warning_ignore("shadowed_variable")
|
||||
var outgoing := OutgoingConnection.new()
|
||||
outgoing.to_node = d.outgoing.to_node
|
||||
outgoing.to_port = d.outgoing.to_port
|
||||
|
||||
@warning_ignore("shadowed_variable")
|
||||
var incoming := IncomingConnection.new()
|
||||
incoming.from_node = d.incoming.from_node
|
||||
incoming.from_port = d.incoming.from_port
|
||||
|
||||
outgoing.counterpart = weakref(incoming)
|
||||
incoming.counterpart = weakref(outgoing)
|
||||
|
||||
return from_incoming(incoming)
|
||||
|
||||
|
||||
class IncomingConnection:
|
||||
var from_node: String
|
||||
var from_port: int
|
||||
|
||||
var counterpart: WeakRef # OutgoingConnection
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return str({"from_node": from_node, "from_port": from_port})
|
||||
|
||||
|
||||
func to_dict() -> Dictionary:
|
||||
return {"from_node": from_node, "from_port": from_port}
|
||||
|
||||
|
||||
class OutgoingConnection:
|
||||
var to_node: String
|
||||
var to_port: int
|
||||
|
||||
var counterpart: WeakRef # IncomingConnection
|
||||
|
||||
|
||||
func _to_string() -> String:
|
||||
return str({"to_node": to_node, "to_port": to_port})
|
||||
|
||||
|
||||
func to_dict() -> Dictionary:
|
||||
return {"to_node": to_node, "to_port": to_port}
|
||||
|
|
|
@ -14,6 +14,10 @@ static var groups_emitted: Array[String]
|
|||
static var logger := Logger.new()
|
||||
static var signals := Signals.new()
|
||||
|
||||
enum Compat {
|
||||
CONNECTIONS_IN_DECK = 1 << 0,
|
||||
}
|
||||
|
||||
|
||||
static func _static_init() -> void:
|
||||
signals.deck_added.connect(RPCSignalLayer._on_deck_added)
|
||||
|
@ -31,6 +35,28 @@ static func add_empty_deck() -> Deck:
|
|||
return deck
|
||||
|
||||
|
||||
static func get_deck_compat(data: Dictionary) -> int:
|
||||
var res := 0
|
||||
|
||||
if not data.deck.has("connections"):
|
||||
res |= Compat.CONNECTIONS_IN_DECK
|
||||
|
||||
return res
|
||||
|
||||
|
||||
static func apply_compat_patches(data: Dictionary, compat: int) -> void:
|
||||
if compat & Compat.CONNECTIONS_IN_DECK:
|
||||
# convert pre-0.0.6 connections to be stored in the deck instead
|
||||
var connections := Deck.NodeConnections.new()
|
||||
for node: String in data.deck.nodes:
|
||||
for from_port in data.deck.nodes[node].outgoing_connections:
|
||||
for to_node: String in data.deck.nodes[node].outgoing_connections[from_port]:
|
||||
for to_port: int in data.deck.nodes[node].outgoing_connections[from_port][to_node]:
|
||||
connections.add_connection(node, to_node, int(from_port), to_port)
|
||||
|
||||
data.deck.connections = connections.to_dict()
|
||||
|
||||
|
||||
## Opens a deck from the [param path].
|
||||
static func open_deck_from_file(path: String) -> Deck:
|
||||
var f := FileAccess.open(path, FileAccess.READ)
|
||||
|
@ -42,6 +68,8 @@ static func open_deck_from_file(path: String) -> Deck:
|
|||
|
||||
|
||||
static func open_deck_from_dict(data: Dictionary, path := "") -> Deck:
|
||||
if get_deck_compat(data) != 0:
|
||||
apply_compat_patches(data, get_deck_compat(data))
|
||||
var deck := Deck.from_dict(data, path)
|
||||
decks[deck.id] = deck
|
||||
deck.connect_rpc_signals()
|
||||
|
@ -72,7 +100,10 @@ static func add_group_from_dict(data: Dictionary, deck_id: String, instance_id:
|
|||
static func make_new_group_instance(group_id: String, parent: String = "") -> Deck:
|
||||
var group := get_deck(group_id)
|
||||
var data := group.to_dict()
|
||||
return add_group_from_dict(data, group_id, UUID.v4(), parent)
|
||||
var inst := add_group_from_dict(data, group_id, UUID.v4(), parent)
|
||||
# copy connections
|
||||
inst.connections = group.connections
|
||||
return inst
|
||||
|
||||
|
||||
static func make_group_instance_unique(group_id: String, instance_id: String, parent_deck_id: String, group_node_id: String) -> Deck:
|
||||
|
@ -119,8 +150,6 @@ static func add_empty_group(parent: String = "") -> Deck:
|
|||
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.nodes_connected_in_group.connect(DeckHolder._on_nodes_connected_in_group)
|
||||
group.nodes_disconnected_in_group.connect(DeckHolder._on_nodes_disconnected_in_group)
|
||||
group.node_port_value_updated.connect(DeckHolder._on_node_port_value_updated)
|
||||
group.node_renamed.connect(DeckHolder._on_node_renamed)
|
||||
group.node_moved.connect(DeckHolder._on_node_moved)
|
||||
|
@ -216,30 +245,6 @@ static func _on_node_removed_from_group(node_id: String, remove_connections: boo
|
|||
instance.emit_group_signals = true
|
||||
|
||||
|
||||
static func _on_nodes_connected_in_group(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int, deck: Deck) -> void:
|
||||
var group_id := deck.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
|
||||
instance.connect_nodes(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
instance.emit_group_signals = true
|
||||
|
||||
|
||||
static func _on_nodes_disconnected_in_group(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int, deck: Deck) -> void:
|
||||
var group_id := deck.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
|
||||
instance.disconnect_nodes(from_node_id, to_node_id, from_output_port, to_input_port)
|
||||
instance.emit_group_signals = true
|
||||
|
||||
|
||||
static func _on_node_port_value_updated(node_id: String, port_idx: int, new_value: Variant, deck: Deck) -> void:
|
||||
var group_id := deck.id
|
||||
for instance_id: String in decks[group_id]:
|
||||
|
|
|
@ -10,12 +10,6 @@ class_name DeckNode
|
|||
## The name initially shown to a renderer.
|
||||
var name: String
|
||||
|
||||
## A map of outgoing connections from this node, in the format[br]
|
||||
## [code]Dictionary[int -> output port, Dictionary[String -> DeckNode#_id, Array[int -> input port]]][/code]
|
||||
var outgoing_connections: Dictionary
|
||||
## A map of incoming connections to this node, in the format[br]
|
||||
## [code]Dictionary[int -> input port, Dictionary[String -> DeckNode#_id, int -> output port][/code]
|
||||
var incoming_connections: Dictionary
|
||||
|
||||
## A list of [Port]s on this node.
|
||||
var ports: Array[Port]
|
||||
|
@ -127,23 +121,9 @@ func add_port(type: DeckType.Types,
|
|||
return port
|
||||
|
||||
|
||||
## Remove a port from this node.
|
||||
## @deprecated
|
||||
func remove_port(port_idx: int) -> void:
|
||||
outgoing_connections.erase(port_idx)
|
||||
incoming_connections.erase(port_idx)
|
||||
ports.remove_at(port_idx)
|
||||
port_removed.emit(port_idx)
|
||||
|
||||
|
||||
## Send data to all outgoing connections on port [param from_output_port].
|
||||
func send(from_output_port: int, data: Variant, send_id: String = UUID.v4()) -> void:
|
||||
if outgoing_connections.get(from_output_port) == null:
|
||||
return
|
||||
|
||||
for node: String in outgoing_connections[from_output_port]:
|
||||
for input_port: int in outgoing_connections[from_output_port][node]:
|
||||
get_node(node).handle_receive(input_port, data, send_id)
|
||||
_belonging_to.send(_id, from_output_port, data, send_id)
|
||||
|
||||
|
||||
func handle_receive(to_input_port: int, data: Variant, send_id: String) -> void:
|
||||
|
@ -160,36 +140,11 @@ func _receive(to_input_port: int, data: Variant) -> void:
|
|||
pass
|
||||
|
||||
|
||||
## Add a connection from the output port at [param from_port] to [param to_node]'s input port
|
||||
## at [param to_port].
|
||||
func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> void:
|
||||
var inner: Dictionary = outgoing_connections.get(from_port, {}) as Dictionary
|
||||
var inner_ports: Array = inner.get(to_node, []) as Array
|
||||
inner_ports.append(to_port)
|
||||
inner[to_node] = inner_ports
|
||||
outgoing_connections[from_port] = inner
|
||||
get_node(to_node).add_incoming_connection(to_port, _id, from_port)
|
||||
outgoing_connection_added.emit(from_port)
|
||||
|
||||
|
||||
## Add an incoming connection from [param from_node]'s output port at [param from_port] to this node's
|
||||
## input port at [param to_port].
|
||||
func add_incoming_connection(to_port: int, from_node: String, from_port: int) -> void:
|
||||
var connection := {from_node: from_port}
|
||||
incoming_connections[to_port] = connection
|
||||
incoming_connection_added.emit(to_port)
|
||||
|
||||
|
||||
## Asynchronously request a value from an incoming connection on this node's input port at [param on_port].
|
||||
## Returns [code]null[/code] if no incoming connection exists on that port.
|
||||
## The connected node may also return [code]null[/code].
|
||||
func request_value_async(on_port: int) -> Variant:
|
||||
if not incoming_connections.has(on_port):
|
||||
return null
|
||||
|
||||
var connection: Dictionary = incoming_connections[on_port]
|
||||
var node := get_node(connection.keys()[0])
|
||||
return await node._value_request(connection.values()[0])
|
||||
return await _belonging_to.request_value_async(_id, on_port)
|
||||
|
||||
|
||||
## Virtual function that's called when this node has been requested a value from the output port
|
||||
|
@ -199,52 +154,6 @@ func _value_request(from_port: int) -> Variant:
|
|||
return null
|
||||
|
||||
|
||||
## Remove an outgoing connection from this node.
|
||||
## Does [b]not[/b] remove the other node's incoming connection equivalent.
|
||||
func remove_outgoing_connection(from_port: int, to_node: String, to_port: int) -> void:
|
||||
var connections: Dictionary = outgoing_connections.get(from_port, {}) as Dictionary
|
||||
if connections.is_empty():
|
||||
return
|
||||
|
||||
var inner_ports: Array = connections.get(to_node, []) as Array
|
||||
inner_ports.erase(to_port)
|
||||
|
||||
if inner_ports.is_empty():
|
||||
(outgoing_connections[from_port] as Dictionary).erase(to_node)
|
||||
if (outgoing_connections[from_port] as Dictionary).is_empty():
|
||||
outgoing_connections.erase(from_port)
|
||||
|
||||
outgoing_connection_removed.emit(from_port)
|
||||
|
||||
|
||||
## Remove an incoming connection to this node on the input port at [param to_port].
|
||||
## Does [b]not[/b] remove the other node's outgoing connection equivalent.
|
||||
func remove_incoming_connection(to_port: int) -> void:
|
||||
incoming_connections.erase(to_port)
|
||||
incoming_connection_removed.emit(to_port)
|
||||
|
||||
|
||||
## Returns [code]true[/code] if the exact connection from this node exists.
|
||||
func has_outgoing_connection_exact(from_port: int, to_node: String, to_port: int) -> bool:
|
||||
if not outgoing_connections.has(from_port):
|
||||
return false
|
||||
|
||||
var connection: Dictionary = outgoing_connections[from_port]
|
||||
if not connection.has(to_node):
|
||||
return false
|
||||
|
||||
var connections_to_node: Array = connection[to_node]
|
||||
if to_port not in connections_to_node:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Returns [code]true[/code] if the node has an incoming connection at input port [param on_port].
|
||||
func has_incoming_connection(on_port: int) -> bool:
|
||||
return incoming_connections.has(on_port)
|
||||
|
||||
|
||||
func rename(new_name: String) -> void:
|
||||
name = new_name
|
||||
renamed.emit(new_name)
|
||||
|
@ -324,8 +233,8 @@ func get_node(uuid: String) -> DeckNode:
|
|||
return _belonging_to.get_node(uuid)
|
||||
|
||||
|
||||
## Virtual function that's called during deserialization before connections are loaded in.
|
||||
func _pre_connection() -> void:
|
||||
## Virtual function that's called during deserialization before connections are loaded in.[br]
|
||||
func _pre_port_load() -> void:
|
||||
pass
|
||||
|
||||
|
||||
|
@ -357,8 +266,8 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
|||
var d := {
|
||||
"_id": _id,
|
||||
"name": name,
|
||||
"outgoing_connections": outgoing_connections.duplicate(true),
|
||||
"incoming_connections": incoming_connections.duplicate(true),
|
||||
#"outgoing_connections": outgoing_connections.duplicate(true),
|
||||
#"incoming_connections": incoming_connections.duplicate(true),
|
||||
"props": {},
|
||||
"node_type": node_type,
|
||||
"port_values": [],
|
||||
|
@ -389,22 +298,22 @@ static func from_dict(data: Dictionary) -> DeckNode:
|
|||
for prop in data.props:
|
||||
node.set(prop, data.props[prop])
|
||||
|
||||
node._pre_connection()
|
||||
node._pre_port_load()
|
||||
|
||||
for from_port in data.outgoing_connections:
|
||||
var connection_data: Dictionary = data.outgoing_connections[from_port]
|
||||
node.outgoing_connections[int(from_port)] = {}
|
||||
for to_node in connection_data:
|
||||
var input_ports: Array = connection_data[to_node]
|
||||
node.outgoing_connections[int(from_port)][to_node] = []
|
||||
for to_input_port in input_ports:
|
||||
node.outgoing_connections[int(from_port)][to_node].append(int(to_input_port))
|
||||
|
||||
for to_port in data.incoming_connections:
|
||||
var connection_data = data.incoming_connections[to_port]
|
||||
for connection in connection_data:
|
||||
connection_data[connection] = int(connection_data[connection])
|
||||
node.incoming_connections[int(to_port)] = connection_data
|
||||
#for from_port in data.outgoing_connections:
|
||||
#var connection_data: Dictionary = data.outgoing_connections[from_port]
|
||||
#node.outgoing_connections[int(from_port)] = {}
|
||||
#for to_node in connection_data:
|
||||
#var input_ports: Array = connection_data[to_node]
|
||||
#node.outgoing_connections[int(from_port)][to_node] = []
|
||||
#for to_input_port in input_ports:
|
||||
#node.outgoing_connections[int(from_port)][to_node].append(int(to_input_port))
|
||||
#
|
||||
#for to_port in data.incoming_connections:
|
||||
#var connection_data = data.incoming_connections[to_port]
|
||||
#for connection in connection_data:
|
||||
#connection_data[connection] = int(connection_data[connection])
|
||||
#node.incoming_connections[int(to_port)] = connection_data
|
||||
|
||||
for i in node.ports.size():
|
||||
var port_value: Variant
|
||||
|
|
|
@ -37,13 +37,10 @@ func _on_outgoing_connection_added(port_idx: int) -> void:
|
|||
|
||||
func _on_outgoing_connection_removed(port_idx: int) -> void:
|
||||
var last_connected_port := 0
|
||||
#for port: int in outgoing_connections.keys().slice(1):
|
||||
#if !(outgoing_connections[port] as Array).is_empty():
|
||||
#last_connected_port = port
|
||||
for port: int in outgoing_connections.keys().slice(1):
|
||||
if not (outgoing_connections.get(port, {}) as Dictionary).is_empty():
|
||||
var outgoing_connections = _belonging_to.connections.get_all_outgoing_connections(_id)
|
||||
for port: int in outgoing_connections:
|
||||
if not (outgoing_connections[port] as Array).is_empty():
|
||||
last_connected_port = port
|
||||
|
||||
#prints("l:", last_connected_port, "p:", port_idx)
|
||||
|
||||
if port_idx < last_connected_port:
|
||||
|
@ -54,7 +51,7 @@ func _on_outgoing_connection_removed(port_idx: int) -> void:
|
|||
ports_updated.emit()
|
||||
|
||||
|
||||
func _pre_connection() -> void:
|
||||
func _pre_port_load() -> void:
|
||||
for i in output_count + 1:
|
||||
add_output_port(
|
||||
DeckType.Types.ANY,
|
||||
|
@ -65,6 +62,7 @@ func _pre_connection() -> void:
|
|||
func _post_load() -> void:
|
||||
# ensure we have enough ports after connections
|
||||
var last_connected_port := 0
|
||||
var outgoing_connections = _belonging_to.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
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ func _init() -> void:
|
|||
appears_in_search = false
|
||||
|
||||
|
||||
func _pre_connection() -> void:
|
||||
func _pre_port_load() -> void:
|
||||
for port_type: PortType in extra_ports:
|
||||
match port_type:
|
||||
PortType.OUTPUT:
|
||||
|
|
|
@ -38,9 +38,9 @@ func _on_incoming_connection_added(port_idx: int) -> void:
|
|||
|
||||
func _on_incoming_connection_removed(port_idx: int) -> void:
|
||||
var last_connected_port := 0
|
||||
for port: int in incoming_connections.keys().slice(1):
|
||||
if not (incoming_connections[port] as Dictionary).is_empty():
|
||||
last_connected_port = port
|
||||
var incoming_connections := _belonging_to.connections.get_all_incoming_connections(_id)
|
||||
if not incoming_connections.is_empty():
|
||||
last_connected_port = incoming_connections.keys()[-1]
|
||||
|
||||
#prints("l:", last_connected_port, "p:", port_idx)
|
||||
|
||||
|
@ -52,7 +52,7 @@ func _on_incoming_connection_removed(port_idx: int) -> void:
|
|||
ports_updated.emit()
|
||||
|
||||
|
||||
func _pre_connection() -> void:
|
||||
func _pre_port_load() -> void:
|
||||
for i in input_count + 1:
|
||||
add_input_port(
|
||||
DeckType.Types.ANY,
|
||||
|
@ -63,6 +63,7 @@ func _pre_connection() -> void:
|
|||
func _post_load() -> void:
|
||||
# ensure we have enough ports after connections
|
||||
var last_connected_port := 0
|
||||
var incoming_connections := _belonging_to.connections.get_all_incoming_connections(_id)
|
||||
for port: int in incoming_connections:
|
||||
last_connected_port = port if incoming_connections.has(port) else last_connected_port
|
||||
|
||||
|
|
18
graph_node_renderer/compat_dialog.tscn
Normal file
18
graph_node_renderer/compat_dialog.tscn
Normal file
|
@ -0,0 +1,18 @@
|
|||
[gd_scene format=3 uid="uid://cd1t0gvi022gx"]
|
||||
|
||||
[node name="CompatDialog" type="ConfirmationDialog"]
|
||||
initial_position = 1
|
||||
size = Vector2i(440, 175)
|
||||
ok_button_text = "Open"
|
||||
dialog_autowrap = true
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = 432.0
|
||||
offset_bottom = 129.0
|
||||
text = "Warning: This deck was last saved with an earlier version of StreamGraph.
|
||||
|
||||
Open anyway? The file will be modified, and opening it in the version it was saved with may lead to errors."
|
||||
horizontal_alignment = 1
|
||||
autowrap_mode = 2
|
|
@ -77,6 +77,8 @@ var _deck_to_save: WeakRef
|
|||
@onready var sidebar_split: HSplitContainer = %SidebarSplit
|
||||
@onready var sidebar: Sidebar = %Sidebar as Sidebar
|
||||
|
||||
@onready var compat_dialog: ConfirmationDialog = %CompatDialog
|
||||
|
||||
signal quit_completed()
|
||||
signal rpc_start_requested(port: int)
|
||||
signal rpc_stop_requested()
|
||||
|
@ -330,6 +332,7 @@ func close_tab(tab: int) -> void:
|
|||
if tab_container.get_tab_count() == 0:
|
||||
bottom_dock.variable_viewer.disable_new_button()
|
||||
|
||||
|
||||
## Opens [member file_dialog] with the mode [member FileDialog.FILE_MODE_SAVE_FILE]
|
||||
## as well as getting a weakref to the active [Deck]
|
||||
func open_save_dialog(path: String) -> void:
|
||||
|
@ -340,14 +343,20 @@ func open_save_dialog(path: String) -> void:
|
|||
file_dialog.popup_centered()
|
||||
file_dialog.file_selected.connect(_on_file_dialog_save_file, CONNECT_ONE_SHOT)
|
||||
|
||||
|
||||
## Opens [member file_dialog] with the mode [FileDialog.FILE_MODE_OPEN_FILES]
|
||||
## with the supplied [param path]
|
||||
func open_open_dialog(path: String) -> void:
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES
|
||||
file_dialog.title = "Open Deck(s)"
|
||||
#file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES
|
||||
# TODO: disabled opening multiple for now until better compat dialog method is found
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
#file_dialog.title = "Open Deck(s)"
|
||||
file_dialog.title = "Open Deck"
|
||||
file_dialog.current_path = path + "/"
|
||||
file_dialog.popup_centered()
|
||||
file_dialog.files_selected.connect(_on_file_dialog_open_files, CONNECT_ONE_SHOT)
|
||||
#file_dialog.files_selected.connect(_on_file_dialog_open_files, CONNECT_ONE_SHOT)
|
||||
file_dialog.file_selected.connect(open_deck_at_path, CONNECT_ONE_SHOT)
|
||||
|
||||
|
||||
## Connected to [signal FileDialog.save_file] on [member file_dialog].
|
||||
## Saves the selected [Deck] if it still exists.
|
||||
|
@ -381,8 +390,23 @@ func open_deck_at_path(path: String) -> void:
|
|||
if tab_container.get_tab_metadata(tab, "path") == path:
|
||||
tab_container.set_current_tab(tab)
|
||||
return
|
||||
|
||||
var deck := DeckHolder.open_deck_from_file(path)
|
||||
|
||||
var f := FileAccess.open(path, FileAccess.READ)
|
||||
if f.get_error() != OK:
|
||||
return
|
||||
|
||||
var deck_data: Dictionary = JSON.parse_string(f.get_as_text())
|
||||
if DeckHolder.get_deck_compat(deck_data) != 0:
|
||||
compat_dialog.set_meta(&"path", path)
|
||||
file_dialog.hide()
|
||||
compat_dialog.popup_centered()
|
||||
return
|
||||
|
||||
open_deck_from_dict(deck_data, path)
|
||||
|
||||
|
||||
func open_deck_from_dict(data: Dictionary, path: String) -> void:
|
||||
var deck := DeckHolder.open_deck_from_dict(data, path)
|
||||
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
||||
inst.deck = deck
|
||||
var tab := tab_container.add_content(inst, path.get_file())
|
||||
|
@ -450,6 +474,10 @@ func disconnect_file_dialog_signals() -> void:
|
|||
|
||||
if file_dialog.files_selected.is_connected(_on_file_dialog_open_files):
|
||||
file_dialog.files_selected.disconnect(_on_file_dialog_open_files)
|
||||
|
||||
if file_dialog.file_selected.is_connected(open_deck_at_path):
|
||||
file_dialog.file_selected.disconnect(open_deck_at_path)
|
||||
|
||||
|
||||
## Connected to [signal DeckRenderGraphEdit.group_entered_request] to allow entering
|
||||
## groups based off the given [param group_id] and [param deck]. As well as adding
|
||||
|
@ -652,3 +680,19 @@ func _on_help_id_pressed(id: int) -> void:
|
|||
HelpMenuId.DOCS:
|
||||
OS.shell_open("https://codeberg.org/Eroax/StreamGraph/wiki")
|
||||
|
||||
|
||||
func _on_compat_dialog_confirmed() -> void:
|
||||
var path: String = compat_dialog.get_meta(&"path", "")
|
||||
var f := FileAccess.open(path, FileAccess.READ)
|
||||
if f.get_error() != OK:
|
||||
return
|
||||
|
||||
# save a backup
|
||||
if path.split(".")[-2] != "old":
|
||||
var backup_path := "%s.old.deck" % path.trim_suffix(".deck")
|
||||
DirAccess.copy_absolute(path, backup_path)
|
||||
|
||||
var deck_data: Dictionary = JSON.parse_string(f.get_as_text())
|
||||
open_deck_from_dict(deck_data, path)
|
||||
# set it as dirty to make sure the user resaves
|
||||
get_active_deck_renderer().dirty = true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=17 format=3 uid="uid://duaah5x0jhkn6"]
|
||||
[gd_scene load_steps=18 format=3 uid="uid://duaah5x0jhkn6"]
|
||||
|
||||
[ext_resource type="Script" path="res://graph_node_renderer/deck_holder_renderer.gd" id="1_67g2g"]
|
||||
[ext_resource type="PackedScene" uid="uid://b84f2ngtcm5b8" path="res://graph_node_renderer/tab_container_custom.tscn" id="1_s3ug2"]
|
||||
|
@ -16,6 +16,7 @@
|
|||
[ext_resource type="PackedScene" uid="uid://bu466w2w3q08c" path="res://graph_node_renderer/about_dialog.tscn" id="11_6ln7n"]
|
||||
[ext_resource type="PackedScene" uid="uid://brfrufvkjwcor" path="res://graph_node_renderer/rpc_setup_dialog.tscn" id="12_1xrfk"]
|
||||
[ext_resource type="PackedScene" uid="uid://dodqetbke5wji" path="res://graph_node_renderer/settings_dialog.tscn" id="16_rktri"]
|
||||
[ext_resource type="PackedScene" uid="uid://cd1t0gvi022gx" path="res://graph_node_renderer/compat_dialog.tscn" id="17_2ndnq"]
|
||||
|
||||
[node name="DeckHolderRenderer" type="Control"]
|
||||
layout_mode = 3
|
||||
|
@ -170,6 +171,9 @@ unique_name_in_owner = true
|
|||
[node name="SettingsDialog" parent="." instance=ExtResource("16_rktri")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="CompatDialog" parent="." instance=ExtResource("17_2ndnq")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[connection signal="id_pressed" from="MarginContainer/SidebarSplit/BottomSplit/VBoxContainer/MenuBar/File" to="." method="_on_file_id_pressed"]
|
||||
[connection signal="about_to_popup" from="MarginContainer/SidebarSplit/BottomSplit/VBoxContainer/MenuBar/Edit" to="." method="_on_edit_about_to_popup"]
|
||||
[connection signal="id_pressed" from="MarginContainer/SidebarSplit/BottomSplit/VBoxContainer/MenuBar/Edit" to="." method="_on_edit_id_pressed"]
|
||||
|
@ -180,3 +184,4 @@ unique_name_in_owner = true
|
|||
[connection signal="confirmed" from="UnsavedChangesDialogSingleDeck" to="." method="_on_unsaved_changes_dialog_single_deck_confirmed"]
|
||||
[connection signal="custom_action" from="UnsavedChangesDialogSingleDeck" to="." method="_on_unsaved_changes_dialog_single_deck_custom_action"]
|
||||
[connection signal="confirmed" from="UnsavedChangesDialog" to="." method="_on_unsaved_changes_dialog_confirmed"]
|
||||
[connection signal="confirmed" from="CompatDialog" to="." method="_on_compat_dialog_confirmed"]
|
||||
|
|
|
@ -119,11 +119,7 @@ func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name
|
|||
## Returns the associated [DeckNodeRendererGraphNode] for the supplied [DeckNode].
|
||||
## Or [code]null[/code] if none is found.
|
||||
func get_node_renderer(node: DeckNode) -> DeckNodeRendererGraphNode:
|
||||
for i: DeckNodeRendererGraphNode in get_children():
|
||||
if i.node == node:
|
||||
return i
|
||||
|
||||
return null
|
||||
return get_node_or_null(NodePath(node._id))
|
||||
|
||||
|
||||
func focus_node(node: DeckNodeRendererGraphNode) -> void:
|
||||
|
@ -162,7 +158,8 @@ func initialize_from_deck() -> void:
|
|||
is_group = deck.is_group
|
||||
for node_id in deck.nodes:
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = deck.nodes[node_id]
|
||||
node_renderer.node = deck.get_node(node_id)
|
||||
node_renderer.name = node_id
|
||||
add_child(node_renderer)
|
||||
node_renderer.position_offset = node_renderer.node.position_as_vector2()
|
||||
change_dirty = true
|
||||
|
@ -178,29 +175,16 @@ func initialize_from_deck() -> void:
|
|||
## [method GraphEdit.connect_node] for all the connections that exist in each
|
||||
func refresh_connections() -> void:
|
||||
for node_id in deck.nodes:
|
||||
var node: DeckNode = deck.nodes[node_id]
|
||||
var from_node: DeckNodeRendererGraphNode = get_children().filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == node_id
|
||||
)[0]
|
||||
|
||||
for from_port in node.outgoing_connections:
|
||||
for to_node_id: String in node.outgoing_connections[from_port]:
|
||||
var to_node_ports = node.outgoing_connections[from_port][to_node_id]
|
||||
var renderer: Array = get_children().filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == to_node_id
|
||||
if not deck.get_connections_dict().has(node_id):
|
||||
continue
|
||||
for from_port: int in deck.get_connections_dict()[node_id].outgoing:
|
||||
for outgoing: Deck.OutgoingConnection in deck.get_connections_dict()[node_id].outgoing[from_port]:
|
||||
connect_node(
|
||||
node_id,
|
||||
from_port,
|
||||
outgoing.to_node,
|
||||
outgoing.to_port
|
||||
)
|
||||
if renderer.is_empty():
|
||||
break
|
||||
var to_node: DeckNodeRendererGraphNode = renderer[0]
|
||||
for to_node_port: int in to_node_ports:
|
||||
connect_node(
|
||||
from_node.name,
|
||||
from_port,
|
||||
to_node.name,
|
||||
to_node_port
|
||||
)
|
||||
|
||||
|
||||
## Connected to [signal Deck.node_added], used to instance the required
|
||||
|
@ -208,6 +192,7 @@ func refresh_connections() -> void:
|
|||
func _on_deck_node_added(node: DeckNode) -> void:
|
||||
var inst: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
inst.node = node
|
||||
inst.name = node._id
|
||||
add_child(inst)
|
||||
inst.position_offset = inst.node.position_as_vector2()
|
||||
dirty = true
|
||||
|
@ -236,8 +221,6 @@ func get_selected_nodes() -> Array:
|
|||
)
|
||||
|
||||
|
||||
## Executes functionality based off hotkey inputs. Specifically handles creating groups
|
||||
## based off the action "group_nodes".
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if RendererShortcuts.check_shortcut("group_nodes", event) and get_selected_nodes().size() > 0:
|
||||
clear_connections()
|
||||
|
@ -293,8 +276,6 @@ func _gui_input(event: InputEvent) -> void:
|
|||
focus_selection()
|
||||
|
||||
|
||||
## Handles entering groups with action "enter_group". Done here to bypass neighbor
|
||||
## functionality.
|
||||
func _input(event: InputEvent) -> void:
|
||||
if not has_focus():
|
||||
return
|
||||
|
@ -343,7 +324,6 @@ func _on_add_node_menu_node_selected(type: String) -> void:
|
|||
|
||||
|
||||
func _on_deck_nodes_disconnected(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> void:
|
||||
print("1")
|
||||
var from_node: DeckNodeRendererGraphNode = get_children().filter(
|
||||
func(x: DeckNodeRendererGraphNode):
|
||||
return x.node._id == from_node_id
|
||||
|
|
Loading…
Reference in a new issue