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