ux-primitives 0.2.2

Graphics Primitives for Angular Rust
Documentation
#![cfg(any(feature = "color_from_css", test))]

use super::Color;
use lazy_static::lazy_static;
use std::collections::HashMap;

lazy_static! {
    pub static ref COLORS: HashMap<&'static str, Color> = {
        let colors: Vec<(&'static str, u32)> = vec![
            // css 1
            ("black",   0x000000),
            ("silver",  0xc0c0c0),
            ("gray",    0x808080),
            ("white",   0xffffff),
            ("maroon",  0x800000),
            ("red",     0xff0000),
            ("purple",  0x800080),
            ("fuchsia", 0xff00ff),
            ("green",   0x008000),
            ("lime",    0x00ff00),
            ("olive",   0x808000),
            ("yellow",  0xffff00),
            ("navy",    0x000080),
            ("blue",    0x0000ff),
            ("teal",    0x008080),
            ("aqua",    0x00ffff),

            // css2 rev 1
            ("orange",          0xffa500),
            ("aliceblue",       0xf0f8ff),
            ("antiquewhite",    0xfaebd7),
            ("aquamarine",      0x7fffd4),
            ("azure",           0xf0ffff),
            ("beige",           0xf5f5dc),
            ("bisque",          0xffe4c4),
            ("blanchedalmond",  0xffebcd),
            ("blueviolet",      0x8a2be2),
            ("brown",           0xa52a2a),
            ("burlywood",       0xdeb887),
            ("cadetblue",       0x5f9ea0),
            ("chartreuse",      0x7fff00),
            ("chocolate",       0xd2691e),
            ("coral",           0xff7f50),
            ("cornflowerblue",  0x6495ed),
            ("cornsilk",        0xfff8dc),
            ("crimson",         0xdc143c),
            ("cyan",            0x00ffff),
            ("darkblue",        0x00008b),
            ("darkcyan",        0x008b8b),
            ("darkgoldenrod",   0xb8860b),
            ("darkgray",        0xa9a9a9),
            ("darkgreen",       0x006400),
            ("darkgrey",        0xa9a9a9),
            ("darkkhaki",       0xbdb76b),
            ("darkmagenta",     0x8b008b),
            ("darkolivegreen",  0x556b2f),
            ("darkorange",      0xff8c00),
            ("darkorchid",      0x9932cc),
            ("darkred",         0x8b0000),
            ("darksalmon",      0xe9967a),
            ("darkseagreen",    0x8fbc8f),
            ("darkslateblue",   0x483d8b),
            ("darkslategray",   0x2f4f4f),
            ("darkslategrey",   0x2f4f4f),
            ("darkturquoise",   0x00ced1),
            ("darkviolet",      0x9400d3),
            ("deeppink",        0xff1493),
            ("deepskyblue",     0x00bfff),
            ("dimgray",         0x696969),
            ("dimgrey",         0x696969),
            ("dodgerblue",      0x1e90ff),
            ("firebrick",       0xb22222),
            ("floralwhite",     0xfffaf0),
            ("forestgreen",     0x228b22),
            ("gainsboro",       0xdcdcdc),
            ("ghostwhite",      0xf8f8ff),
            ("gold",            0xffd700),
            ("goldenrod",       0xdaa520),
            ("greenyellow",     0xadff2f),
            ("grey",            0x808080),
            ("honeydew",        0xf0fff0),
            ("hotpink",         0xff69b4),
            ("indianred",       0xcd5c5c),
            ("indigo",          0x4b0082),
            ("ivory",           0xfffff0),
            ("khaki",           0xf0e68c),
            ("lavender",        0xe6e6fa),
            ("lavenderblush",   0xfff0f5),
            ("lawngreen",       0x7cfc00),
            ("lemonchiffon",    0xfffacd),
            ("lightblue",       0xadd8e6),
            ("lightcoral",      0xf08080),
            ("lightcyan",       0xe0ffff),
            ("lightgoldenrodyellow", 0xfafad2),

            // css3
            ("lightgray",           0xd3d3d3),
            ("lightgreen",          0x90ee90),
            ("lightgrey",           0xd3d3d3),
            ("lightpink",           0xffb6c1),
            ("lightsalmon",         0xffa07a),
            ("lightseagreen",       0x20b2aa),
            ("lightskyblue",        0x87cefa),
            ("lightslategray",      0x778899),
            ("lightslategrey",      0x778899),
            ("lightsteelblue",      0xb0c4de),
            ("lightyellow",         0xffffe0),
            ("limegreen",           0x32cd32),
            ("linen",               0xfaf0e6),
            ("magenta",             0xff00ff),
            ("mediumaquamarine",    0x66cdaa),
            ("mediumblue",          0x0000cd),
            ("mediumorchid",        0xba55d3),
            ("mediumpurple",        0x9370db),
            ("mediumseagreen",      0x3cb371),
            ("mediumslateblue",     0x7b68ee),
            ("mediumspringgreen",   0x00fa9a),
            ("mediumturquoise",     0x48d1cc),
            ("mediumvioletred",     0xc71585),
            ("midnightblue",        0x191970),
            ("mintcream",           0xf5fffa),
            ("mistyrose",           0xffe4e1),
            ("moccasin",            0xffe4b5),
            ("navajowhite",         0xffdead),
            ("oldlace",             0xfdf5e6),
            ("olivedrab",           0x6b8e23),
            ("orangered",           0xff4500),
            ("orchid",              0xda70d6),
            ("palegoldenrod",       0xeee8aa),
            ("palegreen",           0x98fb98),
            ("paleturquoise",       0xafeeee),
            ("palevioletred",       0xdb7093),
            ("papayawhip",          0xffefd5),
            ("peachpuff",           0xffdab9),
            ("peru",                0xcd853f),
            ("pink",                0xffc0cb),
            ("plum",                0xdda0dd),
            ("powderblue",          0xb0e0e6),
            ("rosybrown",           0xbc8f8f),
            ("royalblue",           0x4169e1),
            ("saddlebrown",         0x8b4513),
            ("salmon",              0xfa8072),
            ("sandybrown",          0xf4a460),
            ("seagreen",            0x2e8b57),
            ("seashell",            0xfff5ee),
            ("sienna",              0xa0522d),
            ("skyblue",             0x87ceeb),
            ("slateblue",           0x6a5acd),
            ("slategray",           0x708090),
            ("slategrey",           0x708090),
            ("snow",                0xfffafa),
            ("springgreen",         0x00ff7f),
            ("steelblue",           0x4682b4),
            ("tan",                 0xd2b48c),
            ("thistle",             0xd8bfd8),
            ("tomato",              0xff6347),
            ("turquoise",           0x40e0d0),
            ("violet",              0xee82ee),
            ("wheat",               0xf5deb3),
            ("whitesmoke",          0xf5f5f5),
            ("yellowgreen",         0x9acd32),

            // css4
            ("rebeccapurple",       0x663399),
        ];
        let mut map = HashMap::new();
        for (color_name, color_u32) in colors.iter() {
            map.insert(*color_name, (*color_u32).into());
        }
        map
    };
}

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

impl From<&str> for Color {
    fn from(color_str: &str) -> Self {
        if color_str.starts_with('#') {
            Self::from_hex_str(color_str)
        } else {
            Self::from_css_name(color_str)
        }
    }
}

impl Color {
    pub fn from_css_name(name: &str) -> Self {
        *COLORS.get(name).expect("Unknown css name of color")
    }

    pub fn from_hex_str(color: &str) -> Self {
        let color_hex_str = if color.len() > 9 { &color[0..9] } else { color };
        let panic_string = format!("Color hex invalid format of string \"{}\"", color_hex_str);
        if !color_hex_str.starts_with('#') {
            panic!("Color hex should start from \"#\" character");
        };
        let color_hex_str = &color_hex_str[1..];
        let color_len = color_hex_str.len();
        if color_len < 3 {
            panic!("{}", panic_string);
        }
        let color_u32 = u32::from_str_radix(color_hex_str, 16).expect(&*panic_string);
        match color_len {
            3 => Self::from_short_rgb_u16(color_u32 as u16),
            6 => Self::from_rgb_u32(color_u32),
            4 => Self::from_short_rgba_u16(color_u32 as u16),
            8 => Self::from_rgba_u32(color_u32),
            _ => panic!("{}", panic_string),
        }
    }

    pub fn from_short_rgb_u16(c: u16) -> Color {
        let (red, green, blue, _) = (
            ((c >> 8) + ((c >> 8) << 4)) as u8,
            ((c & 0x0f0) + ((c & 0x0f0) >> 4)) as u8,
            ((c & 0x00f) + ((c & 0x00f) << 4)) as u8,
            0xff,
        );
        Color::rgb(red, green, blue)
    }

    pub fn from_rgb_u32(c: u32) -> Color {
        let (red, green, blue, _) = (
            (c >> 16) as u8,
            ((c & 0x00ff00) >> 8) as u8,
            (c & 0x0000ff) as u8,
            0xff,
        );
        Color::rgb(red, green, blue)
    }

    pub fn from_short_rgba_u16(c: u16) -> Color {
        let (red, green, blue, alpha) = (
            ((c >> 12) + ((c >> 12) << 4)) as u8,
            (((c & 0x0f00) >> 4) + ((c & 0x0f00) >> 8)) as u8,
            ((c & 0x00f0) + ((c & 0x00f0) >> 4)) as u8,
            ((c & 0x000f) + ((c & 0x000f) << 4)) as u8,
        );
        Color::rgba(red, green, blue, alpha)
    }

    pub fn from_rgba_u32(c: u32) -> Color {
        let (red, green, blue, alpha) = (
            (c >> 24) as u8,
            ((c & 0x00ff0000) >> 16) as u8,
            ((c & 0x0000ff00) >> 8) as u8,
            (c & 0x000000ff) as u8,
        );
        Color::rgba(red, green, blue, alpha)
    }
}

#[cfg(test)]
mod test {
    use super::super::{Color, prelude::IntoColor, RgbColor};

    #[test]
    fn get_color_from_impl() {
        let test_data: Vec<(&str, &str, u32, Color)> = vec![
            (
                "palegoldenrod",
                "#eee8aa",
                0xeee8aa,
                Color::rgb(0xee, 0xe8, 0xaa),
            ),
            (
                "palegreen",
                "#98fb98",
                0x98fb98,
                Color::rgb(0x98, 0xfb, 0x98),
            ),
            (
                "paleturquoise",
                "#afeeee",
                0xafeeee,
                Color::rgb(0xaf, 0xee, 0xee),
            ),
            (
                "palevioletred",
                "#db7093",
                0xdb7093,
                Color::rgb(0xdb, 0x70, 0x93),
            ),
            (
                "papayawhip",
                "#ffefd5",
                0xffefd5,
                Color::rgb(0xff, 0xef, 0xd5),
            ),
            (
                "peachpuff",
                "#ffdab9",
                0xffdab9,
                Color::rgb(0xff, 0xda, 0xb9),
            ),
            ("peru", "#cd853f", 0xcd853f, Color::rgb(0xcd, 0x85, 0x3f)),
            ("pink", "#ffc0cb", 0xffc0cb, Color::rgb(0xff, 0xc0, 0xcb)),
            ("plum", "#dda0dd", 0xdda0dd, Color::rgb(0xdd, 0xa0, 0xdd)),
            (
                "powderblue",
                "#b0e0e6",
                0xb0e0e6,
                Color::rgb(0xb0, 0xe0, 0xe6),
            ),
        ];
        for (color_name, color_hex_str, color_u32, color) in test_data.iter() {
            let RgbColor {
                red: expected_red,
                green: expected_green,
                blue: expected_blue,
            } = (*color).into_color();
            let actual_colors_vec: Vec<Color> = vec![
                (*color_name).into(),
                (*color_hex_str).into(),
                (*color_u32).into(),
            ];
            for actual_color in actual_colors_vec {
                let RgbColor {
                    red: actual_red,
                    green: actual_green,
                    blue: actual_blue,
                } = actual_color.into_color();
                assert_eq!(actual_red, expected_red);
                assert_eq!(actual_green, expected_green);
                assert_eq!(actual_blue, expected_blue);
            }
        }
    }
}