scene.rs

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