mod convert;
mod hsla;
mod hwba;
mod rgba;
pub use self::hsla::Hsla;
pub use self::hwba::Hwba;
pub use self::rgba::{RgbFormat, Rgba};
use super::Rational;
use crate::output::{Format, Formatted};
use num_traits::{one, zero, One, Zero};
use std::borrow::Cow;
use std::fmt::{self, Display};
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Color {
Rgba(Rgba),
Hsla(Hsla),
Hwba(Hwba),
}
impl Color {
pub fn to_rgba(&self) -> Cow<Rgba> {
match self {
Color::Rgba(rgba) => Cow::Borrowed(rgba),
Color::Hsla(hsla) => Cow::Owned(Rgba::from(hsla)),
Color::Hwba(hwba) => Cow::Owned(Rgba::from(hwba)),
}
}
pub fn to_hsla(&self) -> Cow<Hsla> {
match self {
Color::Rgba(rgba) => Cow::Owned(Hsla::from(rgba)),
Color::Hsla(ref hsla) => Cow::Borrowed(hsla),
Color::Hwba(hwba) => Cow::Owned(Hsla::from(hwba)),
}
}
pub fn to_hwba(&self) -> Cow<Hwba> {
match self {
Color::Rgba(rgba) => Cow::Owned(Hwba::from(rgba)),
Color::Hsla(hsla) => Cow::Owned(Hwba::from(hsla)),
Color::Hwba(hwba) => Cow::Borrowed(hwba),
}
}
pub fn get_alpha(&self) -> Rational {
match self {
Color::Rgba(rgba) => rgba.alpha(),
Color::Hsla(hsla) => hsla.alpha(),
Color::Hwba(hwba) => hwba.alpha(),
}
}
pub fn set_alpha(&mut self, alpha: Rational) {
let alpha = clamp(alpha, zero(), one());
match self {
Color::Rgba(ref mut rgba) => rgba.set_alpha(alpha),
Color::Hsla(ref mut hsla) => hsla.set_alpha(alpha),
Color::Hwba(ref mut hwba) => hwba.set_alpha(alpha),
}
}
pub fn rotate_hue(&self, val: Rational) -> Self {
match self {
Color::Rgba(rgba) => {
let hsla = Hsla::from(rgba);
Hsla::new(
hsla.hue() + val,
hsla.sat(),
hsla.lum(),
hsla.alpha(),
hsla.hsla_format,
)
.into()
}
Color::Hsla(hsla) => Hsla::new(
hsla.hue() + val,
hsla.sat(),
hsla.lum(),
hsla.alpha(),
hsla.hsla_format,
)
.into(),
Color::Hwba(hwba) => Hwba::new(
hwba.hue() + val,
hwba.whiteness(),
hwba.blackness(),
hwba.alpha(),
)
.into(),
}
}
pub(crate) fn reset_source(&mut self) {
match self {
Color::Rgba(rgba) => rgba.reset_source(),
Color::Hsla(hsla) => hsla.reset_source(),
_ => (),
}
}
pub fn format(&self, format: Format) -> Formatted<Self> {
Formatted {
value: self,
format,
}
}
}
impl From<Rgba> for Color {
fn from(rgba: Rgba) -> Color {
Color::Rgba(rgba)
}
}
impl From<Hsla> for Color {
fn from(hsla: Hsla) -> Color {
Color::Hsla(hsla)
}
}
impl From<Hwba> for Color {
fn from(hwba: Hwba) -> Color {
Color::Hwba(hwba)
}
}
fn clamp(v: Rational, min: Rational, max: Rational) -> Rational {
if v >= max {
max
} else if v <= min {
min
} else {
v
}
}
impl<'a> Display for Formatted<'a, Color> {
fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
match self.value {
Color::Rgba(rgba) => rgba.format(self.format).fmt(out),
Color::Hsla(hsla) if hsla.hsla_format => {
hsla.format(self.format).fmt(out)
}
any => any.to_rgba().format(self.format).fmt(out),
}
}
}