1use std::{
2 fmt::{
3 self,
4 Pointer,
5 },
6 hash::{
7 Hash,
8 Hasher,
9 },
10 mem::discriminant,
11};
12
13use freya_engine::prelude::{
14 Paint,
15 SkColor,
16 TextStyle,
17};
18use torin::prelude::Area;
19
20use crate::{
21 prelude::Color,
22 style::{
23 gradient::{
24 ConicGradient,
25 LinearGradient,
26 RadialGradient,
27 },
28 shader::ShaderFill,
29 },
30};
31
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46#[derive(Clone, Debug, PartialEq)]
47pub enum Fill {
48 Color(Color),
50 Shader(Box<ShaderFill>),
52 LinearGradient(Box<LinearGradient>),
54 RadialGradient(Box<RadialGradient>),
56 ConicGradient(Box<ConicGradient>),
58}
59
60impl Fill {
61 pub fn set_a(&mut self, a: u8) {
62 if let Fill::Color(color) = self {
63 if *color != Color::TRANSPARENT {
65 *color = color.with_a(a);
66 }
67 }
68 }
69
70 pub fn as_color(&self) -> Option<Color> {
72 match self {
73 Fill::Color(color) => Some(*color),
74 _ => None,
75 }
76 }
77
78 pub fn apply_to_text_style(&self, text_style: &mut TextStyle, area: Area) {
80 if let Some(color) = self.as_color() {
81 text_style.set_color(color);
82 return;
83 }
84
85 let mut paint = Paint::default();
86 paint.set_anti_alias(true);
87 self.apply_to_paint(&mut paint, area);
88 text_style.set_foreground_paint(&paint);
89 }
90
91 pub fn apply_to_paint(&self, paint: &mut Paint, area: Area) {
92 match &self {
93 Fill::Color(color) => {
94 paint.set_color(*color);
95 }
96 Fill::LinearGradient(gradient) => {
97 paint.set_shader(gradient.prepare_shader(area));
98 }
99 Fill::RadialGradient(gradient) => {
100 paint.set_shader(gradient.prepare_shader(area));
101 }
102 Fill::ConicGradient(gradient) => {
103 paint.set_shader(gradient.prepare_shader(area));
104 }
105 Fill::Shader(shader) => {
106 paint.set_shader(shader.prepare_shader(area));
107 }
108 }
109 }
110}
111
112impl Default for Fill {
113 fn default() -> Self {
114 Self::Color(Color::default())
115 }
116}
117
118impl Hash for Fill {
119 fn hash<H: Hasher>(&self, state: &mut H) {
120 discriminant(self).hash(state);
121 match self {
122 Fill::Color(color) => color.hash(state),
123 Fill::Shader(shader) => shader.hash(state),
124 Fill::LinearGradient(gradient) => gradient.hash(state),
125 Fill::RadialGradient(gradient) => gradient.hash(state),
126 Fill::ConicGradient(gradient) => gradient.hash(state),
127 }
128 }
129}
130
131impl From<Color> for Fill {
132 fn from(color: Color) -> Self {
133 Fill::Color(color)
134 }
135}
136
137impl From<(u8, u8, u8)> for Fill {
138 fn from(color: (u8, u8, u8)) -> Self {
139 Fill::Color(color.into())
140 }
141}
142
143impl From<(u8, u8, u8, f32)> for Fill {
144 fn from(color: (u8, u8, u8, f32)) -> Self {
145 Fill::Color(color.into())
146 }
147}
148
149impl From<(u8, u8, u8, u8)> for Fill {
150 fn from(color: (u8, u8, u8, u8)) -> Self {
151 Fill::Color(color.into())
152 }
153}
154
155impl From<u32> for Fill {
156 fn from(color: u32) -> Self {
157 Fill::Color(color.into())
158 }
159}
160
161impl From<SkColor> for Fill {
162 fn from(color: SkColor) -> Self {
163 Fill::Color(color.into())
164 }
165}
166
167impl From<LinearGradient> for Fill {
168 fn from(gradient: LinearGradient) -> Self {
169 Fill::LinearGradient(Box::new(gradient))
170 }
171}
172
173impl From<RadialGradient> for Fill {
174 fn from(gradient: RadialGradient) -> Self {
175 Fill::RadialGradient(Box::new(gradient))
176 }
177}
178
179impl From<ConicGradient> for Fill {
180 fn from(gradient: ConicGradient) -> Self {
181 Fill::ConicGradient(Box::new(gradient))
182 }
183}
184
185impl From<ShaderFill> for Fill {
186 fn from(shader: ShaderFill) -> Self {
187 Fill::Shader(Box::new(shader))
188 }
189}
190
191impl fmt::Display for Fill {
192 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193 match self {
194 Self::Color(color) => color.fmt(f),
195 Self::Shader(shader) => shader.as_ref().fmt(f),
196 Self::LinearGradient(gradient) => gradient.as_ref().fmt(f),
197 Self::RadialGradient(gradient) => gradient.as_ref().fmt(f),
198 Self::ConicGradient(gradient) => gradient.as_ref().fmt(f),
199 }
200 }
201}