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