diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index ac85badb..bf51549e 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -2,7 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 mod model; -pub use self::model::SpinButtonModel; +use std::borrow::Cow; + +pub use self::model::{Message, Model}; use crate::widget::icon; use crate::{theme, Element}; @@ -12,95 +14,83 @@ use iced::{ widget::{button, container, row, text}, Alignment, Background, Length, }; -use std::hash::Hash; -pub struct SpinButton { - value: T, - on_change: Box Message + 'static>, +pub struct SpinButton<'a, Message> { + label: Cow<'a, str>, + on_change: Box Message + 'static>, } -/// A message emitted by the [`SpinButton`] widget. -#[derive(Clone, Copy, Debug, Hash)] -pub enum SpinMessage { - Increment, - Decrement, +pub fn spin_button<'a, Message: 'static>( + label: impl Into>, + on_change: impl Fn(model::Message) -> Message + 'static, +) -> SpinButton<'a, Message> { + SpinButton::new(label, on_change) } -pub fn spin_button( - model: &SpinButtonModel, - on_change: impl Fn(SpinMessage) -> Message + 'static, -) -> SpinButton { - SpinButton::new(model.value, on_change) -} - -impl SpinButton { - pub fn new(value: T, on_change: impl Fn(SpinMessage) -> Message + 'static) -> Self { +impl<'a, Message: 'static> SpinButton<'a, Message> { + pub fn new( + label: impl Into>, + on_change: impl Fn(model::Message) -> Message + 'static, + ) -> Self { Self { on_change: Box::from(on_change), - value, + label: label.into(), } } - pub fn into_element(self) -> Element<'static, Message> { - let Self { on_change, value } = self; - - Element::from(iced_lazy::lazy( - (value, crate::settings::default_icon_theme()), - move || -> Element<'static, SpinMessage> { - container( - row![ - icon("list-remove-symbolic", 24) - .style(theme::Svg::Symbolic) - .apply(container) - .width(Length::Fill) - .height(Length::Fill) - .align_x(Horizontal::Center) - .align_y(Vertical::Center) - .apply(button) - .width(Length::Fill) - .height(Length::Fill) - .style(theme::Button::Text) - .on_press(SpinMessage::Decrement), - text(value) - .vertical_alignment(Vertical::Center) - .apply(container) - .width(Length::Fill) - .height(Length::Fill) - .align_x(Horizontal::Center) - .align_y(Vertical::Center), - icon("list-add-symbolic", 24) - .style(theme::Svg::Symbolic) - .apply(container) - .width(Length::Fill) - .height(Length::Fill) - .align_x(Horizontal::Center) - .align_y(Vertical::Center) - .apply(button) - .width(Length::Fill) - .height(Length::Fill) - .style(theme::Button::Text) - .on_press(SpinMessage::Increment), - ] + #[must_use] + pub fn into_element(self) -> Element<'a, Message> { + let Self { on_change, label } = self; + container( + row![ + icon("list-remove-symbolic", 24) + .style(theme::Svg::Symbolic) + .apply(container) .width(Length::Fill) - .height(Length::Units(32)) - .align_items(Alignment::Center), - ) - .padding([4, 4]) - .align_y(Vertical::Center) - .width(Length::Units(95)) - .height(Length::Units(32)) - .style(theme::Container::Custom(container_style)) - .into() - }, - )) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .apply(button) + .width(Length::Fill) + .height(Length::Fill) + .style(theme::Button::Text) + .on_press(model::Message::Decrement), + text(label) + .vertical_alignment(Vertical::Center) + .apply(container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center), + icon("list-add-symbolic", 24) + .style(theme::Svg::Symbolic) + .apply(container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .apply(button) + .width(Length::Fill) + .height(Length::Fill) + .style(theme::Button::Text) + .on_press(model::Message::Increment), + ] + .width(Length::Fill) + .height(Length::Units(32)) + .align_items(Alignment::Center), + ) + .padding([4, 4]) + .align_y(Vertical::Center) + .width(Length::Units(95)) + .height(Length::Units(32)) + .style(theme::Container::Custom(container_style)) + .apply(Element::from) .map(on_change) } } -impl<'a, T: 'static + Copy + Hash + ToString, Message: 'static> From> - for Element<'a, Message> -{ - fn from(spin_button: SpinButton) -> Self { +impl<'a, Message: 'static> From> for Element<'a, Message> { + fn from(spin_button: SpinButton<'a, Message>) -> Self { spin_button.into_element() } } diff --git a/src/widget/spin_button/model.rs b/src/widget/spin_button/model.rs index 06003178..be281636 100644 --- a/src/widget/spin_button/model.rs +++ b/src/widget/spin_button/model.rs @@ -1,48 +1,51 @@ // Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 -use super::{SpinButton, SpinMessage}; -use crate::Element; use derive_setters::Setters; +use fraction::{Bounded, Decimal}; use std::hash::Hash; use std::ops::{Add, Sub}; +/// A message emitted by the [`SpinButton`] widget. +#[derive(Clone, Copy, Debug, Hash)] +pub enum Message { + Increment, + Decrement, +} + #[derive(Setters)] -pub struct SpinButtonModel { +pub struct Model { /// The current value of the spin button. + #[setters(into)] pub value: T, /// The amount to increment the value. + #[setters(into)] pub step: T, /// The minimum value permitted. + #[setters(into)] pub min: T, /// The maximum value permitted. + #[setters(into)] pub max: T, } -impl SpinButtonModel +impl Model where - T: Copy + Hash + ToString + Sub + Add + Ord, + T: Copy + Hash + Sub + Add + Ord, { - pub fn view( - &self, - on_change: impl Fn(SpinMessage) -> Message + 'static, - ) -> Element<'static, Message> { - SpinButton::new(self.value, on_change).into_element() - } - - pub fn update(&mut self, message: SpinMessage) { + pub fn update(&mut self, message: Message) { self.value = match message { - SpinMessage::Increment => { + Message::Increment => { std::cmp::min(std::cmp::max(self.value + self.step, self.min), self.max) } - SpinMessage::Decrement => { + Message::Decrement => { std::cmp::max(std::cmp::min(self.value - self.step, self.max), self.min) } } } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -53,7 +56,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -64,7 +67,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -75,7 +78,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -86,7 +89,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -97,7 +100,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -108,7 +111,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -119,7 +122,7 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { value: 0, @@ -130,24 +133,13 @@ impl Default for SpinButtonModel { } } -impl Default for SpinButtonModel { +impl Default for Model { fn default() -> Self { Self { - value: 0.0, - step: 1.0, - min: f32::MIN, - max: f32::MAX, - } - } -} - -impl Default for SpinButtonModel { - fn default() -> Self { - Self { - value: 0.0, - step: 1.0, - min: f64::MIN, - max: f64::MAX, + value: Decimal::from(0.0), + step: Decimal::from(0.0), + min: Decimal::min_positive_value(), + max: Decimal::max_value(), } } }