use std::{
fmt::{Display, Formatter},
str::FromStr,
};
use strum::{EnumCount, EnumIter, IntoEnumIterator as _};
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, EnumIter, EnumCount)]
pub enum Hue {
Gray,
Green,
Red,
Blue,
Purple,
}
impl Display for Hue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Gray => f.write_str("Gray"),
Self::Green => f.write_str("Green"),
Self::Red => f.write_str("Red"),
Self::Blue => f.write_str("Blue"),
Self::Purple => f.write_str("Purple"),
}
}
}
impl FromStr for Hue {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"Gray" => Self::Gray,
"Green" => Self::Green,
"Red" => Self::Red,
"Blue" => Self::Blue,
"Purple" => Self::Purple,
_ => return Err(anyhow::anyhow!("Invalid hue: {s:?}")),
})
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, EnumIter, EnumCount)]
pub enum Scale {
S0,
S25,
S50,
S75,
S100,
S125,
S150,
S175,
S200,
S225,
S250,
S275,
S300,
S325,
S350,
S375,
S400,
S425,
S450,
S475,
S500,
S525,
S550,
S575,
S600,
S625,
S650,
S675,
S700,
S725,
S750,
S775,
S800,
S825,
S850,
S875,
S900,
S925,
S950,
S975,
S1000,
}
impl Display for Scale {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let txt = match self {
Self::S0 => "0",
Self::S25 => "25",
Self::S50 => "50",
Self::S75 => "75",
Self::S100 => "100",
Self::S125 => "125",
Self::S150 => "150",
Self::S175 => "175",
Self::S200 => "200",
Self::S225 => "225",
Self::S250 => "250",
Self::S275 => "275",
Self::S300 => "300",
Self::S325 => "325",
Self::S350 => "350",
Self::S375 => "375",
Self::S400 => "400",
Self::S425 => "425",
Self::S450 => "450",
Self::S475 => "475",
Self::S500 => "500",
Self::S525 => "525",
Self::S550 => "550",
Self::S575 => "575",
Self::S600 => "600",
Self::S625 => "625",
Self::S650 => "650",
Self::S675 => "675",
Self::S700 => "700",
Self::S725 => "725",
Self::S750 => "750",
Self::S775 => "775",
Self::S800 => "800",
Self::S825 => "825",
Self::S850 => "850",
Self::S875 => "875",
Self::S900 => "900",
Self::S925 => "925",
Self::S950 => "950",
Self::S975 => "975",
Self::S1000 => "1000",
};
txt.fmt(f)
}
}
impl FromStr for Scale {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"0" => Self::S0,
"25" => Self::S25,
"50" => Self::S50,
"75" => Self::S75,
"100" => Self::S100,
"125" => Self::S125,
"150" => Self::S150,
"175" => Self::S175,
"200" => Self::S200,
"225" => Self::S225,
"250" => Self::S250,
"275" => Self::S275,
"300" => Self::S300,
"325" => Self::S325,
"350" => Self::S350,
"375" => Self::S375,
"400" => Self::S400,
"425" => Self::S425,
"450" => Self::S450,
"475" => Self::S475,
"500" => Self::S500,
"525" => Self::S525,
"550" => Self::S550,
"575" => Self::S575,
"600" => Self::S600,
"625" => Self::S625,
"650" => Self::S650,
"675" => Self::S675,
"700" => Self::S700,
"725" => Self::S725,
"750" => Self::S750,
"775" => Self::S775,
"800" => Self::S800,
"825" => Self::S825,
"850" => Self::S850,
"875" => Self::S875,
"900" => Self::S900,
"925" => Self::S925,
"950" => Self::S950,
"975" => Self::S975,
"1000" => Self::S1000,
_ => return Err(anyhow::anyhow!("Invalid scale: {s:?}")),
})
}
}
#[derive(Debug)]
pub struct ColorTable {
color_lut: Vec<Vec<egui::Color32>>,
}
impl ColorTable {
pub fn new(mut color_lut_fn: impl FnMut(ColorToken) -> egui::Color32) -> Self {
Self {
color_lut: Hue::iter()
.map(|hue| {
Scale::iter()
.map(|scale| color_lut_fn(ColorToken::new(hue, scale)))
.collect()
})
.collect(),
}
}
#[inline]
pub fn get(&self, token: ColorToken) -> egui::Color32 {
self.color_lut[token.hue as usize][token.scale as usize]
}
}
#[derive(Debug, Clone, Copy, Hash)]
pub struct ColorToken {
pub hue: Hue,
pub scale: Scale,
}
impl ColorToken {
#[inline]
pub fn new(hue: Hue, shade: Scale) -> Self {
Self { hue, scale: shade }
}
}