scene.rs

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