class_name ValueStepper extends Control ## A reusable UI control for stepping through discrete values with arrow buttons ## ## ValueStepper provides left/right arrow navigation for cycling through predefined options. ## Perfect for settings like language, resolution, difficulty, graphics quality, etc. ## Supports both mouse clicks and keyboard/gamepad navigation. ## ## @tutorial(ValueStepper Usage): See docs/UI_COMPONENTS.md signal value_changed(new_value: String, new_index: int) ## The data source for values. @export var data_source: String = "language" ## Custom display format function. Leave empty to use default. @export var custom_format_function: String = "" var values: Array[String] = [] var display_names: Array[String] = [] var current_index: int = 0 var original_scale: Vector2 var original_modulate: Color var is_highlighted: bool = false @onready var left_button: Button = $LeftButton @onready var right_button: Button = $RightButton @onready var value_display: Label = $ValueDisplay func _ready() -> void: DebugManager.log_info( "ValueStepper ready for: " + data_source, "ValueStepper" ) # Store original visual properties original_scale = scale original_modulate = modulate # Connect button signals if ( left_button and not left_button.pressed.is_connected(_on_left_button_pressed) ): left_button.pressed.connect(_on_left_button_pressed) if ( right_button and not right_button.pressed.is_connected(_on_right_button_pressed) ): right_button.pressed.connect(_on_right_button_pressed) # Initialize data _load_data() _update_display() ## Loads data based on the data_source type func _load_data() -> void: match data_source: "language": _load_language_data() "resolution": _load_resolution_data() "difficulty": _load_difficulty_data() _: DebugManager.log_warn( "Unknown data_source: " + data_source, "ValueStepper" ) func _load_language_data() -> void: var languages_data: Dictionary = SettingsManager.get_languages_data() if languages_data.has("languages"): values.clear() display_names.clear() for lang_code in languages_data.languages.keys(): values.append(lang_code) display_names.append( languages_data.languages[lang_code]["display_name"] ) # Set current index based on current language var current_lang: String = SettingsManager.get_setting("language") var index: int = values.find(current_lang) current_index = max(0, index) DebugManager.log_info( "Loaded %d languages" % values.size(), "ValueStepper" ) func _load_resolution_data() -> void: # Example resolution data - customize as needed values = ["1920x1080", "1366x768", "1280x720", "1024x768"] display_names = [ "1920×1080 (Full HD)", "1366×768", "1280×720 (HD)", "1024×768" ] current_index = 0 DebugManager.log_info( "Loaded %d resolutions" % values.size(), "ValueStepper" ) func _load_difficulty_data() -> void: # Example difficulty data - customize as needed values = ["easy", "normal", "hard", "nightmare"] display_names = ["Easy", "Normal", "Hard", "Nightmare"] current_index = 1 # Default to "normal" DebugManager.log_info( "Loaded %d difficulty levels" % values.size(), "ValueStepper" ) ## Updates the display text based on current selection func _update_display() -> void: if ( values.size() == 0 or current_index < 0 or current_index >= values.size() ): value_display.text = "N/A" return if display_names.size() > current_index: value_display.text = display_names[current_index] else: value_display.text = values[current_index] ## Changes the current value by the specified direction (-1 for previous, +1 for next) func change_value(direction: int) -> void: if values.size() == 0: DebugManager.log_warn( "No values available for: " + data_source, "ValueStepper" ) return var new_index: int = (current_index + direction) % values.size() if new_index < 0: new_index = values.size() - 1 current_index = new_index var new_value: String = values[current_index] _update_display() _apply_value_change(new_value, current_index) value_changed.emit(new_value, current_index) DebugManager.log_info( ( "Value changed to: " + new_value + " (index: " + str(current_index) + ")" ), "ValueStepper" ) ## Override this method for custom value application logic func _apply_value_change(new_value: String, _index: int) -> void: match data_source: "language": SettingsManager.set_setting("language", new_value) if LocalizationManager: LocalizationManager.change_language(new_value) "resolution": # Apply resolution change logic here DebugManager.log_info( "Resolution would change to: " + new_value, "ValueStepper" ) "difficulty": # Apply difficulty change logic here DebugManager.log_info( "Difficulty would change to: " + new_value, "ValueStepper" ) ## Sets up custom values for the stepper func setup_custom_values( custom_values: Array[String], custom_display_names: Array[String] = [] ) -> void: values = custom_values.duplicate() display_names = ( custom_display_names.duplicate() if custom_display_names.size() > 0 else values.duplicate() ) current_index = 0 _update_display() DebugManager.log_info( "Setup custom values: " + str(values.size()) + " items", "ValueStepper" ) ## Gets the current value func get_current_value() -> String: if ( values.size() > 0 and current_index >= 0 and current_index < values.size() ): return values[current_index] return "" ## Sets the current value by string func set_current_value(value: String) -> void: var index: int = values.find(value) if index >= 0: current_index = index _update_display() ## Visual highlighting for navigation systems func set_highlighted(highlighted: bool) -> void: is_highlighted = highlighted if highlighted: scale = original_scale * UIConstants.UI_CONTROL_HIGHLIGHT_SCALE modulate = Color(1.1, 1.1, 0.9) else: scale = original_scale modulate = original_modulate ## Handle input actions for navigation integration func handle_input_action(action: String) -> bool: match action: "move_left": change_value(-1) return true "move_right": change_value(1) return true _: return false func _on_left_button_pressed() -> void: AudioManager.play_ui_click() DebugManager.log_info("Left button clicked", "ValueStepper") change_value(-1) func _on_right_button_pressed() -> void: AudioManager.play_ui_click() DebugManager.log_info("Right button clicked", "ValueStepper") change_value(1) ## For navigation system integration func get_control_name() -> String: return data_source + "_stepper"