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