1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use super::{Style, StyleUpdater};
use palette::{FromColor, IntoColor, Packed, Srgb, Srgba};

pub use palette::{self, named};

pub fn display_rgb(rgb: &Srgb) -> String {
    let (red, green, blue) = rgb.into_components();
    format!(
        "rgb({:.2}%, {:.2}%, {:.2}%)",
        (red * 100.0),
        green * 100.0,
        blue * 100.0
    )
}

pub fn display_rgba(rgb: &Srgba) -> String {
    let (red, green, blue, alpha) = rgb.into_components();
    format!(
        "rgba({:.2}%, {:.2}%, {:.2}%, {})",
        red * 100.0,
        green * 100.0,
        blue * 100.0,
        alpha
    )
}

pub fn display_rgb_u8(rgb: &Srgb<u8>) -> String {
    let (red, green, blue) = rgb.into_components();
    format!("rgb({}, {}, {})", red, green, blue)
}

pub fn display_rgba_u8(rgb: &Srgba<u8>) -> String {
    let (red, green, blue, alpha) = rgb.into_components();
    format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
}

#[derive(Clone, Copy, Debug, PartialEq, Display, From)]
pub enum Color {
    #[from]
    #[display(fmt = "{}", "display_rgb(_0)")]
    Rgb(Srgb),
    #[from]
    #[display(fmt = "{}", "display_rgba(_0)")]
    Rgba(Srgba),
    #[from]
    #[display(fmt = "{}", "display_rgba_u8(_0)")]
    RgbaU8(Srgba<u8>),
    #[from]
    #[display(fmt = "{}", "display_rgb_u8(_0)")]
    RgbU8(Srgb<u8>),
    // https://www.w3.org/TR/css-color-3/#transparent
    #[display(fmt = "transparent")]
    Transparent,
    #[display(fmt = "currentColor")]
    CurrentColor,
}

impl From<Packed> for Color {
    fn from(source: Packed) -> Self {
        Color::RgbaU8(source.into())
    }
}

impl From<u32> for Color {
    fn from(source: u32) -> Self {
        Color::from(Packed::from(source))
    }
}

impl From<(u8, u8, u8)> for Color {
    fn from(source: (u8, u8, u8)) -> Self {
        Color::RgbU8(source.into())
    }
}

impl From<(u8, u8, u8, u8)> for Color {
    fn from(source: (u8, u8, u8, u8)) -> Self {
        Color::RgbaU8(source.into())
    }
}

impl From<(f32, f32, f32)> for Color {
    fn from(source: (f32, f32, f32)) -> Self {
        Color::Rgb(source.into())
    }
}

impl From<(f32, f32, f32, f32)> for Color {
    fn from(source: (f32, f32, f32, f32)) -> Self {
        Color::Rgba(source.into())
    }
}

impl<T> FromColor<T> for Color
where
    T: IntoColor<Srgba>,
{
    fn from_color(t: T) -> Self {
        let rgba = t.into_color();
        Color::Rgba(rgba)
    }
}

impl StyleUpdater for Color {
    fn update_style(self, style: Style) -> Style {
        style.insert("color", self)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, From)]
pub struct Opacity(f32);

impl StyleUpdater for Opacity {
    fn update_style(self, style: Style) -> Style {
        style.insert("opacity", self.0)
    }
}

impl TryFrom<Color> for Srgba {
    type Error = &'static str;

    fn try_from(value: Color) -> Result<Self, Self::Error> {
        match value {
            Color::Rgb(rgb) => Ok(rgb.into()),
            Color::Rgba(rgba) => Ok(rgba),
            Color::RgbaU8(rgb) => Ok(rgb.into_format()),
            Color::RgbU8(rgb) => Ok(rgb.into_format().into()),
            Color::Transparent => Ok(Srgba::new(0.0, 0.0, 0.0, 0.0)),
            Color::CurrentColor => Err("Cannot convert CurrentColor into a color"),
        }
    }
}

impl TryFrom<Color> for Srgb {
    type Error = &'static str;

    fn try_from(value: Color) -> Result<Self, Self::Error> {
        let rgba: Srgba = value.try_into()?;
        Ok(rgba.color)
    }
}