css_style/
color.rs

1use super::{Style, StyleUpdater};
2use palette::{FromColor, IntoColor, Packed, Srgb, Srgba};
3
4pub use palette::{self, named};
5
6pub fn display_rgb(rgb: &Srgb) -> String {
7    let (red, green, blue) = rgb.into_components();
8    format!(
9        "rgb({:.2}%, {:.2}%, {:.2}%)",
10        (red * 100.0),
11        green * 100.0,
12        blue * 100.0
13    )
14}
15
16pub fn display_rgba(rgb: &Srgba) -> String {
17    let (red, green, blue, alpha) = rgb.into_components();
18    format!(
19        "rgba({:.2}%, {:.2}%, {:.2}%, {})",
20        red * 100.0,
21        green * 100.0,
22        blue * 100.0,
23        alpha
24    )
25}
26
27pub fn display_rgb_u8(rgb: &Srgb<u8>) -> String {
28    let (red, green, blue) = rgb.into_components();
29    format!("rgb({}, {}, {})", red, green, blue)
30}
31
32pub fn display_rgba_u8(rgb: &Srgba<u8>) -> String {
33    let (red, green, blue, alpha) = rgb.into_components();
34    format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
35}
36
37#[derive(Clone, Copy, Debug, PartialEq, Display, From)]
38pub enum Color {
39    #[from]
40    #[display(fmt = "{}", "display_rgb(_0)")]
41    Rgb(Srgb),
42    #[from]
43    #[display(fmt = "{}", "display_rgba(_0)")]
44    Rgba(Srgba),
45    #[from]
46    #[display(fmt = "{}", "display_rgba_u8(_0)")]
47    RgbaU8(Srgba<u8>),
48    #[from]
49    #[display(fmt = "{}", "display_rgb_u8(_0)")]
50    RgbU8(Srgb<u8>),
51    // https://www.w3.org/TR/css-color-3/#transparent
52    #[display(fmt = "transparent")]
53    Transparent,
54    #[display(fmt = "currentColor")]
55    CurrentColor,
56}
57
58impl From<Packed> for Color {
59    fn from(source: Packed) -> Self {
60        Color::RgbaU8(source.into())
61    }
62}
63
64impl From<u32> for Color {
65    fn from(source: u32) -> Self {
66        Color::from(Packed::from(source))
67    }
68}
69
70impl From<(u8, u8, u8)> for Color {
71    fn from(source: (u8, u8, u8)) -> Self {
72        Color::RgbU8(source.into())
73    }
74}
75
76impl From<(u8, u8, u8, u8)> for Color {
77    fn from(source: (u8, u8, u8, u8)) -> Self {
78        Color::RgbaU8(source.into())
79    }
80}
81
82impl From<(f32, f32, f32)> for Color {
83    fn from(source: (f32, f32, f32)) -> Self {
84        Color::Rgb(source.into())
85    }
86}
87
88impl From<(f32, f32, f32, f32)> for Color {
89    fn from(source: (f32, f32, f32, f32)) -> Self {
90        Color::Rgba(source.into())
91    }
92}
93
94impl<T> FromColor<T> for Color
95where
96    T: IntoColor<Srgba>,
97{
98    fn from_color(t: T) -> Self {
99        let rgba = t.into_color();
100        Color::Rgba(rgba)
101    }
102}
103
104impl StyleUpdater for Color {
105    fn update_style(self, style: Style) -> Style {
106        style.insert("color", self)
107    }
108}
109
110#[derive(Clone, Copy, Debug, PartialEq, From)]
111pub struct Opacity(f32);
112
113impl StyleUpdater for Opacity {
114    fn update_style(self, style: Style) -> Style {
115        style.insert("opacity", self.0)
116    }
117}
118
119impl TryFrom<Color> for Srgba {
120    type Error = &'static str;
121
122    fn try_from(value: Color) -> Result<Self, Self::Error> {
123        match value {
124            Color::Rgb(rgb) => Ok(rgb.into()),
125            Color::Rgba(rgba) => Ok(rgba),
126            Color::RgbaU8(rgb) => Ok(rgb.into_format()),
127            Color::RgbU8(rgb) => Ok(rgb.into_format().into()),
128            Color::Transparent => Ok(Srgba::new(0.0, 0.0, 0.0, 0.0)),
129            Color::CurrentColor => Err("Cannot convert CurrentColor into a color"),
130        }
131    }
132}
133
134impl TryFrom<Color> for Srgb {
135    type Error = &'static str;
136
137    fn try_from(value: Color) -> Result<Self, Self::Error> {
138        let rgba: Srgba = value.try_into()?;
139        Ok(rgba.color)
140    }
141}