Files
skelly/docs/UI_COMPONENTS.md

281 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.