Stepper Widget
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
I'm considering adding a `Stepper` widget to bevy_ui_widgets. This is a widget mainly used in console games, but it can also be useful in examples if we do a feathers version. (For example, we could use it to control which gltf scene is displayed).
The stepper is simply a button with two arrows, increment and decrement. It's like a slider, but without the draggable thumb.
The stepper widget is unopinionated about how the value is displayed: it could be a number, or it could be a word. An example of the latter would be a game difficulty stepper, which displays easy / normal / veteran / hardcore / insanity. (I can even envision an animated version in which the old word slides out and the new word slides in.)
While the stepper does respond to mouse clicks, it's main purpose is to be driven by the keyboard, or if available, a gamepad. For example, the D-Pad inputs could be used to increment or decrement the stepper.
## Open Question
Currently the `Slider` widget only supports `f32`. FeathersNumberInput takes a much more complex route, and supports `i32`, `i64`, `f32`, and `f64` through the use of enum variants. That's fine for feathers, which isn't intended to be a lightweight solution.
The stepper needs to support at least `i32` and `f32`; The "game difficulty" use case is an example of the former, and "dead zone adjust" is an example of the latter.
One solution would be to migrate the feathers `NumberInputValue` into bevy_ui_widgets. One concern I have about this is small platforms like GBA which might not have i64 support, in which case we'd be generating extra code that never gets used, bloating the binary size. `NumberInputValue` does a lot of its internal calculations in f64 (like `.offset_by` and `.scale_by`, and while this is fine for an editor, a console game in which there's a fixed memory budget may want something slimmer.
It would also mean that Stepper was inconsistent with Slider (unless we update Slider too).
A variant of this would be to replace `NumberInputValue`'s enum implementation with a trait-based generic, so that apps could choose which number types they wanted to support.
Another approach would be to make Stepper generic; this would also require making its plugin and all of its observers generic too. Going too far down this road leads to a combinatorial explosion of observers. Like, do we really want `Stepper` to be part of `DefaultPlugins`?
This, too, is inconsistent with the way the other widgets behave.
A third option is to go with a "pure MVC" approach, and not have the stepper manage the value at all - that is, it only generates increment / decrement events and leaves the mutation and clamping of the value up to the app/model. However, this also has problems: first, it means that the app would also be responsible for updating the a11y information, which violates our "a11y is the path of least resistance" principle. Second, this also is inconsistent with how the other widgets work.
A final alternative is to have explicitly two different steppers: `StepperI32` and `StepperF32`.
@alice-i-cecile @kfc35 @ickshonpe
Contributor guide
Research direction
Start by reviewing the existing Slider widget and FeathersNumberInput implementation, then compare their value-handling, plugin, observer, keyboard, gamepad, and accessibility behavior against the proposed Stepper. Before implementation, resolve the open question of supported numeric types and whether the widget should manage values or emit increment/decrement events; done is a documented design and an agreed implementation scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- frontend, game-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100