summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/color_palette/src/main.rs38
-rw-r--r--examples/progress_bar/src/main.rs15
-rw-r--r--examples/tour/src/main.rs77
-rw-r--r--glow/src/widget/slider.rs2
-rw-r--r--graphics/src/widget/slider.rs4
-rw-r--r--native/Cargo.toml1
-rw-r--r--native/src/widget/slider.rs81
-rw-r--r--web/Cargo.toml1
-rw-r--r--web/src/widget/slider.rs64
-rw-r--r--wgpu/src/widget/slider.rs2
10 files changed, 171 insertions, 114 deletions
diff --git a/examples/color_palette/src/main.rs b/examples/color_palette/src/main.rs
index 9f39fe56..3186deff 100644
--- a/examples/color_palette/src/main.rs
+++ b/examples/color_palette/src/main.rs
@@ -269,7 +269,7 @@ struct ColorPicker<C: ColorSpace> {
trait ColorSpace: Sized {
const LABEL: &'static str;
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3];
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3];
fn new(a: f32, b: f32, c: f32) -> Self;
@@ -284,19 +284,25 @@ impl<C: 'static + ColorSpace + Copy> ColorPicker<C> {
let [s1, s2, s3] = &mut self.sliders;
let [cr1, cr2, cr3] = C::COMPONENT_RANGES;
+ fn slider<C>(
+ state: &mut slider::State,
+ range: RangeInclusive<f64>,
+ component: f32,
+ update: impl Fn(f32) -> C + 'static,
+ ) -> Slider<f64, C> {
+ Slider::new(state, range, f64::from(component), move |v| {
+ update(v as f32)
+ })
+ .step(0.01)
+ }
+
Row::new()
.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)).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(slider(s1, cr1, c1, move |v| C::new(v, c2, c3)))
+ .push(slider(s2, cr2, c2, move |v| C::new(c1, v, c3)))
+ .push(slider(s3, cr3, c3, move |v| C::new(c1, c2, v)))
.push(
Text::new(color.to_string())
.width(Length::Units(185))
@@ -308,7 +314,7 @@ impl<C: 'static + ColorSpace + Copy> ColorPicker<C> {
impl ColorSpace for Color {
const LABEL: &'static str = "RGB";
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=1.0, 0.0..=1.0, 0.0..=1.0];
fn new(r: f32, g: f32, b: f32) -> Self {
@@ -331,7 +337,7 @@ impl ColorSpace for Color {
impl ColorSpace for palette::Hsl {
const LABEL: &'static str = "HSL";
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
fn new(hue: f32, saturation: f32, lightness: f32) -> Self {
@@ -362,7 +368,7 @@ impl ColorSpace for palette::Hsl {
impl ColorSpace for palette::Hsv {
const LABEL: &'static str = "HSV";
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
fn new(hue: f32, saturation: f32, value: f32) -> Self {
@@ -385,7 +391,7 @@ impl ColorSpace for palette::Hsv {
impl ColorSpace for palette::Hwb {
const LABEL: &'static str = "HWB";
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
fn new(hue: f32, whiteness: f32, blackness: f32) -> Self {
@@ -416,7 +422,7 @@ impl ColorSpace for palette::Hwb {
impl ColorSpace for palette::Lab {
const LABEL: &'static str = "Lab";
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=100.0, -128.0..=127.0, -128.0..=127.0];
fn new(l: f32, a: f32, b: f32) -> Self {
@@ -434,7 +440,7 @@ impl ColorSpace for palette::Lab {
impl ColorSpace for palette::Lch {
const LABEL: &'static str = "Lch";
- const COMPONENT_RANGES: [RangeInclusive<f32>; 3] =
+ const COMPONENT_RANGES: [RangeInclusive<f64>; 3] =
[0.0..=100.0, 0.0..=128.0, 0.0..=360.0];
fn new(l: f32, chroma: f32, hue: f32) -> Self {
diff --git a/examples/progress_bar/src/main.rs b/examples/progress_bar/src/main.rs
index 43b09928..51b56eda 100644
--- a/examples/progress_bar/src/main.rs
+++ b/examples/progress_bar/src/main.rs
@@ -36,12 +36,15 @@ impl Sandbox for Progress {
Column::new()
.padding(20)
.push(ProgressBar::new(0.0..=100.0, self.value))
- .push(Slider::new(
- &mut self.progress_bar_slider,
- 0.0..=100.0,
- self.value,
- Message::SliderChanged,
- ))
+ .push(
+ Slider::new(
+ &mut self.progress_bar_slider,
+ 0.0..=100.0,
+ self.value,
+ Message::SliderChanged,
+ )
+ .step(0.01),
+ )
.into()
}
}
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index 43627cc3..4f8a4b32 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -190,7 +190,7 @@ enum Step {
Welcome,
Slider {
state: slider::State,
- value: u16,
+ value: u8,
},
RowsAndColumns {
layout: Layout,
@@ -222,13 +222,13 @@ enum Step {
#[derive(Debug, Clone)]
pub enum StepMessage {
- SliderChanged(f32),
+ SliderChanged(u8),
LayoutChanged(Layout),
- SpacingChanged(f32),
- TextSizeChanged(f32),
+ SpacingChanged(u16),
+ TextSizeChanged(u16),
TextColorChanged(Color),
LanguageSelected(Language),
- ImageWidthChanged(f32),
+ ImageWidthChanged(u16),
InputChanged(String),
ToggleSecureInput(bool),
DebugToggled(bool),
@@ -249,12 +249,12 @@ impl<'a> Step {
}
StepMessage::SliderChanged(new_value) => {
if let Step::Slider { value, .. } = self {
- *value = new_value.round() as u16;
+ *value = new_value;
}
}
StepMessage::TextSizeChanged(new_size) => {
if let Step::Text { size, .. } = self {
- *size = new_size.round() as u16;
+ *size = new_size;
}
}
StepMessage::TextColorChanged(new_color) => {
@@ -269,12 +269,12 @@ impl<'a> Step {
}
StepMessage::SpacingChanged(new_spacing) => {
if let Step::RowsAndColumns { spacing, .. } = self {
- *spacing = new_spacing.round() as u16;
+ *spacing = new_spacing;
}
}
StepMessage::ImageWidthChanged(new_width) => {
if let Step::Image { width, .. } = self {
- *width = new_width.round() as u16;
+ *width = new_width;
}
}
StepMessage::InputChanged(new_value) => {
@@ -384,7 +384,7 @@ impl<'a> Step {
fn slider(
state: &'a mut slider::State,
- value: u16,
+ value: u8,
) -> Column<'a, StepMessage> {
Self::container("Slider")
.push(Text::new(
@@ -397,8 +397,8 @@ impl<'a> Step {
))
.push(Slider::new(
state,
- 0.0..=100.0,
- value as f32,
+ 0..=100,
+ value,
StepMessage::SliderChanged,
))
.push(
@@ -444,8 +444,8 @@ impl<'a> Step {
.spacing(10)
.push(Slider::new(
spacing_slider,
- 0.0..=80.0,
- spacing as f32,
+ 0..=80,
+ spacing,
StepMessage::SpacingChanged,
))
.push(
@@ -486,39 +486,25 @@ impl<'a> Step {
)
.push(Slider::new(
size_slider,
- 10.0..=70.0,
- size as f32,
+ 10..=70,
+ size,
StepMessage::TextSizeChanged,
));
let [red, green, blue] = color_sliders;
+
+ let color_sliders = Row::new()
+ .spacing(10)
+ .push(color_slider(red, color.r, move |r| Color { r, ..color }))
+ .push(color_slider(green, color.g, move |g| Color { g, ..color }))
+ .push(color_slider(blue, color.b, move |b| Color { b, ..color }));
+
let color_section = Column::new()
.padding(20)
.spacing(20)
.push(Text::new("And its color:"))
.push(Text::new(&format!("{:?}", color)).color(color))
- .push(
- Row::new()
- .spacing(10)
- .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),
- ),
- );
+ .push(color_sliders);
Self::container("Text")
.push(Text::new(
@@ -568,8 +554,8 @@ impl<'a> Step {
.push(ferris(width))
.push(Slider::new(
slider,
- 100.0..=500.0,
- width as f32,
+ 100..=500,
+ width,
StepMessage::ImageWidthChanged,
))
.push(
@@ -715,6 +701,17 @@ fn button<'a, Message>(
.min_width(100)
}
+fn color_slider(
+ state: &mut slider::State,
+ component: f32,
+ update: impl Fn(f32) -> Color + 'static,
+) -> Slider<f64, StepMessage> {
+ Slider::new(state, 0.0..=1.0, f64::from(component), move |c| {
+ StepMessage::TextColorChanged(update(c as f32))
+ })
+ .step(0.01)
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Language {
Rust,
diff --git a/glow/src/widget/slider.rs b/glow/src/widget/slider.rs
index cf036829..3a8c2595 100644
--- a/glow/src/widget/slider.rs
+++ b/glow/src/widget/slider.rs
@@ -13,4 +13,4 @@ pub use iced_native::slider::State;
/// values.
///
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`.
-pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Renderer>;
+pub type Slider<'a, T, Message> = iced_native::Slider<'a, T, Message, Renderer>;
diff --git a/graphics/src/widget/slider.rs b/graphics/src/widget/slider.rs
index b00cde9a..da8b5a86 100644
--- a/graphics/src/widget/slider.rs
+++ b/graphics/src/widget/slider.rs
@@ -16,8 +16,8 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
/// values.
///
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`.
-pub type Slider<'a, Message, Backend> =
- iced_native::Slider<'a, Message, Renderer<Backend>>;
+pub type Slider<'a, T, Message, Backend> =
+ iced_native::Slider<'a, T, Message, Renderer<Backend>>;
const HANDLE_HEIGHT: f32 = 22.0;
diff --git a/native/Cargo.toml b/native/Cargo.toml
index 75b4a56b..13052a93 100644
--- a/native/Cargo.toml
+++ b/native/Cargo.toml
@@ -13,6 +13,7 @@ debug = []
[dependencies]
twox-hash = "1.5"
unicode-segmentation = "1.6"
+num-traits = "0.2"
[dependencies.iced_core]
version = "0.2"
diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs
index 8670628c..70f2b6ac 100644
--- a/native/src/widget/slider.rs
+++ b/native/src/widget/slider.rs
@@ -16,7 +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.
+/// The [`Slider`] range of numeric values is generic and its step size defaults
+/// to 1 unit.
///
/// [`Slider`]: struct.Slider.html
///
@@ -24,7 +25,7 @@ use std::{hash::Hash, ops::RangeInclusive};
/// ```
/// # use iced_native::{slider, renderer::Null};
/// #
-/// # pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Null>;
+/// # pub type Slider<'a, T, Message> = iced_native::Slider<'a, T, Message, Null>;
/// pub enum Message {
/// SliderChanged(f32),
/// }
@@ -37,18 +38,22 @@ use std::{hash::Hash, ops::RangeInclusive};
///
/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true)
#[allow(missing_debug_implementations)]
-pub struct Slider<'a, Message, Renderer: self::Renderer> {
+pub struct Slider<'a, T, Message, Renderer: self::Renderer> {
state: &'a mut State,
- range: RangeInclusive<f32>,
- step: f32,
- value: f32,
- on_change: Box<dyn Fn(f32) -> Message>,
+ range: RangeInclusive<T>,
+ step: T,
+ value: T,
+ on_change: Box<dyn Fn(T) -> Message>,
on_release: Option<Message>,
width: Length,
style: Renderer::Style,
}
-impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> {
+impl<'a, T, Message, Renderer> Slider<'a, T, Message, Renderer>
+where
+ T: Copy + From<u8> + std::cmp::PartialOrd,
+ Renderer: self::Renderer,
+{
/// Creates a new [`Slider`].
///
/// It expects:
@@ -63,18 +68,30 @@ impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> {
/// [`State`]: struct.State.html
pub fn new<F>(
state: &'a mut State,
- range: RangeInclusive<f32>,
- value: f32,
+ range: RangeInclusive<T>,
+ value: T,
on_change: F,
) -> Self
where
- F: 'static + Fn(f32) -> Message,
+ F: 'static + Fn(T) -> Message,
{
+ let value = if value >= *range.start() {
+ value
+ } else {
+ *range.start()
+ };
+
+ let value = if value <= *range.end() {
+ value
+ } else {
+ *range.end()
+ };
+
Slider {
state,
- value: value.max(*range.start()).min(*range.end()),
+ value,
range,
- step: 1.0,
+ step: T::from(1),
on_change: Box::new(on_change),
on_release: None,
width: Length::Fill,
@@ -114,7 +131,7 @@ impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> {
/// Sets the step size of the [`Slider`].
///
/// [`Slider`]: struct.Slider.html
- pub fn step(mut self, step: f32) -> Self {
+ pub fn step(mut self, step: T) -> Self {
self.step = step;
self
}
@@ -137,9 +154,10 @@ impl State {
}
}
-impl<'a, Message, Renderer> Widget<Message, Renderer>
- for Slider<'a, Message, Renderer>
+impl<'a, T, Message, Renderer> Widget<Message, Renderer>
+ for Slider<'a, T, Message, Renderer>
where
+ T: Copy + Into<f64> + num_traits::FromPrimitive,
Renderer: self::Renderer,
Message: Clone,
{
@@ -181,12 +199,19 @@ where
} 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 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));
+ let step = self.step.into();
+ let start = (*self.range.start()).into();
+ let end = (*self.range.end()).into();
+
+ let percent = f64::from(cursor_position.x - bounds.x)
+ / f64::from(bounds.width);
+
+ let steps = (percent * (end - start) / step).round();
+ let value = steps * step + start;
+
+ if let Some(value) = T::from_f64(value) {
+ messages.push((self.on_change)(value));
+ }
}
};
@@ -224,11 +249,14 @@ where
layout: Layout<'_>,
cursor_position: Point,
) -> Renderer::Output {
+ let start = *self.range.start();
+ let end = *self.range.end();
+
renderer.draw(
layout.bounds(),
cursor_position,
- self.range.clone(),
- self.value,
+ start.into() as f32..=end.into() as f32,
+ self.value.into() as f32,
self.state.is_dragging,
&self.style,
)
@@ -281,14 +309,15 @@ pub trait Renderer: crate::Renderer {
) -> Self::Output;
}
-impl<'a, Message, Renderer> From<Slider<'a, Message, Renderer>>
+impl<'a, T, Message, Renderer> From<Slider<'a, T, Message, Renderer>>
for Element<'a, Message, Renderer>
where
+ T: 'a + Copy + Into<f64> + num_traits::FromPrimitive,
Renderer: 'a + self::Renderer,
Message: 'a + Clone,
{
fn from(
- slider: Slider<'a, Message, Renderer>,
+ slider: Slider<'a, T, Message, Renderer>,
) -> Element<'a, Message, Renderer> {
Element::new(slider)
}
diff --git a/web/Cargo.toml b/web/Cargo.toml
index 12d3865e..88c3102f 100644
--- a/web/Cargo.toml
+++ b/web/Cargo.toml
@@ -19,6 +19,7 @@ dodrio = "0.1.0"
wasm-bindgen = "0.2.51"
wasm-bindgen-futures = "0.4"
url = "2.0"
+num-traits = "0.2"
[dependencies.iced_core]
version = "0.2"
diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs
index 60d69798..a0d9df00 100644
--- a/web/src/widget/slider.rs
+++ b/web/src/widget/slider.rs
@@ -16,7 +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.
+/// The [`Slider`] range of numeric values is generic and its step size defaults
+/// to 1 unit.
///
/// [`Slider`]: struct.Slider.html
///
@@ -36,17 +37,20 @@ use std::{ops::RangeInclusive, rc::Rc};
///
/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true)
#[allow(missing_debug_implementations)]
-pub struct Slider<'a, Message> {
+pub struct Slider<'a, T, Message> {
_state: &'a mut State,
- range: RangeInclusive<f32>,
- step: f32,
- value: f32,
- on_change: Rc<Box<dyn Fn(f32) -> Message>>,
+ range: RangeInclusive<T>,
+ step: T,
+ value: T,
+ on_change: Rc<Box<dyn Fn(T) -> Message>>,
width: Length,
style: Box<dyn StyleSheet>,
}
-impl<'a, Message> Slider<'a, Message> {
+impl<'a, T, Message> Slider<'a, T, Message>
+where
+ T: Copy + From<u8> + std::cmp::PartialOrd,
+{
/// Creates a new [`Slider`].
///
/// It expects:
@@ -61,18 +65,30 @@ impl<'a, Message> Slider<'a, Message> {
/// [`State`]: struct.State.html
pub fn new<F>(
state: &'a mut State,
- range: RangeInclusive<f32>,
- value: f32,
+ range: RangeInclusive<T>,
+ value: T,
on_change: F,
) -> Self
where
- F: 'static + Fn(f32) -> Message,
+ F: 'static + Fn(T) -> Message,
{
+ let value = if value >= *range.start() {
+ value
+ } else {
+ *range.start()
+ };
+
+ let value = if value <= *range.end() {
+ value
+ } else {
+ *range.end()
+ };
+
Slider {
_state: state,
- value: value.max(*range.start()).min(*range.end()),
+ value,
range,
- step: 1.0,
+ step: T::from(1),
on_change: Rc::new(Box::new(on_change)),
width: Length::Fill,
style: Default::default(),
@@ -98,14 +114,15 @@ impl<'a, Message> Slider<'a, Message> {
/// Sets the step size of the [`Slider`].
///
/// [`Slider`]: struct.Slider.html
- pub fn step(mut self, step: f32) -> Self {
+ pub fn step(mut self, step: T) -> Self {
self.step = step;
self
}
}
-impl<'a, Message> Widget<Message> for Slider<'a, Message>
+impl<'a, T, Message> Widget<Message> for Slider<'a, T, Message>
where
+ T: 'static + Copy + Into<f64> + num_traits::FromPrimitive,
Message: 'static,
{
fn node<'b>(
@@ -119,10 +136,10 @@ where
let (start, end) = self.range.clone().into_inner();
- 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 min = bumpalo::format!(in bump, "{}", start.into());
+ let max = bumpalo::format!(in bump, "{}", end.into());
+ let value = bumpalo::format!(in bump, "{}", self.value.into());
+ let step = bumpalo::format!(in bump, "{}", self.step.into());
let on_change = self.on_change.clone();
let event_bus = bus.clone();
@@ -143,19 +160,22 @@ where
Some(slider) => slider,
};
- if let Ok(value) = slider.value().parse::<f32>() {
- event_bus.publish(on_change(value));
+ if let Ok(value) = slider.value().parse::<f64>() {
+ if let Some(value) = T::from_f64(value) {
+ event_bus.publish(on_change(value));
+ }
}
})
.finish()
}
}
-impl<'a, Message> From<Slider<'a, Message>> for Element<'a, Message>
+impl<'a, T, Message> From<Slider<'a, T, Message>> for Element<'a, Message>
where
+ T: 'static + Copy + Into<f64> + num_traits::FromPrimitive,
Message: 'static,
{
- fn from(slider: Slider<'a, Message>) -> Element<'a, Message> {
+ fn from(slider: Slider<'a, T, Message>) -> Element<'a, Message> {
Element::new(slider)
}
}
diff --git a/wgpu/src/widget/slider.rs b/wgpu/src/widget/slider.rs
index cf036829..3a8c2595 100644
--- a/wgpu/src/widget/slider.rs
+++ b/wgpu/src/widget/slider.rs
@@ -13,4 +13,4 @@ pub use iced_native::slider::State;
/// values.
///
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`.
-pub type Slider<'a, Message> = iced_native::Slider<'a, Message, Renderer>;
+pub type Slider<'a, T, Message> = iced_native::Slider<'a, T, Message, Renderer>;