use super::Hsl;
use crate::converters::{as_rounded_rgb_tuple, rgb_invert, rgb_to_hex, rgb_to_hsl};
use crate::error::ParseError;
use crate::grayscale::{rgb_grayscale, GrayScaleMethod};
use crate::normalize::{normalize_ratio, normalize_rgb, normalize_rgb_unit};
use crate::{from_str, AlphaColor, Color, ColorTuple, ColorTupleA, RgbUnit};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Rgb {
r: f32,
g: f32,
b: f32,
a: Option<f32>,
}
impl Rgb {
pub fn from(r: f32, g: f32, b: f32) -> Rgb {
Rgb::from_tuple(&(r, g, b))
}
pub fn grayscale(&self, method: GrayScaleMethod) -> Rgb {
Rgb::from_tuple(&rgb_grayscale(&self.as_tuple(), method))
}
pub fn from_hex_str(s: &str) -> Result<Rgb, ParseError> {
match from_str::hex(s) {
Ok(rgb_tuple) => Ok(Rgb::from_tuple(&rgb_tuple)),
Err(err) => Err(err),
}
}
pub fn to_css_hex_string(&self) -> String {
let (r, g, b) = rgb_to_hex(&self.as_tuple());
format!("#{}{}{}", r, g, b)
}
}
impl std::str::FromStr for Rgb {
type Err = ParseError;
fn from_str(s: &str) -> Result<Rgb, ParseError> {
match from_str::rgb(s) {
Ok(rgb_tuple) => Ok(Rgb::from_tuple(&rgb_tuple)),
Err(err) => Err(err),
}
}
}
impl Color for Rgb {
type Tuple = ColorTuple;
type TupleA = ColorTupleA;
fn new() -> Rgb {
Rgb { r: 0.0, g: 0.0, b: 0.0, a: None }
}
fn get_red(&self) -> f32 {
self.r
}
fn get_green(&self) -> f32 {
self.g
}
fn get_blue(&self) -> f32 {
self.b
}
fn set_red(&self, val: f32) -> Rgb {
Rgb { r: normalize_rgb_unit(val), g: self.g, b: self.b, a: self.a }
}
fn set_green(&self, val: f32) -> Rgb {
Rgb { r: self.r, g: normalize_rgb_unit(val), b: self.b, a: self.a }
}
fn set_blue(&self, val: f32) -> Rgb {
Rgb { r: self.r, g: self.g, b: normalize_rgb_unit(val), a: self.a }
}
fn get_hue(&self) -> f32 {
self.to_hsl().get_hue()
}
fn get_saturation(&self) -> f32 {
self.to_hsl().get_saturation()
}
fn get_lightness(&self) -> f32 {
self.to_hsl().get_lightness()
}
fn set_hue(&self, val: f32) -> Rgb {
self.to_hsl().set_hue(val).to_rgb()
}
fn set_saturation(&self, val: f32) -> Rgb {
self.to_hsl().set_saturation(val).to_rgb()
}
fn set_lightness(&self, val: f32) -> Rgb {
self.to_hsl().set_lightness(val).to_rgb()
}
fn to_rgb(&self) -> Rgb {
*self
}
fn to_hsl(&self) -> Hsl {
Hsl::from_tuple(&rgb_to_hsl(&self.as_tuple()))
}
fn to_css_string(&self) -> String {
let (r, g, b) = as_rounded_rgb_tuple(&self.as_tuple());
format!("rgb({},{},{})", r, g, b)
}
fn from_tuple(t: &ColorTuple) -> Rgb {
let (r, g, b) = normalize_rgb(&t);
Rgb { r, g, b, a: None }
}
fn from_tuple_with_alpha(t: &ColorTupleA) -> Rgb {
let (r, g, b) = normalize_rgb(&(t.0, t.1, t.2));
Rgb { r, g, b, a: Some(normalize_ratio(t.3)) }
}
fn as_tuple(&self) -> ColorTuple {
(self.r, self.g, self.b)
}
fn lighten(&self, amt: f32) -> Rgb {
self.to_hsl().lighten(amt).to_rgb()
}
fn saturate(&self, amt: f32) -> Rgb {
self.to_hsl().saturate(amt).to_rgb()
}
fn adjust_hue(&self, amt: f32) -> Rgb {
self.to_hsl().adjust_hue(amt).to_rgb()
}
fn adjust_color(&self, name: RgbUnit, val: f32) -> Rgb {
let (r, g, b) = self.as_tuple();
match name {
RgbUnit::Red => self.set_red(r + val),
RgbUnit::Green => self.set_green(g + val),
RgbUnit::Blue => self.set_blue(b + val),
}
}
fn invert(&self) -> Rgb {
Rgb::from_tuple(&rgb_invert(&self.as_tuple()))
}
}
impl AlphaColor for Rgb {
fn get_alpha(&self) -> f32 {
self.a.unwrap_or(1.0)
}
fn set_alpha(&self, a: f32) -> Rgb {
Rgb { r: self.r, g: self.g, b: self.b, a: Some(normalize_ratio(a)) }
}
fn opacify(&self, a: f32) -> Rgb {
self.set_alpha(self.get_alpha() + a)
}
}