scene.rs

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