Files
skelly/scenes/ui/SettingsMenu.gd
Vladimir nett00n Budylnikov ea8c85d7ad feature/match3/move-gems (#7)
Reviewed-on: #7
Co-authored-by: Vladimir nett00n Budylnikov <git@nett00n.org>
Co-committed-by: Vladimir nett00n Budylnikov <git@nett00n.org>
2025-09-25 11:48:08 +02:00

221 lines
8.0 KiB
GDScript

extends Control
signal back_to_main_menu
@onready var master_slider = $SettingsContainer/MasterVolumeContainer/MasterVolumeSlider
@onready var music_slider = $SettingsContainer/MusicVolumeContainer/MusicVolumeSlider
@onready var sfx_slider = $SettingsContainer/SFXVolumeContainer/SFXVolumeSlider
@onready var language_stepper = $SettingsContainer/LanguageContainer/LanguageStepper
@export var settings_manager: Node = SettingsManager
@export var localization_manager: Node = LocalizationManager
# Navigation system variables
var navigable_controls: Array[Control] = []
var current_control_index: int = 0
var original_control_scales: Array[Vector2] = []
var original_control_modulates: Array[Color] = []
func _ready():
add_to_group("localizable")
DebugManager.log_info("SettingsMenu ready", "Settings")
# Language selector is initialized automatically
var master_callback = _on_volume_slider_changed.bind("master_volume")
if not master_slider.value_changed.is_connected(master_callback):
master_slider.value_changed.connect(master_callback)
var music_callback = _on_volume_slider_changed.bind("music_volume")
if not music_slider.value_changed.is_connected(music_callback):
music_slider.value_changed.connect(music_callback)
var sfx_callback = _on_volume_slider_changed.bind("sfx_volume")
if not sfx_slider.value_changed.is_connected(sfx_callback):
sfx_slider.value_changed.connect(sfx_callback)
# Language stepper connections are handled in the .tscn file
_update_controls_from_settings()
update_text()
_setup_navigation_system()
func _update_controls_from_settings():
master_slider.value = settings_manager.get_setting("master_volume")
music_slider.value = settings_manager.get_setting("music_volume")
sfx_slider.value = settings_manager.get_setting("sfx_volume")
# Language display is handled by the ValueStepper component
func _on_volume_slider_changed(value, setting_key):
# Input validation for volume settings
if not setting_key in ["master_volume", "music_volume", "sfx_volume"]:
DebugManager.log_error("Invalid volume setting key: " + str(setting_key), "Settings")
return
if not (value is float or value is int):
DebugManager.log_error("Invalid volume value type: " + str(typeof(value)), "Settings")
return
# Clamp value to valid range
var clamped_value = clamp(float(value), 0.0, 1.0)
if clamped_value != value:
DebugManager.log_warn("Volume value %f clamped to %f" % [value, clamped_value], "Settings")
if not settings_manager.set_setting(setting_key, clamped_value):
DebugManager.log_error("Failed to set volume setting: " + setting_key, "Settings")
func _exit_settings():
DebugManager.log_info("Exiting settings", "Settings")
settings_manager.save_settings()
back_to_main_menu.emit()
func _input(event):
if event.is_action_pressed("action_east") or event.is_action_pressed("pause_menu"):
DebugManager.log_debug("Cancel/back action pressed in settings", "Settings")
_exit_settings()
get_viewport().set_input_as_handled()
return
# Vertical navigation between controls
if event.is_action_pressed("move_up"):
_navigate_controls(-1)
get_viewport().set_input_as_handled()
elif event.is_action_pressed("move_down"):
_navigate_controls(1)
get_viewport().set_input_as_handled()
# Horizontal navigation for current control
elif event.is_action_pressed("move_left"):
_adjust_current_control(-1)
get_viewport().set_input_as_handled()
elif event.is_action_pressed("move_right"):
_adjust_current_control(1)
get_viewport().set_input_as_handled()
# Activate current control
elif event.is_action_pressed("action_south"):
_activate_current_control()
get_viewport().set_input_as_handled()
func _on_back_button_pressed():
AudioManager.play_ui_click()
DebugManager.log_info("Back button pressed", "Settings")
_exit_settings()
func update_text():
$SettingsContainer/SettingsTitle.text = tr("settings_title")
$SettingsContainer/MasterVolumeContainer/MasterVolume.text = tr("master_volume")
$SettingsContainer/MusicVolumeContainer/MusicVolume.text = tr("music_volume")
$SettingsContainer/SFXVolumeContainer/SFXVolume.text = tr("sfx_volume")
$SettingsContainer/LanguageContainer/LanguageLabel.text = tr("language")
$BackButtonContainer/BackButton.text = tr("back")
func _on_reset_setting_button_pressed() -> void:
AudioManager.play_ui_click()
DebugManager.log_info("Resetting settings", "Settings")
settings_manager.reset_settings_to_defaults()
_update_controls_from_settings()
localization_manager.change_language(settings_manager.get_setting("language"))
func _setup_navigation_system():
navigable_controls.clear()
original_control_scales.clear()
original_control_modulates.clear()
# Add controls in navigation order
navigable_controls.append(master_slider)
navigable_controls.append(music_slider)
navigable_controls.append(sfx_slider)
navigable_controls.append(language_stepper) # Use the ValueStepper component
navigable_controls.append($BackButtonContainer/BackButton)
navigable_controls.append($ResetSettingsContainer/ResetSettingButton)
# Store original visual properties
for control in navigable_controls:
original_control_scales.append(control.scale)
original_control_modulates.append(control.modulate)
_update_visual_selection()
func _navigate_controls(direction: int):
AudioManager.play_ui_click()
current_control_index = (current_control_index + direction) % navigable_controls.size()
if current_control_index < 0:
current_control_index = navigable_controls.size() - 1
_update_visual_selection()
DebugManager.log_info("Settings navigation: index " + str(current_control_index), "Settings")
func _adjust_current_control(direction: int):
if current_control_index < 0 or current_control_index >= navigable_controls.size():
return
var control = navigable_controls[current_control_index]
# Handle sliders
if control is HSlider:
var slider = control as HSlider
var step = slider.step if slider.step > 0 else 0.1
var new_value = slider.value + (direction * step)
new_value = clamp(new_value, slider.min_value, slider.max_value)
slider.value = new_value
AudioManager.play_ui_click()
DebugManager.log_info("Slider adjusted: %s = %f" % [_get_control_name(control), new_value], "Settings")
# Handle language stepper with left/right
elif control == language_stepper:
if language_stepper.handle_input_action("move_left" if direction == -1 else "move_right"):
AudioManager.play_ui_click()
func _activate_current_control():
if current_control_index < 0 or current_control_index >= navigable_controls.size():
return
var control = navigable_controls[current_control_index]
# Handle buttons
if control is Button:
AudioManager.play_ui_click()
DebugManager.log_info("Activating button via keyboard/gamepad: " + control.text, "Settings")
control.pressed.emit()
# Handle language stepper (no action needed on activation, left/right handles it)
elif control == language_stepper:
DebugManager.log_info("Language stepper selected - use left/right to change", "Settings")
func _update_visual_selection():
for i in range(navigable_controls.size()):
var control = navigable_controls[i]
if i == current_control_index:
# Use the ValueStepper's built-in highlighting
if control == language_stepper:
language_stepper.set_highlighted(true)
else:
control.scale = original_control_scales[i] * 1.05
control.modulate = Color(1.1, 1.1, 0.9)
else:
# Reset highlighting
if control == language_stepper:
language_stepper.set_highlighted(false)
else:
control.scale = original_control_scales[i]
control.modulate = original_control_modulates[i]
func _get_control_name(control: Control) -> String:
if control == master_slider:
return "master_volume"
elif control == music_slider:
return "music_volume"
elif control == sfx_slider:
return "sfx_volume"
elif control == language_stepper:
return language_stepper.get_control_name()
else:
return "button"
func _on_language_stepper_value_changed(new_value: String, new_index: int):
DebugManager.log_info("Language changed via ValueStepper: " + new_value + " (index: " + str(new_index) + ")", "Settings")