extends GraphEdit class_name DeckRendererGraphEdit const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_node.tscn") const ADD_NODE_MENU_SCENE := preload("res://graph_node_renderer/add_node_menu.tscn") var search_popup_panel: PopupPanel var add_node_menu: AddNodeMenu @export var add_node_popup_size: Vector2i = Vector2i(500, 300) var popup_position: Vector2 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: add_node_menu = ADD_NODE_MENU_SCENE.instantiate() search_popup_panel = PopupPanel.new() search_popup_panel.add_child(add_node_menu) search_popup_panel.size = add_node_popup_size add_child(search_popup_panel, false, Node.INTERNAL_MODE_BACK) add_node_menu.node_selected.connect(_on_add_node_menu_node_selected) connection_request.connect(attempt_connection) disconnection_request.connect(attempt_disconnect) func attempt_connection(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void: 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_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_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_renderer: DeckNodeRendererGraphNode = get_node(NodePath(from_node_name)) var to_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(to_node_name)) #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_renderer.node, to_node_renderer.node, from_port, to_port) disconnect_node( from_node_renderer.name, from_port, to_node_renderer.name, to_port ) func get_node_renderer(node: DeckNode) -> DeckNodeRendererGraphNode: for i: DeckNodeRendererGraphNode in get_children().slice(1): if i.node == node: return i return null func _on_scroll_offset_changed(offset: Vector2) -> void: deck.set_meta("offset", offset) 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() 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() func _on_popup_request(p_popup_position: Vector2) -> void: var p := get_viewport_rect().position + get_global_mouse_position() p += Vector2(10, 10) var r := Rect2i(p, search_popup_panel.size) search_popup_panel.popup_on_parent(r) add_node_menu.focus_search_bar() popup_position = p_popup_position func _on_add_node_menu_node_selected(type: String) -> void: var node := NodeDB.instance_node(type) as DeckNode deck.add_node_inst(node) var node_pos := ((scroll_offset + popup_position) / zoom) if snapping_enabled: node_pos = node_pos.snapped(Vector2(snapping_distance, snapping_distance)) get_node_renderer(node).position_offset = node_pos search_popup_panel.hide()