use super::{deg, percent, Angle, Color, Ratio, RGB, RGBA};
use std::fmt;
pub fn hsl(h: i32, s: u8, l: u8) -> HSL {
HSL {
h: deg(h),
s: percent(s),
l: percent(l),
}
}
pub fn hsla(h: i32, s: u8, l: u8, a: f32) -> HSLA {
HSLA {
h: deg(h),
s: percent(s),
l: percent(l),
a: Ratio::from_f32(a),
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct HSL {
pub h: Angle,
pub s: Ratio,
pub l: Ratio,
}
impl fmt::Display for HSL {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "hsl({}, {}, {})", self.h.degrees(), self.s, self.l)
}
}
impl Color for HSL {
type Alpha = HSLA;
fn to_css(self) -> String {
self.to_string()
}
fn to_rgb(self) -> RGB {
self.to_hsla().to_rgb()
}
fn to_rgba(self) -> RGBA {
self.to_hsla().to_rgba()
}
fn to_hsl(self) -> HSL {
self
}
fn to_hsla(self) -> HSLA {
let HSL { h, s, l } = self;
HSLA {
h,
s,
l,
a: percent(100),
}
}
fn saturate(self, amount: Ratio) -> Self {
self.to_hsla().saturate(amount).to_hsl()
}
fn desaturate(self, amount: Ratio) -> Self {
self.to_hsla().desaturate(amount).to_hsl()
}
fn lighten(self, amount: Ratio) -> Self {
self.to_hsla().lighten(amount).to_hsl()
}
fn darken(self, amount: Ratio) -> Self {
self.to_hsla().darken(amount).to_hsl()
}
fn fadein(self, amount: Ratio) -> Self::Alpha {
self.to_hsla().fadein(amount)
}
fn fadeout(self, amount: Ratio) -> Self::Alpha {
self.to_hsla().fadeout(amount)
}
fn fade(self, amount: Ratio) -> Self::Alpha {
self.to_hsla().fade(amount)
}
fn spin(self, amount: Angle) -> Self {
self.to_hsla().spin(amount).to_hsl()
}
fn mix<T: Color>(self, other: T, weight: Ratio) -> Self::Alpha {
self.to_hsla().mix(other, weight)
}
fn tint(self, weight: Ratio) -> Self {
self.to_hsla().tint(weight).to_hsl()
}
fn shade(self, weight: Ratio) -> Self {
self.to_hsla().shade(weight).to_hsl()
}
fn greyscale(self) -> Self {
self.to_hsla().greyscale().to_hsl()
}
}
fn to_rgb_value(val: u16, temp_1: f32, temp_2: f32) -> f32 {
let value = val as f32 / 360.0;
if value > (2.0 / 3.0) {
temp_2
} else if value > (1.0 / 2.0) {
temp_2 + ((temp_1 - temp_2) * ((2.0 / 3.0) - value) * 6.0)
} else if value > (1.0 / 6.0) {
temp_1
} else {
temp_2 + ((temp_1 - temp_2) * value * 6.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct HSLA {
pub h: Angle,
pub s: Ratio,
pub l: Ratio,
pub a: Ratio,
}
impl fmt::Display for HSLA {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"hsla({}, {}, {}, {:.02})",
self.h.degrees(),
self.s,
self.l,
self.a.as_f32()
)
}
}
impl Color for HSLA {
type Alpha = Self;
fn to_css(self) -> String {
self.to_string()
}
fn to_rgb(self) -> RGB {
self.to_rgba().to_rgb()
}
fn to_rgba(self) -> RGBA {
let HSLA { h, s, l, a } = self;
if s == percent(0) {
return RGBA {
r: l,
g: l,
b: l,
a,
};
}
let s = s.as_f32();
let l = l.as_f32();
let temp_1 = if l < 0.5 {
l * (1.0 + s)
} else {
(l + s) - (l * s)
};
let temp_2 = (2.0 * l) - temp_1;
let rotation = Angle::new(120);
let temporary_r = (h + rotation).degrees();
let temporary_g = h.degrees();
let temporary_b = (h - rotation).degrees();
let red = to_rgb_value(temporary_r, temp_1, temp_2);
let green = to_rgb_value(temporary_g, temp_1, temp_2);
let blue = to_rgb_value(temporary_b, temp_1, temp_2);
RGBA {
r: Ratio::from_f32(red),
g: Ratio::from_f32(green),
b: Ratio::from_f32(blue),
a,
}
}
fn to_hsl(self) -> HSL {
let HSLA { h, s, l, .. } = self;
HSL { h, s, l }
}
fn to_hsla(self) -> HSLA {
self
}
fn saturate(self, amount: Ratio) -> Self {
let HSLA { h, s, l, a } = self;
HSLA {
h,
s: s + amount,
l,
a,
}
}
fn desaturate(self, amount: Ratio) -> Self {
let HSLA { h, s, l, a } = self;
HSLA {
h,
s: s - amount,
l,
a,
}
}
fn lighten(self, amount: Ratio) -> Self {
let HSLA { h, s, l, a } = self;
HSLA {
h,
s,
l: l + amount,
a,
}
}
fn darken(self, amount: Ratio) -> Self {
let HSLA { h, s, l, a } = self;
HSLA {
h,
s,
l: l - amount,
a,
}
}
fn fadein(self, amount: Ratio) -> Self {
self.fade(self.a + amount)
}
fn fadeout(self, amount: Ratio) -> Self {
self.fade(self.a - amount)
}
fn fade(self, amount: Ratio) -> Self::Alpha {
let HSLA { h, s, l, .. } = self;
HSLA { h, s, l, a: amount }
}
fn spin(self, amount: Angle) -> Self {
let HSLA { h, s, l, a } = self;
HSLA {
h: h + amount,
s,
l,
a,
}
}
fn mix<T: Color>(self, other: T, weight: Ratio) -> Self::Alpha {
self.to_rgba().mix(other, weight).to_hsla()
}
fn tint(self, weight: Ratio) -> Self {
self.to_rgba().tint(weight).to_hsla()
}
fn shade(self, weight: Ratio) -> Self {
self.to_rgba().shade(weight).to_hsla()
}
fn greyscale(self) -> Self {
let HSLA { h, l, a, .. } = self;
HSLA {
h,
s: percent(0),
l,
a,
}
}
}