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