diff options
| author | pml68 <contact@pml68.dev> | 2025-06-26 12:16:52 +0200 |
|---|---|---|
| committer | pml68 <contact@pml68.dev> | 2025-06-26 12:16:52 +0200 |
| commit | 00c6cf80cb9c4587700078a062a6b32873b6f8ff (patch) | |
| tree | 9aad054c784b51d4a0bc97c928b89da7dbcab863 /crates/material_theme/src | |
| parent | feat: update for hot reloading support (diff) | |
| download | iced-builder-00c6cf80cb9c4587700078a062a6b32873b6f8ff.tar.gz | |
feat: extract `material_theme` into separate repo (`pml68/iced_material`)
Diffstat (limited to 'crates/material_theme/src')
22 files changed, 0 insertions, 1936 deletions
diff --git a/crates/material_theme/src/button.rs b/crates/material_theme/src/button.rs deleted file mode 100644 index 2800ac4..0000000 --- a/crates/material_theme/src/button.rs +++ /dev/null @@ -1,157 +0,0 @@ -use iced_widget::button::{Catalog, Status, Style, StyleFn}; -use iced_widget::core::{Background, Border, Color, border}; - -use crate::Theme; -use crate::utils::{ - HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, disabled_container, - disabled_text, elevation, mix, shadow_from_elevation, -}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(filled) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -fn button( - background: Color, - foreground: Color, - disabled: Color, - shadow_color: Color, - elevation_level: u8, - status: Status, -) -> Style { - let active = Style { - background: Some(Background::Color(background)), - text_color: foreground, - border: border::rounded(400), - shadow: shadow_from_elevation(elevation(elevation_level), shadow_color), - snap: cfg!(feature = "crisp"), - }; - - match status { - Status::Active => active, - Status::Pressed => Style { - background: Some(Background::Color(mix( - background, - foreground, - HOVERED_LAYER_OPACITY, - ))), - ..active - }, - Status::Hovered => Style { - background: Some(Background::Color(mix( - background, - foreground, - PRESSED_LAYER_OPACITY, - ))), - shadow: shadow_from_elevation( - elevation(elevation_level + 1), - shadow_color, - ), - ..active - }, - Status::Disabled => Style { - background: Some(Background::Color(disabled_container(disabled))), - text_color: disabled_text(disabled), - border: border::rounded(400), - ..Default::default() - }, - } -} - -pub fn elevated(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - - let foreground = theme.colors().primary.color; - let background = surface.surface_container.low; - let disabled = surface.on_surface; - - let shadow_color = theme.colors().shadow; - - button(background, foreground, disabled, shadow_color, 1, status) -} - -pub fn filled(theme: &Theme, status: Status) -> Style { - let primary = theme.colors().primary; - - let foreground = primary.on_primary; - let background = primary.color; - let disabled = theme.colors().surface.on_surface; - - let shadow_color = theme.colors().shadow; - - button(background, foreground, disabled, shadow_color, 0, status) -} - -pub fn filled_tonal(theme: &Theme, status: Status) -> Style { - let secondary = theme.colors().secondary; - - let foreground = secondary.on_secondary_container; - let background = secondary.secondary_container; - let disabled = theme.colors().surface.on_surface; - let shadow_color = theme.colors().shadow; - - button(background, foreground, disabled, shadow_color, 0, status) -} - -pub fn outlined(theme: &Theme, status: Status) -> Style { - let foreground = theme.colors().primary.color; - let background = Color::TRANSPARENT; - let disabled = theme.colors().surface.on_surface; - - let outline = theme.colors().outline.color; - - let border = match status { - Status::Active | Status::Pressed | Status::Hovered => Border { - color: outline, - width: 1.0, - radius: 400.into(), - }, - Status::Disabled => Border { - color: disabled_container(disabled), - width: 1.0, - radius: 400.into(), - }, - }; - - let style = button( - background, - foreground, - disabled, - Color::TRANSPARENT, - 0, - status, - ); - - Style { border, ..style } -} - -pub fn text(theme: &Theme, status: Status) -> Style { - let foreground = theme.colors().primary.color; - let background = Color::TRANSPARENT; - let disabled = theme.colors().surface.on_surface; - - let style = button( - background, - foreground, - disabled, - Color::TRANSPARENT, - 0, - status, - ); - - match status { - Status::Hovered | Status::Pressed => style, - Status::Active | Status::Disabled => Style { - background: None, - ..style - }, - } -} diff --git a/crates/material_theme/src/checkbox.rs b/crates/material_theme/src/checkbox.rs deleted file mode 100644 index 7a3729c..0000000 --- a/crates/material_theme/src/checkbox.rs +++ /dev/null @@ -1,115 +0,0 @@ -use iced_widget::checkbox::{Catalog, Status, Style, StyleFn}; -use iced_widget::core::{Background, Border, Color, border}; - -use super::Theme; -use crate::utils::{HOVERED_LAYER_OPACITY, disabled_text, mix}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn styled( - background_color: Color, - background_unchecked: Option<Color>, - icon_color: Color, - border_color: Color, - text_color: Option<Color>, - is_checked: bool, -) -> Style { - Style { - background: Background::Color(if is_checked { - background_color - } else { - background_unchecked.unwrap_or(Color::TRANSPARENT) - }), - icon_color, - border: if is_checked { - border::rounded(2) - } else { - Border { - color: border_color, - width: 2.0, - radius: 2.into(), - } - }, - text_color, - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let primary = theme.colors().primary; - - match status { - Status::Active { is_checked } => styled( - primary.color, - None, - primary.on_primary, - surface.on_surface_variant, - Some(surface.on_surface), - is_checked, - ), - Status::Hovered { is_checked } => styled( - mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY), - Some(Color { - a: HOVERED_LAYER_OPACITY, - ..surface.on_surface - }), - primary.on_primary, - surface.on_surface_variant, - Some(surface.on_surface), - is_checked, - ), - Status::Disabled { is_checked } => styled( - disabled_text(surface.on_surface), - None, - surface.color, - disabled_text(surface.on_surface), - Some(surface.on_surface), - is_checked, - ), - } -} - -pub fn error(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let error = theme.colors().error; - - match status { - Status::Active { is_checked } => styled( - error.color, - None, - error.on_error, - error.color, - Some(error.color), - is_checked, - ), - Status::Hovered { is_checked } => styled( - mix(error.color, surface.on_surface, HOVERED_LAYER_OPACITY), - Some(Color { - a: HOVERED_LAYER_OPACITY, - ..error.color - }), - error.on_error, - error.color, - Some(error.color), - is_checked, - ), - Status::Disabled { is_checked } => styled( - disabled_text(surface.on_surface), - None, - surface.color, - disabled_text(surface.on_surface), - Some(surface.on_surface), - is_checked, - ), - } -} diff --git a/crates/material_theme/src/combo_box.rs b/crates/material_theme/src/combo_box.rs deleted file mode 100644 index 3024176..0000000 --- a/crates/material_theme/src/combo_box.rs +++ /dev/null @@ -1,5 +0,0 @@ -use iced_widget::combo_box::Catalog; - -use super::Theme; - -impl Catalog for Theme {} diff --git a/crates/material_theme/src/container.rs b/crates/material_theme/src/container.rs deleted file mode 100644 index 5c253ad..0000000 --- a/crates/material_theme/src/container.rs +++ /dev/null @@ -1,200 +0,0 @@ -use iced_widget::container::{Catalog, Style, StyleFn}; -use iced_widget::core::{Background, Border, border}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(transparent) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn transparent(_theme: &Theme) -> Style { - Style { - border: border::rounded(4), - ..Style::default() - } -} - -pub fn primary(theme: &Theme) -> Style { - let primary = theme.colors().primary; - - Style { - background: Some(Background::Color(primary.color)), - text_color: Some(primary.on_primary), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn primary_container(theme: &Theme) -> Style { - let primary = theme.colors().primary; - - Style { - background: Some(Background::Color(primary.primary_container)), - text_color: Some(primary.on_primary_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn secondary(theme: &Theme) -> Style { - let secondary = theme.colors().secondary; - - Style { - background: Some(Background::Color(secondary.color)), - text_color: Some(secondary.on_secondary), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn secondary_container(theme: &Theme) -> Style { - let secondary = theme.colors().secondary; - - Style { - background: Some(Background::Color(secondary.secondary_container)), - text_color: Some(secondary.on_secondary_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn tertiary(theme: &Theme) -> Style { - let tertiary = theme.colors().tertiary; - - Style { - background: Some(Background::Color(tertiary.color)), - text_color: Some(tertiary.on_tertiary), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn tertiary_container(theme: &Theme) -> Style { - let tertiary = theme.colors().tertiary; - - Style { - background: Some(Background::Color(tertiary.tertiary_container)), - text_color: Some(tertiary.on_tertiary_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn error(theme: &Theme) -> Style { - let error = theme.colors().error; - - Style { - background: Some(Background::Color(error.color)), - text_color: Some(error.on_error), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn error_container(theme: &Theme) -> Style { - let error = theme.colors().error; - - Style { - background: Some(Background::Color(error.error_container)), - text_color: Some(error.on_error_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - background: Some(Background::Color(surface.color)), - text_color: Some(surface.on_surface), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn surface_container_lowest(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - background: Some(Background::Color(surface.surface_container.lowest)), - text_color: Some(surface.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container_low(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - background: Some(Background::Color(surface.surface_container.low)), - text_color: Some(surface.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - background: Some(Background::Color(surface.surface_container.base)), - text_color: Some(surface.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container_high(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - background: Some(Background::Color(surface.surface_container.high)), - text_color: Some(surface.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container_highest(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - background: Some(Background::Color(surface.surface_container.highest)), - text_color: Some(surface.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn inverse_surface(theme: &Theme) -> Style { - let inverse = theme.colors().inverse; - - Style { - background: Some(Background::Color(inverse.inverse_surface)), - text_color: Some(inverse.inverse_on_surface), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn outlined(theme: &Theme) -> Style { - let base = transparent(theme); - - Style { - border: Border { - color: theme.colors().outline.color, - ..base.border - }, - ..base - } -} diff --git a/crates/material_theme/src/dialog.rs b/crates/material_theme/src/dialog.rs deleted file mode 100644 index c839948..0000000 --- a/crates/material_theme/src/dialog.rs +++ /dev/null @@ -1,41 +0,0 @@ -use iced_dialog::dialog::{Catalog, Style, StyleFn}; -use iced_widget::container; -use iced_widget::core::{Background, border}; - -use super::{Theme, text}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> <Self as Catalog>::Class<'a> { - Box::new(default) - } - - fn default_container<'a>() -> <Self as container::Catalog>::Class<'a> { - Box::new(default_container) - } - - fn default_title<'a>() -> <Self as iced_widget::text::Catalog>::Class<'a> { - Box::new(text::surface) - } - - fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style { - class(self) - } -} - -pub fn default_container(theme: &Theme) -> container::Style { - let colors = theme.colors().surface; - container::Style { - background: Some(Background::Color(colors.surface_container.high)), - text_color: Some(colors.on_surface_variant), - border: border::rounded(28), - ..container::Style::default() - } -} - -pub fn default(theme: &Theme) -> Style { - Style { - backdrop_color: theme.colors().scrim, - } -} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs deleted file mode 100644 index d2ae6ed..0000000 --- a/crates/material_theme/src/lib.rs +++ /dev/null @@ -1,474 +0,0 @@ -use std::borrow::Cow; -use std::sync::LazyLock; - -use iced_widget::core::theme::{Base, Style}; -use iced_widget::core::{Color, color}; -use utils::{lightness, mix}; - -pub mod button; -pub mod checkbox; -pub mod combo_box; -pub mod container; -#[cfg(feature = "dialog")] -pub mod dialog; -#[cfg(feature = "markdown")] -pub mod markdown; -pub mod menu; -pub mod pane_grid; -pub mod pick_list; -pub mod progress_bar; -#[cfg(feature = "qr_code")] -pub mod qr_code; -pub mod radio; -pub mod rule; -pub mod scrollable; -pub mod slider; -#[cfg(feature = "svg")] -pub mod svg; -pub mod text; -pub mod text_editor; -pub mod text_input; -pub mod toggler; -pub mod utils; - -#[allow(clippy::cast_precision_loss)] -macro_rules! from_argb { - ($hex:expr) => {{ - let hex = $hex as u32; - - let a = ((hex & 0xff000000) >> 24) as f32 / 255.0; - let r = (hex & 0x00ff0000) >> 16; - let g = (hex & 0x0000ff00) >> 8; - let b = (hex & 0x000000ff); - - ::iced_widget::core::color!(r as u8, g as u8, b as u8, a) - }}; -} - -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(from = "Custom", into = "Custom"))] -pub enum Theme { - Dark, - Light, - Custom(Custom), -} - -impl Theme { - pub const ALL: &'static [Self] = &[Self::Dark, Self::Light]; - - pub fn new( - name: impl Into<Cow<'static, str>>, - colorscheme: ColorScheme, - ) -> Self { - Self::Custom(Custom { - name: name.into(), - is_dark: lightness(colorscheme.surface.color) <= 0.5, - colorscheme, - }) - } - - pub const fn new_const( - name: &'static str, - colorscheme: ColorScheme, - ) -> Self { - Self::Custom(Custom { - name: Cow::Borrowed(name), - is_dark: lightness(colorscheme.surface.color) <= 0.5, - colorscheme, - }) - } - - pub fn name(&self) -> Cow<'static, str> { - match self { - Self::Dark => "Dark".into(), - Self::Light => "Light".into(), - Self::Custom(custom) => custom.name.clone(), - } - } - - pub fn is_dark(&self) -> bool { - match self { - Self::Dark => true, - Self::Light => false, - Self::Custom(custom) => custom.is_dark, - } - } - - pub fn colors(&self) -> ColorScheme { - match self { - Self::Dark => ColorScheme::DARK, - Self::Light => ColorScheme::LIGHT, - Self::Custom(custom) => custom.colorscheme, - } - } -} - -impl Default for Theme { - fn default() -> Self { - static DEFAULT: LazyLock<Theme> = LazyLock::new(|| { - if dark_light::detect() - .ok() - .is_none_or(|mode| mode == dark_light::Mode::Unspecified) - { - Theme::Dark - } else { - Theme::Light - } - }); - - DEFAULT.clone() - } -} - -impl std::fmt::Display for Theme { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name()) - } -} - -impl Base for Theme { - fn base(&self) -> Style { - Style { - background_color: self.colors().surface.color, - text_color: self.colors().surface.on_surface, - } - } - - fn palette(&self) -> Option<iced_widget::theme::Palette> { - let colors = self.colors(); - - Some(iced_widget::theme::Palette { - background: colors.surface.color, - text: colors.surface.on_surface, - primary: colors.primary.color, - success: colors.primary.primary_container, - warning: mix(from_argb!(0xffffff00), colors.primary.color, 0.25), - danger: colors.error.color, - }) - } -} - -#[cfg(feature = "animate")] -impl iced_anim::Animate for Theme { - fn components() -> usize { - ColorScheme::components() - } - - fn update(&mut self, components: &mut impl Iterator<Item = f32>) { - let mut colorscheme = self.colors(); - colorscheme.update(components); - *self = Self::Custom(Custom { - name: "Animating Theme".into(), - is_dark: self.is_dark(), - colorscheme, - }); - } - - fn distance_to(&self, end: &Self) -> Vec<f32> { - self.colors().distance_to(&end.colors()) - } - - fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { - let mut colorscheme = self.colors(); - colorscheme.lerp(&start.colors(), &end.colors(), progress); - *self = Self::Custom(Custom { - name: "Animating Theme".into(), - is_dark: self.is_dark(), - colorscheme, - }); - } -} - -#[derive(Debug, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Custom { - pub name: Cow<'static, str>, - pub is_dark: bool, - #[cfg_attr(feature = "serde", serde(flatten))] - pub colorscheme: ColorScheme, -} - -impl From<Custom> for Theme { - fn from(custom: Custom) -> Self { - Self::Custom(custom) - } -} - -impl From<Theme> for Custom { - fn from(theme: Theme) -> Self { - Self { - name: theme.name(), - is_dark: theme.is_dark(), - colorscheme: theme.colors(), - } - } -} - -impl Clone for Custom { - fn clone(&self) -> Self { - Self { - name: self.name.clone(), - is_dark: self.is_dark, - colorscheme: self.colorscheme, - } - } - - fn clone_from(&mut self, source: &Self) { - self.name.clone_from(&source.name); - self.is_dark = source.is_dark; - self.colorscheme = source.colorscheme; - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ColorScheme { - pub primary: Primary, - pub secondary: Secondary, - pub tertiary: Tertiary, - pub error: Error, - pub surface: Surface, - pub inverse: Inverse, - pub outline: Outline, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub shadow: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub scrim: Color, -} - -#[allow(clippy::cast_precision_loss)] -impl ColorScheme { - const DARK: Self = Self { - primary: Primary { - color: color!(0x9bd4a1), - on_primary: color!(0x003916), - primary_container: color!(0x1b5129), - on_primary_container: color!(0xb6f1bb), - }, - secondary: Secondary { - color: color!(0xb8ccb6), - on_secondary: color!(0x233425), - secondary_container: color!(0x394b3a), - on_secondary_container: color!(0xd3e8d1), - }, - tertiary: Tertiary { - color: color!(0xa1ced7), - on_tertiary: color!(0x00363e), - tertiary_container: color!(0x1f4d55), - on_tertiary_container: color!(0xbdeaf4), - }, - error: Error { - color: color!(0xffb4ab), - on_error: color!(0x690005), - error_container: color!(0x93000a), - on_error_container: color!(0xffdad6), - }, - surface: Surface { - color: color!(0x101510), - on_surface: color!(0xe0e4dc), - on_surface_variant: color!(0xc1c9be), - surface_container: SurfaceContainer { - lowest: color!(0x0b0f0b), - low: color!(0x181d18), - base: color!(0x1c211c), - high: color!(0x262b26), - highest: color!(0x313631), - }, - }, - inverse: Inverse { - inverse_surface: color!(0xe0e4dc), - inverse_on_surface: color!(0x2d322c), - inverse_primary: color!(0x34693f), - }, - outline: Outline { - color: color!(0x8b9389), - variant: color!(0x414941), - }, - shadow: color!(0x000000), - scrim: from_argb!(0x4d000000), - }; - - const LIGHT: Self = Self { - primary: Primary { - color: color!(0x34693f), - on_primary: color!(0xffffff), - primary_container: color!(0xb6f1bb), - on_primary_container: color!(0x1b5129), - }, - secondary: Secondary { - color: color!(0x516351), - on_secondary: color!(0xffffff), - secondary_container: color!(0xd3e8d1), - on_secondary_container: color!(0x394b3a), - }, - tertiary: Tertiary { - color: color!(0x39656d), - on_tertiary: color!(0xffffff), - tertiary_container: color!(0xbdeaf4), - on_tertiary_container: color!(0x1f4d55), - }, - error: Error { - color: color!(0xba1a1a), - on_error: color!(0xffffff), - error_container: color!(0xffdad6), - on_error_container: color!(0x93000a), - }, - surface: Surface { - color: color!(0xf7fbf2), - on_surface: color!(0x181d18), - on_surface_variant: color!(0x414941), - surface_container: SurfaceContainer { - lowest: color!(0xffffff), - low: color!(0xf1f5ed), - base: color!(0xebefe7), - high: color!(0xe5e9e1), - highest: color!(0xe0e4dc), - }, - }, - inverse: Inverse { - inverse_surface: color!(0x2d322c), - inverse_on_surface: color!(0xeef2ea), - inverse_primary: color!(0x9bd4a1), - }, - outline: Outline { - color: color!(0x727970), - variant: color!(0xc1c9be), - }, - shadow: color!(0x000000), - scrim: from_argb!(0x4d000000), - }; -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Primary { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub color: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_primary: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub primary_container: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_primary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Secondary { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub color: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_secondary: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub secondary_container: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_secondary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Tertiary { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub color: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_tertiary: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub tertiary_container: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_tertiary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Error { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub color: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_error: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub error_container: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_error_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Surface { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub color: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_surface: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub on_surface_variant: Color, - pub surface_container: SurfaceContainer, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct SurfaceContainer { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub lowest: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub low: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub base: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub high: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub highest: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Inverse { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub inverse_surface: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub inverse_on_surface: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub inverse_primary: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Outline { - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub color: Color, - #[cfg_attr(feature = "serde", serde(with = "color_serde"))] - pub variant: Color, -} - -#[cfg(feature = "serde")] -mod color_serde { - use iced_widget::core::Color; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::utils::{color_to_argb, parse_argb}; - - pub fn deserialize<'de, D>(deserializer: D) -> Result<Color, D::Error> - where - D: Deserializer<'de>, - { - Ok(String::deserialize(deserializer) - .map(|hex| parse_argb(&hex))? - .unwrap_or(Color::TRANSPARENT)) - } - - pub fn serialize<S>(color: &Color, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - color_to_argb(*color).serialize(serializer) - } -} diff --git a/crates/material_theme/src/markdown.rs b/crates/material_theme/src/markdown.rs deleted file mode 100644 index bc14ffe..0000000 --- a/crates/material_theme/src/markdown.rs +++ /dev/null @@ -1,10 +0,0 @@ -use iced_widget::markdown::Catalog; - -use super::{Theme, container}; - -impl Catalog for Theme { - fn code_block<'a>() -> <Self as iced_widget::container::Catalog>::Class<'a> - { - Box::new(container::surface_container_highest) - } -} diff --git a/crates/material_theme/src/menu.rs b/crates/material_theme/src/menu.rs deleted file mode 100644 index d595c2f..0000000 --- a/crates/material_theme/src/menu.rs +++ /dev/null @@ -1,33 +0,0 @@ -use iced_widget::core::{Background, border}; -use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; - -use super::Theme; -use crate::utils::{HOVERED_LAYER_OPACITY, mix}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> <Self as Catalog>::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style { - class(self) - } -} - -pub fn default(theme: &Theme) -> Style { - let colors = theme.colors().surface; - - Style { - border: border::rounded(4), - background: Background::Color(colors.surface_container.base), - text_color: colors.on_surface, - selected_background: Background::Color(mix( - colors.surface_container.base, - colors.on_surface, - HOVERED_LAYER_OPACITY, - )), - selected_text_color: colors.on_surface, - } -} diff --git a/crates/material_theme/src/pane_grid.rs b/crates/material_theme/src/pane_grid.rs deleted file mode 100644 index fb69a32..0000000 --- a/crates/material_theme/src/pane_grid.rs +++ /dev/null @@ -1,38 +0,0 @@ -use iced_widget::core::{Background, border}; -use iced_widget::pane_grid::{Catalog, Highlight, Line, Style, StyleFn}; - -use super::Theme; -use crate::utils::{HOVERED_LAYER_OPACITY, mix}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> <Self as Catalog>::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &<Self as Catalog>::Class<'_>) -> Style { - class(self) - } -} - -pub fn default(theme: &Theme) -> Style { - Style { - hovered_region: Highlight { - background: Background::Color(mix( - theme.colors().tertiary.tertiary_container, - theme.colors().surface.on_surface, - HOVERED_LAYER_OPACITY, - )), - border: border::rounded(12), - }, - picked_split: Line { - color: theme.colors().outline.variant, - width: 2.0, - }, - hovered_split: Line { - color: theme.colors().surface.on_surface, - width: 6.0, - }, - } -} diff --git a/crates/material_theme/src/pick_list.rs b/crates/material_theme/src/pick_list.rs deleted file mode 100644 index 1fe015e..0000000 --- a/crates/material_theme/src/pick_list.rs +++ /dev/null @@ -1,45 +0,0 @@ -use iced_widget::core::{Background, border}; -use iced_widget::pick_list::{Catalog, Status, Style, StyleFn}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> <Self as Catalog>::Class<'a> { - Box::new(default) - } - - fn style( - &self, - class: &<Self as Catalog>::Class<'_>, - status: Status, - ) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - - let active = Style { - text_color: surface.on_surface, - placeholder_color: surface.on_surface_variant, - handle_color: surface.on_surface_variant, - background: Background::Color(surface.surface_container.highest), - border: border::rounded(4), - }; - - match status { - Status::Active => active, - Status::Hovered => Style { - background: Background::Color(surface.surface_container.highest), - ..active - }, - Status::Opened { .. } => Style { - background: Background::Color(surface.surface_container.highest), - border: border::rounded(4), - ..active - }, - } -} diff --git a/crates/material_theme/src/progress_bar.rs b/crates/material_theme/src/progress_bar.rs deleted file mode 100644 index 9b4e844..0000000 --- a/crates/material_theme/src/progress_bar.rs +++ /dev/null @@ -1,26 +0,0 @@ -use iced_widget::core::{Background, border}; -use iced_widget::progress_bar::{Catalog, Style, StyleFn}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn default(theme: &Theme) -> Style { - Style { - background: Background::Color( - theme.colors().secondary.secondary_container, - ), - bar: Background::Color(theme.colors().primary.color), - border: border::rounded(400), - } -} diff --git a/crates/material_theme/src/qr_code.rs b/crates/material_theme/src/qr_code.rs deleted file mode 100644 index f603440..0000000 --- a/crates/material_theme/src/qr_code.rs +++ /dev/null @@ -1,24 +0,0 @@ -use iced_widget::qr_code::{Catalog, Style, StyleFn}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn default(theme: &Theme) -> Style { - let surface = theme.colors().surface; - - Style { - cell: surface.on_surface, - background: surface.color, - } -} diff --git a/crates/material_theme/src/radio.rs b/crates/material_theme/src/radio.rs deleted file mode 100644 index 7fb7a3f..0000000 --- a/crates/material_theme/src/radio.rs +++ /dev/null @@ -1,62 +0,0 @@ -use iced_widget::core::{Background, Color}; -use iced_widget::radio::{Catalog, Status, Style, StyleFn}; - -use super::Theme; -use crate::utils::{HOVERED_LAYER_OPACITY, disabled_text, mix}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let primary = theme.colors().primary; - - let active = Style { - background: Color::TRANSPARENT.into(), - dot_color: primary.color, - border_width: 1.0, - border_color: primary.color, - text_color: None, - }; - - match status { - Status::Active { is_selected } => Style { - border_color: if is_selected { - active.border_color - } else { - surface.on_surface - }, - ..active - }, - Status::Hovered { is_selected } => Style { - dot_color: mix( - primary.color, - surface.on_surface, - HOVERED_LAYER_OPACITY, - ), - border_color: if is_selected { - mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY) - } else { - disabled_text(surface.on_surface) - }, - background: Background::Color(if is_selected { - Color { - a: HOVERED_LAYER_OPACITY, - ..surface.on_surface - } - } else { - Color::TRANSPARENT - }), - ..active - }, - } -} diff --git a/crates/material_theme/src/rule.rs b/crates/material_theme/src/rule.rs deleted file mode 100644 index 77cb0ef..0000000 --- a/crates/material_theme/src/rule.rs +++ /dev/null @@ -1,35 +0,0 @@ -use iced_widget::core::border::Radius; -use iced_widget::rule::{Catalog, FillMode, Style, StyleFn}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(inset) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn inset(theme: &Theme) -> Style { - Style { - color: theme.colors().outline.variant, - fill_mode: FillMode::Padded(8), - width: 1, - radius: Radius::default(), - snap: cfg!(feature = "crisp"), - } -} -pub fn full_width(theme: &Theme) -> Style { - Style { - color: theme.colors().outline.variant, - fill_mode: FillMode::Full, - width: 1, - radius: Radius::default(), - snap: cfg!(feature = "crisp"), - } -} diff --git a/crates/material_theme/src/scrollable.rs b/crates/material_theme/src/scrollable.rs deleted file mode 100644 index 341f047..0000000 --- a/crates/material_theme/src/scrollable.rs +++ /dev/null @@ -1,146 +0,0 @@ -use iced_widget::core::{Background, Border, border}; -use iced_widget::scrollable::{ - Catalog, Rail, Scroller, Status, Style, StyleFn, -}; - -use super::Theme; -use super::container::surface_container; -use super::utils::mix; -use crate::utils::{ - HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, disabled_container, - disabled_text, -}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - - let active = Rail { - background: None, - scroller: Scroller { - color: surface.on_surface, - border: border::rounded(400), - }, - border: Border::default(), - }; - - let disabled = Rail { - background: Some(Background::Color(disabled_container( - surface.on_surface, - ))), - scroller: Scroller { - color: disabled_text(surface.on_surface), - border: border::rounded(400), - }, - ..active - }; - - let style = Style { - container: surface_container(theme), - vertical_rail: active, - horizontal_rail: active, - gap: None, - }; - - match status { - Status::Active { - is_horizontal_scrollbar_disabled, - is_vertical_scrollbar_disabled, - } => Style { - horizontal_rail: if is_horizontal_scrollbar_disabled { - disabled - } else { - active - }, - vertical_rail: if is_vertical_scrollbar_disabled { - disabled - } else { - active - }, - ..style - }, - Status::Hovered { - is_horizontal_scrollbar_hovered, - is_vertical_scrollbar_hovered, - is_horizontal_scrollbar_disabled, - is_vertical_scrollbar_disabled, - } => { - let hovered_rail = Rail { - scroller: Scroller { - color: mix( - surface.on_surface, - surface.color, - HOVERED_LAYER_OPACITY, - ), - border: border::rounded(400), - }, - ..active - }; - - Style { - horizontal_rail: if is_horizontal_scrollbar_disabled { - disabled - } else if is_horizontal_scrollbar_hovered { - hovered_rail - } else { - active - }, - vertical_rail: if is_vertical_scrollbar_disabled { - disabled - } else if is_vertical_scrollbar_hovered { - hovered_rail - } else { - active - }, - ..style - } - } - Status::Dragged { - is_horizontal_scrollbar_dragged, - is_vertical_scrollbar_dragged, - is_horizontal_scrollbar_disabled, - is_vertical_scrollbar_disabled, - } => { - let dragged_rail = Rail { - scroller: Scroller { - color: mix( - surface.on_surface, - surface.color, - PRESSED_LAYER_OPACITY, - ), - border: border::rounded(400), - }, - ..active - }; - - Style { - horizontal_rail: if is_horizontal_scrollbar_disabled { - disabled - } else if is_horizontal_scrollbar_dragged { - dragged_rail - } else { - active - }, - vertical_rail: if is_vertical_scrollbar_disabled { - disabled - } else if is_vertical_scrollbar_dragged { - dragged_rail - } else { - active - }, - ..style - } - } - } -} diff --git a/crates/material_theme/src/slider.rs b/crates/material_theme/src/slider.rs deleted file mode 100644 index ae9ee4b..0000000 --- a/crates/material_theme/src/slider.rs +++ /dev/null @@ -1,63 +0,0 @@ -use iced_widget::core::{Background, Color, border}; -use iced_widget::slider::{ - Catalog, Handle, HandleShape, Rail, Status, Style, StyleFn, -}; - -use super::Theme; -use crate::utils::{HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, mix}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> <Self as Catalog>::Class<'a> { - Box::new(default) - } - - fn style( - &self, - class: &<Self as Catalog>::Class<'_>, - status: Status, - ) -> Style { - class(self, status) - } -} - -pub fn styled(left: Color, right: Color, handle_radius: f32) -> Style { - Style { - rail: Rail { - backgrounds: (left.into(), right.into()), - width: 8.0, - border: border::rounded(400), - }, - handle: Handle { - shape: HandleShape::Circle { - radius: handle_radius, - }, - background: Background::Color(left), - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let primary = theme.colors().primary; - let secondary = theme.colors().secondary; - - match status { - Status::Active => { - styled(primary.color, secondary.secondary_container, 12.0) - } - Status::Hovered => styled( - mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY), - secondary.secondary_container, - 12.0, - ), - Status::Dragged => styled( - mix(primary.color, surface.on_surface, PRESSED_LAYER_OPACITY), - secondary.secondary_container, - 11.0, - ), - } -} diff --git a/crates/material_theme/src/svg.rs b/crates/material_theme/src/svg.rs deleted file mode 100644 index 885d743..0000000 --- a/crates/material_theme/src/svg.rs +++ /dev/null @@ -1,15 +0,0 @@ -use iced_widget::svg::{Catalog, Status, Style, StyleFn}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(|_theme, _status| Style::default()) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} diff --git a/crates/material_theme/src/text.rs b/crates/material_theme/src/text.rs deleted file mode 100644 index 8da3cdf..0000000 --- a/crates/material_theme/src/text.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![allow(dead_code)] -use iced_widget::text::{Catalog, Style, StyleFn}; - -use crate::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(none) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn none(_: &Theme) -> Style { - Style { color: None } -} - -pub fn primary(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().primary.on_primary), - } -} - -pub fn primary_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().primary.on_primary_container), - } -} - -pub fn secondary(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().secondary.on_secondary), - } -} - -pub fn secondary_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().secondary.on_secondary_container), - } -} - -pub fn tertiary(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().tertiary.on_tertiary), - } -} - -pub fn tertiary_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().tertiary.on_tertiary_container), - } -} - -pub fn error(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().error.on_error), - } -} - -pub fn error_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().error.on_error_container), - } -} - -pub fn surface(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().surface.on_surface), - } -} - -pub fn surface_variant(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().surface.on_surface_variant), - } -} - -pub fn inverse_surface(theme: &Theme) -> Style { - Style { - color: Some(theme.colors().inverse.inverse_on_surface), - } -} diff --git a/crates/material_theme/src/text_editor.rs b/crates/material_theme/src/text_editor.rs deleted file mode 100644 index 14d7104..0000000 --- a/crates/material_theme/src/text_editor.rs +++ /dev/null @@ -1,67 +0,0 @@ -use iced_widget::core::{Background, Border, Color, border}; -use iced_widget::text_editor::{Catalog, Status, Style, StyleFn}; - -use super::Theme; -use crate::utils::{disabled_container, disabled_text}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let primary = theme.colors().primary; - - let active = Style { - background: Background::Color(surface.surface_container.highest), - border: Border { - color: theme.colors().outline.color, - width: 1.0, - radius: 4.into(), - }, - icon: surface.on_surface_variant, - placeholder: surface.on_surface_variant, - value: surface.on_surface, - selection: disabled_text(primary.color), - }; - - match status { - Status::Active => active, - Status::Hovered => Style { - border: Border { - color: surface.on_surface, - ..active.border - }, - ..active - }, - Status::Focused { .. } => Style { - border: Border { - color: primary.color, - width: 2.0, - ..active.border - }, - placeholder: primary.color, - ..active - }, - Status::Disabled => Style { - background: Color::TRANSPARENT.into(), - border: Border { - color: disabled_container(surface.on_surface), - width: 1.0, - radius: border::radius(4), - }, - icon: disabled_text(surface.on_surface), - placeholder: disabled_text(surface.on_surface), - value: disabled_text(surface.on_surface), - selection: disabled_text(surface.on_surface), - }, - } -} diff --git a/crates/material_theme/src/text_input.rs b/crates/material_theme/src/text_input.rs deleted file mode 100644 index 4db220b..0000000 --- a/crates/material_theme/src/text_input.rs +++ /dev/null @@ -1,63 +0,0 @@ -use iced_widget::core::{Background, Border, Color}; -use iced_widget::text_input::{Catalog, Status, Style, StyleFn}; - -use super::Theme; -use crate::utils::{disabled_container, disabled_text}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let primary = theme.colors().primary; - - let active = Style { - background: Background::Color(surface.surface_container.highest), - border: Border { - color: theme.colors().outline.color, - width: 1.0, - radius: 4.into(), - }, - icon: surface.on_surface_variant, - placeholder: surface.on_surface_variant, - value: surface.on_surface, - selection: disabled_text(primary.color), - }; - - match status { - Status::Active => active, - Status::Hovered => Style { - border: active.border.color(surface.on_surface), - ..active - }, - Status::Disabled => Style { - background: Color::TRANSPARENT.into(), - border: Border { - color: disabled_container(surface.on_surface), - ..active.border - }, - icon: disabled_text(surface.on_surface), - placeholder: disabled_text(surface.on_surface), - value: disabled_text(surface.on_surface), - selection: disabled_text(surface.on_surface), - }, - Status::Focused { .. } => Style { - border: Border { - color: primary.color, - width: 2.0, - ..active.border - }, - placeholder: primary.color, - ..active - }, - } -} diff --git a/crates/material_theme/src/toggler.rs b/crates/material_theme/src/toggler.rs deleted file mode 100644 index 5cebc88..0000000 --- a/crates/material_theme/src/toggler.rs +++ /dev/null @@ -1,73 +0,0 @@ -use iced_widget::core::Color; -use iced_widget::toggler::{Catalog, Status, Style, StyleFn}; - -use super::Theme; -use crate::utils::{ - HOVERED_LAYER_OPACITY, disabled_container, disabled_text, mix, -}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn styled( - background: Color, - foreground: Color, - border: Option<Color>, -) -> Style { - Style { - background, - background_border_width: if border.is_some() { 2.0 } else { 0.0 }, - background_border_color: border.unwrap_or(Color::TRANSPARENT), - foreground, - foreground_border_width: 0.0, - foreground_border_color: Color::TRANSPARENT, - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colors().surface; - let primary = theme.colors().primary; - - match status { - Status::Active { is_toggled } => { - if is_toggled { - styled(primary.color, primary.on_primary, None) - } else { - styled( - surface.surface_container.highest, - theme.colors().outline.color, - Some(theme.colors().outline.color), - ) - } - } - Status::Hovered { is_toggled } => { - if is_toggled { - styled(primary.color, primary.primary_container, None) - } else { - styled( - mix( - surface.surface_container.highest, - surface.on_surface, - HOVERED_LAYER_OPACITY, - ), - surface.on_surface_variant, - Some(theme.colors().outline.color), - ) - } - } - Status::Disabled => styled( - disabled_container(surface.surface_container.highest), - disabled_text(surface.on_surface), - Some(disabled_text(surface.on_surface)), - ), - } -} diff --git a/crates/material_theme/src/utils.rs b/crates/material_theme/src/utils.rs deleted file mode 100644 index 4c62ec3..0000000 --- a/crates/material_theme/src/utils.rs +++ /dev/null @@ -1,158 +0,0 @@ -use iced_widget::core::{Color, Shadow, Vector}; - -const COLOR_ERROR_MARGIN: f32 = 0.0001; - -pub const HOVERED_LAYER_OPACITY: f32 = 0.08; -pub const PRESSED_LAYER_OPACITY: f32 = 0.1; - -pub const DISABLED_TEXT_OPACITY: f32 = 0.38; -pub const DISABLED_CONTAINER_OPACITY: f32 = 0.12; - -pub fn elevation(elevation_level: u8) -> f32 { - (match elevation_level { - 0 => 0.0, - 1 => 1.0, - 2 => 3.0, - 3 => 6.0, - 4 => 8.0, - _ => 12.0, - } as f32) -} - -pub fn shadow_from_elevation(elevation: f32, color: Color) -> Shadow { - Shadow { - color, - offset: Vector { - x: 0.0, - y: elevation, - }, - blur_radius: (elevation) * (1.0 + 0.4_f32.powf(elevation)), - } -} - -pub fn disabled_text(color: Color) -> Color { - Color { - a: DISABLED_TEXT_OPACITY, - ..color - } -} - -pub fn disabled_container(color: Color) -> Color { - Color { - a: DISABLED_CONTAINER_OPACITY, - ..color - } -} - -pub fn parse_argb(s: &str) -> Option<Color> { - let hex = s.strip_prefix('#').unwrap_or(s); - - let parse_channel = |from: usize, to: usize| { - let num = - usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; - - // If we only got half a byte (one letter), expand it into a full byte (two letters) - Some(if from == to { num + num * 16.0 } else { num }) - }; - - Some(match hex.len() { - 3 => Color::from_rgb( - parse_channel(0, 0)?, - parse_channel(1, 1)?, - parse_channel(2, 2)?, - ), - 4 => Color::from_rgba( - parse_channel(1, 1)?, - parse_channel(2, 2)?, - parse_channel(3, 3)?, - parse_channel(0, 0)?, - ), - 6 => Color::from_rgb( - parse_channel(0, 1)?, - parse_channel(2, 3)?, - parse_channel(4, 5)?, - ), - 8 => Color::from_rgba( - parse_channel(2, 3)?, - parse_channel(4, 5)?, - parse_channel(6, 7)?, - parse_channel(0, 1)?, - ), - _ => None?, - }) -} - -pub fn color_to_argb(color: Color) -> String { - use std::fmt::Write; - - let mut hex = String::with_capacity(9); - - let [r, g, b, a] = color.into_rgba8(); - - let _ = write!(&mut hex, "#"); - - if a < u8::MAX { - let _ = write!(&mut hex, "{a:02X}"); - } - - let _ = write!(&mut hex, "{r:02X}"); - let _ = write!(&mut hex, "{g:02X}"); - let _ = write!(&mut hex, "{b:02X}"); - - hex -} - -pub const fn lightness(color: Color) -> f32 { - color.r * 0.299 + color.g * 0.587 + color.b * 0.114 -} - -pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { - if p2 <= 0.0 { - return color1; - } else if p2 >= 1.0 { - return color2; - } - - let p1 = 1.0 - p2; - - if (color1.a - 1.0).abs() > COLOR_ERROR_MARGIN - || (color2.a - 1.0).abs() > COLOR_ERROR_MARGIN - { - let a = color1.a * p1 + color2.a * p2; - if a > 0.0 { - let c1 = color1.into_linear().map(|c| c * color1.a * p1); - let c2 = color2.into_linear().map(|c| c * color2.a * p2); - - let [r, g, b] = - [c1[0] + c2[0], c1[1] + c2[1], c1[2] + c2[2]].map(|u| u / a); - - return Color::from_linear_rgba(r, g, b, a); - } - } - - let c1 = color1.into_linear().map(|c| c * p1); - let c2 = color2.into_linear().map(|c| c * p2); - - Color::from_linear_rgba( - c1[0] + c2[0], - c1[1] + c2[1], - c1[2] + c2[2], - c1[3] + c2[3], - ) -} - -#[cfg(test)] -mod tests { - use super::{Color, mix}; - - #[test] - fn mixing_works() { - let base = Color::from_rgba(1.0, 0.0, 0.0, 0.7); - let overlay = Color::from_rgba(0.0, 1.0, 0.0, 0.2); - - assert_eq!( - mix(base, overlay, 0.75).into_rgba8(), - Color::from_linear_rgba(0.53846, 0.46154, 0.0, 0.325).into_rgba8() - ); - } -} |
