use crate::css::Value;
use crate::output::{Format, Formatted};
use crate::value::{Number, Numeric};
use std::fmt::{self, Display};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Hsla {
hue: f64,
sat: f64,
lum: f64,
alpha: f64,
pub(crate) hsla_format: bool,
}
impl Hsla {
pub fn new(
hue: f64,
sat: f64,
lum: f64,
alpha: f64,
hsla_format: bool,
) -> Self {
Self {
hue: deg_mod(hue),
sat: sat.clamp(0., f64::INFINITY),
lum,
#[allow(clippy::manual_clamp)] alpha: alpha.max(0.).min(1.),
hsla_format,
}
}
pub fn hue(&self) -> f64 {
self.hue
}
pub fn sat(&self) -> f64 {
self.sat
}
pub fn lum(&self) -> f64 {
self.lum
}
pub fn alpha(&self) -> f64 {
self.alpha
}
pub fn set_alpha(&mut self, alpha: f64) {
self.alpha = alpha.clamp(0., 1.);
}
pub(crate) fn invert(&self, weight: f64) -> Self {
Self {
hue: deg_mod(self.hue + 180.),
sat: self.sat,
lum: (1. - self.lum) * weight + self.lum * (1. - weight),
alpha: self.alpha,
hsla_format: self.hsla_format,
}
}
pub(crate) fn reset_source(&mut self) {
self.hsla_format = false;
}
pub fn format(&self, format: Format) -> Formatted<Self> {
Formatted {
value: self,
format,
}
}
}
fn deg_mod(value: f64) -> f64 {
let turn = 360.;
let value = value % turn;
if value.is_sign_negative() {
value + turn
} else {
value
}
}
impl Display for Formatted<'_, Hsla> {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
let hsla = self.value;
let hue = if hsla.hue + 1e-7 > 360. { 0. } else { hsla.hue };
let hue = Value::scalar(hue);
let sat = Value::from(Numeric::percentage(hsla.sat));
let lum = Value::from(Numeric::percentage(hsla.lum));
let a = hsla.alpha;
if a >= 1. {
write!(
out,
"hsl({}, {}, {})",
hue.to_string(self.format),
sat.to_string(self.format),
lum.to_string(self.format),
)
} else {
let a = Number::from(a);
write!(
out,
"hsla({}, {}, {}, {})",
hue.to_string(self.format),
sat.to_string(self.format),
lum.to_string(self.format),
a.format(self.format)
)
}
}
}