1use serde::Deserialize;
2use serde_json::json;
3use std::borrow::Cow;
4
5use crate::{
6 color::Color,
7 fonts::{FontId, GlyphId},
8 geometry::{rect::RectF, vector::Vector2F},
9 json::ToJson,
10};
11
12pub struct Scene {
13 scale_factor: f32,
14 stacking_contexts: Vec<StackingContext>,
15 active_stacking_context_stack: Vec<usize>,
16}
17
18struct StackingContext {
19 layers: Vec<Layer>,
20 active_layer_stack: Vec<usize>,
21}
22
23#[derive(Default)]
24pub struct Layer {
25 clip_bounds: Option<RectF>,
26 quads: Vec<Quad>,
27 shadows: Vec<Shadow>,
28 glyphs: Vec<Glyph>,
29 icons: Vec<Icon>,
30 paths: Vec<Path>,
31}
32
33#[derive(Default, Debug)]
34pub struct Quad {
35 pub bounds: RectF,
36 pub background: Option<Color>,
37 pub border: Border,
38 pub corner_radius: f32,
39}
40
41#[derive(Debug)]
42pub struct Shadow {
43 pub bounds: RectF,
44 pub corner_radius: f32,
45 pub sigma: f32,
46 pub color: Color,
47}
48
49#[derive(Debug)]
50pub struct Glyph {
51 pub font_id: FontId,
52 pub font_size: f32,
53 pub id: GlyphId,
54 pub origin: Vector2F,
55 pub color: Color,
56}
57
58pub struct Icon {
59 pub bounds: RectF,
60 pub svg: usvg::Tree,
61 pub path: Cow<'static, str>,
62 pub color: Color,
63}
64
65#[derive(Clone, Copy, Default, Debug)]
66pub struct Border {
67 pub width: f32,
68 pub color: Color,
69 pub top: bool,
70 pub right: bool,
71 pub bottom: bool,
72 pub left: bool,
73}
74
75impl<'de> Deserialize<'de> for Border {
76 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77 where
78 D: serde::Deserializer<'de>,
79 {
80 #[derive(Deserialize)]
81 struct BorderData {
82 pub width: f32,
83 pub color: Color,
84 #[serde(default)]
85 pub top: bool,
86 #[serde(default)]
87 pub right: bool,
88 #[serde(default)]
89 pub bottom: bool,
90 #[serde(default)]
91 pub left: bool,
92 }
93
94 let data = BorderData::deserialize(deserializer)?;
95 let mut border = Border {
96 width: data.width,
97 color: data.color,
98 top: data.top,
99 bottom: data.bottom,
100 left: data.left,
101 right: data.right,
102 };
103 if !border.top && !border.bottom && !border.left && !border.right {
104 border.top = true;
105 border.bottom = true;
106 border.left = true;
107 border.right = true;
108 }
109 Ok(border)
110 }
111}
112
113#[derive(Debug)]
114pub struct Path {
115 pub bounds: RectF,
116 pub color: Color,
117 pub vertices: Vec<PathVertex>,
118}
119
120#[derive(Debug)]
121pub struct PathVertex {
122 pub xy_position: Vector2F,
123 pub st_position: Vector2F,
124}
125
126impl Scene {
127 pub fn new(scale_factor: f32) -> Self {
128 let stacking_context = StackingContext::new(None);
129 Scene {
130 scale_factor,
131 stacking_contexts: vec![stacking_context],
132 active_stacking_context_stack: vec![0],
133 }
134 }
135
136 pub fn scale_factor(&self) -> f32 {
137 self.scale_factor
138 }
139
140 pub fn layers(&self) -> impl Iterator<Item = &Layer> {
141 self.stacking_contexts.iter().flat_map(|s| &s.layers)
142 }
143
144 pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
145 self.active_stacking_context_stack
146 .push(self.stacking_contexts.len());
147 self.stacking_contexts
148 .push(StackingContext::new(clip_bounds))
149 }
150
151 pub fn pop_stacking_context(&mut self) {
152 self.active_stacking_context_stack.pop();
153 assert!(!self.active_stacking_context_stack.is_empty());
154 }
155
156 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
157 self.active_stacking_context().push_layer(clip_bounds);
158 }
159
160 pub fn pop_layer(&mut self) {
161 self.active_stacking_context().pop_layer();
162 }
163
164 pub fn push_quad(&mut self, quad: Quad) {
165 self.active_layer().push_quad(quad)
166 }
167
168 pub fn push_shadow(&mut self, shadow: Shadow) {
169 self.active_layer().push_shadow(shadow)
170 }
171
172 pub fn push_glyph(&mut self, glyph: Glyph) {
173 self.active_layer().push_glyph(glyph)
174 }
175
176 pub fn push_icon(&mut self, icon: Icon) {
177 self.active_layer().push_icon(icon)
178 }
179
180 pub fn push_path(&mut self, path: Path) {
181 self.active_layer().push_path(path);
182 }
183
184 fn active_stacking_context(&mut self) -> &mut StackingContext {
185 let ix = *self.active_stacking_context_stack.last().unwrap();
186 &mut self.stacking_contexts[ix]
187 }
188
189 fn active_layer(&mut self) -> &mut Layer {
190 self.active_stacking_context().active_layer()
191 }
192}
193
194impl StackingContext {
195 fn new(clip_bounds: Option<RectF>) -> Self {
196 Self {
197 layers: vec![Layer::new(clip_bounds)],
198 active_layer_stack: vec![0],
199 }
200 }
201
202 fn active_layer(&mut self) -> &mut Layer {
203 &mut self.layers[*self.active_layer_stack.last().unwrap()]
204 }
205
206 fn push_layer(&mut self, clip_bounds: Option<RectF>) {
207 let parent_clip_bounds = self.active_layer().clip_bounds();
208 let clip_bounds = clip_bounds
209 .map(|clip_bounds| {
210 clip_bounds
211 .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
212 .unwrap_or_else(|| {
213 log::warn!("specified clip bounds are disjoint from parent layer");
214 RectF::default()
215 })
216 })
217 .or(parent_clip_bounds);
218
219 let ix = self.layers.len();
220 self.layers.push(Layer::new(clip_bounds));
221 self.active_layer_stack.push(ix);
222 }
223
224 fn pop_layer(&mut self) {
225 self.active_layer_stack.pop().unwrap();
226 assert!(!self.active_layer_stack.is_empty());
227 }
228}
229
230impl Layer {
231 pub fn new(clip_bounds: Option<RectF>) -> Self {
232 Self {
233 clip_bounds,
234 quads: Vec::new(),
235 shadows: Vec::new(),
236 glyphs: Vec::new(),
237 icons: Vec::new(),
238 paths: Vec::new(),
239 }
240 }
241
242 pub fn clip_bounds(&self) -> Option<RectF> {
243 self.clip_bounds
244 }
245
246 fn push_quad(&mut self, quad: Quad) {
247 self.quads.push(quad);
248 }
249
250 pub fn quads(&self) -> &[Quad] {
251 self.quads.as_slice()
252 }
253
254 fn push_shadow(&mut self, shadow: Shadow) {
255 self.shadows.push(shadow);
256 }
257
258 pub fn shadows(&self) -> &[Shadow] {
259 self.shadows.as_slice()
260 }
261
262 fn push_glyph(&mut self, glyph: Glyph) {
263 self.glyphs.push(glyph);
264 }
265
266 pub fn glyphs(&self) -> &[Glyph] {
267 self.glyphs.as_slice()
268 }
269
270 pub fn push_icon(&mut self, icon: Icon) {
271 self.icons.push(icon);
272 }
273
274 pub fn icons(&self) -> &[Icon] {
275 self.icons.as_slice()
276 }
277
278 fn push_path(&mut self, path: Path) {
279 if !path.bounds.is_empty() {
280 self.paths.push(path);
281 }
282 }
283
284 pub fn paths(&self) -> &[Path] {
285 self.paths.as_slice()
286 }
287}
288
289impl Border {
290 pub fn new(width: f32, color: Color) -> Self {
291 Self {
292 width,
293 color,
294 top: false,
295 left: false,
296 bottom: false,
297 right: false,
298 }
299 }
300
301 pub fn all(width: f32, color: Color) -> Self {
302 Self {
303 width,
304 color,
305 top: true,
306 left: true,
307 bottom: true,
308 right: true,
309 }
310 }
311
312 pub fn top(width: f32, color: Color) -> Self {
313 let mut border = Self::new(width, color);
314 border.top = true;
315 border
316 }
317
318 pub fn left(width: f32, color: Color) -> Self {
319 let mut border = Self::new(width, color);
320 border.left = true;
321 border
322 }
323
324 pub fn bottom(width: f32, color: Color) -> Self {
325 let mut border = Self::new(width, color);
326 border.bottom = true;
327 border
328 }
329
330 pub fn right(width: f32, color: Color) -> Self {
331 let mut border = Self::new(width, color);
332 border.right = true;
333 border
334 }
335
336 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
337 self.top = top;
338 self.left = left;
339 self.bottom = bottom;
340 self.right = right;
341 self
342 }
343
344 pub fn top_width(&self) -> f32 {
345 if self.top {
346 self.width
347 } else {
348 0.0
349 }
350 }
351
352 pub fn left_width(&self) -> f32 {
353 if self.left {
354 self.width
355 } else {
356 0.0
357 }
358 }
359}
360
361impl ToJson for Border {
362 fn to_json(&self) -> serde_json::Value {
363 let mut value = json!({});
364 if self.top {
365 value["top"] = json!(self.width);
366 }
367 if self.right {
368 value["right"] = json!(self.width);
369 }
370 if self.bottom {
371 value["bottom"] = json!(self.width);
372 }
373 if self.left {
374 value["left"] = json!(self.width);
375 }
376 value
377 }
378}