// Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 mod model; use std::borrow::Cow; pub use self::model::{Message, Model}; use crate::widget::{button, container, icon, row, text}; use crate::{theme, Element}; use apply::Apply; use iced::{ alignment::{Horizontal, Vertical}, Alignment, Length, }; use iced_core::{Border, Shadow}; pub struct SpinButton<'a, Message> { label: Cow<'a, str>, on_change: Box Message + 'static>, } 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) } 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), label: label.into(), } } #[must_use] pub fn into_element(self) -> Element<'a, Message> { let Self { on_change, label } = self; container( row::with_children(vec![ icon::from_name("list-remove-symbolic") .size(24) .apply(container) .width(Length::Fixed(32.0)) .height(Length::Fixed(32.0)) .align_x(Horizontal::Center) .align_y(Vertical::Center) .apply(button) .width(Length::Fixed(32.0)) .height(Length::Fixed(32.0)) .style(theme::Button::Text) .on_press(model::Message::Decrement) .into(), text(label) .vertical_alignment(Vertical::Center) .apply(container) .align_x(Horizontal::Center) .align_y(Vertical::Center) .into(), icon::from_name("list-add-symbolic") .size(24) .apply(container) .width(Length::Fixed(32.0)) .height(Length::Fixed(32.0)) .align_x(Horizontal::Center) .align_y(Vertical::Center) .apply(button) .width(Length::Fixed(32.0)) .height(Length::Fixed(32.0)) .style(theme::Button::Text) .on_press(model::Message::Increment) .into(), ]) .width(Length::Shrink) .height(Length::Fixed(32.0)) .spacing(4.0) .align_items(Alignment::Center), ) .align_y(Vertical::Center) .width(Length::Shrink) .height(Length::Fixed(32.0)) .style(theme::Container::custom(container_style)) .apply(Element::from) .map(on_change) } } impl<'a, Message: 'static> From> for Element<'a, Message> { fn from(spin_button: SpinButton<'a, Message>) -> Self { spin_button.into_element() } } #[allow(clippy::trivially_copy_pass_by_ref)] fn container_style(theme: &crate::Theme) -> iced_style::container::Appearance { let basic = &theme.cosmic(); let mut neutral_10 = basic.palette.neutral_10; neutral_10.alpha = 0.1; let accent = &basic.accent; let corners = &basic.corner_radii; iced_style::container::Appearance { icon_color: Some(basic.palette.neutral_10.into()), text_color: Some(basic.palette.neutral_10.into()), background: None, border: Border { radius: corners.radius_s.into(), width: 0.0, color: accent.base.into(), }, shadow: Shadow::default(), } }