Components / Selection & input
Slider
Markdown crates/ui/src/widgets/controls.rs docs.rs
use ui::widgets::{self, Controls, SliderDrag};
focus::focusable(&theme, &self.slider, theme.slider(self.level))
.id("slider")
.on_drag(SliderDrag("slider".into()), |_, _, _, cx| cx.new(|_| gpui::Empty))
.on_drag_move(cx.listener(|view, event: &DragMoveEvent<SliderDrag>, _, cx| {
let Some(fraction) = widgets::slider_fraction(event, "slider", cx) else {
return;
};
view.level = fraction;
cx.notify();
}))The element is the drag source, so the gesture is grab-anywhere-and-slide rather than aim-at-the-knob.
Keyboard
.on_action(cx.listener(|view, _: &focus::Decrement, _, cx| view.nudge(-STEP, cx)))
.on_action(cx.listener(|view, _: &focus::Increment, _, cx| view.nudge(STEP, cx)))API
pub trait Controls: ThemeExt {
fn slider(&self, fraction: f32) -> Div;
// ...
}
/// Where the drag lands on the track it is asked about, or `None` when the
/// gesture belongs to another slider.
pub fn slider_fraction(
event: &DragMoveEvent<SliderDrag>,
id: impl Into<ElementId>,
cx: &App,
) -> Option<f32>;
/// A type of its own, so two sliders never answer each other's `on_drag_move`;
/// the id inside it is which one the gesture started on.
pub struct SliderDrag(pub ElementId);focus::Decrement and focus::Increment are ←/→. They carry no step: only the caller knows the range.