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
use crate::{append_property::AppendProperty, prelude::*, Property};
use num_traits::cast::AsPrimitive;

#[derive(Debug, PartialEq, Eq, Hash, Default, Clone, PartialOrd, Ord)]
pub enum Filter {
	#[default]
	None,
	Initial,
	Inherit,
	Some(Vec<FilterFunction>),
}

#[rustfmt::skip]
impl std::fmt::Display for Filter {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::None       => "filter:none;".fmt(f),
			Self::Initial    => "filter:initial;".fmt(f),
			Self::Inherit    => "filter:inherit;".fmt(f),
			Self::Some(fns)  => {
				"filter:".fmt(f)?;
				if let Some((first, rest)) = fns.split_first() {
					write!(f, "{}", first)?;
					for func in rest {
						write!(f, " {}", func)?;
					}
				}
				";".fmt(f)
			},
		}
	}
}

#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
pub enum FilterFunction {
	Blur(i32),
	Brightness(F32),
	Contrast(F32),
	DropShadow(Unit, Unit, Unit, Option<crate::Color>),
	Grayscale(F32),
	HueRotate(F32),
	Invert(F32),
	Opacity(F32),
	Saturate(F32),
	Sepia(F32),
	Url(String),
}

impl FilterFunction {
	pub fn blur(x: i32) -> Self { Self::Blur(x) }
	pub fn brightness<T: AsPrimitive<f32>>(x: T) -> Self { Self::Brightness(F32::new(x.as_()).unwrap()) }
	pub fn contrast<T: AsPrimitive<f32>>(x: T) -> Self { Self::Contrast(F32::new(x.as_()).unwrap()) }
	pub fn drop_shadow(h_shadow: Unit, v_shadow: Unit, blur: Unit, color: Option<crate::Color>) -> Self { Self::DropShadow(h_shadow, v_shadow, blur, color) }
	pub fn grayscale<T: AsPrimitive<f32>>(x: T) -> Self { Self::Grayscale(F32::new(x.as_()).unwrap()) }
	pub fn hue_rotate<T: AsPrimitive<f32>>(x: T) -> Self { Self::HueRotate(F32::new(x.as_()).unwrap()) }
	pub fn invert<T: AsPrimitive<f32>>(x: T) -> Self { Self::Invert(F32::new(x.as_()).unwrap()) }
	pub fn opacity<T: AsPrimitive<f32>>(x: T) -> Self { Self::Opacity(F32::new(x.as_()).unwrap()) }
	pub fn saturate<T: AsPrimitive<f32>>(x: T) -> Self { Self::Saturate(F32::new(x.as_()).unwrap()) }
	pub fn sepia<T: AsPrimitive<f32>>(x: T) -> Self { Self::Sepia(F32::new(x.as_()).unwrap()) }
	pub fn url<T: Into<String>>(x: T) -> Self { Self::Url(x.into()) }
}

impl AppendProperty for FilterFunction {
	fn append_property(self, props: &mut Vec<Property>) { Filter::Some(vec![self]).append_property(props) }
}

impl std::fmt::Display for FilterFunction {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Blur(x)                                     => write!(f, "blur({}px)", x),
			Self::Brightness(x)                               => write!(f, "brightness({})", x),
			Self::Contrast(x)                                 => write!(f, "contrast({})", x),
			Self::DropShadow(h_shadow, v_shadow, blur, color) => write!(f, "drop-shadow({} {} {} {})", h_shadow, v_shadow, blur, color.unwrap_or_else(|| crate::Color::from_hex(0x00_00_00_00))),
			Self::Grayscale(x)                                => write!(f, "grayscale({})", x),
			Self::HueRotate(x)                                => write!(f, "hue-rotate({}deg)", x),
			Self::Invert(x)                                   => write!(f, "invert({})", x),
			Self::Opacity(x)                                  => write!(f, "opacity({})", x),
			Self::Saturate(x)                                 => write!(f, "saturate({})", x),
			Self::Sepia(x)                                    => write!(f, "sepia({})", x),
			Self::Url(x)                                      => write!(f, r#"url("{}")"#, x),
		}
	}
}