Graph Nodes Sticking

Godot Version

4.6 MONO

Question

I have a GraphEdit node and I have created some GraphNodes. When I click and drag them I have to click a second time for the mouse to release them. I have resize set to true on one of them but as soon as the mouse exits the body of the node it no longer resizes. As soon as the mouse enters the body of the node again it is still in resize mode and immediately shrinks to wherever the mouse position is. So I am never able to make them bigger only smaller. My graph nodes have _on_resize_request connected and set to change the size to the new size. I have tried setting the mouse settings to ignore for everything within my node that is not a button or text input and this made no difference. I can see the cursor change for a second back to the arrow when I release the mouse button before it changes back to the 4-way arrow. I am never seeing the _on_dragged signal come on either when I drag the node around. I have attached some code. I used the mouse up signal to deselect my node and that stopped it from sticking to the mouse but the mouse is still in a 4-way arrow mode until I click somewhere else again. Has anyone come across this?

If you share code, please wrap it inside three backticks or replace the code in the next block:

# GRAPHEDIT CODE
extends GraphEdit

var ConnectionsList : Array[Dictionary]
@export var StartNode : PackedScene
@export var AddStringNode : PackedScene
@export var StringNode : PackedScene
@export var AddNumberNode : PackedScene
@export var ScriptNode : PackedScene

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	pass

func _on_connection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void:
	connect_node(from_node, from_port, to_node, to_port)

func _on_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void:
	disconnect_node(from_node, from_port, to_node, to_port)

func node_connection_request(node : String) -> Array[Dictionary]:
	#print("Graph Edit Connection Request Called: ")
	#print(get_connection_list_from_node(node))
	return get_connection_list_from_node(node)

func port_connection_request(node, port) -> Array[Dictionary]:
	var conns = get_connection_list_from_node(node)
	var result : Array[Dictionary] = []
	for conn in conns:
		var dict = {}
		if conn["from_node"] == node and conn["from_port"] == port:
			dict["to_node"] = conn["to_node"]
			dict["to_port"] = conn["to_port"]
			dict["type"] = "left"
			result.push_back(dict)
		elif conn["to_node"] == node and conn["to_port"] == port:
			dict["from_node"] = conn["from_node"]
			dict["from_port"] = conn["from_port"]
			dict["type"] = "right"
			result.push_back(dict)
	return result

func from_port_connection_request(node : StringName, port : int) -> Array[Dictionary]:
	var conns = get_connection_list_from_node(node)
	var result : Array[Dictionary] = []
	for conn in conns:
		var dict : Dictionary = {}
		if conn["from_node"] == node and conn["from_port"] == port:
			print_debug("Match was Found in From Port Connection Request")
			dict["to_node"] = conn["to_node"]
			dict["to_port"] = conn["to_port"]
			dict["type"] = "left"
			result.push_back(dict)
	return result


func to_port_connection_request(node, port) -> Array[Dictionary]:
	var conns = get_connection_list_from_node(node)
	var result : Array[Dictionary] = []
	for conn in conns:
		var dict = {}
		if conn["to_node"] == node and conn["to_port"] == port:
			dict["from_node"] = conn["from_node"]
			dict["from_port"] = conn["from_port"]
			dict["type"] = "right"
			result.push_back(dict)
	return result

func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
	if data["Type"] != "":
		return true
	else:
		return false

func _drop_data(at_position: Vector2, data: Variant) -> void:
	match data["Type"]:
		"StartNode":
			var node = StartNode.instantiate()
			add_child(node)
			node.position_offset = at_position
		"AddStringNode":
			var node = AddStringNode.instantiate()
			add_child(node)
			node.position_offset = at_position
		"StringNode":
			var node = StringNode.instantiate()
			add_child(node)
			node.position_offset = at_position
		"AddNumberNode":
			var node = AddNumberNode.instantiate()
			add_child(node)
			node.position_offset = at_position
		"ScriptNode":
			var node = ScriptNode.instantiate()
			add_child(node)
			node.position_offset = at_position
		_:
			print("Unknown Node Dropped")

func get_node_from_path(path : String) -> Node:
	return get_node(path)



#GRAPHNODE
extends GraphNode

@export var Code : CodeEdit
@export var SizeButton : Button
var big : bool
const NormalSize : Vector2 = Vector2(450, 200)
var parent : GraphEdit
var node_data : Dictionary
var output_data : Dictionary

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	if get_parent().get_class() == "GraphEdit":
		parent = get_parent()
		node_data = {
			"Type" : null
		}
	else:
		node_data = {
			"Type" : "ScriptNode"
		}

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	pass
	
func _get_drag_data(_at_position: Vector2) -> Variant:
	return node_data

func _on_button_pressed() -> void:
	if !big:
		_on_resize_request((size * Vector2(4.0, 4.0)))
		SizeButton.text = "Restore"
		big = true
	else:
		Code.size = NormalSize
		SizeButton.text = "Maximize"
		big = true

func _on_resize_request(new_size: Vector2) -> void:
	size = new_size
	SizeButton.text = "Restore"
	big = true


func _on_dragged(_from: Vector2, _to: Vector2) -> void:
	print("Dragged was called")


func _input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_graph_delete"):
		if selected:
			queue_free()
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT && !event.pressed:
			selected = false
			DisplayServer.cursor_set_shape(DisplayServer.CURSOR_ARROW)

func _unhandled_input(event: InputEvent) -> void:
	print(event)

I inspected the scene, and found a bug, here it is:

func _get_drag_data(_at_position: Vector2) → Variant:
    return node_data

This worked for me:

func _get_drag_data(_at_position: Vector2) → Variant:
    if big:
        return null
    else:
        return node_data

Also another bug, when i try to resize the GraphNode by clicking a button, there is no actual resize logic, my advice is to store the previous size of the GraphNode or just use const

func _on_button_pressed() -> void:
	if !big:
		_on_resize_request((size * Vector2(4.0, 4.0)))
		SizeButton.text = "Restore"
		big = true
	else:
		_on_resize_request(default_size) #"Vector2(200, 150)
		Code.size = NormalSize
		SizeButton.text = "Maximize"
		big = true

Thank you. I was experimenting with the same thing and found it also. The graph nodes do not like the _get_drag_data function. I had it like that temporarily while I am developing so I can drag nodes into the graphedit from the sidebar. I am going to create textures for my nodes and remove the _get_drag_data function all together. Great catch though!

1 Like

What are you working btw? Just curious, maybe i can help with something since i’ve worked a bit with GraphNodes