use crate::math;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SolidColor {
r: f64,
g: f64,
b: f64,
a: f64,
}
impl SolidColor {
pub fn r(&self) -> f64 {
self.r
}
pub fn g(&self) -> f64 {
self.g
}
pub fn b(&self) -> f64 {
self.b
}
pub fn a(&self) -> f64 {
self.a
}
}
impl Default for SolidColor {
fn default() -> Self {
Self {
r: 0.5,
g: 0.5,
b: 0.5,
a: 1.0,
}
}
}
impl SolidColor {
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
Self {
r: r as f64 / 255.0,
g: g as f64 / 255.0,
b: b as f64 / 255.0,
a: 1.0,
}
}
pub fn to_rgb(&self) -> (u8, u8, u8) {
(
(self.r * 255.0).round() as u8,
(self.g * 255.0).round() as u8,
(self.b * 255.0).round() as u8,
)
}
pub fn from_hex(hex: &str) -> Option<Self> {
let stripped = hex.trim_start_matches('#');
if !stripped.chars().all(|c| c.is_ascii_hexdigit()) {
return None;
}
match stripped.len() {
3 => {
let r = u8::from_str_radix(&stripped[0..1], 16).ok()?;
let g = u8::from_str_radix(&stripped[1..2], 16).ok()?;
let b = u8::from_str_radix(&stripped[2..3], 16).ok()?;
Some(Self {
r: (r * 17) as f64 / 255.0,
g: (g * 17) as f64 / 255.0,
b: (b * 17) as f64 / 255.0,
a: 1.0,
})
}
6 => {
let r = u8::from_str_radix(&stripped[0..2], 16).ok()?;
let g = u8::from_str_radix(&stripped[2..4], 16).ok()?;
let b = u8::from_str_radix(&stripped[4..6], 16).ok()?;
Some(Self {
r: r as f64 / 255.0,
g: g as f64 / 255.0,
b: b as f64 / 255.0,
a: 1.0,
})
}
8 => {
let r = u8::from_str_radix(&stripped[0..2], 16).ok()?;
let g = u8::from_str_radix(&stripped[2..4], 16).ok()?;
let b = u8::from_str_radix(&stripped[4..6], 16).ok()?;
let a = u8::from_str_radix(&stripped[6..8], 16).ok()?;
Some(Self {
r: r as f64 / 255.0,
g: g as f64 / 255.0,
b: b as f64 / 255.0,
a: a as f64 / 255.0,
})
}
_ => None,
}
}
pub fn to_hex(&self) -> String {
let (r, g, b) = self.to_rgb();
let is_black = r == 0 && g == 0 && b == 0;
if (self.a - 1.0).abs() < 0.001 || is_black {
format!("{:02X}{:02X}{:02X}", r, g, b)
} else {
let a = (self.a * 255.0).round() as u8;
format!("{:02X}{:02X}{:02X}{:02X}", r, g, b, a)
}
}
pub fn from_hsb(h: f64, s: f64, b: f64, a: f64) -> Self {
let (r, g, bl) = math::hsb_to_rgb(h, s, b);
Self { r, g, b: bl, a }
}
pub fn to_hsb(&self) -> (f64, f64, f64) {
math::rgb_to_hsb(self.r, self.g, self.b)
}
pub fn from_hsl(h: f64, s: f64, l: f64, a: f64) -> Self {
let (hb, sb, vb) = math::hsl_to_hsb(h, s, l);
let (r, g, bl) = math::hsb_to_rgb(hb, sb, vb);
Self { r, g, b: bl, a }
}
pub fn to_hsl(&self) -> (f64, f64, f64) {
let (h, s, v) = math::rgb_to_hsb(self.r, self.g, self.b);
math::hsb_to_hsl(h, s, v)
}
pub fn from_rgba(r: f64, g: f64, b: f64, a: f64) -> Self {
Self { r, g, b, a }
}
}