Make Slider value type generic

This commit is contained in:
Héctor Ramón Jiménez 2020-06-13 14:17:41 +02:00
parent f131969c47
commit 0b819de3e2
5 changed files with 58 additions and 29 deletions

View File

@ -13,4 +13,4 @@ pub use iced_native::slider::State;
/// values. /// values.
/// ///
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. /// 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>;

View File

@ -16,8 +16,8 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
/// values. /// values.
/// ///
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. /// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`.
pub type Slider<'a, Message, Backend> = pub type Slider<'a, T, Message, Backend> =
iced_native::Slider<'a, Message, Renderer<Backend>>; iced_native::Slider<'a, T, Message, Renderer<Backend>>;
const HANDLE_HEIGHT: f32 = 22.0; const HANDLE_HEIGHT: f32 = 22.0;

View File

@ -13,6 +13,7 @@ debug = []
[dependencies] [dependencies]
twox-hash = "1.5" twox-hash = "1.5"
unicode-segmentation = "1.6" unicode-segmentation = "1.6"
num-traits = "0.2"
[dependencies.iced_core] [dependencies.iced_core]
version = "0.2" version = "0.2"

View File

@ -24,7 +24,7 @@ use std::{hash::Hash, ops::RangeInclusive};
/// ``` /// ```
/// # use iced_native::{slider, renderer::Null}; /// # 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 { /// pub enum Message {
/// SliderChanged(f32), /// SliderChanged(f32),
/// } /// }
@ -37,18 +37,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) /// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true)
#[allow(missing_debug_implementations)] #[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, state: &'a mut State,
range: RangeInclusive<f32>, range: RangeInclusive<T>,
step: f32, step: T,
value: f32, value: T,
on_change: Box<dyn Fn(f32) -> Message>, on_change: Box<dyn Fn(T) -> Message>,
on_release: Option<Message>, on_release: Option<Message>,
width: Length, width: Length,
style: Renderer::Style, 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`]. /// Creates a new [`Slider`].
/// ///
/// It expects: /// It expects:
@ -63,18 +67,30 @@ impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> {
/// [`State`]: struct.State.html /// [`State`]: struct.State.html
pub fn new<F>( pub fn new<F>(
state: &'a mut State, state: &'a mut State,
range: RangeInclusive<f32>, range: RangeInclusive<T>,
value: f32, value: T,
on_change: F, on_change: F,
) -> Self ) -> Self
where 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 { Slider {
state, state,
value: value.max(*range.start()).min(*range.end()), value,
range, range,
step: 1.0, step: T::from(1),
on_change: Box::new(on_change), on_change: Box::new(on_change),
on_release: None, on_release: None,
width: Length::Fill, width: Length::Fill,
@ -114,7 +130,7 @@ impl<'a, Message, Renderer: self::Renderer> Slider<'a, Message, Renderer> {
/// Sets the step size of the [`Slider`]. /// Sets the step size of the [`Slider`].
/// ///
/// [`Slider`]: struct.Slider.html /// [`Slider`]: struct.Slider.html
pub fn step(mut self, step: f32) -> Self { pub fn step(mut self, step: T) -> Self {
self.step = step; self.step = step;
self self
} }
@ -137,9 +153,10 @@ impl State {
} }
} }
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, T, Message, Renderer> Widget<Message, Renderer>
for Slider<'a, Message, Renderer> for Slider<'a, T, Message, Renderer>
where where
T: Copy + Into<f64> + num_traits::FromPrimitive,
Renderer: self::Renderer, Renderer: self::Renderer,
Message: Clone, Message: Clone,
{ {
@ -181,13 +198,20 @@ where
} else if cursor_position.x >= bounds.x + bounds.width { } else if cursor_position.x >= bounds.x + bounds.width {
messages.push((self.on_change)(*self.range.end())); messages.push((self.on_change)(*self.range.end()));
} else { } else {
let percent = (cursor_position.x - bounds.x) / bounds.width; let step: f64 = self.step.into();
let steps = (percent * (self.range.end() - self.range.start()) let start: f64 = (*self.range.start()).into();
/ self.step) let end: f64 = (*self.range.end()).into();
.round();
let value = steps * self.step + self.range.start(); 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)); messages.push((self.on_change)(value));
} }
}
}; };
match event { match event {
@ -224,11 +248,14 @@ where
layout: Layout<'_>, layout: Layout<'_>,
cursor_position: Point, cursor_position: Point,
) -> Renderer::Output { ) -> Renderer::Output {
let start = *self.range.start();
let end = *self.range.end();
renderer.draw( renderer.draw(
layout.bounds(), layout.bounds(),
cursor_position, cursor_position,
self.range.clone(), start.into() as f32..=end.into() as f32,
self.value, self.value.into() as f32,
self.state.is_dragging, self.state.is_dragging,
&self.style, &self.style,
) )
@ -281,14 +308,15 @@ pub trait Renderer: crate::Renderer {
) -> Self::Output; ) -> 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> for Element<'a, Message, Renderer>
where where
T: 'a + Copy + Into<f64> + num_traits::FromPrimitive,
Renderer: 'a + self::Renderer, Renderer: 'a + self::Renderer,
Message: 'a + Clone, Message: 'a + Clone,
{ {
fn from( fn from(
slider: Slider<'a, Message, Renderer>, slider: Slider<'a, T, Message, Renderer>,
) -> Element<'a, Message, Renderer> { ) -> Element<'a, Message, Renderer> {
Element::new(slider) Element::new(slider)
} }

View File

@ -13,4 +13,4 @@ pub use iced_native::slider::State;
/// values. /// values.
/// ///
/// This is an alias of an `iced_native` slider with an `iced_wgpu::Renderer`. /// 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>;