scene.rs

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