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