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 data::TextStyleState,
22 prelude::Color,
23 style::{
24 gradient::{
25 ConicGradient,
26 LinearGradient,
27 RadialGradient,
28 },
29 render_callback::{
30 RenderCallback,
31 RenderContext,
32 RenderTarget,
33 },
34 shader::ShaderFill,
35 },
36};
37
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
52#[derive(Clone, Debug, PartialEq)]
53pub enum Fill {
54 Color(Color),
56 Shader(Box<ShaderFill>),
58 LinearGradient(Box<LinearGradient>),
60 RadialGradient(Box<RadialGradient>),
62 ConicGradient(Box<ConicGradient>),
64 Callback(#[cfg_attr(feature = "serde", serde(skip))] RenderCallback),
66}
67
68impl Fill {
69 pub fn set_a(&mut self, a: u8) {
70 if let Fill::Color(color) = self {
71 *color = color.with_a(a);
72 }
73 }
74
75 pub fn as_color(&self) -> Option<Color> {
77 match self {
78 Fill::Color(color) => Some(*color),
79 _ => None,
80 }
81 }
82
83 pub fn apply_to_text_style(
85 &self,
86 text_style: &mut TextStyle,
87 area: Area,
88 text_style_state: &TextStyleState,
89 scale_factor: f64,
90 ) {
91 match self {
92 Self::Color(color) => {
93 text_style.set_color(*color);
94 }
95 Self::Callback(callback) => {
96 text_style.set_color(Color::TRANSPARENT);
97 callback.call(&mut RenderContext {
98 target: RenderTarget::TextStyle(text_style),
99 scale_factor,
100 origin: area.origin,
101 size: area.size,
102 text_style_state,
103 });
104 }
105 _ => {
106 let mut paint = Paint::default();
107 paint.set_anti_alias(true);
108 self.apply_to_paint(&mut paint, area);
109 text_style.set_foreground_paint(&paint);
110 }
111 }
112 }
113
114 pub fn render_callback(&self) -> Option<&RenderCallback> {
115 match self {
116 Self::Callback(callback) => Some(callback),
117 _ => None,
118 }
119 }
120
121 pub fn apply_to_paint(&self, paint: &mut Paint, area: Area) {
122 match self {
123 Fill::Color(color) => {
124 paint.set_color(*color);
125 }
126 Fill::LinearGradient(gradient) => {
127 paint.set_dither(gradient.dither);
128 paint.set_shader(gradient.prepare_shader(area));
129 }
130 Fill::RadialGradient(gradient) => {
131 paint.set_dither(gradient.dither);
132 paint.set_shader(gradient.prepare_shader(area));
133 }
134 Fill::ConicGradient(gradient) => {
135 paint.set_dither(gradient.dither);
136 paint.set_shader(gradient.prepare_shader(area));
137 }
138 Fill::Shader(shader) => {
139 paint.set_shader(shader.prepare_shader(area));
140 }
141 Fill::Callback(_) => {
142 paint.set_color(Color::TRANSPARENT);
143 }
144 }
145 }
146}
147
148impl Default for Fill {
149 fn default() -> Self {
150 Self::Color(Color::default())
151 }
152}
153
154impl Hash for Fill {
155 fn hash<H: Hasher>(&self, state: &mut H) {
156 discriminant(self).hash(state);
157 match self {
158 Fill::Color(color) => color.hash(state),
159 Fill::Shader(shader) => shader.hash(state),
160 Fill::LinearGradient(gradient) => gradient.hash(state),
161 Fill::RadialGradient(gradient) => gradient.hash(state),
162 Fill::ConicGradient(gradient) => gradient.hash(state),
163 Fill::Callback(callback) => callback.hash(state),
164 }
165 }
166}
167
168impl From<RenderCallback> for Fill {
169 fn from(callback: RenderCallback) -> Self {
170 Self::Callback(callback)
171 }
172}
173
174impl From<Color> for Fill {
175 fn from(color: Color) -> Self {
176 Fill::Color(color)
177 }
178}
179
180impl From<(u8, u8, u8)> for Fill {
181 fn from(color: (u8, u8, u8)) -> Self {
182 Fill::Color(color.into())
183 }
184}
185
186impl From<(u8, u8, u8, f32)> for Fill {
187 fn from(color: (u8, u8, u8, f32)) -> Self {
188 Fill::Color(color.into())
189 }
190}
191
192impl From<(u8, u8, u8, u8)> for Fill {
193 fn from(color: (u8, u8, u8, u8)) -> Self {
194 Fill::Color(color.into())
195 }
196}
197
198impl From<u32> for Fill {
199 fn from(color: u32) -> Self {
200 Fill::Color(color.into())
201 }
202}
203
204impl From<SkColor> for Fill {
205 fn from(color: SkColor) -> Self {
206 Fill::Color(color.into())
207 }
208}
209
210impl From<LinearGradient> for Fill {
211 fn from(gradient: LinearGradient) -> Self {
212 Fill::LinearGradient(Box::new(gradient))
213 }
214}
215
216impl From<RadialGradient> for Fill {
217 fn from(gradient: RadialGradient) -> Self {
218 Fill::RadialGradient(Box::new(gradient))
219 }
220}
221
222impl From<ConicGradient> for Fill {
223 fn from(gradient: ConicGradient) -> Self {
224 Fill::ConicGradient(Box::new(gradient))
225 }
226}
227
228impl From<ShaderFill> for Fill {
229 fn from(shader: ShaderFill) -> Self {
230 Fill::Shader(Box::new(shader))
231 }
232}
233
234impl fmt::Display for Fill {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 match self {
237 Self::Color(color) => color.fmt(f),
238 Self::Shader(shader) => shader.as_ref().fmt(f),
239 Self::LinearGradient(gradient) => gradient.as_ref().fmt(f),
240 Self::RadialGradient(gradient) => gradient.as_ref().fmt(f),
241 Self::ConicGradient(gradient) => gradient.as_ref().fmt(f),
242 Self::Callback(callback) => callback.fmt(f),
243 }
244 }
245}