mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
add copying and pasting nodes
This commit is contained in:
parent
d3bf258ba9
commit
8520f240d0
4 changed files with 161 additions and 44 deletions
|
@ -59,6 +59,7 @@ func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool
|
||||||
node._id = uuid
|
node._id = uuid
|
||||||
else:
|
else:
|
||||||
nodes[assign_id] = node
|
nodes[assign_id] = node
|
||||||
|
node._id = assign_id
|
||||||
|
|
||||||
node_added.emit(node)
|
node_added.emit(node)
|
||||||
|
|
||||||
|
@ -197,6 +198,86 @@ func get_group(uuid: String) -> Deck:
|
||||||
return groups.get(uuid)
|
return groups.get(uuid)
|
||||||
|
|
||||||
|
|
||||||
|
func copy_nodes_json(nodes_to_copy: Array[String]) -> String:
|
||||||
|
var d := {"nodes": {}}
|
||||||
|
|
||||||
|
for node_id: String in nodes_to_copy:
|
||||||
|
d.nodes[node_id] = get_node(node_id).to_dict()
|
||||||
|
|
||||||
|
for node: String in d.nodes:
|
||||||
|
var outgoing_connections: Dictionary = d.nodes[node].outgoing_connections.duplicate(true)
|
||||||
|
|
||||||
|
for from_port: int in outgoing_connections:
|
||||||
|
for to_node: String in outgoing_connections[from_port]:
|
||||||
|
if !(to_node in nodes_to_copy):
|
||||||
|
(d.nodes[node].outgoing_connections[from_port] as Dictionary).erase(to_node)
|
||||||
|
|
||||||
|
var incoming_connections: Dictionary = d.nodes[node].incoming_connections.duplicate(true)
|
||||||
|
|
||||||
|
for to_port: int in incoming_connections:
|
||||||
|
for from_node: String in incoming_connections[to_port]:
|
||||||
|
if !(from_node in nodes_to_copy):
|
||||||
|
(d.nodes[node].incoming_connections[to_port] as Dictionary).erase(from_node)
|
||||||
|
|
||||||
|
for node: Dictionary in d.nodes.values().slice(1):
|
||||||
|
node.position.x = node.position.x - d.nodes.values()[0].position.x
|
||||||
|
node.position.y = node.position.y - d.nodes.values()[0].position.y
|
||||||
|
|
||||||
|
d.nodes.values()[0].position.x = 0
|
||||||
|
d.nodes.values()[0].position.y = 0
|
||||||
|
|
||||||
|
return JSON.stringify(d)
|
||||||
|
|
||||||
|
|
||||||
|
func allocate_ids(count: int) -> Array[String]:
|
||||||
|
var res: Array[String]
|
||||||
|
for i in count:
|
||||||
|
res.append(UUID.v4())
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
func paste_nodes_from_json(json: String, position: Vector2 = Vector2()) -> void:
|
||||||
|
var d: Dictionary = JSON.parse_string(json) as Dictionary
|
||||||
|
if !d.get("nodes"):
|
||||||
|
return
|
||||||
|
|
||||||
|
var new_ids := allocate_ids(d.nodes.size())
|
||||||
|
var ids_map := {}
|
||||||
|
for i: int in d.nodes.keys().size():
|
||||||
|
var node_id: String = d.nodes.keys()[i]
|
||||||
|
ids_map[node_id] = new_ids[i]
|
||||||
|
|
||||||
|
var new_json := json
|
||||||
|
for old_id: String in ids_map:
|
||||||
|
new_json = new_json.replace(old_id, ids_map[old_id])
|
||||||
|
|
||||||
|
for node_id: String in d.nodes:
|
||||||
|
d.nodes[node_id]._id = ids_map[node_id]
|
||||||
|
|
||||||
|
d.nodes[node_id].position.x += position.x
|
||||||
|
d.nodes[node_id].position.y += position.y
|
||||||
|
|
||||||
|
var outgoing_connections: Dictionary = d.nodes[node_id].outgoing_connections as Dictionary
|
||||||
|
var outgoing_connections_res := {}
|
||||||
|
for from_port: String in outgoing_connections:
|
||||||
|
outgoing_connections_res[from_port] = {}
|
||||||
|
for to_node_id: String 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 = d.nodes[node_id].incoming_connections as Dictionary
|
||||||
|
var incoming_connections_res := {}
|
||||||
|
for to_port: String in incoming_connections:
|
||||||
|
incoming_connections_res[to_port] = {}
|
||||||
|
for from_node_id: String in incoming_connections[to_port]:
|
||||||
|
incoming_connections_res[to_port][ids_map[from_node_id]] = incoming_connections[to_port][from_node_id]
|
||||||
|
|
||||||
|
d.nodes[node_id].outgoing_connections = outgoing_connections_res
|
||||||
|
d.nodes[node_id].incoming_connections = incoming_connections_res
|
||||||
|
|
||||||
|
var node := DeckNode.from_dict(d.nodes[node_id])
|
||||||
|
add_node_inst(node, ids_map[node_id])
|
||||||
|
|
||||||
|
|
||||||
## Returns a [Dictionary] representation of this deck.
|
## Returns a [Dictionary] representation of this deck.
|
||||||
func to_dict(with_meta: bool = true) -> Dictionary:
|
func to_dict(with_meta: bool = true) -> Dictionary:
|
||||||
var inner := {
|
var inner := {
|
||||||
|
@ -239,44 +320,8 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
||||||
var nodes_data: Dictionary = data.deck.nodes as Dictionary
|
var nodes_data: Dictionary = data.deck.nodes as Dictionary
|
||||||
|
|
||||||
for node_id in nodes_data:
|
for node_id in nodes_data:
|
||||||
var node := deck.add_node_type(nodes_data[node_id].node_type, node_id, false)
|
var node := DeckNode.from_dict(nodes_data[node_id])
|
||||||
node._id = node_id
|
deck.add_node_inst(node, node_id)
|
||||||
node.name = nodes_data[node_id].name
|
|
||||||
node._belonging_to = deck
|
|
||||||
node.position = nodes_data[node_id].position
|
|
||||||
|
|
||||||
for prop in nodes_data[node_id].props:
|
|
||||||
node.set(prop, nodes_data[node_id].props[prop])
|
|
||||||
|
|
||||||
node._pre_connection()
|
|
||||||
|
|
||||||
for from_port: String in nodes_data[node_id].outgoing_connections:
|
|
||||||
var connection_data: Dictionary = nodes_data[node_id].outgoing_connections[from_port]
|
|
||||||
node.outgoing_connections[int(from_port)] = {}
|
|
||||||
for to_node: String 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: String in nodes_data[node_id].incoming_connections:
|
|
||||||
var connection_data = nodes_data[node_id].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
|
|
||||||
if (nodes_data[node_id].port_values as Array).size() <= i:
|
|
||||||
port_value = null
|
|
||||||
else:
|
|
||||||
port_value = (nodes_data[node_id].port_values as Array)[i]
|
|
||||||
node.ports[i].value = port_value
|
|
||||||
|
|
||||||
for key in nodes_data[node_id].meta:
|
|
||||||
node.set_meta(key, str_to_var(nodes_data[node_id].meta[key]))
|
|
||||||
|
|
||||||
node._post_load()
|
|
||||||
|
|
||||||
var groups_data: Dictionary = data.deck.groups as Dictionary
|
var groups_data: Dictionary = data.deck.groups as Dictionary
|
||||||
|
|
||||||
|
|
|
@ -250,12 +250,12 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
||||||
var d := {
|
var d := {
|
||||||
"_id": _id,
|
"_id": _id,
|
||||||
"name": name,
|
"name": name,
|
||||||
"outgoing_connections": outgoing_connections,
|
"outgoing_connections": outgoing_connections.duplicate(true),
|
||||||
"incoming_connections": incoming_connections,
|
"incoming_connections": incoming_connections.duplicate(true),
|
||||||
"props": {},
|
"props": {},
|
||||||
"node_type": node_type,
|
"node_type": node_type,
|
||||||
"port_values": [],
|
"port_values": [],
|
||||||
"position": position,
|
"position": position.duplicate(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for prop in props_to_serialize:
|
for prop in props_to_serialize:
|
||||||
|
@ -273,6 +273,48 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
static func from_dict(data: Dictionary) -> DeckNode:
|
||||||
|
var node := NodeDB.instance_node(data.node_type)
|
||||||
|
#node._id = data._id
|
||||||
|
node.name = data.name
|
||||||
|
node.position = data.position
|
||||||
|
|
||||||
|
for prop in data.props:
|
||||||
|
node.set(prop, data.props[prop])
|
||||||
|
|
||||||
|
node._pre_connection()
|
||||||
|
|
||||||
|
for from_port: String in data.outgoing_connections:
|
||||||
|
var connection_data: Dictionary = data.outgoing_connections[from_port]
|
||||||
|
node.outgoing_connections[int(from_port)] = {}
|
||||||
|
for to_node: String 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: String 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
|
||||||
|
if (data.port_values as Array).size() <= i:
|
||||||
|
port_value = null
|
||||||
|
else:
|
||||||
|
port_value = (data.port_values as Array)[i]
|
||||||
|
node.ports[i].value = port_value
|
||||||
|
|
||||||
|
for key in data.meta:
|
||||||
|
node.set_meta(key, str_to_var(data.meta[key]))
|
||||||
|
|
||||||
|
node._post_load()
|
||||||
|
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
## Returns the node's [member position] as a [Vector2].
|
## Returns the node's [member position] as a [Vector2].
|
||||||
func position_as_vector2() -> Vector2:
|
func position_as_vector2() -> Vector2:
|
||||||
return Vector2(position.x, position.y)
|
return Vector2(position.x, position.y)
|
||||||
|
|
|
@ -129,10 +129,13 @@ func refresh_connections() -> void:
|
||||||
for from_port in node.outgoing_connections:
|
for from_port in node.outgoing_connections:
|
||||||
for to_node_id: String in node.outgoing_connections[from_port]:
|
for to_node_id: String in node.outgoing_connections[from_port]:
|
||||||
var to_node_ports = node.outgoing_connections[from_port][to_node_id]
|
var to_node_ports = node.outgoing_connections[from_port][to_node_id]
|
||||||
var to_node: DeckNodeRendererGraphNode = get_children().filter(
|
var renderer: Array = get_children().filter(
|
||||||
func(c: DeckNodeRendererGraphNode):
|
func(c: DeckNodeRendererGraphNode):
|
||||||
return c.node._id == to_node_id
|
return c.node._id == to_node_id
|
||||||
)[0]
|
)
|
||||||
|
if renderer.is_empty():
|
||||||
|
break
|
||||||
|
var to_node: DeckNodeRendererGraphNode = renderer[0]
|
||||||
for to_node_port: int in to_node_ports:
|
for to_node_port: int in to_node_ports:
|
||||||
connect_node(
|
connect_node(
|
||||||
from_node.name,
|
from_node.name,
|
||||||
|
@ -148,6 +151,8 @@ func _on_deck_node_added(node: DeckNode) -> void:
|
||||||
inst.node = node
|
inst.node = node
|
||||||
add_child(inst)
|
add_child(inst)
|
||||||
inst.position_offset = inst.node.position_as_vector2()
|
inst.position_offset = inst.node.position_as_vector2()
|
||||||
|
clear_connections()
|
||||||
|
refresh_connections()
|
||||||
|
|
||||||
## Connected to [signal Deck.node_added], used to remove the specified
|
## Connected to [signal Deck.node_added], used to remove the specified
|
||||||
## [DeckNodeRendererGraphNode] and queue_free it.
|
## [DeckNodeRendererGraphNode] and queue_free it.
|
||||||
|
@ -229,5 +234,28 @@ func _on_delete_nodes_request(nodes: Array[StringName]) -> void:
|
||||||
for node_id in node_ids:
|
for node_id in node_ids:
|
||||||
deck.remove_node(node_id, true)
|
deck.remove_node(node_id, true)
|
||||||
|
|
||||||
#await get_tree().process_frame
|
|
||||||
refresh_connections()
|
refresh_connections()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_copy_nodes_request() -> void:
|
||||||
|
var selected := get_selected_nodes()
|
||||||
|
if selected.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
var selected_ids: Array[String]
|
||||||
|
selected_ids.assign(selected.map(
|
||||||
|
func(x: DeckNodeRendererGraphNode):
|
||||||
|
return x.node._id
|
||||||
|
))
|
||||||
|
|
||||||
|
DisplayServer.clipboard_set(deck.copy_nodes_json(selected_ids))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_paste_nodes_request() -> void:
|
||||||
|
var clip := DisplayServer.clipboard_get()
|
||||||
|
var node_pos := (get_local_mouse_position() + scroll_offset - (Vector2(75.0, 0.0) * zoom)) / zoom
|
||||||
|
|
||||||
|
if snapping_enabled:
|
||||||
|
node_pos = node_pos.snapped(Vector2(snapping_distance, snapping_distance))
|
||||||
|
|
||||||
|
deck.paste_nodes_from_json(clip, node_pos)
|
||||||
|
|
|
@ -12,6 +12,8 @@ right_disconnects = true
|
||||||
show_arrange_button = false
|
show_arrange_button = false
|
||||||
script = ExtResource("1_pojfs")
|
script = ExtResource("1_pojfs")
|
||||||
|
|
||||||
|
[connection signal="copy_nodes_request" from="." to="." method="_on_copy_nodes_request"]
|
||||||
[connection signal="delete_nodes_request" from="." to="." method="_on_delete_nodes_request"]
|
[connection signal="delete_nodes_request" from="." to="." method="_on_delete_nodes_request"]
|
||||||
|
[connection signal="paste_nodes_request" from="." to="." method="_on_paste_nodes_request"]
|
||||||
[connection signal="popup_request" from="." to="." method="_on_popup_request"]
|
[connection signal="popup_request" from="." to="." method="_on_popup_request"]
|
||||||
[connection signal="scroll_offset_changed" from="." to="." method="_on_scroll_offset_changed"]
|
[connection signal="scroll_offset_changed" from="." to="." method="_on_scroll_offset_changed"]
|
||||||
|
|
Loading…
Reference in a new issue