1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! Types for color values.
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};
/// A color in sass/css. May be a Rgba, Hsla, or Hwba value.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Color {
/// A rgba color, defined by red, green, blue and alpha components.
Rgba(Rgba),
/// A hsla color, defined by its hue, saturation, lightness and alpha.
Hsla(Hsla),
/// A hwba color, defined by its hue, whiteness, blackness and alpha.
Hwba(Hwba),
}
impl Color {
/// Get this color as a rgba value.
///
/// If this color is a rgba value, return a borrow of it.
/// Otherwise, do the conversion and return an owned value.
pub fn to_rgba(&self) -> Cow<Rgba> {
match self {
Self::Rgba(rgba) => Cow::Borrowed(rgba),
Self::Hsla(hsla) => Cow::Owned(Rgba::from(hsla)),
Self::Hwba(hwba) => Cow::Owned(Rgba::from(hwba)),
}
}
/// Get this color as a hsla value.
///
/// If this color is a hsla value, return a borrow of it.
/// Otherwise, do the conversion and return an owned value.
pub fn to_hsla(&self) -> Cow<Hsla> {
match self {
Self::Rgba(rgba) => Cow::Owned(Hsla::from(rgba)),
Self::Hsla(ref hsla) => Cow::Borrowed(hsla),
Self::Hwba(hwba) => Cow::Owned(Hsla::from(hwba)),
}
}
/// Get this color as a hwba value.
///
/// If this color is a hwba value, return a borrow of it.
/// Otherwise, do the conversion and return an owned value.
pub fn to_hwba(&self) -> Cow<Hwba> {
match self {
Self::Rgba(rgba) => Cow::Owned(Hwba::from(rgba)),
Self::Hsla(hsla) => Cow::Owned(Hwba::from(hsla)),
Self::Hwba(hwba) => Cow::Borrowed(hwba),
}
}
/// Get the alpha channel of this color.
///
/// The alpha channel is a rational value between 0 and 1.
pub fn get_alpha(&self) -> Rational {
match self {
Self::Rgba(rgba) => rgba.alpha(),
Self::Hsla(hsla) => hsla.alpha(),
Self::Hwba(hwba) => hwba.alpha(),
}
}
/// Set the alpha channel of this color.
///
/// The alpha channel is a rational value between 0 and 1.
pub fn set_alpha(&mut self, alpha: Rational) {
let alpha = alpha.clamp(zero(), one());
match self {
Self::Rgba(ref mut rgba) => rgba.set_alpha(alpha),
Self::Hsla(ref mut hsla) => hsla.set_alpha(alpha),
Self::Hwba(ref mut hwba) => hwba.set_alpha(alpha),
}
}
/// Rotate the hue of this color by a specific number of degrees.
pub fn rotate_hue(&self, val: Rational) -> Self {
match self {
Self::Rgba(rgba) => {
let hsla = Hsla::from(rgba);
Hsla::new(
hsla.hue() + val,
hsla.sat(),
hsla.lum(),
hsla.alpha(),
hsla.hsla_format,
)
.into()
}
Self::Hsla(hsla) => Hsla::new(
hsla.hue() + val,
hsla.sat(),
hsla.lum(),
hsla.alpha(),
hsla.hsla_format,
)
.into(),
Self::Hwba(hwba) => Hwba::new(
hwba.hue() + val,
hwba.whiteness(),
hwba.blackness(),
hwba.alpha(),
)
.into(),
}
}
pub(crate) fn reset_source(&mut self) {
match self {
Self::Rgba(rgba) => rgba.reset_source(),
Self::Hsla(hsla) => hsla.reset_source(),
_ => (),
}
}
/// Get a reference to this `Value` bound to an output format.
pub fn format(&self, format: Format) -> Formatted<Self> {
Formatted {
value: self,
format,
}
}
}
impl From<Rgba> for Color {
fn from(rgba: Rgba) -> Self {
Self::Rgba(rgba)
}
}
impl From<Hsla> for Color {
fn from(hsla: Hsla) -> Self {
Self::Hsla(hsla)
}
}
impl From<Hwba> for Color {
fn from(hwba: Hwba) -> Self {
Self::Hwba(hwba)
}
}
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),
}
}
}