Placeholder:
just a quick AI summary from the comment mentioned below (Open for discussion)
Split out from a side discussion in #883 (comment): the default iced slider is fairly crude for our use case, and we keep working around it at the call sites. This issue is to discuss replacing it with a custom slider widget used consistently across the shell.
Current state
slider_control() in src/components/slider_control.rs builds every slider in the shell (audio sink/source, brightness, and the keyboard backlight added in #883). It composes:
- iced's built-in
slider for the track/handle,
- a wrapping
MouseArea just to get on_scroll,
utils::remote_value::Remote<u32> for optimistic value display while the async backend catches up,
- an ad-hoc
.style() override for the audio overdrive (>100%) rail color.
Two consequences:
- Scroll handling is duplicated per caller. Each module writes its own
on_scroll closure that re-implements step size, clamping and message wrapping (Audio::on_scroll, Brightness::on_scroll), and the same closures are re-used for the bar indicators via format_indicator().on_scroll(). The step/clamp policy lives in the modules rather than in one place.
- Appearance is limited by what
slider::Style exposes. Rail thickness, handle shape, and the overdrive segment are only reachable through style patches, and there is no way to render e.g. a filled portion past the "normal" mark differently from the rest.
What a custom widget could give us
- Thicker rail / different handle. Several of us prefer a thick slider; right now that's a theme hack rather than a design decision. Worth agreeing on the look first (mockups welcome).
- Scroll as a first-class input. Step size and clamping become widget-level concerns configured once, instead of a closure per module. Removes the
MouseArea wrapper.
- Animated transitions. Values that arrive from outside the widget (a keybinding changing volume, a
Remote value settling back to the received value, an external brightnessctl call) currently snap. A widget owning its own animation state could ease those jumps in one place. We already have components/animated_size.rs and components/slide.rs as precedent for widget-local animation.
- A place for the overdrive/threshold rendering the audio slider needs, instead of a style closure at the call site.
Open questions
- Full custom
Widget impl (own layout/draw/on_event), or a thinner wrapper that still delegates to iced's slider internals?
- Does the animation belong in the widget, or in
Remote<Value> where the requested/received distinction already lives?
- Should the bar indicators (
format_indicator) share the same scroll configuration, or stay separate?
- What's actually configurable by users vs. fixed by the theme? (See
theme.rs — thickness would presumably be theme-derived, not a per-module config key.)
Scope
Out of scope for #883 — that PR should land with the existing slider_control. This is a follow-up refactor + design change touching audio, brightness, and keyboard backlight together.
Ref: #883, #883 (comment)
Placeholder:
just a quick AI summary from the comment mentioned below (Open for discussion)
Split out from a side discussion in #883 (comment): the default iced slider is fairly crude for our use case, and we keep working around it at the call sites. This issue is to discuss replacing it with a custom slider widget used consistently across the shell.
Current state
slider_control()insrc/components/slider_control.rsbuilds every slider in the shell (audio sink/source, brightness, and the keyboard backlight added in #883). It composes:sliderfor the track/handle,MouseAreajust to geton_scroll,utils::remote_value::Remote<u32>for optimistic value display while the async backend catches up,.style()override for the audio overdrive (>100%) rail color.Two consequences:
on_scrollclosure that re-implements step size, clamping and message wrapping (Audio::on_scroll,Brightness::on_scroll), and the same closures are re-used for the bar indicators viaformat_indicator().on_scroll(). The step/clamp policy lives in the modules rather than in one place.slider::Styleexposes. Rail thickness, handle shape, and the overdrive segment are only reachable through style patches, and there is no way to render e.g. a filled portion past the "normal" mark differently from the rest.What a custom widget could give us
MouseAreawrapper.Remotevalue settling back to the received value, an externalbrightnessctlcall) currently snap. A widget owning its own animation state could ease those jumps in one place. We already havecomponents/animated_size.rsandcomponents/slide.rsas precedent for widget-local animation.Open questions
Widgetimpl (ownlayout/draw/on_event), or a thinner wrapper that still delegates to iced'ssliderinternals?Remote<Value>where the requested/received distinction already lives?format_indicator) share the same scroll configuration, or stay separate?theme.rs— thickness would presumably be theme-derived, not a per-module config key.)Scope
Out of scope for #883 — that PR should land with the existing
slider_control. This is a follow-up refactor + design change touching audio, brightness, and keyboard backlight together.Ref: #883, #883 (comment)