From 5c29c530a5bb9fe69262b19e9e47f17fda11269c Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Thu, 14 Nov 2024 14:33:22 -0800 Subject: [PATCH 01/16] Created vertical spin button and example --- examples/vertical-spin-button/Cargo.toml | 16 +++ examples/vertical-spin-button/src/main.rs | 133 ++++++++++++++++++++++ src/widget/mod.rs | 4 + src/widget/vertical_spin_button.rs | 116 +++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 examples/vertical-spin-button/Cargo.toml create mode 100644 examples/vertical-spin-button/src/main.rs create mode 100644 src/widget/vertical_spin_button.rs diff --git a/examples/vertical-spin-button/Cargo.toml b/examples/vertical-spin-button/Cargo.toml new file mode 100644 index 00000000000..65c2260623a --- /dev/null +++ b/examples/vertical-spin-button/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "vertical-spin-button" +version = "0.1.0" +edition = "2021" + +[features] +default = ["xdg-portal"] +rfd = ["libcosmic/rfd"] +xdg-portal = ["libcosmic/xdg-portal"] + +[dependencies] + +[dependencies.libcosmic] +features = ["debug", "winit", "wayland", "desktop", "tokio"] +path ="../.." +default-features = false \ No newline at end of file diff --git a/examples/vertical-spin-button/src/main.rs b/examples/vertical-spin-button/src/main.rs new file mode 100644 index 00000000000..b3b09349d24 --- /dev/null +++ b/examples/vertical-spin-button/src/main.rs @@ -0,0 +1,133 @@ +use cosmic::widget::{button, container, text, vertical_spinner}; +use cosmic::{ + app::{Core, Task}, + iced::{ + alignment::{Horizontal, Vertical}, + widget::{column, row, vertical_space}, + Alignment, Size, + }, + Application, Element, +}; + +pub struct VertSpinnerApp { + core: Core, + hours: i32, + mins: i16, + secs: i8, + time_msg: String, +} + +#[derive(Debug, Clone)] +pub enum VertSpinnerMessages { + UpdateHours(i32), + UpdateMins(i16), + UpdateSecs(i8), + UpdateTimeMessage, +} + +impl Application for VertSpinnerApp { + type Executor = cosmic::executor::Default; + type Flags = (); + type Message = VertSpinnerMessages; + + const APP_ID: &'static str = "com.system76.VertSpinnerExample"; + + fn core(&self) -> &Core { + &self.core + } + + fn core_mut(&mut self) -> &mut Core { + &mut self.core + } + + fn init(core: Core, _flags: Self::Flags) -> (Self, Task) { + ( + Self { + core, + hours: 0, + mins: 0, + secs: 0, + time_msg: String::new(), + }, + Task::none(), + ) + } + + fn update(&mut self, message: Self::Message) -> Task { + match message { + VertSpinnerMessages::UpdateHours(hours) => self.hours = hours, + VertSpinnerMessages::UpdateMins(mins) => self.mins = mins, + VertSpinnerMessages::UpdateSecs(secs) => self.secs = secs, + VertSpinnerMessages::UpdateTimeMessage => { + self.time_msg = format!( + "{}:{}:{}", + self.hours, + // Add a zero in front of a single digit number + if self.mins < 10 { + format!("0{}", self.mins) + } else { + self.mins.to_string() + }, + // Add a zero in front of a single digit number + if self.secs < 10 { + format!("0{}", self.secs) + } else { + self.secs.to_string() + } + ) + } + } + + Task::none() + } + + fn view(&self) -> Element { + let spinner_row = row![ + vertical_spinner( + "Hours", + 1, + self.hours, + 0, + 12, + VertSpinnerMessages::UpdateHours + ), + vertical_spinner( + "Minutes", + 1, + self.mins, + 0, + 59, + VertSpinnerMessages::UpdateMins + ), + vertical_spinner( + "Seconds", + 1, + self.secs, + 0, + 59, + VertSpinnerMessages::UpdateSecs + ), + ] + .align_y(Vertical::Center); + + let final_col = column![ + spinner_row, + button::standard("Update Time").on_press(VertSpinnerMessages::UpdateTimeMessage), + vertical_space().height(10), + text(self.time_msg.clone()), + ] + .align_x(Alignment::Center); + + container(final_col) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() + } +} + +fn main() -> Result<(), Box> { + let settings = cosmic::app::Settings::default().size(Size::new(260., 240.)); + cosmic::app::run::(settings, ())?; + + Ok(()) +} diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 52acf06d44c..703f88e1992 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -358,6 +358,10 @@ pub mod tooltip { } } +pub mod vertical_spin_button; +#[doc(inline)] +pub use vertical_spin_button::*; + pub mod warning; #[doc(inline)] pub use warning::*; diff --git a/src/widget/vertical_spin_button.rs b/src/widget/vertical_spin_button.rs new file mode 100644 index 00000000000..768da2c3dae --- /dev/null +++ b/src/widget/vertical_spin_button.rs @@ -0,0 +1,116 @@ +// Spinner for integer selection +// Author: Bryan Hyland + +use crate::iced::alignment::Horizontal; +use crate::iced::Alignment; +use crate::widget::{button, column, icon, row, text}; +use crate::Element; +use std::fmt::Display; +use std::marker::PhantomData; +use std::ops::{Add, Sub}; + +/// Spinner is the state/model of the vertical spinner widget. +/// Restricts T to Add, Sub, Eq, Ord, Display, and Copy so that +/// T can only be numerical values. +pub struct VerticalSpinner<'a, T, M> +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + label: String, + step: T, + value: T, + min: T, + max: T, + on_select: Box M>, + phantom_data: PhantomData<&'a M>, +} + +impl<'a, T, M> VerticalSpinner<'a, T, M> +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + /// Creates a new vertical spinner widget + pub fn new( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + on_select: impl Fn(T) -> M + 'static, + ) -> Self { + VerticalSpinner { + label: label.into(), + step, + value, + min, + max, + on_select: Box::new(on_select), + phantom_data: PhantomData, + } + } +} + +pub fn vertical_spinner( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + on_select: impl Fn(T) -> M + 'static, +) -> VerticalSpinner<'static, T, M> +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + VerticalSpinner::new(label, step, value, min, max, on_select) +} + +fn increment(step: T, val: T, min: T, max: T) -> T +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + std::cmp::min(std::cmp::max(val + step, min), max) +} + +fn decrement(step: T, val: T, min: T, max: T) -> T +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + std::cmp::max(std::cmp::min(val - step, max), min) +} + +impl<'a, T, Message> From> for Element<'a, Message> +where + Message: Clone + 'static, + T: Add + Sub + Eq + Ord + Display + Copy, +{ + fn from(this: VerticalSpinner) -> Self { + let val_text = text(format!("{}", this.value)).size(14); + let spinner_container = column::with_capacity(3) + .push( + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((this.on_select)(increment::( + this.step, this.value, this.min, this.max, + ))), + ) + .push(val_text) + .push( + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((this.on_select)(decrement::( + this.step, this.value, this.min, this.max, + ))), + ) + .align_x(Horizontal::Center); + + let content_list = column::with_children(vec![ + row::with_capacity(1).push(text(this.label)).into(), + row::with_children(vec![Element::from(spinner_container)]).into(), + ]) + .width(75) + .padding([8, 0]) + .align_x(Alignment::Center); + + Self::new(content_list) + } +} From 3cf473c26bcbb519f71936d6e048beb87e20ca7c Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Fri, 15 Nov 2024 19:43:22 -0800 Subject: [PATCH 02/16] Moved the vertical spin button widget into spin button's mod.rs --- examples/vertical-spin-button/src/main.rs | 8 +- src/widget/mod.rs | 4 - src/widget/spin_button/mod.rs | 114 ++++++++++++++++++++- src/widget/vertical_spin_button.rs | 116 ---------------------- 4 files changed, 117 insertions(+), 125 deletions(-) delete mode 100644 src/widget/vertical_spin_button.rs diff --git a/examples/vertical-spin-button/src/main.rs b/examples/vertical-spin-button/src/main.rs index b3b09349d24..5b0e02ff582 100644 --- a/examples/vertical-spin-button/src/main.rs +++ b/examples/vertical-spin-button/src/main.rs @@ -1,4 +1,4 @@ -use cosmic::widget::{button, container, text, vertical_spinner}; +use cosmic::widget::{button, container, text, spin_button::vertical_spin_button}; use cosmic::{ app::{Core, Task}, iced::{ @@ -83,7 +83,7 @@ impl Application for VertSpinnerApp { fn view(&self) -> Element { let spinner_row = row![ - vertical_spinner( + vertical_spin_button( "Hours", 1, self.hours, @@ -91,7 +91,7 @@ impl Application for VertSpinnerApp { 12, VertSpinnerMessages::UpdateHours ), - vertical_spinner( + vertical_spin_button( "Minutes", 1, self.mins, @@ -99,7 +99,7 @@ impl Application for VertSpinnerApp { 59, VertSpinnerMessages::UpdateMins ), - vertical_spinner( + vertical_spin_button( "Seconds", 1, self.secs, diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 703f88e1992..52acf06d44c 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -358,10 +358,6 @@ pub mod tooltip { } } -pub mod vertical_spin_button; -#[doc(inline)] -pub use vertical_spin_button::*; - pub mod warning; #[doc(inline)] pub use warning::*; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index 9da2939496c..eb3005f8244 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -8,10 +8,14 @@ use std::borrow::Cow; pub use self::model::{Message, Model}; -use crate::widget::{button, container, icon, row, text}; +use crate::widget::{button, column, container, icon, row, text}; use crate::{theme, Element}; +use std::fmt::Display; +use std::marker::PhantomData; +use std::ops::{Add, Sub}; use apply::Apply; use iced::{Alignment, Length}; +use iced::alignment::Horizontal; use iced_core::{Border, Shadow}; pub struct SpinButton<'a, Message> { @@ -106,3 +110,111 @@ fn container_style(theme: &crate::Theme) -> iced_widget::container::Style { shadow: Shadow::default(), } } + + + +/// VerticalSpinButton is the state/model of the vertical spin button widget. +/// Restricts T to Add, Sub, Eq, Ord, Display, and Copy so that +/// T can only be numerical values. +pub struct VerticalSpinButton<'a, T, M> +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + label: String, + step: T, + value: T, + min: T, + max: T, + on_select: Box M>, + phantom_data: PhantomData<&'a M>, +} + +impl<'a, T, M> VerticalSpinButton<'a, T, M> +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + /// Creates a new vertical spin button widget + pub fn new( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + on_select: impl Fn(T) -> M + 'static, + ) -> Self { + VerticalSpinButton { + label: label.into(), + step, + value, + min, + max, + on_select: Box::new(on_select), + phantom_data: PhantomData, + } + } +} + +pub fn vertical_spin_button( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + on_select: impl Fn(T) -> M + 'static, +) -> VerticalSpinButton<'static, T, M> +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + VerticalSpinButton::new(label, step, value, min, max, on_select) +} + +fn increment(step: T, val: T, min: T, max: T) -> T +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + std::cmp::min(std::cmp::max(val + step, min), max) +} + +fn decrement(step: T, val: T, min: T, max: T) -> T +where + T: Add + Sub + Eq + Ord + Display + Copy, +{ + std::cmp::max(std::cmp::min(val - step, max), min) +} + +impl<'a, T, Message> From> for Element<'a, Message> +where + Message: Clone + 'static, + T: Add + Sub + Eq + Ord + Display + Copy, +{ + fn from(this: VerticalSpinButton) -> Self { + let val_text = text(format!("{}", this.value)).size(14); + let spinner_container = column::with_capacity(3) + .push( + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((this.on_select)(increment::( + this.step, this.value, this.min, this.max, + ))), + ) + .push(val_text) + .push( + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((this.on_select)(decrement::( + this.step, this.value, this.min, this.max, + ))), + ) + .align_x(Horizontal::Center); + + let content_list = column::with_children(vec![ + row::with_capacity(1).push(text(this.label)).into(), + row::with_children(vec![Element::from(spinner_container)]).into(), + ]) + .width(75) + .padding([8, 0]) + .align_x(Alignment::Center); + + Self::new(content_list) + } +} diff --git a/src/widget/vertical_spin_button.rs b/src/widget/vertical_spin_button.rs deleted file mode 100644 index 768da2c3dae..00000000000 --- a/src/widget/vertical_spin_button.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Spinner for integer selection -// Author: Bryan Hyland - -use crate::iced::alignment::Horizontal; -use crate::iced::Alignment; -use crate::widget::{button, column, icon, row, text}; -use crate::Element; -use std::fmt::Display; -use std::marker::PhantomData; -use std::ops::{Add, Sub}; - -/// Spinner is the state/model of the vertical spinner widget. -/// Restricts T to Add, Sub, Eq, Ord, Display, and Copy so that -/// T can only be numerical values. -pub struct VerticalSpinner<'a, T, M> -where - T: Add + Sub + Eq + Ord + Display + Copy, -{ - label: String, - step: T, - value: T, - min: T, - max: T, - on_select: Box M>, - phantom_data: PhantomData<&'a M>, -} - -impl<'a, T, M> VerticalSpinner<'a, T, M> -where - T: Add + Sub + Eq + Ord + Display + Copy, -{ - /// Creates a new vertical spinner widget - pub fn new( - label: impl Into, - step: T, - value: T, - min: T, - max: T, - on_select: impl Fn(T) -> M + 'static, - ) -> Self { - VerticalSpinner { - label: label.into(), - step, - value, - min, - max, - on_select: Box::new(on_select), - phantom_data: PhantomData, - } - } -} - -pub fn vertical_spinner( - label: impl Into, - step: T, - value: T, - min: T, - max: T, - on_select: impl Fn(T) -> M + 'static, -) -> VerticalSpinner<'static, T, M> -where - T: Add + Sub + Eq + Ord + Display + Copy, -{ - VerticalSpinner::new(label, step, value, min, max, on_select) -} - -fn increment(step: T, val: T, min: T, max: T) -> T -where - T: Add + Sub + Eq + Ord + Display + Copy, -{ - std::cmp::min(std::cmp::max(val + step, min), max) -} - -fn decrement(step: T, val: T, min: T, max: T) -> T -where - T: Add + Sub + Eq + Ord + Display + Copy, -{ - std::cmp::max(std::cmp::min(val - step, max), min) -} - -impl<'a, T, Message> From> for Element<'a, Message> -where - Message: Clone + 'static, - T: Add + Sub + Eq + Ord + Display + Copy, -{ - fn from(this: VerticalSpinner) -> Self { - let val_text = text(format!("{}", this.value)).size(14); - let spinner_container = column::with_capacity(3) - .push( - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((this.on_select)(increment::( - this.step, this.value, this.min, this.max, - ))), - ) - .push(val_text) - .push( - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((this.on_select)(decrement::( - this.step, this.value, this.min, this.max, - ))), - ) - .align_x(Horizontal::Center); - - let content_list = column::with_children(vec![ - row::with_capacity(1).push(text(this.label)).into(), - row::with_children(vec![Element::from(spinner_container)]).into(), - ]) - .width(75) - .padding([8, 0]) - .align_x(Alignment::Center); - - Self::new(content_list) - } -} From 37f07c71545b63d079412e225c4c801b33057a1e Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sat, 16 Nov 2024 13:46:49 -0800 Subject: [PATCH 03/16] Implemented a combined horizontal and vertical spin button implementation --- examples/vertical-spin-button/src/main.rs | 60 +++++-- src/widget/mod.rs | 2 +- src/widget/spin_button/mod.rs | 1 + src/widget/spin_button/spin_button.rs | 196 ++++++++++++++++++++++ 4 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 src/widget/spin_button/spin_button.rs diff --git a/examples/vertical-spin-button/src/main.rs b/examples/vertical-spin-button/src/main.rs index 5b0e02ff582..46a5de7a319 100644 --- a/examples/vertical-spin-button/src/main.rs +++ b/examples/vertical-spin-button/src/main.rs @@ -1,4 +1,4 @@ -use cosmic::widget::{button, container, text, spin_button::vertical_spin_button}; +use cosmic::widget::{button, container, text, spin_button::vertical_spin_button, spin_button::spin_button}; use cosmic::{ app::{Core, Task}, iced::{ @@ -14,21 +14,24 @@ pub struct VertSpinnerApp { hours: i32, mins: i16, secs: i8, + spin_button_num: f32, time_msg: String, + spin_btn_msg: String, } #[derive(Debug, Clone)] -pub enum VertSpinnerMessages { +pub enum SpinBtnMessages { UpdateHours(i32), UpdateMins(i16), UpdateSecs(i8), + UpdateSpinBtnVal(f32), UpdateTimeMessage, } impl Application for VertSpinnerApp { type Executor = cosmic::executor::Default; type Flags = (); - type Message = VertSpinnerMessages; + type Message = SpinBtnMessages; const APP_ID: &'static str = "com.system76.VertSpinnerExample"; @@ -47,7 +50,9 @@ impl Application for VertSpinnerApp { hours: 0, mins: 0, secs: 0, + spin_button_num: 0.0, time_msg: String::new(), + spin_btn_msg: String::new(), }, Task::none(), ) @@ -55,10 +60,11 @@ impl Application for VertSpinnerApp { fn update(&mut self, message: Self::Message) -> Task { match message { - VertSpinnerMessages::UpdateHours(hours) => self.hours = hours, - VertSpinnerMessages::UpdateMins(mins) => self.mins = mins, - VertSpinnerMessages::UpdateSecs(secs) => self.secs = secs, - VertSpinnerMessages::UpdateTimeMessage => { + SpinBtnMessages::UpdateHours(hours) => self.hours = hours, + SpinBtnMessages::UpdateMins(mins) => self.mins = mins, + SpinBtnMessages::UpdateSecs(secs) => self.secs = secs, + SpinBtnMessages::UpdateSpinBtnVal(spin_btn_val) => self.spin_button_num = spin_btn_val, + SpinBtnMessages::UpdateTimeMessage => { self.time_msg = format!( "{}:{}:{}", self.hours, @@ -74,7 +80,9 @@ impl Application for VertSpinnerApp { } else { self.secs.to_string() } - ) + ); + + self.spin_btn_msg = format!("This came from the spin button: {}", self.spin_button_num); } } @@ -83,38 +91,56 @@ impl Application for VertSpinnerApp { fn view(&self) -> Element { let spinner_row = row![ - vertical_spin_button( + spin_button::spin_button( "Hours", 1, self.hours, 0, 12, - VertSpinnerMessages::UpdateHours + spin_button::Direction::Vertical, + SpinBtnMessages::UpdateHours ), - vertical_spin_button( + spin_button::spin_button( "Minutes", 1, self.mins, 0, 59, - VertSpinnerMessages::UpdateMins + spin_button::Direction::Vertical, + SpinBtnMessages::UpdateMins ), - vertical_spin_button( + spin_button::spin_button( "Seconds", 1, self.secs, 0, 59, - VertSpinnerMessages::UpdateSecs + spin_button::Direction::Vertical, + SpinBtnMessages::UpdateSecs ), + spin_button::spin_button( + "Spin Button Demo", + 0.5, + self.spin_button_num, + 0.0, + 10.0, + spin_button::Direction::Horizontal, + SpinBtnMessages::UpdateSpinBtnVal + ) ] .align_y(Vertical::Center); + let status_row = row![ + text(self.time_msg.clone()), + cosmic::widget::horizontal_space().width(10), + text(self.spin_btn_msg.clone()) + ]; + let final_col = column![ spinner_row, - button::standard("Update Time").on_press(VertSpinnerMessages::UpdateTimeMessage), + button::standard("Update Time").on_press(SpinBtnMessages::UpdateTimeMessage), vertical_space().height(10), - text(self.time_msg.clone()), + status_row, ] .align_x(Alignment::Center); @@ -126,7 +152,7 @@ impl Application for VertSpinnerApp { } fn main() -> Result<(), Box> { - let settings = cosmic::app::Settings::default().size(Size::new(260., 240.)); + let settings = cosmic::app::Settings::default().size(Size::new(550., 300.)); cosmic::app::run::(settings, ())?; Ok(()) diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 52acf06d44c..2bd1a0f14b1 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -311,7 +311,7 @@ pub mod settings; pub mod spin_button; #[doc(inline)] -pub use spin_button::{spin_button, SpinButton}; +pub use spin_button::{spin_button::spin_button, SpinButton}; pub mod tab_bar; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index eb3005f8244..110b93c27aa 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -4,6 +4,7 @@ //! A control for incremental adjustments of a value. mod model; +pub mod spin_button; use std::borrow::Cow; pub use self::model::{Message, Model}; diff --git a/src/widget/spin_button/spin_button.rs b/src/widget/spin_button/spin_button.rs new file mode 100644 index 00000000000..862be4f2c93 --- /dev/null +++ b/src/widget/spin_button/spin_button.rs @@ -0,0 +1,196 @@ +use std::borrow::{Borrow, Cow}; +use std::fmt::Display; +use std::ops::{Add, Sub}; +use std::marker::PhantomData; +use apply::Apply; +use iced::alignment::Horizontal; +use iced::{Alignment, Length}; +use crate::{ + Element, + widget::{ + button, + column, + container, + icon, + row, + text, + }, +}; + +pub enum Direction { + Horizontal, + Vertical, +} + +pub struct SpinButton<'a, T, Message> +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + label: String, + step: T, + value: T, + min: T, + max: T, + direction: Direction, + on_press: Box Message>, + phantom_data: PhantomData<&'a Message>, +} + +impl<'a, T, Message> SpinButton<'a, T, Message> +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + pub fn new( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + direction: Direction, + on_press: impl Fn(T) -> Message + 'static, + ) -> Self { + Self { + label: label.into(), + step, + value, + min, + max, + direction, + on_press: Box::from(on_press), + phantom_data: PhantomData, + } + } +} + +pub fn spin_button<'a, T, Message>( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + direction: Direction, + on_press: impl Fn(T) -> Message + 'static, +) -> SpinButton<'a, T, Message> +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + SpinButton::new(label, step, value, min, max, direction, on_press) +} + +fn increment(step: T, value: T, min: T, max: T) -> T +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + //! Make it roll over back to min if the increase is too high + if value + step > max { + min + } else { + value + step + } +} + +fn decrement(step: T, value: T, min: T, max: T) -> T +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + //! Make it roll over back to max if the decrese is too low + if value - step < min { + max + } else { + value - step + } +} + +impl<'a, T, Message> From> for Element<'a, Message> +where + Message: Clone + 'static, + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + fn from(this: SpinButton<'a, T, Message>) -> Self { + //! Matching on the direction enum given by the developer when the + //! widget is initially created in the application's view function. + + // NOTE: I can add a bult-in function that can toggle the widget + // enabled or disabled if the feature is requested. However, for + // the first implementation, I didn't want to go into the complexity + // of doing so. + match this.direction { + Direction::Horizontal => { + // Create a spinner container variable that contains the row with all of + // the combined widgets that make up the widget. + let spinner_container = row::with_children(vec![ + // Using the title4 variant of text, just like the original spin button did. + text::title4(this.label.clone()) + .apply(container) + .center_x(Length::Fill) + .align_y(Alignment::Center) + .into(), + // Using an button instead of an icon for the decrement functionality. + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(decrement::( + this.step, this.value, this.min, this.max, + ))) + .into(), + // Using the title4 variant of text for consistency. + text::title4(format!("{}", this.value)) + .apply(container) + .center_x(Length::Fixed(48.0)) + .align_y(Alignment::Center) + .into(), + // Using another button for the increment functionality. + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(increment::( + this.step, this.value, this.min, this.max, + ))) + .into(), + ]) + .align_y(Alignment::Center); + + // Return the horizontal spin button from the match statement. + Self::new(spinner_container) + }, + Direction::Vertical => { + // Create a text widget that holds the value + let val_text = text(format!("{}", this.value)).size(14); + // Create a spinner container variable that contains the column with all of + // the combined widgets that make up the widget. + let spinner_container = column::with_capacity(3) + .push( + // Use a button for the increment functionality + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(increment::( + this.step, this.value, this.min, this.max, + ))), + ) + // Add the text widget that holds the current value + .push(val_text) + .push( + // Use a button for the decrement functionality + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(decrement::( + this.step, this.value, this.min, this.max, + ))), + ) + .align_x(Horizontal::Center); + + // Create a column that contains two rows: + // First Row -> The label/title for the spin button. + // Second Row -> The spin button container from above. + let content_list = column::with_children(vec![ + row::with_capacity(1).push(text(this.label)).into(), + row::with_children(vec![Element::from(spinner_container)]).into(), + ]) + .width(75) + .padding([8, 0]) + .align_x(Alignment::Center); + + // Return the vertical spin button from the match statement. + Self::new(content_list) + } + } + } +} \ No newline at end of file From 90f7c9b0cfd91ca679a9c5cce69474f6b1d605ed Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sat, 16 Nov 2024 22:59:44 -0800 Subject: [PATCH 04/16] Updated spin button and example - incomplete --- .../Cargo.toml | 0 examples/spin-button/src/main.rs | 213 +++++++++++ examples/vertical-spin-button/src/main.rs | 159 --------- src/widget/mod.rs | 2 +- src/widget/spin_button/mod.rs | 336 +++++++++--------- src/widget/spin_button/model.rs | 156 -------- src/widget/spin_button/spin_button.rs | 196 ---------- 7 files changed, 381 insertions(+), 681 deletions(-) rename examples/{vertical-spin-button => spin-button}/Cargo.toml (100%) create mode 100644 examples/spin-button/src/main.rs delete mode 100644 examples/vertical-spin-button/src/main.rs delete mode 100644 src/widget/spin_button/model.rs delete mode 100644 src/widget/spin_button/spin_button.rs diff --git a/examples/vertical-spin-button/Cargo.toml b/examples/spin-button/Cargo.toml similarity index 100% rename from examples/vertical-spin-button/Cargo.toml rename to examples/spin-button/Cargo.toml diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs new file mode 100644 index 00000000000..c63aace93f0 --- /dev/null +++ b/examples/spin-button/src/main.rs @@ -0,0 +1,213 @@ +use cosmic::widget::divider::horizontal; +use cosmic::widget::{button, container, text, spin_button, spin_button::Direction}; +use cosmic::{ + app::{Core, Task}, + iced::{ + alignment::{Horizontal, Vertical}, + widget::{column, row, vertical_space}, + Alignment, Size, + }, + Application, Element, +}; + +pub struct VertSpinnerApp { + core: Core, + i8_num: i8, + i16_num: i16, + i32_num: i32, + i64_num: i64, + i128_num: i128, + f16_num: f16, + f32_num: f32, + f64_num: f64, + f128_num: f128, + spinner_msg: String, +} + +#[derive(Debug, Clone)] +pub enum SpinBtnMessages { + UpdateI8Num(i8), + UpdateI16Num(i16), + UpdateI32Num(i32), + UpdateI64Num(i64), + UpdateI128Num(i128), + UpdateF16Num(f16), + UpdateF32Num(f32), + UpdateF64Num(f64), + UpdateF128Num(f128), + UpdateSpinnerMsg, +} + +impl Application for VertSpinnerApp { + type Executor = cosmic::executor::Default; + type Flags = (); + type Message = SpinBtnMessages; + + const APP_ID: &'static str = "com.system76.VertSpinnerExample"; + + fn core(&self) -> &Core { + &self.core + } + + fn core_mut(&mut self) -> &mut Core { + &mut self.core + } + + fn init(core: Core, _flags: Self::Flags) -> (Self, Task) { + ( + Self { + core, + i8_num: 0, + i16_num: 0, + i32_num: 0, + i64_num: 0, + i128_num: 0, + f16_num: 0., + f32_num: 0., + f64_num: 0., + f128_num: 0., + spinner_msg: String::new(), + }, + Task::none(), + ) + } + + fn update(&mut self, message: Self::Message) -> Task { + match message { + SpinBtnMessages::UpdateI8Num(new_i8) => { + self.i8_num = new_i8; + SpinBtnMessages::UpdateSpinnerMsg + }, + SpinBtnMessages::UpdateI16Num(new_i16) => self.i16_num = new_i16, + SpinBtnMessages::UpdateI32Num(new_i32) => self.i32_num = new_i32, + SpinBtnMessages::UpdateI64Num(new_i64) => self.i64_num = new_i64, + SpinBtnMessages::UpdateI128Num(new_i128) => self.i128_num = new_i128, + SpinBtnMessages::UpdateF16Num(new_f16) => self.f16_num = new_f16, + SpinBtnMessages::UpdateF32Num(new_f32) => self.f32_num = new_f32, + SpinBtnMessages::UpdateF64Num(new_f64) => self.f64_num = new_f64, + SpinBtnMessages::UpdateF128Num(new_f128) => self.f128_num = new_f128, + SpinBtnMessages::UpdateSpinnerMsg => { + self.spinner_msg = format!("i8: {}, i16: {}, i32: {}, i64: {}, i128: {}\nf16: {}, f32: {}, f64: {}, f128: {}"); + } + } + + Task::none() + } + + fn view(&self) -> Element { + let vert_spinner_row = row![ + spin_button( + "i8", + 1, + self.i8_num, + -5, + 5, + Direction::Vertical, + SpinBtnMessages::UpdateI8Num + ), + spin_button( + "i16", + 1, + self.i16_num, + 0, + 10, + Direction::Vertical, + SpinBtnMessages::UpdateI16Num + ), + spin_button( + "i32", + 1, + self.i32_num, + 0, + 12, + Direction::Vertical, + SpinBtnMessages::UpdateI32Num + ), + spin_button( + "i64", + 15, + self.i64_num, + 15, + 35, + Direction::Vertical, + SpinBtnMessages::UpdateI64Num + ), + ] + .align_y(Vertical::Center); + + let horiz_spinner_row = column![ + row![ + spin_button( + "i128", + 100, + self.i128_num, + -1000, + i128::MAX, + Direction::Horizontal, + SpinBtnMessages::UpdateI128Num + ) + ].into(), + row![ + spin_button( + "f16", + 0.2, + self.f16_num, + -2.2, + 4.8, + Direction::Horizontal, + SpinBtnMessages::UpdateF16Num + ) + ].into(), + row![ + spin_button( + "f32", + 1.5, + self.f32_num, + -35.3, + 12.3, + Direction::Horizontal, + SpinBtnMessages::UpdateF32Num + ) + ].into(), + row![ + spin_button( + "f64", + 1.0, + self.f64_num, + 0.0, + 3.0, + Direction::Horizontal, + SpinBtnMessages::UpdateF64Num + ) + ].into(), + ] + .into() + .align_x(Alignment::Center); + + let status_row = row![ + text(self.spinner_msg.clone()), + ]; + + let final_col = column![ + vert_spinner_row, + vertical_space().height(5), + horiz_spinner_row, + button::standard("Show Spinner Values Passed").on_press(SpinBtnMessages::UpdateSpinnerMsg), + vertical_space().height(10), + status_row, + ] + .align_x(Alignment::Center); + + container(final_col) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() + } +} + +fn main() -> Result<(), Box> { + let settings = cosmic::app::Settings::default().size(Size::new(550., 1024.)); + cosmic::app::run::(settings, ())?; + + Ok(()) +} diff --git a/examples/vertical-spin-button/src/main.rs b/examples/vertical-spin-button/src/main.rs deleted file mode 100644 index 46a5de7a319..00000000000 --- a/examples/vertical-spin-button/src/main.rs +++ /dev/null @@ -1,159 +0,0 @@ -use cosmic::widget::{button, container, text, spin_button::vertical_spin_button, spin_button::spin_button}; -use cosmic::{ - app::{Core, Task}, - iced::{ - alignment::{Horizontal, Vertical}, - widget::{column, row, vertical_space}, - Alignment, Size, - }, - Application, Element, -}; - -pub struct VertSpinnerApp { - core: Core, - hours: i32, - mins: i16, - secs: i8, - spin_button_num: f32, - time_msg: String, - spin_btn_msg: String, -} - -#[derive(Debug, Clone)] -pub enum SpinBtnMessages { - UpdateHours(i32), - UpdateMins(i16), - UpdateSecs(i8), - UpdateSpinBtnVal(f32), - UpdateTimeMessage, -} - -impl Application for VertSpinnerApp { - type Executor = cosmic::executor::Default; - type Flags = (); - type Message = SpinBtnMessages; - - const APP_ID: &'static str = "com.system76.VertSpinnerExample"; - - fn core(&self) -> &Core { - &self.core - } - - fn core_mut(&mut self) -> &mut Core { - &mut self.core - } - - fn init(core: Core, _flags: Self::Flags) -> (Self, Task) { - ( - Self { - core, - hours: 0, - mins: 0, - secs: 0, - spin_button_num: 0.0, - time_msg: String::new(), - spin_btn_msg: String::new(), - }, - Task::none(), - ) - } - - fn update(&mut self, message: Self::Message) -> Task { - match message { - SpinBtnMessages::UpdateHours(hours) => self.hours = hours, - SpinBtnMessages::UpdateMins(mins) => self.mins = mins, - SpinBtnMessages::UpdateSecs(secs) => self.secs = secs, - SpinBtnMessages::UpdateSpinBtnVal(spin_btn_val) => self.spin_button_num = spin_btn_val, - SpinBtnMessages::UpdateTimeMessage => { - self.time_msg = format!( - "{}:{}:{}", - self.hours, - // Add a zero in front of a single digit number - if self.mins < 10 { - format!("0{}", self.mins) - } else { - self.mins.to_string() - }, - // Add a zero in front of a single digit number - if self.secs < 10 { - format!("0{}", self.secs) - } else { - self.secs.to_string() - } - ); - - self.spin_btn_msg = format!("This came from the spin button: {}", self.spin_button_num); - } - } - - Task::none() - } - - fn view(&self) -> Element { - let spinner_row = row![ - spin_button::spin_button( - "Hours", - 1, - self.hours, - 0, - 12, - spin_button::Direction::Vertical, - SpinBtnMessages::UpdateHours - ), - spin_button::spin_button( - "Minutes", - 1, - self.mins, - 0, - 59, - spin_button::Direction::Vertical, - SpinBtnMessages::UpdateMins - ), - spin_button::spin_button( - "Seconds", - 1, - self.secs, - 0, - 59, - spin_button::Direction::Vertical, - SpinBtnMessages::UpdateSecs - ), - spin_button::spin_button( - "Spin Button Demo", - 0.5, - self.spin_button_num, - 0.0, - 10.0, - spin_button::Direction::Horizontal, - SpinBtnMessages::UpdateSpinBtnVal - ) - ] - .align_y(Vertical::Center); - - let status_row = row![ - text(self.time_msg.clone()), - cosmic::widget::horizontal_space().width(10), - text(self.spin_btn_msg.clone()) - ]; - - let final_col = column![ - spinner_row, - button::standard("Update Time").on_press(SpinBtnMessages::UpdateTimeMessage), - vertical_space().height(10), - status_row, - ] - .align_x(Alignment::Center); - - container(final_col) - .align_x(Horizontal::Center) - .align_y(Vertical::Center) - .into() - } -} - -fn main() -> Result<(), Box> { - let settings = cosmic::app::Settings::default().size(Size::new(550., 300.)); - cosmic::app::run::(settings, ())?; - - Ok(()) -} diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 2bd1a0f14b1..52acf06d44c 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -311,7 +311,7 @@ pub mod settings; pub mod spin_button; #[doc(inline)] -pub use spin_button::{spin_button::spin_button, SpinButton}; +pub use spin_button::{spin_button, SpinButton}; pub mod tab_bar; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index 110b93c27aa..30f1fea091d 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -3,219 +3,217 @@ //! A control for incremental adjustments of a value. -mod model; -pub mod spin_button; -use std::borrow::Cow; - -pub use self::model::{Message, Model}; - -use crate::widget::{button, column, container, icon, row, text}; -use crate::{theme, Element}; -use std::fmt::Display; -use std::marker::PhantomData; +use std::borrow::{Borrow, Cow}; +use std::fmt::{Display, Formatter}; use std::ops::{Add, Sub}; +use std::marker::PhantomData; use apply::Apply; -use iced::{Alignment, Length}; +use fraction::Decimal; use iced::alignment::Horizontal; -use iced_core::{Border, Shadow}; - -pub struct SpinButton<'a, Message> { - label: Cow<'a, str>, - on_change: Box Message + 'static>, +use iced::{Alignment, Border, Length, Shadow}; +use crate::{ + Element, + widget::{ + button, + column, + container, + icon, + row, + text, + }, +}; + +pub enum Direction { + Horizontal, + Vertical, } -/// A control for incremental adjustments of a value. -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(16) - .apply(container) - .center(Length::Fixed(32.0)) - .apply(button::custom) - .width(Length::Fixed(32.0)) - .height(Length::Fixed(32.0)) - .class(theme::Button::Text) - .on_press(model::Message::Decrement) - .into(), - text::title4(label) - .apply(container) - .center_x(Length::Fixed(48.0)) - .align_y(Alignment::Center) - .into(), - icon::from_name("list-add-symbolic") - .size(16) - .apply(container) - .center(Length::Fixed(32.0)) - .apply(button::custom) - .width(Length::Fixed(32.0)) - .height(Length::Fixed(32.0)) - .class(theme::Button::Text) - .on_press(model::Message::Increment) - .into(), - ]) - .width(Length::Shrink) - .height(Length::Fixed(32.0)) - .align_y(Alignment::Center), - ) - .width(Length::Shrink) - .center_y(Length::Fixed(32.0)) - .class(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_widget::container::Style { - 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_widget::container::Style { - 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(), - } -} - - - -/// VerticalSpinButton is the state/model of the vertical spin button widget. -/// Restricts T to Add, Sub, Eq, Ord, Display, and Copy so that -/// T can only be numerical values. -pub struct VerticalSpinButton<'a, T, M> +pub struct SpinButton<'a, T, M> where - T: Add + Sub + Eq + Ord + Display + Copy, + T: Add + Sub + PartialEq + PartialOrd + Display + Copy { label: String, - step: T, - value: T, - min: T, - max: T, - on_select: Box M>, + /// The amount to increment or decrement the value. + pub step: T, + /// The current value of the spin button. + pub value: T, + /// The minimum value permitted. + pub min: T, + /// The maximum value permitted. + pub max: T, + /// The direction that the spin button is laid out; Horizontal (default) or Vertical + pub direction: Direction, + on_press: Box M>, phantom_data: PhantomData<&'a M>, } -impl<'a, T, M> VerticalSpinButton<'a, T, M> +impl<'a, T, M> SpinButton<'a, T, M> where - T: Add + Sub + Eq + Ord + Display + Copy, + T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - /// Creates a new vertical spin button widget + /// Create a new default spin button pub fn new( label: impl Into, step: T, value: T, min: T, max: T, - on_select: impl Fn(T) -> M + 'static, + direction: Direction, + on_press: impl Fn(T) -> M + 'static, ) -> Self { - VerticalSpinButton { + Self { label: label.into(), step, value, min, max, - on_select: Box::new(on_select), + direction, + on_press: Box::from(on_press), phantom_data: PhantomData, } } } -pub fn vertical_spin_button( +/// Shorthand function to create a default spin button +pub fn spin_button<'a, T, M>( label: impl Into, step: T, value: T, min: T, max: T, - on_select: impl Fn(T) -> M + 'static, -) -> VerticalSpinButton<'static, T, M> -where - T: Add + Sub + Eq + Ord + Display + Copy, + direction: Direction, + on_press: impl Fn(T) -> M + 'static, +) -> SpinButton<'a, T, M> +where + T: Add + Sub + PartialEq + PartialOrd + Copy { - VerticalSpinButton::new(label, step, value, min, max, on_select) + SpinButton::new(label, step, value, min, max, direction, on_press) } -fn increment(step: T, val: T, min: T, max: T) -> T -where - T: Add + Sub + Eq + Ord + Display + Copy, -{ - std::cmp::min(std::cmp::max(val + step, min), max) +fn increment(step: T, value: T, min: T, max: T) -> T +where + T: Add + Sub + PartialEq + PartialOrd + Copy +{ + //! Make it roll over back to min if the increase is too high + if value + step > max { + min + } else { + value + step + } } -fn decrement(step: T, val: T, min: T, max: T) -> T -where - T: Add + Sub + Eq + Ord + Display + Copy, +fn decrement(step: T, value: T, min: T, max: T) -> T +where + T: Add + Sub + PartialEq + PartialOrd + Copy { - std::cmp::max(std::cmp::min(val - step, max), min) + //! Make it roll over back to max if the decrese is too low + if value - step < min { + max + } else { + value - step + } } -impl<'a, T, Message> From> for Element<'a, Message> -where +impl<'a, T, Message> From> for Element<'a, Message> +where Message: Clone + 'static, - T: Add + Sub + Eq + Ord + Display + Copy, + T: Add + Sub + PartialEq + PartialOrd + Copy { - fn from(this: VerticalSpinButton) -> Self { - let val_text = text(format!("{}", this.value)).size(14); - let spinner_container = column::with_capacity(3) - .push( - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((this.on_select)(increment::( - this.step, this.value, this.min, this.max, - ))), - ) - .push(val_text) - .push( - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((this.on_select)(decrement::( - this.step, this.value, this.min, this.max, - ))), - ) - .align_x(Horizontal::Center); - - let content_list = column::with_children(vec![ - row::with_capacity(1).push(text(this.label)).into(), - row::with_children(vec![Element::from(spinner_container)]).into(), - ]) - .width(75) - .padding([8, 0]) - .align_x(Alignment::Center); - - Self::new(content_list) + fn from(this: SpinButton<'a, T, Message>) -> Self { + //! Matching on the direction enum given by the developer when the + //! widget is initially created in the application's view function. + match this.direction { + Direction::Horizontal => { + // Create a spinner container variable that contains the row with all of + // the combined widgets that make up the widget. + let spinner_container = column::with_capacity(2) + .push( + row::with_children( + vec![ + // Using the title4 variant of text, just like the original spin button did. + text::title4(this.label.clone()) + .apply(container) + .center_x(Length::Fill) + .align_y(Alignment::Center) + .into(), + ] + ) + ) + .push( + row::with_children( + vec![ + // Using an button instead of an icon for the decrement functionality. + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(decrement::( + this.step, this.value, this.min, this.max, + )) + ) + .into(), + // Using the title4 variant of text for consistency. + text::title4(format!("{}", this.value)) + .apply(container) + .center_x(Length::Fixed(48.0)) + .align_y(Alignment::Center) + .into(), + // Using another button for the increment functionality. + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(increment::( + this.step, this.value, this.min, this.max, + )) + ) + .into(), + ] + ) + .align_y(Alignment::Center) + ) + .align_x(Alignment::Center); + + // Return the horizontal spin button from the match statement. + Self::new(spinner_container) + }, + Direction::Vertical => { + // Create a text widget that holds the value + let val_text = text(format!("{}", this.value)).size(14); + // Create a spinner container variable that contains the column with all of + // the combined widgets that make up the widget. + let spinner_container = column::with_capacity(3) + .push( + // Use a button for the increment functionality + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(increment::( + this.step, this.value, this.min, this.max, + ))), + ) + // Add the text widget that holds the current value + .push(val_text) + .push( + // Use a button for the decrement functionality + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((this.on_press)(decrement::( + this.step, this.value, this.min, this.max, + ))), + ) + .align_x(Horizontal::Center); + + // Create a column that contains two rows: + // First Row -> The label/title for the spin button. + // Second Row -> The spin button container from above. + let content_list = column::with_children(vec![ + row::with_capacity(1).push(text(this.label)).into(), + row::with_children(vec![Element::from(spinner_container)]).into(), + ]) + .width(75) + .padding([8, 0]) + .align_x(Alignment::Center); + + // Return the vertical spin button from the match statement. + Self::new(content_list) + } + } } } + diff --git a/src/widget/spin_button/model.rs b/src/widget/spin_button/model.rs deleted file mode 100644 index e617bc877a9..00000000000 --- a/src/widget/spin_button/model.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2022 System76 -// SPDX-License-Identifier: MPL-2.0 - -use derive_setters::Setters; -use fraction::{Bounded, Decimal}; -use std::hash::Hash; -use std::ops::{Add, Sub}; - -/// A message emitted by the [`SpinButton`](super) widget. -#[derive(Clone, Copy, Debug, Hash)] -pub enum Message { - Increment, - Decrement, -} - -#[derive(Setters)] -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 Model -where - T: Copy + Hash + Sub + Add + Ord, -{ - pub fn update(&mut self, message: Message) { - self.value = match message { - Message::Increment => { - std::cmp::min(std::cmp::max(self.value + self.step, self.min), self.max) - } - Message::Decrement => { - std::cmp::max(std::cmp::min(self.value - self.step, self.max), self.min) - } - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: i8::MIN, - max: i8::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: i16::MIN, - max: i16::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: i32::MIN, - max: i32::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: isize::MIN, - max: isize::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: u8::MIN, - max: u8::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: u16::MIN, - max: u16::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: u32::MIN, - max: u32::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: usize::MIN, - max: usize::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: 0, - step: 1, - min: u64::MIN, - max: u64::MAX, - } - } -} - -impl Default for Model { - fn default() -> Self { - Self { - value: Decimal::from(0.0), - step: Decimal::from(0.0), - min: Decimal::min_positive_value(), - max: Decimal::max_value(), - } - } -} diff --git a/src/widget/spin_button/spin_button.rs b/src/widget/spin_button/spin_button.rs deleted file mode 100644 index 862be4f2c93..00000000000 --- a/src/widget/spin_button/spin_button.rs +++ /dev/null @@ -1,196 +0,0 @@ -use std::borrow::{Borrow, Cow}; -use std::fmt::Display; -use std::ops::{Add, Sub}; -use std::marker::PhantomData; -use apply::Apply; -use iced::alignment::Horizontal; -use iced::{Alignment, Length}; -use crate::{ - Element, - widget::{ - button, - column, - container, - icon, - row, - text, - }, -}; - -pub enum Direction { - Horizontal, - Vertical, -} - -pub struct SpinButton<'a, T, Message> -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ - label: String, - step: T, - value: T, - min: T, - max: T, - direction: Direction, - on_press: Box Message>, - phantom_data: PhantomData<&'a Message>, -} - -impl<'a, T, Message> SpinButton<'a, T, Message> -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ - pub fn new( - label: impl Into, - step: T, - value: T, - min: T, - max: T, - direction: Direction, - on_press: impl Fn(T) -> Message + 'static, - ) -> Self { - Self { - label: label.into(), - step, - value, - min, - max, - direction, - on_press: Box::from(on_press), - phantom_data: PhantomData, - } - } -} - -pub fn spin_button<'a, T, Message>( - label: impl Into, - step: T, - value: T, - min: T, - max: T, - direction: Direction, - on_press: impl Fn(T) -> Message + 'static, -) -> SpinButton<'a, T, Message> -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ - SpinButton::new(label, step, value, min, max, direction, on_press) -} - -fn increment(step: T, value: T, min: T, max: T) -> T -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ - //! Make it roll over back to min if the increase is too high - if value + step > max { - min - } else { - value + step - } -} - -fn decrement(step: T, value: T, min: T, max: T) -> T -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ - //! Make it roll over back to max if the decrese is too low - if value - step < min { - max - } else { - value - step - } -} - -impl<'a, T, Message> From> for Element<'a, Message> -where - Message: Clone + 'static, - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ - fn from(this: SpinButton<'a, T, Message>) -> Self { - //! Matching on the direction enum given by the developer when the - //! widget is initially created in the application's view function. - - // NOTE: I can add a bult-in function that can toggle the widget - // enabled or disabled if the feature is requested. However, for - // the first implementation, I didn't want to go into the complexity - // of doing so. - match this.direction { - Direction::Horizontal => { - // Create a spinner container variable that contains the row with all of - // the combined widgets that make up the widget. - let spinner_container = row::with_children(vec![ - // Using the title4 variant of text, just like the original spin button did. - text::title4(this.label.clone()) - .apply(container) - .center_x(Length::Fill) - .align_y(Alignment::Center) - .into(), - // Using an button instead of an icon for the decrement functionality. - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(decrement::( - this.step, this.value, this.min, this.max, - ))) - .into(), - // Using the title4 variant of text for consistency. - text::title4(format!("{}", this.value)) - .apply(container) - .center_x(Length::Fixed(48.0)) - .align_y(Alignment::Center) - .into(), - // Using another button for the increment functionality. - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(increment::( - this.step, this.value, this.min, this.max, - ))) - .into(), - ]) - .align_y(Alignment::Center); - - // Return the horizontal spin button from the match statement. - Self::new(spinner_container) - }, - Direction::Vertical => { - // Create a text widget that holds the value - let val_text = text(format!("{}", this.value)).size(14); - // Create a spinner container variable that contains the column with all of - // the combined widgets that make up the widget. - let spinner_container = column::with_capacity(3) - .push( - // Use a button for the increment functionality - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(increment::( - this.step, this.value, this.min, this.max, - ))), - ) - // Add the text widget that holds the current value - .push(val_text) - .push( - // Use a button for the decrement functionality - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(decrement::( - this.step, this.value, this.min, this.max, - ))), - ) - .align_x(Horizontal::Center); - - // Create a column that contains two rows: - // First Row -> The label/title for the spin button. - // Second Row -> The spin button container from above. - let content_list = column::with_children(vec![ - row::with_capacity(1).push(text(this.label)).into(), - row::with_children(vec![Element::from(spinner_container)]).into(), - ]) - .width(75) - .padding([8, 0]) - .align_x(Alignment::Center); - - // Return the vertical spin button from the match statement. - Self::new(content_list) - } - } - } -} \ No newline at end of file From 28db48bc80c25fa894e8f2f0bbeac54916cd8370 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sun, 17 Nov 2024 08:24:41 -0800 Subject: [PATCH 05/16] Floats work --- examples/spin-button/src/main.rs | 35 ++++++++------------------------ src/widget/spin_button/mod.rs | 8 ++++---- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index c63aace93f0..cb1e8d908e2 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -17,10 +17,8 @@ pub struct VertSpinnerApp { i32_num: i32, i64_num: i64, i128_num: i128, - f16_num: f16, f32_num: f32, f64_num: f64, - f128_num: f128, spinner_msg: String, } @@ -31,10 +29,8 @@ pub enum SpinBtnMessages { UpdateI32Num(i32), UpdateI64Num(i64), UpdateI128Num(i128), - UpdateF16Num(f16), UpdateF32Num(f32), UpdateF64Num(f64), - UpdateF128Num(f128), UpdateSpinnerMsg, } @@ -62,10 +58,8 @@ impl Application for VertSpinnerApp { i32_num: 0, i64_num: 0, i128_num: 0, - f16_num: 0., f32_num: 0., f64_num: 0., - f128_num: 0., spinner_msg: String::new(), }, Task::none(), @@ -76,18 +70,17 @@ impl Application for VertSpinnerApp { match message { SpinBtnMessages::UpdateI8Num(new_i8) => { self.i8_num = new_i8; - SpinBtnMessages::UpdateSpinnerMsg + SpinBtnMessages::UpdateSpinnerMsg; }, SpinBtnMessages::UpdateI16Num(new_i16) => self.i16_num = new_i16, SpinBtnMessages::UpdateI32Num(new_i32) => self.i32_num = new_i32, SpinBtnMessages::UpdateI64Num(new_i64) => self.i64_num = new_i64, SpinBtnMessages::UpdateI128Num(new_i128) => self.i128_num = new_i128, - SpinBtnMessages::UpdateF16Num(new_f16) => self.f16_num = new_f16, SpinBtnMessages::UpdateF32Num(new_f32) => self.f32_num = new_f32, SpinBtnMessages::UpdateF64Num(new_f64) => self.f64_num = new_f64, - SpinBtnMessages::UpdateF128Num(new_f128) => self.f128_num = new_f128, SpinBtnMessages::UpdateSpinnerMsg => { - self.spinner_msg = format!("i8: {}, i16: {}, i32: {}, i64: {}, i128: {}\nf16: {}, f32: {}, f64: {}, f128: {}"); + self.spinner_msg = format!("i8: {}, i16: {}, i32: {}, i64: {}, i128: {}\nf32: {}, f64: {}", + self.i8_num, self.i16_num, self.i32_num, self.i64_num, self.i128_num, self.f32_num, self.f64_num); } } @@ -125,7 +118,7 @@ impl Application for VertSpinnerApp { ), spin_button( "i64", - 15, + 10, self.i64_num, 15, 35, @@ -146,18 +139,7 @@ impl Application for VertSpinnerApp { Direction::Horizontal, SpinBtnMessages::UpdateI128Num ) - ].into(), - row![ - spin_button( - "f16", - 0.2, - self.f16_num, - -2.2, - 4.8, - Direction::Horizontal, - SpinBtnMessages::UpdateF16Num - ) - ].into(), + ], row![ spin_button( "f32", @@ -168,20 +150,19 @@ impl Application for VertSpinnerApp { Direction::Horizontal, SpinBtnMessages::UpdateF32Num ) - ].into(), + ], row![ spin_button( "f64", - 1.0, + 1.3, self.f64_num, 0.0, 3.0, Direction::Horizontal, SpinBtnMessages::UpdateF64Num ) - ].into(), + ], ] - .into() .align_x(Alignment::Center); let status_row = row![ diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index 30f1fea091d..bb92b546b33 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -85,14 +85,14 @@ pub fn spin_button<'a, T, M>( on_press: impl Fn(T) -> M + 'static, ) -> SpinButton<'a, T, M> where - T: Add + Sub + PartialEq + PartialOrd + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy { SpinButton::new(label, step, value, min, max, direction, on_press) } fn increment(step: T, value: T, min: T, max: T) -> T where - T: Add + Sub + PartialEq + PartialOrd + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy { //! Make it roll over back to min if the increase is too high if value + step > max { @@ -104,7 +104,7 @@ where fn decrement(step: T, value: T, min: T, max: T) -> T where - T: Add + Sub + PartialEq + PartialOrd + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy { //! Make it roll over back to max if the decrese is too low if value - step < min { @@ -117,7 +117,7 @@ where impl<'a, T, Message> From> for Element<'a, Message> where Message: Clone + 'static, - T: Add + Sub + PartialEq + PartialOrd + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy { fn from(this: SpinButton<'a, T, Message>) -> Self { //! Matching on the direction enum given by the developer when the From 52fe4920f2c0891f310f301dd3eff6db7c17db63 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sun, 17 Nov 2024 09:57:16 -0800 Subject: [PATCH 06/16] Updated example layout and values --- examples/spin-button/src/main.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index cb1e8d908e2..6752e6f65e6 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -135,15 +135,16 @@ impl Application for VertSpinnerApp { 100, self.i128_num, -1000, - i128::MAX, + 500, Direction::Horizontal, SpinBtnMessages::UpdateI128Num - ) + ), ], + vertical_space().height(5), row![ spin_button( "f32", - 1.5, + 1.3, self.f32_num, -35.3, 12.3, @@ -151,6 +152,7 @@ impl Application for VertSpinnerApp { SpinBtnMessages::UpdateF32Num ) ], + vertical_space().height(5), row![ spin_button( "f64", From 8036be52dcd830fac44cca4e780ef16d208ed940 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sun, 17 Nov 2024 10:08:46 -0800 Subject: [PATCH 07/16] Update example with comments --- examples/spin-button/src/main.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index 6752e6f65e6..cc6b4f84f78 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -90,13 +90,13 @@ impl Application for VertSpinnerApp { fn view(&self) -> Element { let vert_spinner_row = row![ spin_button( - "i8", - 1, - self.i8_num, - -5, - 5, - Direction::Vertical, - SpinBtnMessages::UpdateI8Num + "i8", // label: displayed above the widget no matter the orientation + 1, // step: how much to increment/decrement by + self.i8_num, // current value, this is also what's displayed in the center of the widget + -5, // minimum value, if decremented below this the widget's current value rolls to the max value + 5, // maximum value, if incremented above this the widget's current value rolls to the min value + Direction::Vertical, // oreintation of the widget + SpinBtnMessages::UpdateI8Num // message to send to the application's update function ), spin_button( "i16", From c8aabca37dbbbcd2469b8df7161b5a163c85a277 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sun, 17 Nov 2024 12:28:32 -0800 Subject: [PATCH 08/16] Updated spin button widget and example usage --- examples/spin-button/src/main.rs | 27 ++-- iced | 2 +- src/app/mod.rs | 2 +- src/widget/spin_button/mod.rs | 238 +++++++++++++++++-------------- 4 files changed, 146 insertions(+), 123 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index cc6b4f84f78..f3d1f4edd0b 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -1,5 +1,5 @@ use cosmic::widget::divider::horizontal; -use cosmic::widget::{button, container, text, spin_button, spin_button::Direction}; +use cosmic::widget::{button, container, text, spin_button, spin_button::Orientation}; use cosmic::{ app::{Core, Task}, iced::{ @@ -10,7 +10,7 @@ use cosmic::{ Application, Element, }; -pub struct VertSpinnerApp { +pub struct SpinButtonExamplApp { core: Core, i8_num: i8, i16_num: i16, @@ -34,12 +34,12 @@ pub enum SpinBtnMessages { UpdateSpinnerMsg, } -impl Application for VertSpinnerApp { +impl Application for SpinButtonExamplApp { type Executor = cosmic::executor::Default; type Flags = (); type Message = SpinBtnMessages; - const APP_ID: &'static str = "com.system76.VertSpinnerExample"; + const APP_ID: &'static str = "com.system76.SpinButtonExample"; fn core(&self) -> &Core { &self.core @@ -68,10 +68,7 @@ impl Application for VertSpinnerApp { fn update(&mut self, message: Self::Message) -> Task { match message { - SpinBtnMessages::UpdateI8Num(new_i8) => { - self.i8_num = new_i8; - SpinBtnMessages::UpdateSpinnerMsg; - }, + SpinBtnMessages::UpdateI8Num(new_i8) => self.i8_num = new_i8, SpinBtnMessages::UpdateI16Num(new_i16) => self.i16_num = new_i16, SpinBtnMessages::UpdateI32Num(new_i32) => self.i32_num = new_i32, SpinBtnMessages::UpdateI64Num(new_i64) => self.i64_num = new_i64, @@ -95,7 +92,7 @@ impl Application for VertSpinnerApp { self.i8_num, // current value, this is also what's displayed in the center of the widget -5, // minimum value, if decremented below this the widget's current value rolls to the max value 5, // maximum value, if incremented above this the widget's current value rolls to the min value - Direction::Vertical, // oreintation of the widget + Some(Orientation::Vertical), // oreintation of the widget SpinBtnMessages::UpdateI8Num // message to send to the application's update function ), spin_button( @@ -104,7 +101,7 @@ impl Application for VertSpinnerApp { self.i16_num, 0, 10, - Direction::Vertical, + Some(Orientation::Vertical), SpinBtnMessages::UpdateI16Num ), spin_button( @@ -113,7 +110,7 @@ impl Application for VertSpinnerApp { self.i32_num, 0, 12, - Direction::Vertical, + Some(Orientation::Vertical), SpinBtnMessages::UpdateI32Num ), spin_button( @@ -122,7 +119,7 @@ impl Application for VertSpinnerApp { self.i64_num, 15, 35, - Direction::Vertical, + Some(Orientation::Vertical), SpinBtnMessages::UpdateI64Num ), ] @@ -136,7 +133,7 @@ impl Application for VertSpinnerApp { self.i128_num, -1000, 500, - Direction::Horizontal, + None, // Passing None gives a default of a Horizontal Spin Button widget SpinBtnMessages::UpdateI128Num ), ], @@ -148,7 +145,7 @@ impl Application for VertSpinnerApp { self.f32_num, -35.3, 12.3, - Direction::Horizontal, + Some(Orientation::Horizontal), // It can also be explicitly passed as Orientation::Horizontal SpinBtnMessages::UpdateF32Num ) ], @@ -160,7 +157,7 @@ impl Application for VertSpinnerApp { self.f64_num, 0.0, 3.0, - Direction::Horizontal, + None, SpinBtnMessages::UpdateF64Num ) ], diff --git a/iced b/iced index 256863574ba..d0c2a0371b4 160000 --- a/iced +++ b/iced @@ -1 +1 @@ -Subproject commit 256863574bacfb1d2797c2a48cba7a3388cbeb59 +Subproject commit d0c2a0371b476866cb0f7045fba0215425493d62 diff --git a/src/app/mod.rs b/src/app/mod.rs index e4b59d629fa..6c45cc3f217 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -102,7 +102,7 @@ pub(crate) fn iced_settings( iced.default_font = settings.default_font; iced.default_text_size = iced::Pixels(settings.default_text_size); let exit_on_close = settings.exit_on_close; - iced.is_daemon = false; + //iced.is_daemon = false; iced.exit_on_close_request = settings.is_daemon; let mut window_settings = iced::window::Settings::default(); window_settings.exit_on_close_request = exit_on_close; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index bb92b546b33..fb98b2eda95 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -1,16 +1,17 @@ // Copyright 2022 System76 // SPDX-License-Identifier: MPL-2.0 +// Updated by Bryan Hyland +// Updated on: 17Nov24 + //! A control for incremental adjustments of a value. -use std::borrow::{Borrow, Cow}; -use std::fmt::{Display, Formatter}; +use std::fmt::Display; use std::ops::{Add, Sub}; use std::marker::PhantomData; use apply::Apply; -use fraction::Decimal; use iced::alignment::Horizontal; -use iced::{Alignment, Border, Length, Shadow}; +use iced::{Alignment, Length}; use crate::{ Element, widget::{ @@ -23,7 +24,8 @@ use crate::{ }, }; -pub enum Direction { +#[derive(Clone, Copy)] +pub enum Orientation { Horizontal, Vertical, } @@ -32,17 +34,23 @@ pub struct SpinButton<'a, T, M> where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { + /// The label that the spin button widget will have. + /// It is placed on the top of and centered on the spin button widget itself. label: String, /// The amount to increment or decrement the value. - pub step: T, + step: T, /// The current value of the spin button. - pub value: T, + /// It is displayed in the center of the spin button widget, no matter the orientation. + value: T, /// The minimum value permitted. - pub min: T, + /// If the value is decremented below this value the current value will rollover to the max value. + min: T, /// The maximum value permitted. - pub max: T, + /// If the value is incremented above this value the current value will rollover to the min value. + max: T, /// The direction that the spin button is laid out; Horizontal (default) or Vertical - pub direction: Direction, + orientation: Option, + /// The message that the spin button emits to the application's update function. on_press: Box M>, phantom_data: PhantomData<&'a M>, } @@ -58,7 +66,7 @@ where value: T, min: T, max: T, - direction: Direction, + orientation: Option, on_press: impl Fn(T) -> M + 'static, ) -> Self { Self { @@ -67,7 +75,7 @@ where value, min, max, - direction, + orientation, on_press: Box::from(on_press), phantom_data: PhantomData, } @@ -81,13 +89,13 @@ pub fn spin_button<'a, T, M>( value: T, min: T, max: T, - direction: Direction, + orientation: Option, on_press: impl Fn(T) -> M + 'static, ) -> SpinButton<'a, T, M> where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - SpinButton::new(label, step, value, min, max, direction, on_press) + SpinButton::new(label, step, value, min, max, orientation, on_press) } fn increment(step: T, value: T, min: T, max: T) -> T @@ -120,100 +128,118 @@ where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { fn from(this: SpinButton<'a, T, Message>) -> Self { - //! Matching on the direction enum given by the developer when the - //! widget is initially created in the application's view function. - match this.direction { - Direction::Horizontal => { - // Create a spinner container variable that contains the row with all of - // the combined widgets that make up the widget. - let spinner_container = column::with_capacity(2) - .push( - row::with_children( - vec![ - // Using the title4 variant of text, just like the original spin button did. - text::title4(this.label.clone()) - .apply(container) - .center_x(Length::Fill) - .align_y(Alignment::Center) - .into(), - ] - ) - ) - .push( - row::with_children( - vec![ - // Using an button instead of an icon for the decrement functionality. - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(decrement::( - this.step, this.value, this.min, this.max, - )) - ) - .into(), - // Using the title4 variant of text for consistency. - text::title4(format!("{}", this.value)) - .apply(container) - .center_x(Length::Fixed(48.0)) - .align_y(Alignment::Center) - .into(), - // Using another button for the increment functionality. - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(increment::( - this.step, this.value, this.min, this.max, - )) - ) - .into(), - ] - ) - .align_y(Alignment::Center) - ) - .align_x(Alignment::Center); - - // Return the horizontal spin button from the match statement. - Self::new(spinner_container) - }, - Direction::Vertical => { - // Create a text widget that holds the value - let val_text = text(format!("{}", this.value)).size(14); - // Create a spinner container variable that contains the column with all of - // the combined widgets that make up the widget. - let spinner_container = column::with_capacity(3) - .push( - // Use a button for the increment functionality - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(increment::( - this.step, this.value, this.min, this.max, - ))), - ) - // Add the text widget that holds the current value - .push(val_text) - .push( - // Use a button for the decrement functionality - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((this.on_press)(decrement::( - this.step, this.value, this.min, this.max, - ))), - ) - .align_x(Horizontal::Center); - - // Create a column that contains two rows: - // First Row -> The label/title for the spin button. - // Second Row -> The spin button container from above. - let content_list = column::with_children(vec![ - row::with_capacity(1).push(text(this.label)).into(), - row::with_children(vec![Element::from(spinner_container)]).into(), - ]) - .width(75) - .padding([8, 0]) - .align_x(Alignment::Center); - - // Return the vertical spin button from the match statement. - Self::new(content_list) + // Matching on the direction enum given by the developer when the + // widget is initially created in the application's view function. + match this.orientation { + Some(orien) => match orien { + Orientation::Horizontal => create_horizontal_spin_button(&this), + Orientation::Vertical => create_vertical_spin_button(&this) } + // Default behavior is to create a horizontal spin button widget + None => create_horizontal_spin_button(&this), } } } +// Helper Functions +// Create a horizontal spin button +// Implemented to make the creation easier to read in the from function for Element implementation. +fn create_horizontal_spin_button<'a, T, Message>(spin_btn: &SpinButton) -> Element<'a, Message> +where + Message: Clone + 'static, + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + // Create a spinner container variable that contains the row with all of + // the combined widgets that make up the widget. + let spinner_container = column::with_capacity(2) + .push( + row::with_children( + vec![ + // Using the title4 variant of text, just like the original spin button did. + text::title4(spin_btn.label.clone()) + .apply(container) + .center_x(Length::Fill) + .align_y(Alignment::Center) + .into(), + ] + ) + ) + .push( + row::with_children( + vec![ + // Using an button instead of an icon for the decrement functionality. + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((spin_btn.on_press)(decrement::( + spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, + )) + ).into(), + // Using the title4 variant of text for consistency. + text::title4(format!("{}", spin_btn.value)) + .apply(container) + .center_x(Length::Fixed(48.0)) + .align_y(Alignment::Center) + .into(), + // Using another button for the increment functionality. + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((spin_btn.on_press)(increment::( + spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, + )) + ).into(), + ] + ) + .align_y(Alignment::Center) + ) + .align_x(Alignment::Center); + + // Return the horizontal spin button from the match statement. + Element::new(spinner_container) +} + +// Used to create a vertical spin button widget. +// Implemented to make the creation easier to read in the from function for Element implementation. +fn create_vertical_spin_button<'a, T, Message>(spin_btn: &SpinButton) -> Element<'a, Message> +where + Message: Clone + 'static, + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + // Create a text widget that holds the value + let val_text = text(format!("{}", spin_btn.value)).size(14); + // Create a spinner container variable that contains the column with all of + // the combined widgets that make up the widget. + let spinner_container = column::with_capacity(3) + .push( + // Use a button for the increment functionality + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((spin_btn.on_press)(increment::( + spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, + ))), + ) + // Add the text widget that holds the current value + .push(val_text) + .push( + // Use a button for the decrement functionality + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((spin_btn.on_press)(decrement::( + spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, + ))), + ) + .align_x(Horizontal::Center); + + // Create a column that contains two rows: + // First Row -> The label/title for the spin button. + // Second Row -> The spin button container from above. + let content_list = column::with_children(vec![ + row::with_capacity(1).push(text(spin_btn.label.clone())).into(), + row::with_children(vec![Element::from(spinner_container)]).into(), + ]) + .width(75) + .padding([8, 0]) + .align_x(Alignment::Center); + + // Return the vertical spin button from the match statement. + Element::new(content_list) +} \ No newline at end of file From 12665ace20a6e6a8dd14a9121d6ab82381bf6997 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sun, 17 Nov 2024 13:05:37 -0800 Subject: [PATCH 09/16] Added a standard_spin_button function --- src/widget/spin_button/mod.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index fb98b2eda95..e5ef2f12c4b 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -59,7 +59,7 @@ impl<'a, T, M> SpinButton<'a, T, M> where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - /// Create a new default spin button + /// Create a new new button pub fn new( label: impl Into, step: T, @@ -82,7 +82,7 @@ where } } -/// Shorthand function to create a default spin button +/// Shorthand function to create a new spin button pub fn spin_button<'a, T, M>( label: impl Into, step: T, @@ -98,6 +98,21 @@ where SpinButton::new(label, step, value, min, max, orientation, on_press) } +/// Shorthand to create a standard (horizontal) spin button widget +pub fn spin_button_standard<'a, T, M>( + label: impl Into, + step: T, + value: T, + min: T, + max: T, + on_press: impl Fn(T) -> M + 'static, +) -> SpinButton<'a, T, M> +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy +{ + SpinButton::new(label, step, value, min, max, None, on_press) +} + fn increment(step: T, value: T, min: T, max: T) -> T where T: Add + Sub + PartialEq + PartialOrd + Display + Copy From 57aa3ad6717e0d9dd7eba7930cf6d579d3f4e101 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Sun, 17 Nov 2024 13:24:23 -0800 Subject: [PATCH 10/16] Added spin_button_standard and updated example with it --- examples/spin-button/src/main.rs | 10 +++++----- src/widget/mod.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index f3d1f4edd0b..7940c7f2022 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -1,5 +1,4 @@ -use cosmic::widget::divider::horizontal; -use cosmic::widget::{button, container, text, spin_button, spin_button::Orientation}; +use cosmic::widget::{button, container, text, spin_button, spin_button_standard, spin_button::Orientation}; use cosmic::{ app::{Core, Task}, iced::{ @@ -151,13 +150,14 @@ impl Application for SpinButtonExamplApp { ], vertical_space().height(5), row![ - spin_button( + // This function can be called instead if a Horizontal Spin Button is needed. + // This shortens up the API call for default/standard Spin Button widgets. + spin_button_standard( "f64", 1.3, self.f64_num, 0.0, 3.0, - None, SpinBtnMessages::UpdateF64Num ) ], @@ -187,7 +187,7 @@ impl Application for SpinButtonExamplApp { fn main() -> Result<(), Box> { let settings = cosmic::app::Settings::default().size(Size::new(550., 1024.)); - cosmic::app::run::(settings, ())?; + cosmic::app::run::(settings, ())?; Ok(()) } diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 52acf06d44c..ff1bd7add45 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -311,7 +311,7 @@ pub mod settings; pub mod spin_button; #[doc(inline)] -pub use spin_button::{spin_button, SpinButton}; +pub use spin_button::{spin_button, spin_button_standard, SpinButton}; pub mod tab_bar; From 6e0736dbfcc5c9fcf86e1270ed3493bd97978650 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Mon, 18 Nov 2024 10:25:29 -0800 Subject: [PATCH 11/16] Resovled issues with PR --- examples/spin-button/Cargo.toml | 7 ------- examples/spin-button/src/main.rs | 21 +++++++-------------- iced | 2 +- src/app/mod.rs | 2 +- src/widget/mod.rs | 2 +- src/widget/spin_button/mod.rs | 17 ++++++++--------- 6 files changed, 18 insertions(+), 33 deletions(-) diff --git a/examples/spin-button/Cargo.toml b/examples/spin-button/Cargo.toml index 65c2260623a..ab04ef7ed55 100644 --- a/examples/spin-button/Cargo.toml +++ b/examples/spin-button/Cargo.toml @@ -3,13 +3,6 @@ name = "vertical-spin-button" version = "0.1.0" edition = "2021" -[features] -default = ["xdg-portal"] -rfd = ["libcosmic/rfd"] -xdg-portal = ["libcosmic/xdg-portal"] - -[dependencies] - [dependencies.libcosmic] features = ["debug", "winit", "wayland", "desktop", "tokio"] path ="../.." diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index 7940c7f2022..88adc151671 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -1,4 +1,4 @@ -use cosmic::widget::{button, container, text, spin_button, spin_button_standard, spin_button::Orientation}; +use cosmic::widget::{button, container, text, spin_button, vertical_spin_button, /*spin_button::Orientation*/}; use cosmic::{ app::{Core, Task}, iced::{ @@ -85,40 +85,36 @@ impl Application for SpinButtonExamplApp { fn view(&self) -> Element { let vert_spinner_row = row![ - spin_button( + vertical_spin_button( "i8", // label: displayed above the widget no matter the orientation 1, // step: how much to increment/decrement by self.i8_num, // current value, this is also what's displayed in the center of the widget -5, // minimum value, if decremented below this the widget's current value rolls to the max value 5, // maximum value, if incremented above this the widget's current value rolls to the min value - Some(Orientation::Vertical), // oreintation of the widget SpinBtnMessages::UpdateI8Num // message to send to the application's update function ), - spin_button( + vertical_spin_button( "i16", 1, self.i16_num, 0, 10, - Some(Orientation::Vertical), SpinBtnMessages::UpdateI16Num ), - spin_button( + vertical_spin_button( "i32", 1, self.i32_num, 0, 12, - Some(Orientation::Vertical), SpinBtnMessages::UpdateI32Num ), - spin_button( + vertical_spin_button( "i64", 10, self.i64_num, 15, 35, - Some(Orientation::Vertical), SpinBtnMessages::UpdateI64Num ), ] @@ -126,13 +122,13 @@ impl Application for SpinButtonExamplApp { let horiz_spinner_row = column![ row![ + // This function can be called instead if a Horizontal Spin Button is needed. spin_button( "i128", 100, self.i128_num, -1000, 500, - None, // Passing None gives a default of a Horizontal Spin Button widget SpinBtnMessages::UpdateI128Num ), ], @@ -144,15 +140,12 @@ impl Application for SpinButtonExamplApp { self.f32_num, -35.3, 12.3, - Some(Orientation::Horizontal), // It can also be explicitly passed as Orientation::Horizontal SpinBtnMessages::UpdateF32Num ) ], vertical_space().height(5), row![ - // This function can be called instead if a Horizontal Spin Button is needed. - // This shortens up the API call for default/standard Spin Button widgets. - spin_button_standard( + spin_button( "f64", 1.3, self.f64_num, diff --git a/iced b/iced index d0c2a0371b4..256863574ba 160000 --- a/iced +++ b/iced @@ -1 +1 @@ -Subproject commit d0c2a0371b476866cb0f7045fba0215425493d62 +Subproject commit 256863574bacfb1d2797c2a48cba7a3388cbeb59 diff --git a/src/app/mod.rs b/src/app/mod.rs index 6c45cc3f217..e4b59d629fa 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -102,7 +102,7 @@ pub(crate) fn iced_settings( iced.default_font = settings.default_font; iced.default_text_size = iced::Pixels(settings.default_text_size); let exit_on_close = settings.exit_on_close; - //iced.is_daemon = false; + iced.is_daemon = false; iced.exit_on_close_request = settings.is_daemon; let mut window_settings = iced::window::Settings::default(); window_settings.exit_on_close_request = exit_on_close; diff --git a/src/widget/mod.rs b/src/widget/mod.rs index ff1bd7add45..661a52fad59 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -311,7 +311,7 @@ pub mod settings; pub mod spin_button; #[doc(inline)] -pub use spin_button::{spin_button, spin_button_standard, SpinButton}; +pub use spin_button::{spin_button, vertical_spin_button, SpinButton}; pub mod tab_bar; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index e5ef2f12c4b..85edcf63751 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 // Updated by Bryan Hyland -// Updated on: 17Nov24 +// Updated on: 18Nov24 //! A control for incremental adjustments of a value. @@ -89,17 +89,16 @@ pub fn spin_button<'a, T, M>( value: T, min: T, max: T, - orientation: Option, on_press: impl Fn(T) -> M + 'static, ) -> SpinButton<'a, T, M> where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - SpinButton::new(label, step, value, min, max, orientation, on_press) + SpinButton::new(label, step, value, min, max, None, on_press) } /// Shorthand to create a standard (horizontal) spin button widget -pub fn spin_button_standard<'a, T, M>( +pub fn vertical_spin_button<'a, T, M>( label: impl Into, step: T, value: T, @@ -110,7 +109,7 @@ pub fn spin_button_standard<'a, T, M>( where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - SpinButton::new(label, step, value, min, max, None, on_press) + SpinButton::new(label, step, value, min, max, Some(Orientation::Vertical), on_press) } fn increment(step: T, value: T, min: T, max: T) -> T @@ -220,14 +219,14 @@ where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { // Create a text widget that holds the value - let val_text = text(format!("{}", spin_btn.value)).size(14); + let val_text = text::title4(format!("{}", spin_btn.value)); // Create a spinner container variable that contains the column with all of // the combined widgets that make up the widget. let spinner_container = column::with_capacity(3) .push( // Use a button for the increment functionality button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) + .padding([5, 0]) .on_press((spin_btn.on_press)(increment::( spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, ))), @@ -237,7 +236,7 @@ where .push( // Use a button for the decrement functionality button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) + .padding([5, 0]) .on_press((spin_btn.on_press)(decrement::( spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, ))), @@ -248,7 +247,7 @@ where // First Row -> The label/title for the spin button. // Second Row -> The spin button container from above. let content_list = column::with_children(vec![ - row::with_capacity(1).push(text(spin_btn.label.clone())).into(), + row::with_capacity(1).push(text::title4(spin_btn.label.clone())).into(), row::with_children(vec![Element::from(spinner_container)]).into(), ]) .width(75) From f173996f1234b9a810dfc0233f5877e573e7166d Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Mon, 18 Nov 2024 11:16:31 -0800 Subject: [PATCH 12/16] Resolved vertical vs vertical_spin_button function API --- examples/spin-button/src/main.rs | 10 +++++----- src/widget/mod.rs | 2 +- src/widget/spin_button/mod.rs | 18 +++++++----------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index 88adc151671..092401b39dd 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -1,4 +1,4 @@ -use cosmic::widget::{button, container, text, spin_button, vertical_spin_button, /*spin_button::Orientation*/}; +use cosmic::widget::{button, container, text, spin_button, vertical}; use cosmic::{ app::{Core, Task}, iced::{ @@ -85,7 +85,7 @@ impl Application for SpinButtonExamplApp { fn view(&self) -> Element { let vert_spinner_row = row![ - vertical_spin_button( + vertical( "i8", // label: displayed above the widget no matter the orientation 1, // step: how much to increment/decrement by self.i8_num, // current value, this is also what's displayed in the center of the widget @@ -93,7 +93,7 @@ impl Application for SpinButtonExamplApp { 5, // maximum value, if incremented above this the widget's current value rolls to the min value SpinBtnMessages::UpdateI8Num // message to send to the application's update function ), - vertical_spin_button( + vertical( "i16", 1, self.i16_num, @@ -101,7 +101,7 @@ impl Application for SpinButtonExamplApp { 10, SpinBtnMessages::UpdateI16Num ), - vertical_spin_button( + vertical( "i32", 1, self.i32_num, @@ -109,7 +109,7 @@ impl Application for SpinButtonExamplApp { 12, SpinBtnMessages::UpdateI32Num ), - vertical_spin_button( + vertical( "i64", 10, self.i64_num, diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 661a52fad59..7f474ac1fa0 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -311,7 +311,7 @@ pub mod settings; pub mod spin_button; #[doc(inline)] -pub use spin_button::{spin_button, vertical_spin_button, SpinButton}; +pub use spin_button::{spin_button, vertical}; pub mod tab_bar; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index 85edcf63751..60c96064580 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -48,8 +48,8 @@ where /// The maximum value permitted. /// If the value is incremented above this value the current value will rollover to the min value. max: T, - /// The direction that the spin button is laid out; Horizontal (default) or Vertical - orientation: Option, + /// The direction that the spin button is laid out; Orientation::Horizontal or Orientation::Vertical + orientation: Orientation, /// The message that the spin button emits to the application's update function. on_press: Box M>, phantom_data: PhantomData<&'a M>, @@ -66,7 +66,7 @@ where value: T, min: T, max: T, - orientation: Option, + orientation: Orientation, on_press: impl Fn(T) -> M + 'static, ) -> Self { Self { @@ -94,11 +94,11 @@ pub fn spin_button<'a, T, M>( where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - SpinButton::new(label, step, value, min, max, None, on_press) + SpinButton::new(label, step, value, min, max, Orientation::Horizontal, on_press) } /// Shorthand to create a standard (horizontal) spin button widget -pub fn vertical_spin_button<'a, T, M>( +pub fn vertical<'a, T, M>( label: impl Into, step: T, value: T, @@ -109,7 +109,7 @@ pub fn vertical_spin_button<'a, T, M>( where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { - SpinButton::new(label, step, value, min, max, Some(Orientation::Vertical), on_press) + SpinButton::new(label, step, value, min, max, Orientation::Vertical, on_press) } fn increment(step: T, value: T, min: T, max: T) -> T @@ -145,12 +145,8 @@ where // Matching on the direction enum given by the developer when the // widget is initially created in the application's view function. match this.orientation { - Some(orien) => match orien { Orientation::Horizontal => create_horizontal_spin_button(&this), - Orientation::Vertical => create_vertical_spin_button(&this) - } - // Default behavior is to create a horizontal spin button widget - None => create_horizontal_spin_button(&this), + Orientation::Vertical => create_vertical_spin_button(&this), } } } From 757e078e0b6e53b74d14f29581e5c55257770b5d Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Mon, 18 Nov 2024 12:03:47 -0800 Subject: [PATCH 13/16] Updated SpinButton::new() and enum Orientation to be private --- src/widget/mod.rs | 2 +- src/widget/spin_button/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 7f474ac1fa0..78d8f43ebdb 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -311,7 +311,7 @@ pub mod settings; pub mod spin_button; #[doc(inline)] -pub use spin_button::{spin_button, vertical}; +pub use spin_button::{spin_button, vertical, SpinButton}; pub mod tab_bar; diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index 60c96064580..8f035b3ca05 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -25,7 +25,7 @@ use crate::{ }; #[derive(Clone, Copy)] -pub enum Orientation { +enum Orientation { Horizontal, Vertical, } @@ -60,7 +60,7 @@ where T: Add + Sub + PartialEq + PartialOrd + Display + Copy { /// Create a new new button - pub fn new( + fn new( label: impl Into, step: T, value: T, From e7762e16f182f52bcedc40ac4ab86910d89a4d24 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Mon, 18 Nov 2024 12:17:29 -0800 Subject: [PATCH 14/16] Fixed formatting issues for spin button example --- examples/spin-button/src/main.rs | 81 ++++++++++++++------------------ 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/examples/spin-button/src/main.rs b/examples/spin-button/src/main.rs index 092401b39dd..0062b1bcb6b 100644 --- a/examples/spin-button/src/main.rs +++ b/examples/spin-button/src/main.rs @@ -1,4 +1,4 @@ -use cosmic::widget::{button, container, text, spin_button, vertical}; +use cosmic::widget::{button, container, spin_button, text, vertical}; use cosmic::{ app::{Core, Task}, iced::{ @@ -75,8 +75,16 @@ impl Application for SpinButtonExamplApp { SpinBtnMessages::UpdateF32Num(new_f32) => self.f32_num = new_f32, SpinBtnMessages::UpdateF64Num(new_f64) => self.f64_num = new_f64, SpinBtnMessages::UpdateSpinnerMsg => { - self.spinner_msg = format!("i8: {}, i16: {}, i32: {}, i64: {}, i128: {}\nf32: {}, f64: {}", - self.i8_num, self.i16_num, self.i32_num, self.i64_num, self.i128_num, self.f32_num, self.f64_num); + self.spinner_msg = format!( + "i8: {}, i16: {}, i32: {}, i64: {}, i128: {}\nf32: {}, f64: {}", + self.i8_num, + self.i16_num, + self.i32_num, + self.i64_num, + self.i128_num, + self.f32_num, + self.f64_num + ); } } @@ -86,29 +94,15 @@ impl Application for SpinButtonExamplApp { fn view(&self) -> Element { let vert_spinner_row = row![ vertical( - "i8", // label: displayed above the widget no matter the orientation - 1, // step: how much to increment/decrement by + "i8", // label: displayed above the widget no matter the orientation + 1, // step: how much to increment/decrement by self.i8_num, // current value, this is also what's displayed in the center of the widget -5, // minimum value, if decremented below this the widget's current value rolls to the max value 5, // maximum value, if incremented above this the widget's current value rolls to the min value - SpinBtnMessages::UpdateI8Num // message to send to the application's update function - ), - vertical( - "i16", - 1, - self.i16_num, - 0, - 10, - SpinBtnMessages::UpdateI16Num - ), - vertical( - "i32", - 1, - self.i32_num, - 0, - 12, - SpinBtnMessages::UpdateI32Num + SpinBtnMessages::UpdateI8Num // message to send to the application's update function ), + vertical("i16", 1, self.i16_num, 0, 10, SpinBtnMessages::UpdateI16Num), + vertical("i32", 1, self.i32_num, 0, 12, SpinBtnMessages::UpdateI32Num), vertical( "i64", 10, @@ -133,39 +127,34 @@ impl Application for SpinButtonExamplApp { ), ], vertical_space().height(5), - row![ - spin_button( - "f32", - 1.3, - self.f32_num, - -35.3, - 12.3, - SpinBtnMessages::UpdateF32Num - ) - ], + row![spin_button( + "f32", + 1.3, + self.f32_num, + -35.3, + 12.3, + SpinBtnMessages::UpdateF32Num + )], vertical_space().height(5), - row![ - spin_button( - "f64", - 1.3, - self.f64_num, - 0.0, - 3.0, - SpinBtnMessages::UpdateF64Num - ) - ], + row![spin_button( + "f64", + 1.3, + self.f64_num, + 0.0, + 3.0, + SpinBtnMessages::UpdateF64Num + )], ] .align_x(Alignment::Center); - let status_row = row![ - text(self.spinner_msg.clone()), - ]; + let status_row = row![text(self.spinner_msg.clone()),]; let final_col = column![ vert_spinner_row, vertical_space().height(5), horiz_spinner_row, - button::standard("Show Spinner Values Passed").on_press(SpinBtnMessages::UpdateSpinnerMsg), + button::standard("Show Spinner Values Passed") + .on_press(SpinBtnMessages::UpdateSpinnerMsg), vertical_space().height(10), status_row, ] From 83a6450776fb891732bade00bd6abdbbf4d92ae6 Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Mon, 18 Nov 2024 19:45:48 -0800 Subject: [PATCH 15/16] Updated formatting --- src/widget/spin_button/mod.rs | 207 +++++++++++++++++++--------------- 1 file changed, 114 insertions(+), 93 deletions(-) diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index 8f035b3ca05..b4c18d017ed 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -6,23 +6,16 @@ //! A control for incremental adjustments of a value. -use std::fmt::Display; -use std::ops::{Add, Sub}; -use std::marker::PhantomData; -use apply::Apply; -use iced::alignment::Horizontal; -use iced::{Alignment, Length}; use crate::{ + widget::{button, column, container, icon, row, text}, Element, - widget::{ - button, - column, - container, - icon, - row, - text, - }, }; +use apply::Apply; +use iced::alignment::Horizontal; +use iced::{Alignment, Length}; +use std::fmt::Display; +use std::marker::PhantomData; +use std::ops::{Add, Sub}; #[derive(Clone, Copy)] enum Orientation { @@ -30,9 +23,9 @@ enum Orientation { Vertical, } -pub struct SpinButton<'a, T, M> +pub struct SpinButton<'a, T, M> where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { /// The label that the spin button widget will have. /// It is placed on the top of and centered on the spin button widget itself. @@ -57,7 +50,7 @@ where impl<'a, T, M> SpinButton<'a, T, M> where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { /// Create a new new button fn new( @@ -91,10 +84,18 @@ pub fn spin_button<'a, T, M>( max: T, on_press: impl Fn(T) -> M + 'static, ) -> SpinButton<'a, T, M> -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { - SpinButton::new(label, step, value, min, max, Orientation::Horizontal, on_press) + SpinButton::new( + label, + step, + value, + min, + max, + Orientation::Horizontal, + on_press, + ) } /// Shorthand to create a standard (horizontal) spin button widget @@ -106,16 +107,24 @@ pub fn vertical<'a, T, M>( max: T, on_press: impl Fn(T) -> M + 'static, ) -> SpinButton<'a, T, M> -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { - SpinButton::new(label, step, value, min, max, Orientation::Vertical, on_press) + SpinButton::new( + label, + step, + value, + min, + max, + Orientation::Vertical, + on_press, + ) } fn increment(step: T, value: T, min: T, max: T) -> T -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy -{ +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, +{ //! Make it roll over back to min if the increase is too high if value + step > max { min @@ -125,8 +134,8 @@ where } fn decrement(step: T, value: T, min: T, max: T) -> T -where - T: Add + Sub + PartialEq + PartialOrd + Display + Copy +where + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { //! Make it roll over back to max if the decrese is too low if value - step < min { @@ -137,16 +146,16 @@ where } impl<'a, T, Message> From> for Element<'a, Message> -where +where Message: Clone + 'static, - T: Add + Sub + PartialEq + PartialOrd + Display + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { fn from(this: SpinButton<'a, T, Message>) -> Self { // Matching on the direction enum given by the developer when the // widget is initially created in the application's view function. match this.orientation { - Orientation::Horizontal => create_horizontal_spin_button(&this), - Orientation::Vertical => create_vertical_spin_button(&this), + Orientation::Horizontal => create_horizontal_spin_button(&this), + Orientation::Vertical => create_vertical_spin_button(&this), } } } @@ -154,102 +163,114 @@ where // Helper Functions // Create a horizontal spin button // Implemented to make the creation easier to read in the from function for Element implementation. -fn create_horizontal_spin_button<'a, T, Message>(spin_btn: &SpinButton) -> Element<'a, Message> +fn create_horizontal_spin_button<'a, T, Message>( + spin_btn: &SpinButton, +) -> Element<'a, Message> where Message: Clone + 'static, - T: Add + Sub + PartialEq + PartialOrd + Display + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { // Create a spinner container variable that contains the row with all of // the combined widgets that make up the widget. let spinner_container = column::with_capacity(2) + .push(row::with_children(vec![ + // Using the title4 variant of text, just like the original spin button did. + text::title4(spin_btn.label.clone()) + .apply(container) + .center_x(Length::Fill) + .align_y(Alignment::Center) + .into(), + ])) .push( - row::with_children( - vec![ - // Using the title4 variant of text, just like the original spin button did. - text::title4(spin_btn.label.clone()) + row::with_children(vec![ + // Using an button instead of an icon for the decrement functionality. + button::icon(icon::from_name("list-remove-symbolic")) + .padding([0, 12]) + .on_press((spin_btn.on_press)(decrement::( + spin_btn.step, + spin_btn.value, + spin_btn.min, + spin_btn.max, + ))) + .into(), + // Using the title4 variant of text for consistency. + text::title4(format!("{}", spin_btn.value)) .apply(container) - .center_x(Length::Fill) + .center_x(Length::Fixed(48.0)) .align_y(Alignment::Center) .into(), - ] - ) - ) - .push( - row::with_children( - vec![ - // Using an button instead of an icon for the decrement functionality. - button::icon(icon::from_name("list-remove-symbolic")) - .padding([0, 12]) - .on_press((spin_btn.on_press)(decrement::( - spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, - )) - ).into(), - // Using the title4 variant of text for consistency. - text::title4(format!("{}", spin_btn.value)) - .apply(container) - .center_x(Length::Fixed(48.0)) - .align_y(Alignment::Center) - .into(), - // Using another button for the increment functionality. - button::icon(icon::from_name("list-add-symbolic")) - .padding([0, 12]) - .on_press((spin_btn.on_press)(increment::( - spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, - )) - ).into(), - ] - ) - .align_y(Alignment::Center) + // Using another button for the increment functionality. + button::icon(icon::from_name("list-add-symbolic")) + .padding([0, 12]) + .on_press((spin_btn.on_press)(increment::( + spin_btn.step, + spin_btn.value, + spin_btn.min, + spin_btn.max, + ))) + .into(), + ]) + .align_y(Alignment::Center), ) .align_x(Alignment::Center); - + // Return the horizontal spin button from the match statement. Element::new(spinner_container) } // Used to create a vertical spin button widget. // Implemented to make the creation easier to read in the from function for Element implementation. -fn create_vertical_spin_button<'a, T, Message>(spin_btn: &SpinButton) -> Element<'a, Message> +fn create_vertical_spin_button<'a, T, Message>( + spin_btn: &SpinButton, +) -> Element<'a, Message> where Message: Clone + 'static, - T: Add + Sub + PartialEq + PartialOrd + Display + Copy + T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { // Create a text widget that holds the value let val_text = text::title4(format!("{}", spin_btn.value)); // Create a spinner container variable that contains the column with all of // the combined widgets that make up the widget. let spinner_container = column::with_capacity(3) - .push( - // Use a button for the increment functionality - button::icon(icon::from_name("list-add-symbolic")) - .padding([5, 0]) - .on_press((spin_btn.on_press)(increment::( - spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, - ))), - ) - // Add the text widget that holds the current value - .push(val_text) - .push( - // Use a button for the decrement functionality - button::icon(icon::from_name("list-remove-symbolic")) - .padding([5, 0]) - .on_press((spin_btn.on_press)(decrement::( - spin_btn.step, spin_btn.value, spin_btn.min, spin_btn.max, - ))), - ) - .align_x(Horizontal::Center); + .push( + // Use a button for the increment functionality + button::icon(icon::from_name("list-add-symbolic")) + .padding([5, 0]) + .on_press((spin_btn.on_press)(increment::( + spin_btn.step, + spin_btn.value, + spin_btn.min, + spin_btn.max, + ))), + ) + // Add the text widget that holds the current value + .push(val_text) + .push( + // Use a button for the decrement functionality + button::icon(icon::from_name("list-remove-symbolic")) + .padding([5, 0]) + .on_press((spin_btn.on_press)(decrement::( + spin_btn.step, + spin_btn.value, + spin_btn.min, + spin_btn.max, + ))), + ) + .align_x(Horizontal::Center); // Create a column that contains two rows: // First Row -> The label/title for the spin button. // Second Row -> The spin button container from above. let content_list = column::with_children(vec![ - row::with_capacity(1).push(text::title4(spin_btn.label.clone())).into(), + row::with_capacity(1) + .push(text::title4(spin_btn.label.clone())) + .into(), row::with_children(vec![Element::from(spinner_container)]).into(), ]) .width(75) .padding([8, 0]) .align_x(Alignment::Center); - + // Return the vertical spin button from the match statement. Element::new(content_list) -} \ No newline at end of file +} From a6eb4b735cfa77868d3d0a621a627d05de671c4f Mon Sep 17 00:00:00 2001 From: Bryan Hyland Date: Tue, 19 Nov 2024 07:34:25 -0800 Subject: [PATCH 16/16] Updated formatting to pass tests --- src/widget/spin_button/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/spin_button/mod.rs b/src/widget/spin_button/mod.rs index b4c18d017ed..e1e767a86fa 100644 --- a/src/widget/spin_button/mod.rs +++ b/src/widget/spin_button/mod.rs @@ -125,7 +125,7 @@ fn increment(step: T, value: T, min: T, max: T) -> T where T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { - //! Make it roll over back to min if the increase is too high + /// Make it roll over back to min if the increase is too high if value + step > max { min } else { @@ -137,7 +137,7 @@ fn decrement(step: T, value: T, min: T, max: T) -> T where T: Add + Sub + PartialEq + PartialOrd + Display + Copy, { - //! Make it roll over back to max if the decrese is too low + /// Make it roll over back to max if the decrese is too low if value - step < min { max } else {