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