# UI Components This document describes the custom UI components available in the Skelly project. ## ValueStepper Component ### Overview **ValueStepper** is a reusable UI control for stepping through discrete values with left/right arrow navigation. It provides an intuitive interface for selecting from predefined options and is particularly well-suited for game settings menus. **Location**: `scenes/ui/components/ValueStepper.tscn` and `scenes/ui/components/ValueStepper.gd` ### Why ValueStepper Exists Godot's built-in controls have limitations for discrete option selection: - **OptionButton**: Dropdown popups don't work well with gamepad navigation - **SpinBox**: Designed for numeric values, not text options - **HSlider**: Better for continuous values, not discrete choices ValueStepper fills this gap by providing: - ✅ **Gamepad-friendly** discrete option selection - ✅ **No popup complications** - values displayed inline - ✅ **Dual input support** - mouse clicks + keyboard/gamepad - ✅ **Clean horizontal layout** with current value always visible - ✅ **Perfect for game settings** like language, difficulty, resolution ### Features - **Multiple Data Sources**: Built-in support for language, resolution, difficulty - **Custom Values**: Easy setup with custom arrays of values - **Navigation Integration**: Built-in highlighting and input handling - **Signal-Based**: Clean event communication with parent scenes - **Visual Feedback**: Automatic highlighting and animations - **Audio Support**: Integrated click sounds - **Flexible Display**: Separate display names and internal values ### Visual Structure ``` [<] [Current Value] [>] ``` - **Left Arrow Button** (`<`): Navigate to previous value - **Value Display**: Shows current selection (e.g., "English", "Hard", "1920×1080") - **Right Arrow Button** (`>`): Navigate to next value ## API Reference ### Signals ```gdscript signal value_changed(new_value: String, new_index: int) ``` Emitted when the value changes, providing both the new value string and its index. ### Properties ```gdscript @export var data_source: String = "language" @export var custom_format_function: String = "" ``` - **data_source**: Determines the data type ("language", "resolution", "difficulty", or "custom") - **custom_format_function**: Reserved for future custom formatting (currently unused) ### Key Methods #### Setup and Configuration ```gdscript func setup_custom_values(custom_values: Array[String], custom_display_names: Array[String] = []) ``` Configure the stepper with custom values and optional display names. #### Value Management ```gdscript func get_current_value() -> String func set_current_value(value: String) func change_value(direction: int) ``` Get, set, or modify the current value programmatically. #### Navigation Integration ```gdscript func set_highlighted(highlighted: bool) func handle_input_action(action: String) -> bool func get_control_name() -> String ``` Integration methods for navigation systems and visual feedback. ## Usage Examples ### Basic Usage in Scene 1. **Add to Scene**: Instance `ValueStepper.tscn` in your scene 2. **Set Data Source**: Configure the `data_source` property 3. **Connect Signal**: Connect the `value_changed` signal ```gdscript # In your scene script @onready var language_stepper: ValueStepper = $LanguageStepper func _ready(): language_stepper.value_changed.connect(_on_language_changed) func _on_language_changed(new_value: String, new_index: int): print("Language changed to: ", new_value) ``` ### Built-in Data Sources #### Language Selection ```gdscript # Set data_source = "language" in editor or code language_stepper.data_source = "language" ``` Automatically loads available languages from SettingsManager. #### Resolution Selection ```gdscript # Set data_source = "resolution" resolution_stepper.data_source = "resolution" ``` Provides common resolution options with display names. #### Difficulty Selection ```gdscript # Set data_source = "difficulty" difficulty_stepper.data_source = "difficulty" ``` Provides difficulty levels: Easy, Normal, Hard, Nightmare. ### Custom Values ```gdscript # Setup custom theme selector var theme_values = ["light", "dark", "blue", "green"] var theme_names = ["Light Theme", "Dark Theme", "Blue Theme", "Green Theme"] theme_stepper.setup_custom_values(theme_values, theme_names) theme_stepper.data_source = "theme" # For better logging ``` ### Navigation System Integration ```gdscript # In a navigation-enabled menu var navigable_controls: Array[Control] = [] func _setup_navigation(): navigable_controls.append(volume_slider) navigable_controls.append(language_stepper) # Add stepper to navigation navigable_controls.append(back_button) func _update_visual_selection(): for i in range(navigable_controls.size()): var control = navigable_controls[i] if control is ValueStepper: control.set_highlighted(i == current_index) else: # Handle other control highlighting pass func _handle_input(action: String): var current_control = navigable_controls[current_index] if current_control is ValueStepper: if current_control.handle_input_action(action): AudioManager.play_ui_click() return true return false ``` ## Integration Patterns ### Settings Menu Pattern See `scenes/ui/SettingsMenu.gd` for a complete example of integrating ValueStepper into a settings menu with full navigation support. ### Multiple Steppers Navigation See `examples/ValueStepperExample.gd` for an example showing multiple steppers with keyboard/gamepad navigation. ## Extending ValueStepper ### Adding New Data Sources 1. **Add to `_load_data()` method**: ```gdscript func _load_data(): match data_source: "language": _load_language_data() "your_custom_type": _load_your_custom_data() # ... other cases ``` 2. **Implement your loader**: ```gdscript func _load_your_custom_data(): values = ["value1", "value2", "value3"] display_names = ["Display 1", "Display 2", "Display 3"] current_index = 0 ``` 3. **Add value application logic**: ```gdscript func _apply_value_change(new_value: String, index: int): match data_source: "your_custom_type": # Apply your custom logic here YourManager.set_custom_setting(new_value) ``` ### Custom Formatting Override `_update_display()` for custom display formatting: ```gdscript func _update_display(): if data_source == "your_custom_type": # Custom formatting logic value_display.text = "Custom: " + display_names[current_index] else: super._update_display() # Call parent implementation ``` ## Best Practices ### When to Use ValueStepper - ✅ **Discrete options**: Language, difficulty, resolution, theme - ✅ **Settings menus**: Any option with predefined choices - ✅ **Game configuration**: Graphics quality, control schemes - ✅ **Limited options**: 2-10 options work best ### When NOT to Use ValueStepper - ❌ **Continuous values**: Use sliders for volume, brightness - ❌ **Large lists**: Use ItemList or OptionButton for 20+ items - ❌ **Text input**: Use LineEdit for user-entered text - ❌ **Numeric input**: Use SpinBox for number entry ### Performance Considerations - ValueStepper is lightweight and suitable for multiple instances - Data loading happens once in `_ready()` - Visual updates are minimal (just text changes) ### Accessibility - Visual highlighting provides clear focus indication - Audio feedback confirms user actions - Keyboard and gamepad support for non-mouse users - Consistent navigation patterns ## Common Issues and Solutions ### Stepper Not Responding to Input - Ensure `handle_input_action()` is called from parent's `_input()` - Check that the stepper has proper focus/highlighting - Verify input actions are defined in project input map ### Values Not Saving - Override `_apply_value_change()` to handle persistence - Connect to `value_changed` signal for custom save logic - Ensure SettingsManager or your data manager is configured ### Display Names Not Showing - Check that `display_names` array is properly populated - Ensure `display_names.size()` matches `values.size()` - Verify `_update_display()` is called after data loading ## File Structure ``` scenes/ui/components/ ├── ValueStepper.gd # Main component script └── ValueStepper.tscn # Component scene examples/ ├── ValueStepperExample.gd # Usage example script └── ValueStepperExample.tscn # Example scene docs/ └── UI_COMPONENTS.md # This documentation ``` This component provides a solid foundation for any game's settings system and can be easily extended for project-specific needs.