scene.rs

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