How to make it so that when you press ui_cancel the visible layer is hidden and another one appears in the menu

Godot Version

v4.3.stable.steam

Question

I have a main menu with settings, in the settings there are a huge number of parameters (language, sound, etc.), it is easy to open each layer by pressing. But I do not know how to implement the collapse of the visible layer by pressing ui_cancel! Initially, I wrote in func __input a check whether the window is open and so on for all windows, but as for me, this is not a very optimized solution. Does anyone know a solution on how to do this correctly?

func _input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel") and $BoxContainer.visible == false:
		if $Variant_controllera.visible == true:
			$Variant_controllera.hide()
			$BoxContainer.show()
			$BoxContainer/Control.grab_focus()
		elif $ButtonsChangeKeyBoard.visible == true:
			$ButtonsChangeKeyBoard.hide()
			$Variant_controllera.show()
			$Variant_controllera/KeyBoard.grab_focus()
		elif $ButtonsChangeGamepad.visible == true:
			$ButtonsChangeGamepad.hide()
			$Variant_controllera.show()
			$Variant_controllera/Gamepad.grab_focus()
		elif $LanguageChange.visible == true:
			$LanguageChange.hide()
			$BoxContainer.show()
			$BoxContainer/Laguage.grab_focus()
		elif $SoundSettings.visible == true:
			$SoundSettings.hide()
			$BoxContainer.show()
			$BoxContainer/Sound.grab_focus()
	elif $BoxContainer.visible == true and event.is_action_pressed("ui_cancel"):
		$".".hide()

You could decouple your child nodes code from this central UiManager by assigning this piece of code to all of your child nodes that you want to hide with “ui_cancel” action:

extends Control

@export var control_to_grab_focus: Control

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel") and visible:
		hide()
		release_focus()
		if control_to_grab_focus:
			control_to_grab_focus.grab_focus()

This way, upon the “ui_cancel” action, all nodes that are visible will be hidden and you can specify control_to_grab_focus for each of them separately in the Inspector to regrab focus.
You can add as many of these child nodes to your UI as you need and you don’t need to change a single line of code - it will all work the same.

Let me know in case you have any issues with the implementation of this idea.

1 Like

Hi, your solution is great! But I have a problem


Here is the scene with settings. In the “Box Container” node are all the buttons that you see in the screenshot above
My problem is that if I write your code, say, to “LanguageChange” and the same code to “BoxContainer”, it will be executed in both cases and both nodes will immediately disappear.

Below is the code for “LanguageChange” And as you can see I added $“…/BoxContainer”.show() because I need the main node to appear after hiding it (this is logical)

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel") and visible:
		hide()
		release_focus()
		$"../BoxContainer".show()
		if control_to_grab_focus:
			control_to_grab_focus.grab_focus()

And as soon as the “LanguageChange” node disappears, “BoxContainer” appears and then its script immediately triggers and the node also disappears!

I hope I was able to explain it well, forgive me for the mistakes, I use a translator…

But as far as I can see, the BoxContainer node doesn’t have any script attached to it, so why would something trigger there?

If you want the input to be handled only once, then you can add get_viewport().set_input_as_handled() at the end of the function - this way it will be triggered first on the child nodes (starting from the last one), and then if no children handle the input, the parent node will take it.

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel") and visible:
		hide()
		release_focus()
		$"../BoxContainer".show()
		if control_to_grab_focus:
			control_to_grab_focus.grab_focus()
		get_viewport().set_input_as_handled()

The script was attached, but when I started trying to fix it, I deleted it. Thank you very much, your solution helped me! Бро лучший просто!

1 Like