scene.rs

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