Godot Version
4.5.1 stable
Question
So I have a node called navigation, it sends a signal when a button is pressed and an indicator is also visible on the focused button, my issue is, when I grab focus to a button on another script, then they overlap and the indicator isnt on the focused button, adding a timer of 0.5 sec on enter_focus worked but I dont want a delay. The function gets connected with focus_entered, mouse_entered()
extends Control
class_name Navigation
@export var vbox_container: VBoxContainer = find_child(“VBoxContainer”)
@export var hbox_container: HBoxContainer = find_child(“HBoxContainer”)
@export var indicator: Control = find_child(“Indicator”)
@export var nav_node: Control = self
@export var arrow_offset: int = 48
@export var main_button: Control
@export var animated: bool = true
signal button_pressed(button: Button)
func _ready() → void:
process_mode = Node.PROCESS_MODE_ALWAYS
if main_button:
indicator.global_position.y = main_button.global_position.y
pressed(main_button)
main_button.grab_focus()
enter_focus(main_button, "x")
main_button.release_focus()
await get_tree().process_frame
if vbox_container:
for button in vbox_container.get_children():
if button is Button:
button.process_mode = Node.PROCESS_MODE_ALWAYS
button.mouse_entered.connect(enter_focus.bind(button, "y"))
button.focus_entered.connect(enter_focus.bind(button, "y"))
button.pressed.connect(pressed.bind(button))
elif hbox_container:
for button in hbox_container.get_children():
if button is Button:
button.process_mode = Node.PROCESS_MODE_ALWAYS
button.mouse_entered.connect(enter_focus.bind(button, "x"))
button.focus_entered.connect(enter_focus.bind(button, "x"))
button.pressed.connect(pressed.bind(button))
func enter_focus(button: Button, axis: String) → void:
button.grab_focus()
var arrow_right: Sprite2D = indicator.get_child(0)
var arrow_left: Sprite2D = indicator.get_child(1)
var target_x: float = button.global_position.x
var target_y: float = button.global_position.y
var font: Font = button.get_theme_font("font")
var font_size: int = button.get_theme_font_size("font_size")
var text_width: float = font.get_string_size(button.text, font_size).x
# Make the arrow distance dynamic but with a minimum offset
var dynamic_offset: float = max(arrow_offset, text_width * 0.3)
# Arrow local positions
var left_x: float = -(text_width / 2 + dynamic_offset)
var right_x: float = (text_width / 2 + dynamic_offset)
if animated:
var tween: Tween = create_tween().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_CUBIC).set_parallel().set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)
tween.tween_property(indicator, "global_position:y" if axis == "y" else "global_position:x", target_y if axis == "y" else target_x, 0.15)
tween.tween_property(arrow_left, "position:x", left_x, 0.15)
tween.tween_property(arrow_right, "position:x", right_x, 0.15)
else:
if axis == "y":
indicator.global_position.y = target_y
elif axis == "x":
indicator.global_position.x = target_x
arrow_left.position.x = left_x
arrow_right.position.x = right_x
func pressed(button: Button) → void:
if !nav_node:
return
nav_node._on_button_pressed(button)