From 40af65c3aa4a96281db8f642cfa1641479314d27 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Wed, 6 Mar 2024 11:24:51 +0100
Subject: Simplify theming for `Toggler` widget

---
 style/src/lib.rs      |   1 -
 style/src/theme.rs    |  70 ---------------------------
 style/src/toggler.rs  |  35 --------------
 widget/src/helpers.rs |   2 +-
 widget/src/toggler.rs | 131 ++++++++++++++++++++++++++++++++++++++++++--------
 5 files changed, 112 insertions(+), 127 deletions(-)
 delete mode 100644 style/src/toggler.rs

diff --git a/style/src/lib.rs b/style/src/lib.rs
index 09a943aa..3e439f07 100644
--- a/style/src/lib.rs
+++ b/style/src/lib.rs
@@ -23,6 +23,5 @@ pub mod pick_list;
 pub mod svg;
 pub mod text_editor;
 pub mod theme;
-pub mod toggler;
 
 pub use theme::Theme;
diff --git a/style/src/theme.rs b/style/src/theme.rs
index a7a95ab0..993e3d68 100644
--- a/style/src/theme.rs
+++ b/style/src/theme.rs
@@ -10,7 +10,6 @@ use crate::pane_grid;
 use crate::pick_list;
 use crate::svg;
 use crate::text_editor;
-use crate::toggler;
 
 use crate::core::{Background, Border, Color};
 
@@ -378,75 +377,6 @@ impl pick_list::StyleSheet for Theme {
     }
 }
 
-/// The style of a toggler.
-#[derive(Default)]
-pub enum Toggler {
-    /// The default style.
-    #[default]
-    Default,
-    /// A custom style.
-    Custom(Box<dyn toggler::StyleSheet<Style = Theme>>),
-}
-
-impl toggler::StyleSheet for Theme {
-    type Style = Toggler;
-
-    fn active(
-        &self,
-        style: &Self::Style,
-        is_active: bool,
-    ) -> toggler::Appearance {
-        match style {
-            Toggler::Default => {
-                let palette = self.extended_palette();
-
-                toggler::Appearance {
-                    background: if is_active {
-                        palette.primary.strong.color
-                    } else {
-                        palette.background.strong.color
-                    },
-                    background_border_width: 0.0,
-                    background_border_color: Color::TRANSPARENT,
-                    foreground: if is_active {
-                        palette.primary.strong.text
-                    } else {
-                        palette.background.base.color
-                    },
-                    foreground_border_width: 0.0,
-                    foreground_border_color: Color::TRANSPARENT,
-                }
-            }
-            Toggler::Custom(custom) => custom.active(self, is_active),
-        }
-    }
-
-    fn hovered(
-        &self,
-        style: &Self::Style,
-        is_active: bool,
-    ) -> toggler::Appearance {
-        match style {
-            Toggler::Default => {
-                let palette = self.extended_palette();
-
-                toggler::Appearance {
-                    foreground: if is_active {
-                        Color {
-                            a: 0.5,
-                            ..palette.primary.strong.text
-                        }
-                    } else {
-                        palette.background.weak.color
-                    },
-                    ..self.active(style, is_active)
-                }
-            }
-            Toggler::Custom(custom) => custom.hovered(self, is_active),
-        }
-    }
-}
-
 /// The style of a pane grid.
 #[derive(Default)]
 pub enum PaneGrid {
diff --git a/style/src/toggler.rs b/style/src/toggler.rs
deleted file mode 100644
index 731e87ce..00000000
--- a/style/src/toggler.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-//! Change the appearance of a toggler.
-use iced_core::Color;
-
-/// The appearance of a toggler.
-#[derive(Debug, Clone, Copy)]
-pub struct Appearance {
-    /// The background [`Color`] of the toggler.
-    pub background: Color,
-    /// The width of the background border of the toggler.
-    pub background_border_width: f32,
-    /// The [`Color`] of the background border of the toggler.
-    pub background_border_color: Color,
-    /// The foreground [`Color`] of the toggler.
-    pub foreground: Color,
-    /// The width of the foreground border of the toggler.
-    pub foreground_border_width: f32,
-    /// The [`Color`] of the foreground border of the toggler.
-    pub foreground_border_color: Color,
-}
-
-/// A set of rules that dictate the style of a toggler.
-pub trait StyleSheet {
-    /// The supported style of the [`StyleSheet`].
-    type Style: Default;
-
-    /// Returns the active [`Appearance`] of the toggler for the provided [`Style`].
-    ///
-    /// [`Style`]: Self::Style
-    fn active(&self, style: &Self::Style, is_active: bool) -> Appearance;
-
-    /// Returns the hovered [`Appearance`] of the toggler for the provided [`Style`].
-    ///
-    /// [`Style`]: Self::Style
-    fn hovered(&self, style: &Self::Style, is_active: bool) -> Appearance;
-}
diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs
index 33c9f300..8cb03691 100644
--- a/widget/src/helpers.rs
+++ b/widget/src/helpers.rs
@@ -196,7 +196,7 @@ pub fn toggler<'a, Message, Theme, Renderer>(
 ) -> Toggler<'a, Message, Theme, Renderer>
 where
     Renderer: core::text::Renderer,
-    Theme: toggler::StyleSheet,
+    Theme: toggler::Style,
 {
     Toggler::new(label, is_checked, f)
 }
diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs
index 4e3925ba..1f19212d 100644
--- a/widget/src/toggler.rs
+++ b/widget/src/toggler.rs
@@ -9,11 +9,10 @@ use crate::core::touch;
 use crate::core::widget;
 use crate::core::widget::tree::{self, Tree};
 use crate::core::{
-    Border, Clipboard, Element, Event, Layout, Length, Pixels, Rectangle,
-    Shell, Size, Widget,
+    Border, Clipboard, Color, Element, Event, Layout, Length, Pixels,
+    Rectangle, Shell, Size, Widget,
 };
-
-pub use crate::style::toggler::{Appearance, StyleSheet};
+use crate::style::Theme;
 
 /// A toggler widget.
 ///
@@ -38,7 +37,6 @@ pub struct Toggler<
     Theme = crate::Theme,
     Renderer = crate::Renderer,
 > where
-    Theme: StyleSheet,
     Renderer: text::Renderer,
 {
     is_toggled: bool,
@@ -52,12 +50,11 @@ pub struct Toggler<
     text_shaping: text::Shaping,
     spacing: f32,
     font: Option<Renderer::Font>,
-    style: Theme::Style,
+    style: fn(&Theme, Status) -> Appearance,
 }
 
 impl<'a, Message, Theme, Renderer> Toggler<'a, Message, Theme, Renderer>
 where
-    Theme: StyleSheet,
     Renderer: text::Renderer,
 {
     /// The default size of a [`Toggler`].
@@ -77,6 +74,7 @@ where
         f: F,
     ) -> Self
     where
+        Theme: Style,
         F: 'a + Fn(bool) -> Message,
     {
         Toggler {
@@ -91,7 +89,7 @@ where
             text_shaping: text::Shaping::Basic,
             spacing: Self::DEFAULT_SIZE / 2.0,
             font: None,
-            style: Default::default(),
+            style: Theme::style(),
         }
     }
 
@@ -149,7 +147,7 @@ where
     }
 
     /// Sets the style of the [`Toggler`].
-    pub fn style(mut self, style: impl Into<Theme::Style>) -> Self {
+    pub fn style(mut self, style: fn(&Theme, Status) -> Appearance) -> Self {
         self.style = style.into();
         self
     }
@@ -158,7 +156,6 @@ where
 impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
     for Toggler<'a, Message, Theme, Renderer>
 where
-    Theme: StyleSheet + crate::text::StyleSheet,
     Renderer: text::Renderer,
 {
     fn tag(&self) -> tree::Tag {
@@ -294,12 +291,18 @@ where
         let bounds = toggler_layout.bounds();
         let is_mouse_over = cursor.is_over(layout.bounds());
 
-        let style = if is_mouse_over {
-            theme.hovered(&self.style, self.is_toggled)
+        let status = if is_mouse_over {
+            Status::Hovered {
+                is_toggled: self.is_toggled,
+            }
         } else {
-            theme.active(&self.style, self.is_toggled)
+            Status::Active {
+                is_toggled: self.is_toggled,
+            }
         };
 
+        let appearance = (self.style)(theme, status);
+
         let border_radius = bounds.height / BORDER_RADIUS_RATIO;
         let space = SPACE_RATIO * bounds.height;
 
@@ -315,12 +318,12 @@ where
                 bounds: toggler_background_bounds,
                 border: Border {
                     radius: border_radius.into(),
-                    width: style.background_border_width,
-                    color: style.background_border_color,
+                    width: appearance.background_border_width,
+                    color: appearance.background_border_color,
                 },
                 ..renderer::Quad::default()
             },
-            style.background,
+            appearance.background,
         );
 
         let toggler_foreground_bounds = Rectangle {
@@ -340,12 +343,12 @@ where
                 bounds: toggler_foreground_bounds,
                 border: Border {
                     radius: border_radius.into(),
-                    width: style.foreground_border_width,
-                    color: style.foreground_border_color,
+                    width: appearance.foreground_border_width,
+                    color: appearance.foreground_border_color,
                 },
                 ..renderer::Quad::default()
             },
-            style.foreground,
+            appearance.foreground,
         );
     }
 }
@@ -354,7 +357,7 @@ impl<'a, Message, Theme, Renderer> From<Toggler<'a, Message, Theme, Renderer>>
     for Element<'a, Message, Theme, Renderer>
 where
     Message: 'a,
-    Theme: StyleSheet + crate::text::StyleSheet + 'a,
+    Theme: 'a,
     Renderer: text::Renderer + 'a,
 {
     fn from(
@@ -363,3 +366,91 @@ where
         Element::new(toggler)
     }
 }
+
+/// The possible status of a [`Toggler`].
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Status {
+    /// The [`Toggler`] can be interacted with.
+    Active {
+        /// Indicates whether the [`Toggler`] is toggled.
+        is_toggled: bool,
+    },
+    /// The [`Toggler`] is being hovered.
+    Hovered {
+        /// Indicates whether the [`Toggler`] is toggled.
+        is_toggled: bool,
+    },
+}
+
+/// The appearance of a toggler.
+#[derive(Debug, Clone, Copy)]
+pub struct Appearance {
+    /// The background [`Color`] of the toggler.
+    pub background: Color,
+    /// The width of the background border of the toggler.
+    pub background_border_width: f32,
+    /// The [`Color`] of the background border of the toggler.
+    pub background_border_color: Color,
+    /// The foreground [`Color`] of the toggler.
+    pub foreground: Color,
+    /// The width of the foreground border of the toggler.
+    pub foreground_border_width: f32,
+    /// The [`Color`] of the foreground border of the toggler.
+    pub foreground_border_color: Color,
+}
+
+/// The definiton of the default style of a [`Toggler`].
+pub trait Style {
+    /// Returns the default style of a [`Toggler`].
+    fn style() -> fn(&Self, Status) -> Appearance;
+}
+
+impl Style for Theme {
+    fn style() -> fn(&Self, Status) -> Appearance {
+        default
+    }
+}
+
+/// The default style of a [`Toggler`].
+pub fn default(theme: &Theme, status: Status) -> Appearance {
+    let palette = theme.extended_palette();
+
+    let background = match status {
+        Status::Active { is_toggled } | Status::Hovered { is_toggled } => {
+            if is_toggled {
+                palette.primary.strong.color
+            } else {
+                palette.background.strong.color
+            }
+        }
+    };
+
+    let foreground = match status {
+        Status::Active { is_toggled } => {
+            if is_toggled {
+                palette.primary.strong.text
+            } else {
+                palette.background.base.color
+            }
+        }
+        Status::Hovered { is_toggled } => {
+            if is_toggled {
+                Color {
+                    a: 0.5,
+                    ..palette.primary.strong.text
+                }
+            } else {
+                palette.background.weak.color
+            }
+        }
+    };
+
+    Appearance {
+        background,
+        foreground,
+        foreground_border_width: 0.0,
+        foreground_border_color: Color::TRANSPARENT,
+        background_border_width: 0.0,
+        background_border_color: Color::TRANSPARENT,
+    }
+}
-- 
cgit