Merge pull request #407 from hecrj/feature/generic-slider
Make `Slider` value type generic
This commit is contained in:
commit
d19c02035f
@ -269,7 +269,7 @@ struct ColorPicker<C: ColorSpace> {
|
|||||||
|
|
||||||
trait ColorSpace: Sized {
|
trait ColorSpace: Sized {
|
||||||
const LABEL: &'static str;
|
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;
|
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 [s1, s2, s3] = &mut self.sliders;
|
||||||
let [cr1, cr2, cr3] = C::COMPONENT_RANGES;
|
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()
|
Row::new()
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.align_items(Align::Center)
|
.align_items(Align::Center)
|
||||||
.push(Text::new(C::LABEL).width(Length::Units(50)))
|
.push(Text::new(C::LABEL).width(Length::Units(50)))
|
||||||
.push(
|
.push(slider(s1, cr1, c1, move |v| C::new(v, c2, c3)))
|
||||||
Slider::new(s1, cr1, c1, move |v| C::new(v, c2, c3)).step(0.01),
|
.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(
|
|
||||||
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(
|
.push(
|
||||||
Text::new(color.to_string())
|
Text::new(color.to_string())
|
||||||
.width(Length::Units(185))
|
.width(Length::Units(185))
|
||||||
@ -308,7 +314,7 @@ impl<C: 'static + ColorSpace + Copy> ColorPicker<C> {
|
|||||||
|
|
||||||
impl ColorSpace for Color {
|
impl ColorSpace for Color {
|
||||||
const LABEL: &'static str = "RGB";
|
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];
|
[0.0..=1.0, 0.0..=1.0, 0.0..=1.0];
|
||||||
|
|
||||||
fn new(r: f32, g: f32, b: f32) -> Self {
|
fn new(r: f32, g: f32, b: f32) -> Self {
|
||||||
@ -331,7 +337,7 @@ impl ColorSpace for Color {
|
|||||||
|
|
||||||
impl ColorSpace for palette::Hsl {
|
impl ColorSpace for palette::Hsl {
|
||||||
const LABEL: &'static str = "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];
|
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
|
||||||
|
|
||||||
fn new(hue: f32, saturation: f32, lightness: f32) -> Self {
|
fn new(hue: f32, saturation: f32, lightness: f32) -> Self {
|
||||||
@ -362,7 +368,7 @@ impl ColorSpace for palette::Hsl {
|
|||||||
|
|
||||||
impl ColorSpace for palette::Hsv {
|
impl ColorSpace for palette::Hsv {
|
||||||
const LABEL: &'static str = "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];
|
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
|
||||||
|
|
||||||
fn new(hue: f32, saturation: f32, value: f32) -> Self {
|
fn new(hue: f32, saturation: f32, value: f32) -> Self {
|
||||||
@ -385,7 +391,7 @@ impl ColorSpace for palette::Hsv {
|
|||||||
|
|
||||||
impl ColorSpace for palette::Hwb {
|
impl ColorSpace for palette::Hwb {
|
||||||
const LABEL: &'static str = "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];
|
[0.0..=360.0, 0.0..=1.0, 0.0..=1.0];
|
||||||
|
|
||||||
fn new(hue: f32, whiteness: f32, blackness: f32) -> Self {
|
fn new(hue: f32, whiteness: f32, blackness: f32) -> Self {
|
||||||
@ -416,7 +422,7 @@ impl ColorSpace for palette::Hwb {
|
|||||||
|
|
||||||
impl ColorSpace for palette::Lab {
|
impl ColorSpace for palette::Lab {
|
||||||
const LABEL: &'static str = "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];
|
[0.0..=100.0, -128.0..=127.0, -128.0..=127.0];
|
||||||
|
|
||||||
fn new(l: f32, a: f32, b: f32) -> Self {
|
fn new(l: f32, a: f32, b: f32) -> Self {
|
||||||
@ -434,7 +440,7 @@ impl ColorSpace for palette::Lab {
|
|||||||
|
|
||||||
impl ColorSpace for palette::Lch {
|
impl ColorSpace for palette::Lch {
|
||||||
const LABEL: &'static str = "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];
|
[0.0..=100.0, 0.0..=128.0, 0.0..=360.0];
|
||||||
|
|
||||||
fn new(l: f32, chroma: f32, hue: f32) -> Self {
|
fn new(l: f32, chroma: f32, hue: f32) -> Self {
|
||||||
|
@ -36,12 +36,15 @@ impl Sandbox for Progress {
|
|||||||
Column::new()
|
Column::new()
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.push(ProgressBar::new(0.0..=100.0, self.value))
|
.push(ProgressBar::new(0.0..=100.0, self.value))
|
||||||
.push(Slider::new(
|
.push(
|
||||||
|
Slider::new(
|
||||||
&mut self.progress_bar_slider,
|
&mut self.progress_bar_slider,
|
||||||
0.0..=100.0,
|
0.0..=100.0,
|
||||||
self.value,
|
self.value,
|
||||||
Message::SliderChanged,
|
Message::SliderChanged,
|
||||||
))
|
)
|
||||||
|
.step(0.01),
|
||||||
|
)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ enum Step {
|
|||||||
Welcome,
|
Welcome,
|
||||||
Slider {
|
Slider {
|
||||||
state: slider::State,
|
state: slider::State,
|
||||||
value: u16,
|
value: u8,
|
||||||
},
|
},
|
||||||
RowsAndColumns {
|
RowsAndColumns {
|
||||||
layout: Layout,
|
layout: Layout,
|
||||||
@ -222,13 +222,13 @@ enum Step {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum StepMessage {
|
pub enum StepMessage {
|
||||||
SliderChanged(f32),
|
SliderChanged(u8),
|
||||||
LayoutChanged(Layout),
|
LayoutChanged(Layout),
|
||||||
SpacingChanged(f32),
|
SpacingChanged(u16),
|
||||||
TextSizeChanged(f32),
|
TextSizeChanged(u16),
|
||||||
TextColorChanged(Color),
|
TextColorChanged(Color),
|
||||||
LanguageSelected(Language),
|
LanguageSelected(Language),
|
||||||
ImageWidthChanged(f32),
|
ImageWidthChanged(u16),
|
||||||
InputChanged(String),
|
InputChanged(String),
|
||||||
ToggleSecureInput(bool),
|
ToggleSecureInput(bool),
|
||||||
DebugToggled(bool),
|
DebugToggled(bool),
|
||||||
@ -249,12 +249,12 @@ impl<'a> Step {
|
|||||||
}
|
}
|
||||||
StepMessage::SliderChanged(new_value) => {
|
StepMessage::SliderChanged(new_value) => {
|
||||||
if let Step::Slider { value, .. } = self {
|
if let Step::Slider { value, .. } = self {
|
||||||
*value = new_value.round() as u16;
|
*value = new_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StepMessage::TextSizeChanged(new_size) => {
|
StepMessage::TextSizeChanged(new_size) => {
|
||||||
if let Step::Text { size, .. } = self {
|
if let Step::Text { size, .. } = self {
|
||||||
*size = new_size.round() as u16;
|
*size = new_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StepMessage::TextColorChanged(new_color) => {
|
StepMessage::TextColorChanged(new_color) => {
|
||||||
@ -269,12 +269,12 @@ impl<'a> Step {
|
|||||||
}
|
}
|
||||||
StepMessage::SpacingChanged(new_spacing) => {
|
StepMessage::SpacingChanged(new_spacing) => {
|
||||||
if let Step::RowsAndColumns { spacing, .. } = self {
|
if let Step::RowsAndColumns { spacing, .. } = self {
|
||||||
*spacing = new_spacing.round() as u16;
|
*spacing = new_spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StepMessage::ImageWidthChanged(new_width) => {
|
StepMessage::ImageWidthChanged(new_width) => {
|
||||||
if let Step::Image { width, .. } = self {
|
if let Step::Image { width, .. } = self {
|
||||||
*width = new_width.round() as u16;
|
*width = new_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StepMessage::InputChanged(new_value) => {
|
StepMessage::InputChanged(new_value) => {
|
||||||
@ -384,7 +384,7 @@ impl<'a> Step {
|
|||||||
|
|
||||||
fn slider(
|
fn slider(
|
||||||
state: &'a mut slider::State,
|
state: &'a mut slider::State,
|
||||||
value: u16,
|
value: u8,
|
||||||
) -> Column<'a, StepMessage> {
|
) -> Column<'a, StepMessage> {
|
||||||
Self::container("Slider")
|
Self::container("Slider")
|
||||||
.push(Text::new(
|
.push(Text::new(
|
||||||
@ -397,8 +397,8 @@ impl<'a> Step {
|
|||||||
))
|
))
|
||||||
.push(Slider::new(
|
.push(Slider::new(
|
||||||
state,
|
state,
|
||||||
0.0..=100.0,
|
0..=100,
|
||||||
value as f32,
|
value,
|
||||||
StepMessage::SliderChanged,
|
StepMessage::SliderChanged,
|
||||||
))
|
))
|
||||||
.push(
|
.push(
|
||||||
@ -444,8 +444,8 @@ impl<'a> Step {
|
|||||||
.spacing(10)
|
.spacing(10)
|
||||||
.push(Slider::new(
|
.push(Slider::new(
|
||||||
spacing_slider,
|
spacing_slider,
|
||||||
0.0..=80.0,
|
0..=80,
|
||||||
spacing as f32,
|
spacing,
|
||||||
StepMessage::SpacingChanged,
|
StepMessage::SpacingChanged,
|
||||||
))
|
))
|
||||||
.push(
|
.push(
|
||||||
@ -486,39 +486,25 @@ impl<'a> Step {
|
|||||||
)
|
)
|
||||||
.push(Slider::new(
|
.push(Slider::new(
|
||||||
size_slider,
|
size_slider,
|
||||||
10.0..=70.0,
|
10..=70,
|
||||||
size as f32,
|
size,
|
||||||
StepMessage::TextSizeChanged,
|
StepMessage::TextSizeChanged,
|
||||||
));
|
));
|
||||||
|
|
||||||
let [red, green, blue] = color_sliders;
|
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()
|
let color_section = Column::new()
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.spacing(20)
|
.spacing(20)
|
||||||
.push(Text::new("And its color:"))
|
.push(Text::new("And its color:"))
|
||||||
.push(Text::new(&format!("{:?}", color)).color(color))
|
.push(Text::new(&format!("{:?}", color)).color(color))
|
||||||
.push(
|
.push(color_sliders);
|
||||||
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),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Self::container("Text")
|
Self::container("Text")
|
||||||
.push(Text::new(
|
.push(Text::new(
|
||||||
@ -568,8 +554,8 @@ impl<'a> Step {
|
|||||||
.push(ferris(width))
|
.push(ferris(width))
|
||||||
.push(Slider::new(
|
.push(Slider::new(
|
||||||
slider,
|
slider,
|
||||||
100.0..=500.0,
|
100..=500,
|
||||||
width as f32,
|
width,
|
||||||
StepMessage::ImageWidthChanged,
|
StepMessage::ImageWidthChanged,
|
||||||
))
|
))
|
||||||
.push(
|
.push(
|
||||||
@ -715,6 +701,17 @@ fn button<'a, Message>(
|
|||||||
.min_width(100)
|
.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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Language {
|
pub enum Language {
|
||||||
Rust,
|
Rust,
|
||||||
|
@ -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>;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -16,7 +16,8 @@ use std::{hash::Hash, ops::RangeInclusive};
|
|||||||
///
|
///
|
||||||
/// A [`Slider`] will try to fill the horizontal space of its container.
|
/// 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
|
/// [`Slider`]: struct.Slider.html
|
||||||
///
|
///
|
||||||
@ -24,7 +25,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 +38,22 @@ use std::{hash::Hash, ops::RangeInclusive};
|
|||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
#[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 +68,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 +131,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 +154,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 +199,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 = self.step.into();
|
||||||
let steps = (percent * (self.range.end() - self.range.start())
|
let start = (*self.range.start()).into();
|
||||||
/ self.step)
|
let end = (*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 +249,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 +309,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)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ dodrio = "0.1.0"
|
|||||||
wasm-bindgen = "0.2.51"
|
wasm-bindgen = "0.2.51"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
url = "2.0"
|
url = "2.0"
|
||||||
|
num-traits = "0.2"
|
||||||
|
|
||||||
[dependencies.iced_core]
|
[dependencies.iced_core]
|
||||||
version = "0.2"
|
version = "0.2"
|
||||||
|
@ -16,7 +16,8 @@ use std::{ops::RangeInclusive, rc::Rc};
|
|||||||
///
|
///
|
||||||
/// A [`Slider`] will try to fill the horizontal space of its container.
|
/// 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
|
/// [`Slider`]: struct.Slider.html
|
||||||
///
|
///
|
||||||
@ -36,17 +37,20 @@ use std::{ops::RangeInclusive, rc::Rc};
|
|||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Slider<'a, Message> {
|
pub struct Slider<'a, T, Message> {
|
||||||
_state: &'a mut State,
|
_state: &'a mut State,
|
||||||
range: RangeInclusive<f32>,
|
range: RangeInclusive<T>,
|
||||||
step: f32,
|
step: T,
|
||||||
value: f32,
|
value: T,
|
||||||
on_change: Rc<Box<dyn Fn(f32) -> Message>>,
|
on_change: Rc<Box<dyn Fn(T) -> Message>>,
|
||||||
width: Length,
|
width: Length,
|
||||||
style: Box<dyn StyleSheet>,
|
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`].
|
/// Creates a new [`Slider`].
|
||||||
///
|
///
|
||||||
/// It expects:
|
/// It expects:
|
||||||
@ -61,18 +65,30 @@ impl<'a, Message> Slider<'a, Message> {
|
|||||||
/// [`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,
|
_state: state,
|
||||||
value: value.max(*range.start()).min(*range.end()),
|
value,
|
||||||
range,
|
range,
|
||||||
step: 1.0,
|
step: T::from(1),
|
||||||
on_change: Rc::new(Box::new(on_change)),
|
on_change: Rc::new(Box::new(on_change)),
|
||||||
width: Length::Fill,
|
width: Length::Fill,
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
@ -98,14 +114,15 @@ impl<'a, Message> Slider<'a, Message> {
|
|||||||
/// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message> Widget<Message> for Slider<'a, Message>
|
impl<'a, T, Message> Widget<Message> for Slider<'a, T, Message>
|
||||||
where
|
where
|
||||||
|
T: 'static + Copy + Into<f64> + num_traits::FromPrimitive,
|
||||||
Message: 'static,
|
Message: 'static,
|
||||||
{
|
{
|
||||||
fn node<'b>(
|
fn node<'b>(
|
||||||
@ -119,10 +136,10 @@ where
|
|||||||
|
|
||||||
let (start, end) = self.range.clone().into_inner();
|
let (start, end) = self.range.clone().into_inner();
|
||||||
|
|
||||||
let min = bumpalo::format!(in bump, "{}", start);
|
let min = bumpalo::format!(in bump, "{}", start.into());
|
||||||
let max = bumpalo::format!(in bump, "{}", end);
|
let max = bumpalo::format!(in bump, "{}", end.into());
|
||||||
let value = bumpalo::format!(in bump, "{}", self.value);
|
let value = bumpalo::format!(in bump, "{}", self.value.into());
|
||||||
let step = bumpalo::format!(in bump, "{}", self.step);
|
let step = bumpalo::format!(in bump, "{}", self.step.into());
|
||||||
|
|
||||||
let on_change = self.on_change.clone();
|
let on_change = self.on_change.clone();
|
||||||
let event_bus = bus.clone();
|
let event_bus = bus.clone();
|
||||||
@ -143,19 +160,22 @@ where
|
|||||||
Some(slider) => slider,
|
Some(slider) => slider,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(value) = slider.value().parse::<f32>() {
|
if let Ok(value) = slider.value().parse::<f64>() {
|
||||||
|
if let Some(value) = T::from_f64(value) {
|
||||||
event_bus.publish(on_change(value));
|
event_bus.publish(on_change(value));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.finish()
|
.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
|
where
|
||||||
|
T: 'static + Copy + Into<f64> + num_traits::FromPrimitive,
|
||||||
Message: 'static,
|
Message: 'static,
|
||||||
{
|
{
|
||||||
fn from(slider: Slider<'a, Message>) -> Element<'a, Message> {
|
fn from(slider: Slider<'a, T, Message>) -> Element<'a, Message> {
|
||||||
Element::new(slider)
|
Element::new(slider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>;
|
||||||
|
Loading…
Reference in New Issue
Block a user