Godot Version
4.2.2
Question
I’m trying to add drag-n-drop to a pre-existing inventory. In theory it looks like the original approach is solid: all clicks get grabbed with gui_input of specific slots and then signalled up to a “handler” to figure out the rest. However when I started detecting “mouse release”, for some reason it always gets detected by the same slot where the mouse was originally pressed. The docs state that gui_input can’t get detected when the mouse is outside of the confines, so what’s the deal here?
Here’s the minimal reproduction project, with nothing but click/hold detection:
Node structure. Control has “mouse filter pass”, the rest is default except for positions
Code:
extends Control
var dragging_slot : Node
var dragging_event : InputEvent
@onready var slot1 = $Slot
@onready var slot2 = $Slot2
@onready var pickup_timer : Timer = $Timer
func _ready():
slot1.gui_input.connect(_on_slot_gui_input.bind(slot1))
slot2.gui_input.connect(_on_slot_gui_input.bind(slot2))
pickup_timer.one_shot = true
pickup_timer.timeout.connect(timer_timeout)
func _on_slot_gui_input(event : InputEvent, slot_obj):
if event is InputEventMouseButton:
if event.pressed:
print(event)
print("Tap or pressdown started, called by slot:")
print(slot_obj)
start_timer(event, slot_obj)
else: # !pressed = released
if not pickup_timer.is_stopped():
print(event)
print("tap ended, called by slot:")
print(slot_obj)
pickup_timer.stop()
slot_delayed_pointdown(event, slot_obj)
else:
print(event)
print("pressdown ended, called by slot:")
print(slot_obj)
slot_delayed_pointdown(event, slot_obj)
# Actual interaction cut from the slot gui input to allow for flexible input
func slot_delayed_pointdown(event : InputEvent, slot_obj):
print("Pretend emit interaction signal")
func start_timer(event, slot_obj):
pickup_timer.start(0.2)
dragging_slot = slot_obj
dragging_event = event
func timer_timeout():
print(dragging_event)
print("pressdown detected, called by a saved slot:")
print(dragging_slot)
slot_delayed_pointdown(dragging_event, dragging_slot)
Scene and output
In the example above, I’ve pressed down my mouse above the first slot, then pretended to drag it to the second slot and released there. As you can see from the log, all those events fired correctly, but the release event was grabbed by the first slot for some reason, despite happening over the second one. Is it just the same InputEvent object that gets passed around? If so, then how can I detect a new one without disrupting the structure too much (such as moving everything to _process or making the “draggable” object itself responsible for input)?
Thanks, and sorry if this is basic; I just want to rely on gui_input for better scalability so I want to understand the mechanics really well.