From eee336eab0c994f01dbdc6b471739243ad3c463c Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Tue, 21 Nov 2023 19:36:00 -0800 Subject: [PATCH] Progress values are easier to work with --- examples/progress.rs | 22 +++++++++ src/widgets/progress.rs | 98 ++++++++++++++++++++++++++++++----------- 2 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 examples/progress.rs diff --git a/examples/progress.rs b/examples/progress.rs new file mode 100644 index 0000000..fd75406 --- /dev/null +++ b/examples/progress.rs @@ -0,0 +1,22 @@ +use gooey::value::{Dynamic, MapEach}; +use gooey::widget::MakeWidget; +use gooey::widgets::progress::Progressable; +use gooey::widgets::slider::Slidable; +use gooey::widgets::Checkbox; +use gooey::Run; + +fn main() -> gooey::Result { + let indeterminant = Dynamic::new(false); + let value = Dynamic::new(0_u8); + let progress = (&indeterminant, &value) + .map_each(|(&indeterminant, &value)| (!indeterminant).then_some(value)); + + value + .slider() + .and(progress.progress_bar()) + .and(Checkbox::new(indeterminant.clone(), "Indeterminant")) + .into_rows() + .centered() + .expand() + .run() +} diff --git a/src/widgets/progress.rs b/src/widgets/progress.rs index 02bba6e..58c8ef9 100644 --- a/src/widgets/progress.rs +++ b/src/widgets/progress.rs @@ -40,11 +40,11 @@ impl ProgressBar { /// A measurement of progress for an indicator widget like [`ProgressBar`]. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Progress { +pub enum Progress { /// The task has an indeterminant length. Indeterminant, - /// The task is a specified percent complete. - Percent(ZeroToOne), + /// The task is a specified amount complete. + Percent(T), } impl MakeWidget for ProgressBar { @@ -123,16 +123,16 @@ fn update_progress_bar( } /// A value that can be used in a progress indicator. -pub trait Progressable: IntoDynamic + Sized { +pub trait Progressable: IntoDynamic + Sized +where + T: ProgressValue, +{ /// Returns a new progress bar that displays progress from `T::MIN` to /// `T::MAX`. - fn progress_bar(self) -> ProgressBar - where - T: Ranged + PercentBetween, - { + fn progress_bar(self) -> ProgressBar { ProgressBar::new( self.into_dynamic() - .map_each(|t| Progress::Percent(t.percent_between(&T::MIN, &T::MAX))), + .map_each(|value| value.to_progress(None)), ) } @@ -140,15 +140,16 @@ pub trait Progressable: IntoDynamic + Sized { /// `max`. The maximum value can be either a `T` or an `Option`. If /// `None` is the maximum value, an indeterminant progress bar will be /// displayed. - fn progress_bar_to(self, max: impl IntoValue>) -> ProgressBar + fn progress_bar_to(self, max: impl IntoValue) -> ProgressBar where - T: Ranged + PercentBetween + Clone + Send + Sync + 'static, + T: Send, + T::Value: Ranged + Send + Clone, { let max = max.into_value(); match max { - Value::Constant(max) => self.progress_bar_between(max.map(|max| T::MIN..=max)), + Value::Constant(max) => self.progress_bar_between(::MIN..=max), Value::Dynamic(max) => { - self.progress_bar_between(max.map_each(|max| max.clone().map(|max| T::MIN..=max))) + self.progress_bar_between(max.map_each(|max| ::MIN..=max.clone())) } } } @@ -159,27 +160,74 @@ pub trait Progressable: IntoDynamic + Sized { /// displayed. fn progress_bar_between(self, range: Range) -> ProgressBar where - T: PercentBetween + Clone + Send + Sync + 'static, - Range: IntoValue>>, + T: Send, + T::Value: Send, + Range: IntoValue>, { let value = self.into_dynamic(); let range = range.into_value(); match range { - Value::Constant(range) => ProgressBar::new(value.map_each(move |value| { - range - .as_ref() - .map(|range| value.percent_between(range.start(), range.end())) - .map_or(Progress::Indeterminant, Progress::Percent) - })), + Value::Constant(range) => ProgressBar::new( + value.map_each(move |value| value.to_progress(Some(range.start()..=range.end()))), + ), Value::Dynamic(range) => { ProgressBar::new((&range, &value).map_each(|(range, value)| { - range.clone().map_or(Progress::Indeterminant, |range| { - Progress::Percent(value.percent_between(range.start(), range.end())) - }) + value.to_progress(Some(range.start()..=range.end())) })) } } } } -impl Progressable for T where T: IntoDynamic {} +impl Progressable for Dynamic where U: ProgressValue {} + +/// A value that can be used in a progress indicator. +pub trait ProgressValue: 'static { + /// The type that progress is ranged over. + type Value; + + /// Converts this value to a progress using the range given, if provided. If + /// no range is provided, the full range of the type should be considered. + fn to_progress(&self, range: Option>) -> Progress; +} + +impl ProgressValue for T +where + T: Ranged + PercentBetween + 'static, +{ + type Value = T; + + fn to_progress(&self, range: Option>) -> Progress { + if let Some(range) = range { + Progress::Percent(self.percent_between(range.start(), range.end())) + } else { + Progress::Percent(self.percent_between(&T::MIN, &T::MAX)) + } + } +} + +impl ProgressValue for Option +where + T: Ranged + PercentBetween + 'static, +{ + type Value = T; + + fn to_progress(&self, range: Option>) -> Progress { + self.as_ref() + .map_or(Progress::Indeterminant, |value| value.to_progress(range)) + } +} + +impl ProgressValue for Progress +where + T: Ranged + PercentBetween + 'static, +{ + type Value = T; + + fn to_progress(&self, range: Option>) -> Progress { + match self { + Progress::Indeterminant => Progress::Indeterminant, + Progress::Percent(value) => value.to_progress(range), + } + } +}