mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
merge groups (#2)
here we go Reviewed-on: https://codeberg.org/Eroax/Re-DotDeck/pulls/2 Co-authored-by: Lera Elvoé <yagich@poto.cafe> Co-committed-by: Lera Elvoé <yagich@poto.cafe>
This commit is contained in:
parent
b25f6ce6c7
commit
fa5e9997ef
19 changed files with 1109 additions and 181 deletions
|
@ -22,21 +22,24 @@ static var type_assoc: Dictionary = {
|
|||
}
|
||||
|
||||
var variable_stack: Dictionary = {}
|
||||
var save_path: String = ""
|
||||
|
||||
var is_group: bool = false
|
||||
var groups: Dictionary = {} #Dictionary[String -> Deck.id, Deck]
|
||||
var id: String = ""
|
||||
var _belonging_to: Deck # for groups
|
||||
var group_input_node: String
|
||||
var group_output_node: String
|
||||
var group_node: String
|
||||
|
||||
signal node_added(node: DeckNode)
|
||||
signal node_removed(node: DeckNode)
|
||||
|
||||
|
||||
func add_node(node: GDScript, meta: Dictionary = {}) -> DeckNode:
|
||||
# TODO: accept instances of DeckNode instead of instancing here?
|
||||
var uuid := UUID.v4()
|
||||
var node_inst: DeckNode = node.new() as DeckNode
|
||||
nodes[uuid] = node_inst
|
||||
node_inst._belonging_to = self
|
||||
node_inst._id = uuid
|
||||
func add_node_type(type: String, assign_id: String = "", assign_to_self: bool = true) -> DeckNode:
|
||||
var node_inst: DeckNode = NodeDB.instance_node(type)
|
||||
|
||||
if !meta.is_empty():
|
||||
for k in meta:
|
||||
node_inst.set_meta(k, meta[k])
|
||||
|
||||
return node_inst
|
||||
return add_node_inst(node_inst, assign_id, assign_to_self)
|
||||
|
||||
|
||||
func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool = true) -> DeckNode:
|
||||
|
@ -50,10 +53,7 @@ func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool
|
|||
else:
|
||||
nodes[assign_id] = node
|
||||
|
||||
|
||||
# if !meta.is_empty():
|
||||
# for k in meta:
|
||||
# node.set_meta(k, meta[k])
|
||||
node_added.emit(node)
|
||||
|
||||
return node
|
||||
|
||||
|
@ -62,10 +62,10 @@ func get_node(uuid: String) -> DeckNode:
|
|||
return nodes.get(uuid)
|
||||
|
||||
|
||||
func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> bool:
|
||||
func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int, to_input_port: int) -> bool:
|
||||
# first, check that we can do the type conversion.
|
||||
var type_a: Types = from_node.ports[from_port].type
|
||||
var type_b: Types = to_node.ports[to_port].type
|
||||
var type_a: Types = from_node.get_output_ports()[from_output_port].type
|
||||
var type_b: Types = to_node.get_input_ports()[to_input_port].type
|
||||
var err: DeckType = (type_assoc[type_b]).from(type_assoc[type_a].new())
|
||||
if err is DeckType.DeckTypeError:
|
||||
print(err.error_message)
|
||||
|
@ -73,32 +73,106 @@ func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_po
|
|||
|
||||
# TODO: prevent duplicate connections
|
||||
|
||||
from_node.add_outgoing_connection(from_port, to_node._id, to_port)
|
||||
from_node.add_outgoing_connection(from_output_port, to_node._id, to_input_port)
|
||||
return true
|
||||
|
||||
|
||||
func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> void:
|
||||
var hash = {to_node._id: to_port}.hash()
|
||||
# prints({to_node._id: to_port}, "-", {to_node._id: to_port}.hash())
|
||||
# prints(from_node.outgoing_connections[0][0], "-", from_node.outgoing_connections[0][0].hash())
|
||||
#
|
||||
# var a = {to_node._id: to_port}
|
||||
# var b = from_node.outgoing_connections[0][0]
|
||||
#
|
||||
# print(typeof(a.values()[0]))
|
||||
# print(typeof(b.values()[0]))
|
||||
#
|
||||
# prints(a, b)
|
||||
func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int, to_input_port: int) -> void:
|
||||
var hash = {to_node._id: to_input_port}.hash()
|
||||
|
||||
from_node.remove_outgoing_connection(from_port, hash)
|
||||
to_node.remove_incoming_connection(to_port)
|
||||
from_node.remove_outgoing_connection(from_output_port, hash)
|
||||
to_node.remove_incoming_connection(to_input_port)
|
||||
|
||||
|
||||
func to_json(with_meta: bool = true) -> String:
|
||||
var inner := {"nodes": {}, "variable_stack": variable_stack}
|
||||
func is_empty() -> bool:
|
||||
return nodes.is_empty() && variable_stack.is_empty()
|
||||
|
||||
for id in nodes.keys():
|
||||
inner["nodes"][id] = nodes[id].to_dict(with_meta)
|
||||
|
||||
func remove_node(uuid: String) -> void:
|
||||
var node = nodes.get(uuid)
|
||||
nodes.erase(uuid)
|
||||
|
||||
node_removed.emit(node)
|
||||
|
||||
|
||||
func group_nodes(nodes_to_group: Array) -> Deck:
|
||||
if nodes_to_group.is_empty():
|
||||
return null
|
||||
|
||||
var node_ids_to_keep := nodes_to_group.map(
|
||||
func(x: DeckNode):
|
||||
return x._id
|
||||
)
|
||||
|
||||
var group := Deck.new()
|
||||
group.is_group = true
|
||||
group._belonging_to = self
|
||||
var group_id := UUID.v4()
|
||||
group.id = group_id
|
||||
|
||||
var midpoint := Vector2()
|
||||
for node: DeckNode in nodes_to_group:
|
||||
if node.node_type == "group_node": # for recursive grouping
|
||||
var _group_id: String = node.group_id
|
||||
var _group: Deck = groups[_group_id]
|
||||
groups.erase(_group)
|
||||
group.groups[_group_id] = _group
|
||||
_group._belonging_to = group
|
||||
|
||||
for from_port: int in node.outgoing_connections:
|
||||
for connection: Dictionary in node.outgoing_connections[from_port]:
|
||||
if !(connection.keys()[0] in node_ids_to_keep):
|
||||
disconnect_nodes(node, get_node(connection.keys()[0]), from_port, connection.values()[0])
|
||||
|
||||
midpoint += node.position_as_vector2()
|
||||
remove_node(node._id)
|
||||
group.add_node_inst(node, node._id)
|
||||
|
||||
midpoint /= nodes_to_group.size()
|
||||
|
||||
var _group_node := add_node_type("group_node")
|
||||
_group_node.group_id = group_id
|
||||
_group_node.position.x = midpoint.x
|
||||
_group_node.position.y = midpoint.y
|
||||
_group_node.position_updated.emit(_group_node.position)
|
||||
group.group_node = _group_node._id
|
||||
|
||||
var input_node := group.add_node_type("group_input")
|
||||
var output_node := group.add_node_type("group_output")
|
||||
group.group_input_node = input_node._id
|
||||
group.group_output_node = output_node._id
|
||||
|
||||
_group_node.input_node = input_node
|
||||
_group_node.output_node = output_node
|
||||
_group_node.setup_connections()
|
||||
|
||||
groups[group_id] = group
|
||||
|
||||
return group
|
||||
|
||||
|
||||
func get_group(uuid: String) -> Deck:
|
||||
return groups.get(uuid)
|
||||
|
||||
|
||||
func to_dict(with_meta: bool = true) -> Dictionary:
|
||||
var inner := {
|
||||
"nodes": {},
|
||||
"variable_stack": variable_stack,
|
||||
"id": id,
|
||||
"groups": {}
|
||||
}
|
||||
|
||||
for node_id in nodes.keys():
|
||||
inner["nodes"][node_id] = nodes[node_id].to_dict(with_meta)
|
||||
|
||||
for group_id in groups.keys():
|
||||
inner["groups"][group_id] = groups[group_id].to_dict(with_meta)
|
||||
|
||||
if is_group:
|
||||
inner["group_node"] = group_node
|
||||
inner["group_input_node"] = group_input_node
|
||||
inner["group_output_node"] = group_output_node
|
||||
|
||||
var d := {"deck": inner}
|
||||
|
||||
|
@ -106,14 +180,14 @@ func to_json(with_meta: bool = true) -> String:
|
|||
d["meta"] = {}
|
||||
for meta in get_meta_list():
|
||||
d["meta"][meta] = var_to_str(get_meta(meta))
|
||||
return JSON.stringify(d, "\t", false)
|
||||
return d
|
||||
|
||||
|
||||
static func from_json(json: String) -> Deck:
|
||||
var data: Dictionary = JSON.parse_string(json) as Dictionary
|
||||
static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
||||
var deck := Deck.new()
|
||||
|
||||
deck.save_path = path
|
||||
deck.variable_stack = data.deck.variable_stack
|
||||
deck.id = data.deck.id
|
||||
|
||||
for key in data.meta:
|
||||
deck.set_meta(key, str_to_var(data.meta[key]))
|
||||
|
@ -121,12 +195,17 @@ static func from_json(json: String) -> Deck:
|
|||
var nodes_data: Dictionary = data.deck.nodes as Dictionary
|
||||
|
||||
for node_id in nodes_data:
|
||||
var node := deck.add_node_inst(NodeDB.instance_node(nodes_data[node_id].node_type), node_id, false)
|
||||
var node := deck.add_node_type(nodes_data[node_id].node_type, node_id, false)
|
||||
node._id = node_id
|
||||
node.name = nodes_data[node_id].name
|
||||
node._belonging_to = deck
|
||||
# node.outgoing_connections = nodes_data[node_id].outgoing_connections
|
||||
# node.incoming_connections = nodes_data[node_id].incoming_connections
|
||||
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 connection_id in nodes_data[node_id].outgoing_connections:
|
||||
var connection_data = nodes_data[node_id].outgoing_connections[connection_id]
|
||||
for connection in connection_data:
|
||||
|
@ -139,14 +218,29 @@ static func from_json(json: String) -> Deck:
|
|||
connection_data[connection] = int(connection_data[connection])
|
||||
node.incoming_connections[int(connection_id)] = connection_data
|
||||
|
||||
for i in nodes_data[node_id].port_values.size():
|
||||
var port_value = nodes_data[node_id].port_values[i]
|
||||
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]))
|
||||
|
||||
for prop in nodes_data[node_id].props:
|
||||
node.set(prop, nodes_data[node_id].props[prop])
|
||||
node._post_load()
|
||||
|
||||
var groups_data: Dictionary = data.deck.groups as Dictionary
|
||||
|
||||
for group_id: String in groups_data:
|
||||
var group := Deck.from_dict(groups_data[group_id])
|
||||
group._belonging_to = deck
|
||||
group.is_group = true
|
||||
deck.groups[group_id] = group
|
||||
group.group_node = groups_data[group_id]["deck"]["group_node"]
|
||||
group.group_input_node = groups_data[group_id]["deck"]["group_input_node"]
|
||||
group.group_output_node = groups_data[group_id]["deck"]["group_output_node"]
|
||||
deck.get_node(group.group_node).init_io()
|
||||
|
||||
return deck
|
||||
|
|
27
classes/deck/deck_holder.gd
Normal file
27
classes/deck/deck_holder.gd
Normal file
|
@ -0,0 +1,27 @@
|
|||
class_name DeckHolder
|
||||
|
||||
|
||||
static var decks: Array[Deck]
|
||||
|
||||
|
||||
static func add_empty_deck() -> Deck:
|
||||
var deck := Deck.new()
|
||||
DeckHolder.decks.append(deck)
|
||||
var uuid := UUID.v4()
|
||||
deck.id = uuid
|
||||
return deck
|
||||
|
||||
|
||||
static func open_deck_from_file(path: String) -> Deck:
|
||||
var f := FileAccess.open(path, FileAccess.READ)
|
||||
if f.get_error() != OK:
|
||||
return null
|
||||
|
||||
var deck := Deck.from_dict(JSON.parse_string(f.get_as_text()), path)
|
||||
DeckHolder.decks.append(deck)
|
||||
|
||||
return deck
|
||||
|
||||
|
||||
static func close_deck(deck: Deck) -> void:
|
||||
DeckHolder.decks.erase(deck)
|
|
@ -1,9 +1,10 @@
|
|||
class_name DeckNode
|
||||
|
||||
var name: String
|
||||
var input_ports: Array[Port]
|
||||
var output_ports: Array[Port]
|
||||
|
||||
## [code]Dictionary[int -> output port, Array[Dictionary[String -> DeckNode#_id, int -> input port]]]
|
||||
var outgoing_connections: Dictionary
|
||||
## [code]Dictionary[int -> input port, [Dictionary[String -> DeckNode#_id, int -> output port]]
|
||||
var incoming_connections: Dictionary
|
||||
|
||||
var ports: Array[Port]
|
||||
|
@ -17,49 +18,63 @@ var aliases: Array[String]
|
|||
|
||||
var props_to_serialize: Array[StringName]
|
||||
|
||||
var position: Dictionary = {"x": 0.0, "y": 0.0}
|
||||
|
||||
enum PortType{
|
||||
INPUT, ## Input port type (slot on the left).
|
||||
OUTPUT, ## Output port type (slot on the right).
|
||||
VIRTUAL, ## Virtual port type (no slot on left [i]or[/i] right).
|
||||
}
|
||||
|
||||
signal position_updated(new_position: Dictionary)
|
||||
signal port_added(port: int)
|
||||
signal port_removed(port: int)
|
||||
signal ports_updated()
|
||||
signal outgoing_connection_added(from_port: int)
|
||||
signal outgoing_connection_removed(from_port: int)
|
||||
signal incoming_connection_added(from_port: int)
|
||||
signal incoming_connection_removed(from_port: int)
|
||||
|
||||
|
||||
func add_input_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
||||
var port := Port.new(type, label, ports.size(), PortType.INPUT, get_input_ports().size(), descriptor)
|
||||
ports.append(port)
|
||||
add_port(type, label, PortType.INPUT, get_input_ports().size(), descriptor)
|
||||
|
||||
|
||||
func add_output_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
||||
var port := Port.new(type, label, ports.size(), PortType.OUTPUT, get_output_ports().size(), descriptor)
|
||||
ports.append(port)
|
||||
add_port(type, label, PortType.OUTPUT, get_output_ports().size(), descriptor)
|
||||
|
||||
|
||||
func add_virtual_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
||||
var port := Port.new(type, label, ports.size(), PortType.VIRTUAL, get_virtual_ports().size(), descriptor)
|
||||
add_port(type, label, PortType.VIRTUAL, get_virtual_ports().size(), descriptor)
|
||||
|
||||
|
||||
func add_port(type: Deck.Types, label: String, port_type: PortType, index_of_type: int, descriptor: String = "") -> void:
|
||||
var port := Port.new(type, label, ports.size(), port_type, index_of_type, descriptor)
|
||||
ports.append(port)
|
||||
port_added.emit(ports.size() - 1)
|
||||
ports_updated.emit()
|
||||
|
||||
|
||||
func send_from_output_port(output_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
var global_port := get_global_port_idx_from_output(output_port)
|
||||
if global_port == -1:
|
||||
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)
|
||||
|
||||
|
||||
func send(from_output_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if outgoing_connections.get(from_output_port) == null:
|
||||
return
|
||||
|
||||
send(global_port, data, extra_data)
|
||||
|
||||
|
||||
func send(from_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if outgoing_connections.get(from_port) == null:
|
||||
return
|
||||
|
||||
for connection in outgoing_connections[from_port]:
|
||||
for connection in outgoing_connections[from_output_port]:
|
||||
connection = connection as Dictionary
|
||||
# key is node uuid
|
||||
# value is input port on destination node
|
||||
# value is GLOBAL port on destination node
|
||||
for node in connection:
|
||||
get_node(node)._receive(connection[node], data, extra_data)
|
||||
|
||||
|
||||
func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
pass
|
||||
|
||||
|
||||
|
@ -76,11 +91,13 @@ func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> v
|
|||
port_connections.append({to_node: to_port})
|
||||
outgoing_connections[from_port] = port_connections
|
||||
get_node(to_node).add_incoming_connection(to_port, _id, from_port)
|
||||
outgoing_connection_added.emit(from_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)
|
||||
|
||||
|
||||
func request_value(on_port: int) -> Variant:
|
||||
|
@ -116,10 +133,12 @@ func remove_outgoing_connection(from_port: int, connection_hash: int) -> void:
|
|||
|
||||
port_connections.remove_at(to_remove)
|
||||
outgoing_connections[from_port] = port_connections
|
||||
outgoing_connection_removed.emit(from_port)
|
||||
|
||||
|
||||
func remove_incoming_connection(to_port: int) -> void:
|
||||
incoming_connections.erase(to_port)
|
||||
incoming_connection_removed.emit(to_port)
|
||||
|
||||
|
||||
func remove_outgoing_connection_from_port(output_port: int, connection_hash: int) -> void:
|
||||
|
@ -168,6 +187,26 @@ func get_global_port_idx_from_virtual(idx: int) -> int:
|
|||
return -1
|
||||
|
||||
|
||||
func get_port_type_idx_from_global(idx: int) -> int:
|
||||
return ports[idx].index_of_type
|
||||
|
||||
|
||||
func get_outgoing_connection_count(port: int) -> int:
|
||||
return (outgoing_connections[port] as Array).size()
|
||||
|
||||
|
||||
func get_outgoing_connection_count_on_output(port: int) -> int:
|
||||
return get_outgoing_connection_count(get_global_port_idx_from_output(port))
|
||||
|
||||
|
||||
func has_incoming_connection(port: int) -> bool:
|
||||
return incoming_connections.has(port)
|
||||
|
||||
|
||||
func has_incoming_connection_on_input(port: int) -> bool:
|
||||
return has_incoming_connection(get_global_port_idx_from_input(port))
|
||||
|
||||
|
||||
func get_all_ports() -> Array[Port]:
|
||||
return ports
|
||||
|
||||
|
@ -176,6 +215,16 @@ func get_node(uuid: String) -> DeckNode:
|
|||
return _belonging_to.get_node(uuid)
|
||||
|
||||
|
||||
# override this to do setup before connections are loaded but after props were set
|
||||
func _pre_connection() -> void:
|
||||
pass
|
||||
|
||||
|
||||
# override this to do extra setup after it's done loading from dictionary
|
||||
func _post_load() -> void:
|
||||
pass
|
||||
|
||||
|
||||
func to_dict(with_meta: bool = true) -> Dictionary:
|
||||
var d := {
|
||||
"_id": _id,
|
||||
|
@ -184,7 +233,8 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
|||
"incoming_connections": incoming_connections,
|
||||
"props": {},
|
||||
"node_type": node_type,
|
||||
"port_values": []
|
||||
"port_values": [],
|
||||
"position": position,
|
||||
}
|
||||
|
||||
for prop in props_to_serialize:
|
||||
|
@ -200,3 +250,7 @@ func to_dict(with_meta: bool = true) -> Dictionary:
|
|||
for meta in get_meta_list():
|
||||
d["meta"][meta] = var_to_str(get_meta(meta))
|
||||
return d
|
||||
|
||||
|
||||
func position_as_vector2() -> Vector2:
|
||||
return Vector2(position.x, position.y)
|
||||
|
|
|
@ -8,8 +8,8 @@ var nodes: Dictionary = {}
|
|||
|
||||
|
||||
func _init() -> void:
|
||||
if load_node_index():
|
||||
return
|
||||
#if load_node_index():
|
||||
#return
|
||||
|
||||
var dir := DirAccess.open(BASE_NODE_PATH)
|
||||
dir.list_dir_begin()
|
||||
|
|
71
classes/deck/nodes/group_input_node.gd
Normal file
71
classes/deck/nodes/group_input_node.gd
Normal file
|
@ -0,0 +1,71 @@
|
|||
extends DeckNode
|
||||
|
||||
var output_count: int:
|
||||
get:
|
||||
return get_all_ports().size() - 1
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
name = "Group input"
|
||||
node_type = "group_input"
|
||||
props_to_serialize = [&"output_count"]
|
||||
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Input 0"
|
||||
)
|
||||
outgoing_connection_added.connect(_on_outgoing_connection_added)
|
||||
outgoing_connection_removed.connect(_on_outgoing_connection_removed)
|
||||
|
||||
|
||||
func _on_outgoing_connection_added(port_idx: int) -> void:
|
||||
if port_idx + 1 < get_all_ports().size():
|
||||
return
|
||||
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Input %s" % (get_all_ports().size())
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
|
||||
prints("l:", last_connected_port, "p:", port_idx)
|
||||
|
||||
if port_idx < last_connected_port:
|
||||
return
|
||||
|
||||
var s := get_all_ports().slice(0, last_connected_port + 2)
|
||||
ports.assign(s)
|
||||
ports_updated.emit()
|
||||
|
||||
|
||||
func _pre_connection() -> void:
|
||||
for i in output_count + 1:
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Input %s" % (i + 1)
|
||||
)
|
||||
|
||||
|
||||
func _post_load() -> void:
|
||||
# ensure we have enough ports after connections
|
||||
var last_connected_port := 0
|
||||
for port: int in outgoing_connections:
|
||||
last_connected_port = port if outgoing_connections.has(port) else last_connected_port
|
||||
|
||||
if ports.size() <= last_connected_port:
|
||||
for i in last_connected_port:
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Input %s" % get_output_ports().size()
|
||||
)
|
||||
|
||||
|
||||
func _value_request(from_port: int) -> Variant:
|
||||
var group_node := _belonging_to._belonging_to.get_node(_belonging_to.group_node)
|
||||
return group_node.request_value(group_node.get_input_ports()[from_port].index_of_type)
|
68
classes/deck/nodes/group_node.gd
Normal file
68
classes/deck/nodes/group_node.gd
Normal file
|
@ -0,0 +1,68 @@
|
|||
extends DeckNode
|
||||
|
||||
var group_id: String
|
||||
var input_node: DeckNode
|
||||
var output_node: DeckNode
|
||||
|
||||
var extra_ports: Array
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
name = "Group"
|
||||
node_type = "group_node"
|
||||
props_to_serialize = [&"group_id", &"extra_ports"]
|
||||
|
||||
|
||||
func _pre_connection() -> void:
|
||||
for port_type: PortType in extra_ports:
|
||||
var index_of_type: int
|
||||
match port_type:
|
||||
PortType.OUTPUT:
|
||||
add_output_port(Deck.Types.STRING, "Output %s" % get_output_ports().size())
|
||||
PortType.INPUT:
|
||||
add_input_port(Deck.Types.STRING, "Input %s" % get_input_ports().size())
|
||||
|
||||
|
||||
func init_io() -> void:
|
||||
var group: Deck = _belonging_to.groups.get(group_id) as Deck
|
||||
if !group:
|
||||
return
|
||||
|
||||
input_node = group.get_node(group.group_input_node)
|
||||
output_node = group.get_node(group.group_output_node)
|
||||
|
||||
recalculate_ports()
|
||||
setup_connections()
|
||||
|
||||
|
||||
func setup_connections() -> void:
|
||||
input_node.ports_updated.connect(recalculate_ports)
|
||||
output_node.ports_updated.connect(recalculate_ports)
|
||||
|
||||
|
||||
func recalculate_ports() -> void:
|
||||
ports.clear()
|
||||
|
||||
for output_port: Port in output_node.get_input_ports():
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Output %s" % output_port.index
|
||||
)
|
||||
|
||||
for input_port: Port in input_node.get_output_ports():
|
||||
add_input_port(
|
||||
Deck.Types.STRING,
|
||||
"Input %s" % input_port.index
|
||||
)
|
||||
|
||||
extra_ports.clear()
|
||||
for port in ports:
|
||||
extra_ports.append(port.port_type)
|
||||
|
||||
|
||||
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []):
|
||||
input_node.send(get_input_ports()[to_input_port].index_of_type, data, extra_data)
|
||||
|
||||
|
||||
func _value_request(from_port: int) -> Variant:
|
||||
return output_node.request_value(from_port)
|
72
classes/deck/nodes/group_output_node.gd
Normal file
72
classes/deck/nodes/group_output_node.gd
Normal file
|
@ -0,0 +1,72 @@
|
|||
extends DeckNode
|
||||
|
||||
var input_count: int:
|
||||
get:
|
||||
return get_all_ports().size() - 1
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
name = "Group output"
|
||||
node_type = "group_output"
|
||||
props_to_serialize = [&"input_count"]
|
||||
|
||||
add_input_port(
|
||||
Deck.Types.STRING,
|
||||
"Output 0"
|
||||
)
|
||||
|
||||
incoming_connection_added.connect(_on_incoming_connection_added)
|
||||
incoming_connection_removed.connect(_on_incoming_connection_removed)
|
||||
|
||||
|
||||
func _on_incoming_connection_added(port_idx: int) -> void:
|
||||
if port_idx + 1 < get_all_ports().size():
|
||||
return
|
||||
|
||||
add_input_port(
|
||||
Deck.Types.STRING,
|
||||
"Output %s" % (get_all_ports().size())
|
||||
)
|
||||
|
||||
|
||||
func _on_incoming_connection_removed(port_idx: int) -> void:
|
||||
var last_connected_port := 0
|
||||
for port: int in incoming_connections.keys().slice(1):
|
||||
if !(incoming_connections[port] as Dictionary).is_empty():
|
||||
last_connected_port = port
|
||||
|
||||
prints("l:", last_connected_port, "p:", port_idx)
|
||||
|
||||
if port_idx < last_connected_port:
|
||||
return
|
||||
|
||||
var s := get_all_ports().slice(0, last_connected_port + 2)
|
||||
ports.assign(s)
|
||||
ports_updated.emit()
|
||||
|
||||
|
||||
func _pre_connection() -> void:
|
||||
for i in input_count + 1:
|
||||
add_input_port(
|
||||
Deck.Types.STRING,
|
||||
"Output %s" % (i + 1)
|
||||
)
|
||||
|
||||
|
||||
func _post_load() -> void:
|
||||
# ensure we have enough ports after connections
|
||||
var last_connected_port := 0
|
||||
for port: int in incoming_connections:
|
||||
last_connected_port = port if incoming_connections.has(port) else last_connected_port
|
||||
|
||||
if ports.size() <= last_connected_port:
|
||||
for i in last_connected_port:
|
||||
add_input_port(
|
||||
Deck.Types.STRING,
|
||||
"Output %s" % get_input_ports().size()
|
||||
)
|
||||
|
||||
|
||||
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
var group_node := _belonging_to._belonging_to.get_node(_belonging_to.group_node)
|
||||
group_node.send(group_node.get_output_ports()[to_input_port].index_of_type, data, extra_data)
|
|
@ -29,15 +29,15 @@ func _init() -> void:
|
|||
)
|
||||
|
||||
|
||||
func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if to_port != 1:
|
||||
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if to_input_port != 1:
|
||||
return
|
||||
|
||||
var data_to_print
|
||||
if request_value(0) != null:
|
||||
data_to_print = request_value(0)
|
||||
elif ports[0].value_callback.call() != "":
|
||||
data_to_print = ports[0].value_callback.call()
|
||||
elif get_input_ports()[0].value_callback.get_object() && get_input_ports()[0].value_callback.call() != "":
|
||||
data_to_print = get_input_ports()[0].value_callback.call()
|
||||
else:
|
||||
data_to_print = data.get_value()
|
||||
|
||||
|
@ -46,4 +46,4 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void:
|
|||
# var data_to_print = input_ports[0].value_callback.call()
|
||||
print(data_to_print)
|
||||
print("extra data: ", extra_data)
|
||||
send(2, DeckType.DeckTypeBool.new(true))
|
||||
send(0, DeckType.DeckTypeBool.new(true))
|
||||
|
|
|
@ -31,8 +31,8 @@ func _init() -> void:
|
|||
)
|
||||
|
||||
|
||||
func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if to_port != 2:
|
||||
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []) -> void:
|
||||
if to_input_port != 2:
|
||||
return
|
||||
|
||||
var var_name: String = get_value_for_port(0, data)
|
||||
|
@ -41,7 +41,7 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void:
|
|||
|
||||
_belonging_to.variable_stack[var_name] = var_value
|
||||
|
||||
send(3, DeckType.DeckTypeString.new(var_value))
|
||||
send(0, DeckType.DeckTypeString.new(var_value))
|
||||
|
||||
# this can probably go into DeckNode with a different name that makes it clear
|
||||
# that it prioritizes call-time resolution
|
||||
|
|
17
classes/deck/nodes/string_constant.gd
Normal file
17
classes/deck/nodes/string_constant.gd
Normal file
|
@ -0,0 +1,17 @@
|
|||
extends DeckNode
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "string_constant"
|
||||
name = "String Constant"
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Text",
|
||||
"field"
|
||||
)
|
||||
|
||||
func _value_request(from_port: int) -> Variant:
|
||||
if ports[0].value_callback.get_object():
|
||||
return ports[0].value_callback.call()
|
||||
else:
|
||||
return ports[0].value
|
16
classes/deck/nodes/test_interleaved_node.gd
Normal file
16
classes/deck/nodes/test_interleaved_node.gd
Normal file
|
@ -0,0 +1,16 @@
|
|||
extends DeckNode
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
node_type = "test_interleaved"
|
||||
name = "Test Interleaved"
|
||||
|
||||
for i in 4:
|
||||
add_output_port(
|
||||
Deck.Types.STRING,
|
||||
"Test"
|
||||
)
|
||||
add_input_port(
|
||||
Deck.Types.STRING,
|
||||
"Test"
|
||||
)
|
127
graph_node_renderer/deck_holder_renderer.gd
Normal file
127
graph_node_renderer/deck_holder_renderer.gd
Normal file
|
@ -0,0 +1,127 @@
|
|||
extends Control
|
||||
|
||||
const DECK_SCENE := preload("res://graph_node_renderer/deck_renderer_graph_edit.tscn")
|
||||
|
||||
@onready var tab_container: TabContainerCustom = %TabContainerCustom as TabContainerCustom
|
||||
@onready var file_dialog: FileDialog = $FileDialog
|
||||
|
||||
enum FileMenuId {
|
||||
NEW,
|
||||
OPEN,
|
||||
SAVE = 3,
|
||||
SAVE_AS,
|
||||
CLOSE = 6,
|
||||
}
|
||||
|
||||
var _deck_to_save: WeakRef
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
tab_container.add_button_pressed.connect(add_empty_deck)
|
||||
|
||||
tab_container.tab_close_requested.connect(
|
||||
func(tab: int):
|
||||
DeckHolder.close_deck(tab_container.get_tab_metadata(tab))
|
||||
tab_container.close_tab(tab)
|
||||
)
|
||||
|
||||
file_dialog.canceled.connect(disconnect_file_dialog_signals)
|
||||
|
||||
|
||||
func _on_file_id_pressed(id: int) -> void:
|
||||
match id:
|
||||
FileMenuId.NEW:
|
||||
add_empty_deck()
|
||||
FileMenuId.OPEN:
|
||||
open_open_dialog("res://")
|
||||
FileMenuId.SAVE:
|
||||
save_active_deck()
|
||||
FileMenuId.SAVE_AS:
|
||||
open_save_dialog("res://")
|
||||
FileMenuId.CLOSE:
|
||||
close_current_tab()
|
||||
|
||||
|
||||
func add_empty_deck() -> void:
|
||||
var deck := DeckHolder.add_empty_deck()
|
||||
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
||||
inst.deck = deck
|
||||
tab_container.add_content(inst, "Deck %s" % (tab_container.get_tab_count() + 1))
|
||||
tab_container.set_tab_metadata(tab_container.get_current_tab(), deck)
|
||||
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested.bind(deck))
|
||||
|
||||
|
||||
func close_current_tab() -> void:
|
||||
tab_container.close_tab(tab_container.get_current_tab())
|
||||
|
||||
|
||||
func open_save_dialog(path: String) -> void:
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
||||
file_dialog.title = "Save a Deck"
|
||||
file_dialog.current_path = path
|
||||
_deck_to_save = weakref(get_active_deck())
|
||||
file_dialog.popup_centered()
|
||||
file_dialog.file_selected.connect(_on_file_dialog_save_file, CONNECT_ONE_SHOT)
|
||||
|
||||
|
||||
func open_open_dialog(path: String) -> void:
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES
|
||||
file_dialog.title = "Open Deck(s)"
|
||||
file_dialog.current_path = path
|
||||
file_dialog.popup_centered()
|
||||
file_dialog.files_selected.connect(_on_file_dialog_open_files, CONNECT_ONE_SHOT)
|
||||
|
||||
|
||||
func _on_file_dialog_save_file(path: String) -> void:
|
||||
var deck: Deck = _deck_to_save.get_ref() as Deck
|
||||
if !deck:
|
||||
return
|
||||
|
||||
deck.save_path = path
|
||||
var json := JSON.stringify(deck.to_dict(), "\t")
|
||||
var f := FileAccess.open(path, FileAccess.WRITE)
|
||||
f.store_string(json)
|
||||
|
||||
|
||||
func _on_file_dialog_open_files(paths: PackedStringArray) -> void:
|
||||
for path in paths:
|
||||
var deck := DeckHolder.open_deck_from_file(path)
|
||||
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
||||
inst.deck = deck
|
||||
tab_container.add_content(inst, "Deck %s" % (tab_container.get_tab_count() + 1))
|
||||
inst.initialize_from_deck()
|
||||
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested.bind(deck))
|
||||
|
||||
|
||||
func get_active_deck() -> Deck:
|
||||
if tab_container.is_empty():
|
||||
return null
|
||||
|
||||
return (tab_container.get_content(tab_container.get_current_tab()) as DeckRendererGraphEdit).deck
|
||||
|
||||
|
||||
func save_active_deck() -> void:
|
||||
if get_active_deck().save_path.is_empty():
|
||||
open_save_dialog("res://")
|
||||
else:
|
||||
var json := JSON.stringify(get_active_deck().to_dict(), "\t")
|
||||
var f := FileAccess.open(get_active_deck().save_path, FileAccess.WRITE)
|
||||
f.store_string(json)
|
||||
|
||||
|
||||
func disconnect_file_dialog_signals() -> void:
|
||||
if file_dialog.file_selected.is_connected(_on_file_dialog_save_file):
|
||||
file_dialog.file_selected.disconnect(_on_file_dialog_save_file)
|
||||
|
||||
if file_dialog.files_selected.is_connected(_on_file_dialog_open_files):
|
||||
file_dialog.files_selected.disconnect(_on_file_dialog_open_files)
|
||||
|
||||
|
||||
func _on_deck_renderer_group_enter_requested(group_id: String, deck: Deck) -> void:
|
||||
var group_deck := deck.get_group(group_id)
|
||||
var deck_renderer: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
||||
deck_renderer.deck = group_deck
|
||||
deck_renderer.initialize_from_deck()
|
||||
tab_container.add_content(deck_renderer, "Group %s" % (tab_container.get_tab_count() + 1))
|
||||
tab_container.set_tab_metadata(tab_container.get_current_tab(), group_deck)
|
||||
deck_renderer.group_enter_requested.connect(_on_deck_renderer_group_enter_requested.bind(deck_renderer.deck))
|
73
graph_node_renderer/deck_holder_renderer.tscn
Normal file
73
graph_node_renderer/deck_holder_renderer.tscn
Normal file
|
@ -0,0 +1,73 @@
|
|||
[gd_scene load_steps=4 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"]
|
||||
[ext_resource type="Theme" uid="uid://dqqdqscid2iem" path="res://graph_node_renderer/default_theme.tres" id="1_tgul2"]
|
||||
|
||||
[node name="DeckHolderRenderer" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_tgul2")
|
||||
script = ExtResource("1_67g2g")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/margin_left = 2
|
||||
theme_override_constants/margin_top = 2
|
||||
theme_override_constants/margin_right = 2
|
||||
theme_override_constants/margin_bottom = 2
|
||||
|
||||
[node name="VSplitContainer" type="VSplitContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
split_offset = 677
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VSplitContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MenuBar" type="MenuBar" parent="MarginContainer/VSplitContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="File" type="PopupMenu" parent="MarginContainer/VSplitContainer/VBoxContainer/MenuBar"]
|
||||
item_count = 7
|
||||
item_0/text = "New Deck"
|
||||
item_0/id = 0
|
||||
item_1/text = "Open Deck"
|
||||
item_1/id = 1
|
||||
item_2/text = ""
|
||||
item_2/id = 2
|
||||
item_2/separator = true
|
||||
item_3/text = "Save Deck"
|
||||
item_3/id = 3
|
||||
item_4/text = "Save Deck As"
|
||||
item_4/id = 4
|
||||
item_5/text = ""
|
||||
item_5/id = 5
|
||||
item_5/separator = true
|
||||
item_6/text = "Close Deck"
|
||||
item_6/id = 6
|
||||
|
||||
[node name="Edit" type="PopupMenu" parent="MarginContainer/VSplitContainer/VBoxContainer/MenuBar"]
|
||||
|
||||
[node name="TabContainerCustom" parent="MarginContainer/VSplitContainer/VBoxContainer" instance=ExtResource("1_s3ug2")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ConsoleContainer" type="PanelContainer" parent="MarginContainer/VSplitContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="FileDialog" type="FileDialog" parent="."]
|
||||
size = Vector2i(776, 447)
|
||||
mode_overrides_title = false
|
||||
access = 2
|
||||
use_native_dialog = true
|
||||
|
||||
[connection signal="id_pressed" from="MarginContainer/VSplitContainer/VBoxContainer/MenuBar/File" to="." method="_on_file_id_pressed"]
|
|
@ -6,7 +6,10 @@ var node: DeckNode
|
|||
|
||||
func _ready() -> void:
|
||||
title = node.name
|
||||
|
||||
node.position_updated.connect(_on_node_position_updated)
|
||||
#node.port_added.connect(_on_node_port_added)
|
||||
#node.port_removed.connect(_on_node_port_removed)
|
||||
node.ports_updated.connect(_on_node_ports_updated)
|
||||
for port in node.get_all_ports():
|
||||
var descriptor_split := port.descriptor.split(":")
|
||||
match descriptor_split[0]:
|
||||
|
@ -17,12 +20,12 @@ func _ready() -> void:
|
|||
if port.port_type == DeckNode.PortType.OUTPUT:
|
||||
button.pressed.connect(
|
||||
func():
|
||||
node.send(port.index, DeckType.DeckTypeBool.new(true))
|
||||
node.send(port.index_of_type, DeckType.DeckTypeBool.new(true))
|
||||
)
|
||||
elif port.port_type == DeckNode.PortType.INPUT:
|
||||
button.pressed.connect(
|
||||
func():
|
||||
node._receive(port.index, DeckType.DeckTypeBool.new(true))
|
||||
node._receive(port.index_of_type, DeckType.DeckTypeBool.new(true))
|
||||
)
|
||||
"field":
|
||||
var line_edit := LineEdit.new()
|
||||
|
@ -49,4 +52,113 @@ func _ready() -> void:
|
|||
|
||||
|
||||
func _on_position_offset_changed() -> void:
|
||||
node.set_meta("position_offset", position_offset)
|
||||
node.position.x = position_offset.x
|
||||
node.position.y = position_offset.y
|
||||
|
||||
|
||||
func _on_node_position_updated(new_position: Dictionary) -> void:
|
||||
position_offset.x = new_position.x
|
||||
position_offset.y = new_position.y
|
||||
|
||||
|
||||
func _on_node_port_added(port_idx: int) -> void:
|
||||
var port := node.get_all_ports()[port_idx]
|
||||
|
||||
var descriptor_split := port.descriptor.split(":")
|
||||
match descriptor_split[0]:
|
||||
"button":
|
||||
var button := Button.new()
|
||||
add_child(button)
|
||||
button.text = port.label
|
||||
if port.port_type == DeckNode.PortType.OUTPUT:
|
||||
button.pressed.connect(
|
||||
func():
|
||||
node.send(port.index_of_type, DeckType.DeckTypeBool.new(true))
|
||||
)
|
||||
elif port.port_type == DeckNode.PortType.INPUT:
|
||||
button.pressed.connect(
|
||||
func():
|
||||
node._receive(port.index_of_type, DeckType.DeckTypeBool.new(true))
|
||||
)
|
||||
"field":
|
||||
var line_edit := LineEdit.new()
|
||||
add_child(line_edit)
|
||||
if port.value:
|
||||
line_edit.text = str(port.value)
|
||||
line_edit.placeholder_text = port.label
|
||||
port.value_callback = line_edit.get_text
|
||||
line_edit.text_changed.connect(port.set_value)
|
||||
_:
|
||||
var label := Label.new()
|
||||
add_child(label)
|
||||
label.text = port.label
|
||||
|
||||
set_slot(
|
||||
port.index,
|
||||
port.port_type == DeckNode.PortType.INPUT,
|
||||
0,
|
||||
Color.WHITE,
|
||||
port.port_type == DeckNode.PortType.OUTPUT,
|
||||
0,
|
||||
Color.WHITE,
|
||||
)
|
||||
|
||||
|
||||
func _on_node_port_removed(port_idx: int) -> void:
|
||||
set_slot(
|
||||
port_idx,
|
||||
false,
|
||||
0,
|
||||
Color.WHITE,
|
||||
false,
|
||||
0,
|
||||
Color.WHITE,
|
||||
)
|
||||
|
||||
get_child(port_idx).queue_free()
|
||||
|
||||
|
||||
func _on_node_ports_updated() -> void:
|
||||
clear_all_slots()
|
||||
for c in get_children():
|
||||
c.queue_free()
|
||||
|
||||
for port in node.get_all_ports():
|
||||
var descriptor_split := port.descriptor.split(":")
|
||||
match descriptor_split[0]:
|
||||
"button":
|
||||
var button := Button.new()
|
||||
add_child(button)
|
||||
button.text = port.label
|
||||
if port.port_type == DeckNode.PortType.OUTPUT:
|
||||
button.pressed.connect(
|
||||
func():
|
||||
node.send(port.index_of_type, DeckType.DeckTypeBool.new(true))
|
||||
)
|
||||
elif port.port_type == DeckNode.PortType.INPUT:
|
||||
button.pressed.connect(
|
||||
func():
|
||||
node._receive(port.index_of_type, DeckType.DeckTypeBool.new(true))
|
||||
)
|
||||
"field":
|
||||
var line_edit := LineEdit.new()
|
||||
add_child(line_edit)
|
||||
if port.value:
|
||||
line_edit.text = str(port.value)
|
||||
line_edit.placeholder_text = port.label
|
||||
port.value_callback = line_edit.get_text
|
||||
line_edit.text_changed.connect(port.set_value)
|
||||
_:
|
||||
var label := Label.new()
|
||||
add_child(label)
|
||||
label.text = port.label
|
||||
|
||||
set_slot(
|
||||
port.index,
|
||||
port.port_type == DeckNode.PortType.INPUT,
|
||||
0,
|
||||
Color.WHITE,
|
||||
port.port_type == DeckNode.PortType.OUTPUT,
|
||||
0,
|
||||
Color.WHITE,
|
||||
)
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
extends GraphEdit
|
||||
class_name DeckRendererGraphEdit
|
||||
|
||||
const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_node.tscn")
|
||||
|
||||
var deck: Deck = Deck.new()
|
||||
#var button_node = preload("res://classes/deck/nodes/button.gd")
|
||||
#var print_node = preload("res://classes/deck/nodes/print.gd")
|
||||
#var get_var_node = preload("res://classes/deck/nodes/get_deck_var.gd")
|
||||
#var set_var_node = preload("res://classes/deck/nodes/set_deck_var.gd")
|
||||
var deck: Deck:
|
||||
set(v):
|
||||
deck = v
|
||||
deck.node_added.connect(_on_deck_node_added)
|
||||
deck.node_removed.connect(_on_deck_node_removed)
|
||||
|
||||
signal group_enter_requested(group_id: String)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var add_button := Button.new()
|
||||
|
@ -17,100 +21,51 @@ func _ready() -> void:
|
|||
get_var.text = "Get Var"
|
||||
var set_var := Button.new()
|
||||
set_var.text = "Set Var"
|
||||
get_zoom_hbox().add_child(add_button)
|
||||
get_zoom_hbox().add_child(add_print)
|
||||
get_zoom_hbox().add_child(get_var)
|
||||
get_zoom_hbox().add_child(set_var)
|
||||
|
||||
var save_btn := Button.new()
|
||||
save_btn.text = "Save"
|
||||
get_zoom_hbox().add_child(save_btn)
|
||||
var load_btn := Button.new()
|
||||
load_btn.text = "Load"
|
||||
get_zoom_hbox().add_child(load_btn)
|
||||
|
||||
save_btn.pressed.connect(
|
||||
func():
|
||||
var t = deck.to_json()
|
||||
var f := FileAccess.open("user://save_test.json", FileAccess.WRITE)
|
||||
f.store_string(t)
|
||||
)
|
||||
|
||||
load_btn.pressed.connect(
|
||||
func():
|
||||
var f := FileAccess.open("user://save_test.json", FileAccess.READ)
|
||||
for i in get_children():
|
||||
i.queue_free()
|
||||
|
||||
deck = Deck.from_json(f.get_as_text())
|
||||
scroll_offset = str_to_vector2(deck.get_meta("offset", ""))
|
||||
|
||||
for node_id in deck.nodes:
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = deck.nodes[node_id]
|
||||
add_child(node_renderer)
|
||||
node_renderer.position_offset = str_to_vector2(deck.nodes[node_id].get_meta("position_offset", ""))
|
||||
|
||||
for node_id in deck.nodes:
|
||||
var node: DeckNode = deck.nodes[node_id]
|
||||
var from_node_name = get_children().filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == node_id
|
||||
)[0].name
|
||||
# "outgoing_connections": {
|
||||
# "0": [
|
||||
# {
|
||||
# "c8cc7dce-2a86-461c-a24f-0a4dbd06f379": 1
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
for from_port in node.outgoing_connections:
|
||||
for connection in node.outgoing_connections[from_port]:
|
||||
var to_node_id = connection.keys()[0]
|
||||
var to_node_port = connection.values()[0]
|
||||
var to_node_name = get_children().filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == to_node_id
|
||||
)[0].name
|
||||
prints(from_node_name, to_node_name)
|
||||
connect_node(from_node_name, from_port, to_node_name, to_node_port)
|
||||
)
|
||||
|
||||
var test := Button.new()
|
||||
test.text = "Interleaved"
|
||||
var str_const := Button.new()
|
||||
str_const.text = "String"
|
||||
get_menu_hbox().add_child(add_button)
|
||||
get_menu_hbox().add_child(add_print)
|
||||
get_menu_hbox().add_child(get_var)
|
||||
get_menu_hbox().add_child(set_var)
|
||||
get_menu_hbox().add_child(test)
|
||||
get_menu_hbox().add_child(str_const)
|
||||
|
||||
add_button.pressed.connect(
|
||||
func():
|
||||
var node := NodeDB.instance_node("button")
|
||||
deck.add_node_inst(node)
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = node
|
||||
add_child(node_renderer)
|
||||
)
|
||||
|
||||
add_print.pressed.connect(
|
||||
func():
|
||||
var node := NodeDB.instance_node("print")
|
||||
deck.add_node_inst(node)
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = node
|
||||
add_child(node_renderer)
|
||||
)
|
||||
|
||||
get_var.pressed.connect(
|
||||
func():
|
||||
var node := NodeDB.instance_node("get_deck_var")
|
||||
deck.add_node_inst(node)
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = node
|
||||
add_child(node_renderer)
|
||||
)
|
||||
|
||||
set_var.pressed.connect(
|
||||
func():
|
||||
var node := NodeDB.instance_node("set_deck_var")
|
||||
deck.add_node_inst(node)
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = node
|
||||
add_child(node_renderer)
|
||||
)
|
||||
|
||||
test.pressed.connect(
|
||||
func():
|
||||
var node := NodeDB.instance_node("test_interleaved")
|
||||
deck.add_node_inst(node)
|
||||
)
|
||||
|
||||
str_const.pressed.connect(
|
||||
func():
|
||||
var node := NodeDB.instance_node("string_constant")
|
||||
deck.add_node_inst(node)
|
||||
)
|
||||
|
||||
connection_request.connect(attempt_connection)
|
||||
|
@ -118,37 +73,140 @@ func _ready() -> void:
|
|||
|
||||
|
||||
func attempt_connection(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void:
|
||||
var from_node: DeckNode = get_node(NodePath(from_node_name)).node
|
||||
var to_node: DeckNode = get_node(NodePath(to_node_name)).node
|
||||
var from_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(from_node_name))
|
||||
var to_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(to_node_name))
|
||||
|
||||
var from_output := from_node.get_global_port_idx_from_output(from_port)
|
||||
var to_input := to_node.get_global_port_idx_from_input(to_port)
|
||||
#var from_output := from_node_renderer.node.get_global_port_idx_from_output(from_port)
|
||||
#var to_input := to_node_renderer.node.get_global_port_idx_from_input(to_port)
|
||||
|
||||
if deck.connect_nodes(from_node, to_node, from_output, to_input):
|
||||
connect_node(from_node_name, from_port, to_node_name, to_port)
|
||||
if deck.connect_nodes(from_node_renderer.node, to_node_renderer.node, from_port, to_port):
|
||||
connect_node(
|
||||
from_node_renderer.name,
|
||||
from_port,
|
||||
to_node_renderer.name,
|
||||
to_port
|
||||
)
|
||||
|
||||
|
||||
func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void:
|
||||
var from_node: DeckNode = get_node(NodePath(from_node_name)).node
|
||||
var to_node: DeckNode = get_node(NodePath(to_node_name)).node
|
||||
var from_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(from_node_name))
|
||||
var to_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(to_node_name))
|
||||
|
||||
var from_output := from_node.get_global_port_idx_from_output(from_port)
|
||||
var to_input := to_node.get_global_port_idx_from_input(to_port)
|
||||
#var from_output := from_node_renderer.node.get_global_port_idx_from_output(from_port)
|
||||
#var to_input := to_node_renderer.node.get_global_port_idx_from_input(to_port)
|
||||
|
||||
deck.disconnect_nodes(from_node, to_node, from_output, to_input)
|
||||
deck.disconnect_nodes(from_node_renderer.node, to_node_renderer.node, from_port, to_port)
|
||||
|
||||
disconnect_node(from_node_name, from_port, to_node_name, to_port)
|
||||
disconnect_node(
|
||||
from_node_renderer.name,
|
||||
from_port,
|
||||
to_node_renderer.name,
|
||||
to_port
|
||||
)
|
||||
|
||||
|
||||
func _on_scroll_offset_changed(offset: Vector2) -> void:
|
||||
deck.set_meta("offset", offset)
|
||||
|
||||
|
||||
func str_to_vector2(s: String) -> Vector2:
|
||||
if s.is_empty():
|
||||
return Vector2()
|
||||
func initialize_from_deck() -> void:
|
||||
# TODO: wait for https://github.com/godotengine/godot/issues/85005 to get merged
|
||||
# until it is, all calls to GraphEdit#get_children will need to slice off the first element
|
||||
for i in get_children().slice(1):
|
||||
i.queue_free()
|
||||
|
||||
var san := s.trim_prefix("(").trim_suffix(")").split(",")
|
||||
var x := float(san[0])
|
||||
var y := float(san[1])
|
||||
return Vector2(x, y)
|
||||
scroll_offset = deck.get_meta("offset", Vector2())
|
||||
|
||||
for node_id in deck.nodes:
|
||||
var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
node_renderer.node = deck.nodes[node_id]
|
||||
add_child(node_renderer)
|
||||
node_renderer.position_offset = node_renderer.node.position_as_vector2()
|
||||
|
||||
for node_id in deck.nodes:
|
||||
var node: DeckNode = deck.nodes[node_id]
|
||||
var from_node = get_children().slice(1).filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == node_id
|
||||
)[0]
|
||||
|
||||
refresh_connections()
|
||||
|
||||
|
||||
func refresh_connections() -> void:
|
||||
for node_id in deck.nodes:
|
||||
var node: DeckNode = deck.nodes[node_id]
|
||||
var from_node: DeckNodeRendererGraphNode = get_children().slice(1).filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == node_id
|
||||
)[0]
|
||||
|
||||
for from_port in node.outgoing_connections:
|
||||
for connection in node.outgoing_connections[from_port]:
|
||||
var to_node_id = connection.keys()[0]
|
||||
var to_node_port = connection.values()[0]
|
||||
var to_node: DeckNodeRendererGraphNode = get_children().slice(1).filter(
|
||||
func(c: DeckNodeRendererGraphNode):
|
||||
return c.node._id == to_node_id
|
||||
)[0]
|
||||
#print("***")
|
||||
#print("calling connect_node with:")
|
||||
#print(from_node.node.name)
|
||||
#print(from_node.node.get_port_type_idx_from_global(from_port))
|
||||
#print(to_node.node.name)
|
||||
#print(to_node.node.get_port_type_idx_from_global(to_node_port))
|
||||
#print("***")
|
||||
connect_node(
|
||||
from_node.name,
|
||||
from_port,
|
||||
to_node.name,
|
||||
to_node_port
|
||||
)
|
||||
|
||||
|
||||
func _on_deck_node_added(node: DeckNode) -> void:
|
||||
var inst: DeckNodeRendererGraphNode = NODE_SCENE.instantiate()
|
||||
inst.node = node
|
||||
add_child(inst)
|
||||
inst.position_offset = inst.node.position_as_vector2()
|
||||
|
||||
|
||||
func _on_deck_node_removed(node: DeckNode) -> void:
|
||||
for renderer: DeckNodeRendererGraphNode in get_children().slice(1):
|
||||
if renderer.node != node:
|
||||
continue
|
||||
|
||||
renderer.queue_free()
|
||||
break
|
||||
|
||||
|
||||
func get_selected_nodes() -> Array:
|
||||
return get_children().slice(1).filter(
|
||||
func(x: DeckNodeRendererGraphNode):
|
||||
return x.selected
|
||||
)
|
||||
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("group_nodes") && get_selected_nodes().size() > 0:
|
||||
print("?")
|
||||
clear_connections()
|
||||
var nodes = get_selected_nodes().map(
|
||||
func(x: DeckNodeRendererGraphNode):
|
||||
return x.node
|
||||
)
|
||||
deck.group_nodes(nodes)
|
||||
refresh_connections()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if !has_focus():
|
||||
return
|
||||
|
||||
if event.is_action_pressed("enter_group") && get_selected_nodes().size() == 1:
|
||||
if !((get_selected_nodes()[0] as DeckNodeRendererGraphNode).node.node_type == "group_node"):
|
||||
return
|
||||
print("tried to enter group")
|
||||
group_enter_requested.emit((get_selected_nodes()[0] as DeckNodeRendererGraphNode).node.group_id)
|
||||
get_viewport().set_input_as_handled()
|
||||
|
|
4
graph_node_renderer/default_theme.tres
Normal file
4
graph_node_renderer/default_theme.tres
Normal file
|
@ -0,0 +1,4 @@
|
|||
[gd_resource type="Theme" format=3 uid="uid://dqqdqscid2iem"]
|
||||
|
||||
[resource]
|
||||
default_font_size = 14
|
84
graph_node_renderer/tab_container_custom.gd
Normal file
84
graph_node_renderer/tab_container_custom.gd
Normal file
|
@ -0,0 +1,84 @@
|
|||
extends VBoxContainer
|
||||
class_name TabContainerCustom
|
||||
|
||||
@onready var tab_bar: TabBar = %TabBar
|
||||
@onready var add_tab_button: Button = %Button
|
||||
@onready var content_container: MarginContainer = %ContentContainer
|
||||
|
||||
|
||||
signal add_button_pressed
|
||||
signal tab_changed(tab: int)
|
||||
signal tab_closed(tab: int)
|
||||
signal tab_close_requested(tab: int)
|
||||
signal tab_rearranged(old: int, new: int)
|
||||
|
||||
var _previous_active_tab: int = -1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
tab_bar.tab_selected.connect(
|
||||
func(tab: int):
|
||||
if _previous_active_tab == tab:
|
||||
return
|
||||
|
||||
if _previous_active_tab > -1:
|
||||
content_container.get_child(_previous_active_tab).visible = false
|
||||
content_container.get_child(tab).visible = true
|
||||
|
||||
tab_changed.emit(tab)
|
||||
_previous_active_tab = tab
|
||||
)
|
||||
|
||||
tab_bar.tab_close_pressed.connect(func(tab: int): tab_close_requested.emit(tab))
|
||||
|
||||
add_tab_button.pressed.connect(
|
||||
func():
|
||||
add_button_pressed.emit()
|
||||
)
|
||||
|
||||
tab_bar.active_tab_rearranged.connect(
|
||||
func(idx_to: int):
|
||||
tab_rearranged.emit(_previous_active_tab, idx_to)
|
||||
content_container.move_child(content_container.get_child(_previous_active_tab), idx_to)
|
||||
_previous_active_tab = idx_to
|
||||
)
|
||||
|
||||
|
||||
func add_content(c: Node, tab_title: String) -> void:
|
||||
tab_bar.add_tab(tab_title)
|
||||
content_container.add_child(c)
|
||||
tab_bar.set_current_tab(tab_bar.tab_count - 1)
|
||||
|
||||
|
||||
func get_tab_count() -> int:
|
||||
return tab_bar.tab_count
|
||||
|
||||
|
||||
func is_empty() -> bool:
|
||||
return get_tab_count() == 0
|
||||
|
||||
|
||||
func close_tab(tab: int) -> void:
|
||||
content_container.get_child(tab).queue_free()
|
||||
if !tab_bar.select_previous_available():
|
||||
tab_bar.select_next_available()
|
||||
tab_bar.remove_tab(tab)
|
||||
tab_closed.emit(tab)
|
||||
if tab_bar.tab_count == 0:
|
||||
_previous_active_tab = -1
|
||||
|
||||
|
||||
func get_current_tab() -> int:
|
||||
return tab_bar.current_tab
|
||||
|
||||
|
||||
func get_content(idx: int) -> Control:
|
||||
return content_container.get_child(idx)
|
||||
|
||||
|
||||
func set_tab_metadata(tab: int, metadata: Variant) -> void:
|
||||
tab_bar.set_tab_metadata(tab, metadata)
|
||||
|
||||
|
||||
func get_tab_metadata(tab: int) -> Variant:
|
||||
return tab_bar.get_tab_metadata(tab)
|
34
graph_node_renderer/tab_container_custom.tscn
Normal file
34
graph_node_renderer/tab_container_custom.tscn
Normal file
|
@ -0,0 +1,34 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://b84f2ngtcm5b8"]
|
||||
|
||||
[ext_resource type="Script" path="res://graph_node_renderer/tab_container_custom.gd" id="1_63wbq"]
|
||||
|
||||
[node name="TabContainerCustom" type="VBoxContainer"]
|
||||
offset_right = 22.0
|
||||
offset_bottom = 35.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("1_63wbq")
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TabBar" type="TabBar" parent="HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
clip_tabs = false
|
||||
tab_close_display_policy = 1
|
||||
drag_to_rearrange_enabled = true
|
||||
|
||||
[node name="Button" type="Button" parent="HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
text = "+"
|
||||
|
||||
[node name="ContentContainer" type="MarginContainer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
|
@ -12,10 +12,10 @@ config_version=5
|
|||
|
||||
config/name="Re-DotDeck"
|
||||
config/tags=PackedStringArray("dot_deck")
|
||||
run/main_scene="res://graph_node_renderer/deck_renderer_graph_edit.tscn"
|
||||
run/main_scene="res://graph_node_renderer/deck_holder_renderer.tscn"
|
||||
config/use_custom_user_dir=true
|
||||
config/custom_user_dir_name="dotdeck"
|
||||
config/features=PackedStringArray("4.1", "Forward Plus")
|
||||
config/features=PackedStringArray("4.2", "Forward Plus")
|
||||
run/low_processor_mode=true
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
|
@ -23,6 +23,23 @@ config/icon="res://icon.svg"
|
|||
|
||||
NodeDB="*res://classes/deck/node_db.gd"
|
||||
|
||||
[display]
|
||||
|
||||
window/subwindows/embed_subwindows=false
|
||||
|
||||
[input]
|
||||
|
||||
group_nodes={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":71,"physical_keycode":0,"key_label":0,"unicode":103,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
enter_group={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
|
|
Loading…
Reference in a new issue