Is there a global way to get the Control node I'm clicking?
- Best Answerset by popcar2
popcar2 If controls don't run any code, make a script class that inherits Control. In this class declare an enhanced input event signal that forwards regular input event with added control identifier argument. On startup recursively set this script class as a script for every control of interest and connect each control's signal to a central handler.
- Edited
popcar2 Here's an example:
magic_control_script.gd
extends Control
signal my_event(who, what)
func _gui_input(event):
my_event.emit(self, event)
Then in main script:
func _ready():
for c in get_tree().get_nodes_in_group("my_controls"):
c.set_script(preload("res://magic_control_script.gd"))
c.connect("my_event", handler)
func handler(who, what):
print(who,", ", what)
The Godot editor knows which control was last clicked:
Debugger / Misc / Clicked Control
It might be worthwhile to dig into the source code and see if that's something that could be done in your project.
- Edited
xyz This is clever! And I've finally figured it out: Adding a component to each right clickable node. It's a bit roundabout but it works. Thanks everyone for all the ideas.
context_menu_manager.gd (Autoload)
var right_click_handler: PackedScene = preload("[...]/right_click_handler.tscn")
func _ready():
get_tree().node_added.connect(_add_right_click_handler)
func _add_right_click_handler(node: Node):
if node.is_in_group("right_click_enabled"):
node.add_child(right_click_handler.instantiate())
func handle_right_click(node: Control):
pass # Handle stuff here and show context menu
right_click_handler.tscn is just a Node that has right_click_handler.gd, so I won't have to replace any scripts:
extends Node
func _ready():
get_parent().gui_input.connect(_parent_gui_input)
func _parent_gui_input(event: InputEvent):
if event is InputEventMouseButton and event.button_index == 2 and event.is_pressed():
ContextMenu.handle_right_click(get_parent())
So basically the context menu manager adds a little component which calls it whenever its parent gets right clicked, sending the control node with it. I wonder what the performance hit for doing this is, but it's probably not big enough to care.
It looks like someone submitted a PR for it a while back that just hasn't made it in.
https://github.com/godotengine/godot/pull/60143
Since Rindbee made it and KoBeWi wants it, I'm sure it will make it in eventually.
I've created a proposal for a function to get all Control nodes at a position: https://github.com/godotengine/godot-proposals/issues/8408
Not sure how feasible that is from the engine side, but hopefully someone can look into it
I just realized there is a way to do this sort of thing without any script injection.
extends Control
func _ready() -> void:
attach_callback(self)
func attach_callback(node:Node) -> void:
if node is Control:
var cb = Callable(handler).bind(node)
node.gui_input.connect(cb)
for child in node.get_children():
attach_callback(child)
func handler(what:InputEvent, who:Node) -> void:
print(what, who)
We just use bind
to get the signal to send itself back to us.