From c3643eaf6d90dc8b60c0b762200bf1f8097cdfe9 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 2 Jun 2020 20:34:13 +0200 Subject: [PATCH] Add `step` member to slider widgets Both the native and the web slider now have a member `step` to control the least possible change of the slider's value. It defaults to 1.0 for all sliders and can be adjusted with the step method. --- examples/color_palette/src/main.rs | 12 ++++++--- examples/integration/src/controls.rs | 39 +++++++++++++++++----------- examples/tour/src/main.rs | 27 ++++++++++++------- native/src/widget/slider.rs | 20 +++++++++++--- web/src/widget/slider.rs | 16 ++++++++++-- 5 files changed, 81 insertions(+), 33 deletions(-) diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs index cec6ac79..9f39fe56 100644 --- a/examples/color_palette/src/main.rs +++ b/examples/color_palette/src/main.rs @@ -288,9 +288,15 @@ impl ColorPicker { .spacing(10) .align_items(Align::Center) .push(Text::new(C::LABEL).width(Length::Units(50))) - .push(Slider::new(s1, cr1, c1, move |v| C::new(v, c2, c3))) - .push(Slider::new(s2, cr2, c2, move |v| C::new(c1, v, c3))) - .push(Slider::new(s3, cr3, c3, move |v| C::new(c1, c2, v))) + .push( + Slider::new(s1, cr1, c1, move |v| C::new(v, c2, c3)).step(0.01), + ) + .push( + Slider::new(s2, cr2, c2, move |v| C::new(c1, v, c3)).step(0.01), + ) + .push( + Slider::new(s3, cr3, c3, move |v| C::new(c1, c2, v)).step(0.01), + ) .push( Text::new(color.to_string()) .width(Length::Units(185)) diff --git a/examples/integration/src/controls.rs b/examples/integration/src/controls.rs index e6e74995..824f9f53 100644 --- a/examples/integration/src/controls.rs +++ b/examples/integration/src/controls.rs @@ -48,24 +48,33 @@ impl Program for Controls { let sliders = Row::new() .width(Length::Units(500)) .spacing(20) - .push(Slider::new(r, 0.0..=1.0, background_color.r, move |r| { - Message::BackgroundColorChanged(Color { - r, - ..background_color + .push( + Slider::new(r, 0.0..=1.0, background_color.r, move |r| { + Message::BackgroundColorChanged(Color { + r, + ..background_color + }) }) - })) - .push(Slider::new(g, 0.0..=1.0, background_color.g, move |g| { - Message::BackgroundColorChanged(Color { - g, - ..background_color + .step(0.01), + ) + .push( + Slider::new(g, 0.0..=1.0, background_color.g, move |g| { + Message::BackgroundColorChanged(Color { + g, + ..background_color + }) }) - })) - .push(Slider::new(b, 0.0..=1.0, background_color.b, move |b| { - Message::BackgroundColorChanged(Color { - b, - ..background_color + .step(0.01), + ) + .push( + Slider::new(b, 0.0..=1.0, background_color.b, move |b| { + Message::BackgroundColorChanged(Color { + b, + ..background_color + }) }) - })); + .step(0.01), + ); Row::new() .width(Length::Fill) diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index c9678b9d..43627cc3 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -500,15 +500,24 @@ impl<'a> Step { .push( Row::new() .spacing(10) - .push(Slider::new(red, 0.0..=1.0, color.r, move |r| { - StepMessage::TextColorChanged(Color { r, ..color }) - })) - .push(Slider::new(green, 0.0..=1.0, color.g, move |g| { - StepMessage::TextColorChanged(Color { g, ..color }) - })) - .push(Slider::new(blue, 0.0..=1.0, color.b, move |b| { - StepMessage::TextColorChanged(Color { b, ..color }) - })), + .push( + Slider::new(red, 0.0..=1.0, color.r, move |r| { + StepMessage::TextColorChanged(Color { r, ..color }) + }) + .step(0.01), + ) + .push( + Slider::new(green, 0.0..=1.0, color.g, move |g| { + StepMessage::TextColorChanged(Color { g, ..color }) + }) + .step(0.01), + ) + .push( + Slider::new(blue, 0.0..=1.0, color.b, move |b| { + StepMessage::TextColorChanged(Color { b, ..color }) + }) + .step(0.01), + ), ); Self::container("Text") diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs index 753a49fe..8670628c 100644 --- a/native/src/widget/slider.rs +++ b/native/src/widget/slider.rs @@ -16,6 +16,8 @@ use std::{hash::Hash, ops::RangeInclusive}; /// /// A [`Slider`] will try to fill the horizontal space of its container. /// +/// The step size defaults to 1.0. +/// /// [`Slider`]: struct.Slider.html /// /// # Example @@ -38,6 +40,7 @@ use std::{hash::Hash, ops::RangeInclusive}; pub struct Slider<'a, Message, Renderer: self::Renderer> { state: &'a mut State, range: RangeInclusive, + step: f32, value: f32, on_change: Box Message>, on_release: Option, @@ -71,6 +74,7 @@ impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> { state, value: value.max(*range.start()).min(*range.end()), range, + step: 1.0, on_change: Box::new(on_change), on_release: None, width: Length::Fill, @@ -106,6 +110,14 @@ impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> { self.style = style.into(); self } + + /// Sets the step size of the [`Slider`]. + /// + /// [`Slider`]: struct.Slider.html + pub fn step(mut self, step: f32) -> Self { + self.step = step; + self + } } /// The local state of a [`Slider`]. @@ -164,16 +176,16 @@ where ) { let mut change = || { let bounds = layout.bounds(); - if cursor_position.x <= bounds.x { messages.push((self.on_change)(*self.range.start())); } else if cursor_position.x >= bounds.x + bounds.width { messages.push((self.on_change)(*self.range.end())); } else { let percent = (cursor_position.x - bounds.x) / bounds.width; - let value = (self.range.end() - self.range.start()) * percent - + self.range.start(); - + let steps = (percent * (self.range.end() - self.range.start()) + / self.step) + .round(); + let value = steps * self.step + self.range.start(); messages.push((self.on_change)(value)); } }; diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 5aa6439e..60d69798 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -16,6 +16,8 @@ use std::{ops::RangeInclusive, rc::Rc}; /// /// A [`Slider`] will try to fill the horizontal space of its container. /// +/// The step size defaults to 1.0. +/// /// [`Slider`]: struct.Slider.html /// /// # Example @@ -37,6 +39,7 @@ use std::{ops::RangeInclusive, rc::Rc}; pub struct Slider<'a, Message> { _state: &'a mut State, range: RangeInclusive, + step: f32, value: f32, on_change: Rc Message>>, width: Length, @@ -69,6 +72,7 @@ impl<'a, Message> Slider<'a, Message> { _state: state, value: value.max(*range.start()).min(*range.end()), range, + step: 1.0, on_change: Rc::new(Box::new(on_change)), width: Length::Fill, style: Default::default(), @@ -90,6 +94,14 @@ impl<'a, Message> Slider<'a, Message> { self.style = style.into(); self } + + /// Sets the step size of the [`Slider`]. + /// + /// [`Slider`]: struct.Slider.html + pub fn step(mut self, step: f32) -> Self { + self.step = step; + self + } } impl<'a, Message> Widget for Slider<'a, Message> @@ -110,15 +122,15 @@ where let min = bumpalo::format!(in bump, "{}", start); let max = bumpalo::format!(in bump, "{}", end); let value = bumpalo::format!(in bump, "{}", self.value); + let step = bumpalo::format!(in bump, "{}", self.step); let on_change = self.on_change.clone(); let event_bus = bus.clone(); - // TODO: Make `step` configurable // TODO: Styling input(bump) .attr("type", "range") - .attr("step", "0.01") + .attr("step", step.into_bump_str()) .attr("min", min.into_bump_str()) .attr("max", max.into_bump_str()) .attr("value", value.into_bump_str())