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