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 clip_bounds = clip_bounds.map(|clip_bounds| {
208 clip_bounds
209 .intersection(self.active_layer().clip_bounds.unwrap_or(clip_bounds))
210 .unwrap_or_else(|| {
211 log::warn!("specified clip bounds are disjoint from parent layer");
212 RectF::default()
213 })
214 });
215
216 let ix = self.layers.len();
217 self.layers.push(Layer::new(clip_bounds));
218 self.active_layer_stack.push(ix);
219 }
220
221 fn pop_layer(&mut self) {
222 self.active_layer_stack.pop().unwrap();
223 assert!(!self.active_layer_stack.is_empty());
224 }
225}
226
227impl Layer {
228 pub fn new(clip_bounds: Option<RectF>) -> Self {
229 Self {
230 clip_bounds,
231 quads: Vec::new(),
232 shadows: Vec::new(),
233 glyphs: Vec::new(),
234 icons: Vec::new(),
235 paths: Vec::new(),
236 }
237 }
238
239 pub fn clip_bounds(&self) -> Option<RectF> {
240 self.clip_bounds
241 }
242
243 fn push_quad(&mut self, quad: Quad) {
244 self.quads.push(quad);
245 }
246
247 pub fn quads(&self) -> &[Quad] {
248 self.quads.as_slice()
249 }
250
251 fn push_shadow(&mut self, shadow: Shadow) {
252 self.shadows.push(shadow);
253 }
254
255 pub fn shadows(&self) -> &[Shadow] {
256 self.shadows.as_slice()
257 }
258
259 fn push_glyph(&mut self, glyph: Glyph) {
260 self.glyphs.push(glyph);
261 }
262
263 pub fn glyphs(&self) -> &[Glyph] {
264 self.glyphs.as_slice()
265 }
266
267 pub fn push_icon(&mut self, icon: Icon) {
268 self.icons.push(icon);
269 }
270
271 pub fn icons(&self) -> &[Icon] {
272 self.icons.as_slice()
273 }
274
275 fn push_path(&mut self, path: Path) {
276 if !path.bounds.is_empty() {
277 self.paths.push(path);
278 }
279 }
280
281 pub fn paths(&self) -> &[Path] {
282 self.paths.as_slice()
283 }
284}
285
286impl Border {
287 pub fn new(width: f32, color: Color) -> Self {
288 Self {
289 width,
290 color,
291 top: false,
292 left: false,
293 bottom: false,
294 right: false,
295 }
296 }
297
298 pub fn all(width: f32, color: Color) -> Self {
299 Self {
300 width,
301 color,
302 top: true,
303 left: true,
304 bottom: true,
305 right: true,
306 }
307 }
308
309 pub fn top(width: f32, color: Color) -> Self {
310 let mut border = Self::new(width, color);
311 border.top = true;
312 border
313 }
314
315 pub fn left(width: f32, color: Color) -> Self {
316 let mut border = Self::new(width, color);
317 border.left = true;
318 border
319 }
320
321 pub fn bottom(width: f32, color: Color) -> Self {
322 let mut border = Self::new(width, color);
323 border.bottom = true;
324 border
325 }
326
327 pub fn right(width: f32, color: Color) -> Self {
328 let mut border = Self::new(width, color);
329 border.right = true;
330 border
331 }
332
333 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
334 self.top = top;
335 self.left = left;
336 self.bottom = bottom;
337 self.right = right;
338 self
339 }
340
341 pub fn top_width(&self) -> f32 {
342 if self.top {
343 self.width
344 } else {
345 0.0
346 }
347 }
348
349 pub fn left_width(&self) -> f32 {
350 if self.left {
351 self.width
352 } else {
353 0.0
354 }
355 }
356}
357
358impl ToJson for Border {
359 fn to_json(&self) -> serde_json::Value {
360 let mut value = json!({});
361 if self.top {
362 value["top"] = json!(self.width);
363 }
364 if self.right {
365 value["right"] = json!(self.width);
366 }
367 if self.bottom {
368 value["bottom"] = json!(self.width);
369 }
370 if self.left {
371 value["left"] = json!(self.width);
372 }
373 value
374 }
375}