scene.rs

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