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 data: Arc<ImageData>,
176}
177
178impl Scene {
179 pub fn new(scale_factor: f32) -> Self {
180 let stacking_context = StackingContext::new(0, None);
181 Scene {
182 scale_factor,
183 stacking_contexts: vec![stacking_context],
184 active_stacking_context_stack: vec![0],
185 #[cfg(debug_assertions)]
186 mouse_region_ids: Default::default(),
187 }
188 }
189
190 pub fn scale_factor(&self) -> f32 {
191 self.scale_factor
192 }
193
194 pub fn layers(&self) -> impl Iterator<Item = &Layer> {
195 self.stacking_contexts.iter().flat_map(|s| &s.layers)
196 }
197
198 pub fn cursor_regions(&self) -> Vec<CursorRegion> {
199 self.layers()
200 .flat_map(|layer| &layer.cursor_regions)
201 .copied()
202 .collect()
203 }
204
205 pub fn mouse_regions(&self) -> Vec<(MouseRegion, usize)> {
206 let mut regions = Vec::new();
207 for stacking_context in self.stacking_contexts.iter() {
208 for layer in &stacking_context.layers {
209 for mouse_region in &layer.mouse_regions {
210 regions.push((mouse_region.clone(), stacking_context.depth));
211 }
212 }
213 }
214 regions.sort_by_key(|(_, depth)| *depth);
215 regions
216 }
217
218 pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
219 let depth = self.active_stacking_context().depth + 1;
220 self.active_stacking_context_stack
221 .push(self.stacking_contexts.len());
222 self.stacking_contexts
223 .push(StackingContext::new(depth, clip_bounds))
224 }
225
226 pub fn pop_stacking_context(&mut self) {
227 self.active_stacking_context_stack.pop();
228 assert!(!self.active_stacking_context_stack.is_empty());
229 }
230
231 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
232 self.active_stacking_context().push_layer(clip_bounds);
233 }
234
235 pub fn pop_layer(&mut self) {
236 self.active_stacking_context().pop_layer();
237 }
238
239 pub fn push_quad(&mut self, quad: Quad) {
240 self.active_layer().push_quad(quad)
241 }
242
243 pub fn push_cursor_region(&mut self, region: CursorRegion) {
244 if can_draw(region.bounds) {
245 self.active_layer().push_cursor_region(region);
246 }
247 }
248
249 pub fn push_mouse_region(&mut self, region: MouseRegion) {
250 if can_draw(region.bounds) {
251 // Ensure that Regions cannot be added to a scene with the same region id.
252 #[cfg(debug_assertions)]
253 let region_id;
254 #[cfg(debug_assertions)]
255 {
256 region_id = region.id();
257 }
258
259 if self.active_layer().push_mouse_region(region) {
260 #[cfg(debug_assertions)]
261 {
262 if !self.mouse_region_ids.insert(region_id) {
263 let tag_name = region_id.tag_type_name();
264 panic!("Same MouseRegionId: {region_id:?} inserted multiple times to the same scene. \
265 Will cause problems! Look for MouseRegion that uses Tag: {tag_name}");
266 }
267 }
268 }
269 }
270 }
271
272 pub fn push_image(&mut self, image: Image) {
273 self.active_layer().push_image(image)
274 }
275
276 pub fn push_surface(&mut self, surface: Surface) {
277 self.active_layer().push_surface(surface)
278 }
279
280 pub fn push_underline(&mut self, underline: Underline) {
281 self.active_layer().push_underline(underline)
282 }
283
284 pub fn push_shadow(&mut self, shadow: Shadow) {
285 self.active_layer().push_shadow(shadow)
286 }
287
288 pub fn push_glyph(&mut self, glyph: Glyph) {
289 self.active_layer().push_glyph(glyph)
290 }
291
292 pub fn push_image_glyph(&mut self, image_glyph: ImageGlyph) {
293 self.active_layer().push_image_glyph(image_glyph)
294 }
295
296 pub fn push_icon(&mut self, icon: Icon) {
297 self.active_layer().push_icon(icon)
298 }
299
300 pub fn push_path(&mut self, path: Path) {
301 self.active_layer().push_path(path);
302 }
303
304 fn active_stacking_context(&mut self) -> &mut StackingContext {
305 let ix = *self.active_stacking_context_stack.last().unwrap();
306 &mut self.stacking_contexts[ix]
307 }
308
309 fn active_layer(&mut self) -> &mut Layer {
310 self.active_stacking_context().active_layer()
311 }
312}
313
314impl StackingContext {
315 fn new(depth: usize, clip_bounds: Option<RectF>) -> Self {
316 Self {
317 layers: vec![Layer::new(clip_bounds)],
318 active_layer_stack: vec![0],
319 depth,
320 }
321 }
322
323 fn active_layer(&mut self) -> &mut Layer {
324 &mut self.layers[*self.active_layer_stack.last().unwrap()]
325 }
326
327 fn push_layer(&mut self, clip_bounds: Option<RectF>) {
328 let parent_clip_bounds = self.active_layer().clip_bounds();
329 let clip_bounds = clip_bounds
330 .map(|clip_bounds| {
331 clip_bounds
332 .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
333 .unwrap_or_else(|| {
334 if !clip_bounds.is_empty() {
335 log::warn!("specified clip bounds are disjoint from parent layer");
336 }
337 RectF::default()
338 })
339 })
340 .or(parent_clip_bounds);
341
342 let ix = self.layers.len();
343 self.layers.push(Layer::new(clip_bounds));
344 self.active_layer_stack.push(ix);
345 }
346
347 fn pop_layer(&mut self) {
348 self.active_layer_stack.pop().unwrap();
349 assert!(!self.active_layer_stack.is_empty());
350 }
351}
352
353impl Layer {
354 pub fn new(clip_bounds: Option<RectF>) -> Self {
355 Self {
356 clip_bounds,
357 quads: Default::default(),
358 underlines: Default::default(),
359 images: Default::default(),
360 surfaces: Default::default(),
361 shadows: Default::default(),
362 image_glyphs: Default::default(),
363 glyphs: Default::default(),
364 icons: Default::default(),
365 paths: Default::default(),
366 cursor_regions: Default::default(),
367 mouse_regions: Default::default(),
368 }
369 }
370
371 pub fn clip_bounds(&self) -> Option<RectF> {
372 self.clip_bounds
373 }
374
375 fn push_quad(&mut self, quad: Quad) {
376 if can_draw(quad.bounds) {
377 self.quads.push(quad);
378 }
379 }
380
381 pub fn quads(&self) -> &[Quad] {
382 self.quads.as_slice()
383 }
384
385 fn push_cursor_region(&mut self, region: CursorRegion) {
386 if let Some(bounds) = region
387 .bounds
388 .intersection(self.clip_bounds.unwrap_or(region.bounds))
389 {
390 if can_draw(bounds) {
391 self.cursor_regions.push(region);
392 }
393 }
394 }
395
396 fn push_mouse_region(&mut self, region: MouseRegion) -> bool {
397 if let Some(bounds) = region
398 .bounds
399 .intersection(self.clip_bounds.unwrap_or(region.bounds))
400 {
401 if can_draw(bounds) {
402 self.mouse_regions.push(region);
403 return true;
404 }
405 }
406 false
407 }
408
409 fn push_underline(&mut self, underline: Underline) {
410 if underline.width > 0. {
411 self.underlines.push(underline);
412 }
413 }
414
415 pub fn underlines(&self) -> &[Underline] {
416 self.underlines.as_slice()
417 }
418
419 fn push_image(&mut self, image: Image) {
420 if can_draw(image.bounds) {
421 self.images.push(image);
422 }
423 }
424
425 pub fn images(&self) -> &[Image] {
426 self.images.as_slice()
427 }
428
429 fn push_surface(&mut self, surface: Surface) {
430 if can_draw(surface.bounds) {
431 self.surfaces.push(surface);
432 }
433 }
434
435 pub fn surfaces(&self) -> &[Surface] {
436 self.surfaces.as_slice()
437 }
438
439 fn push_shadow(&mut self, shadow: Shadow) {
440 if can_draw(shadow.bounds) {
441 self.shadows.push(shadow);
442 }
443 }
444
445 pub fn shadows(&self) -> &[Shadow] {
446 self.shadows.as_slice()
447 }
448
449 fn push_image_glyph(&mut self, glyph: ImageGlyph) {
450 self.image_glyphs.push(glyph);
451 }
452
453 pub fn image_glyphs(&self) -> &[ImageGlyph] {
454 self.image_glyphs.as_slice()
455 }
456
457 fn push_glyph(&mut self, glyph: Glyph) {
458 self.glyphs.push(glyph);
459 }
460
461 pub fn glyphs(&self) -> &[Glyph] {
462 self.glyphs.as_slice()
463 }
464
465 pub fn push_icon(&mut self, icon: Icon) {
466 if can_draw(icon.bounds) {
467 self.icons.push(icon);
468 }
469 }
470
471 pub fn icons(&self) -> &[Icon] {
472 self.icons.as_slice()
473 }
474
475 fn push_path(&mut self, path: Path) {
476 if can_draw(path.bounds) {
477 self.paths.push(path);
478 }
479 }
480
481 pub fn paths(&self) -> &[Path] {
482 self.paths.as_slice()
483 }
484}
485
486impl Border {
487 pub fn new(width: f32, color: Color) -> Self {
488 Self {
489 width,
490 color,
491 overlay: false,
492 top: false,
493 left: false,
494 bottom: false,
495 right: false,
496 }
497 }
498
499 pub fn all(width: f32, color: Color) -> Self {
500 Self {
501 width,
502 color,
503 overlay: false,
504 top: true,
505 left: true,
506 bottom: true,
507 right: true,
508 }
509 }
510
511 pub fn top(width: f32, color: Color) -> Self {
512 let mut border = Self::new(width, color);
513 border.top = true;
514 border
515 }
516
517 pub fn left(width: f32, color: Color) -> Self {
518 let mut border = Self::new(width, color);
519 border.left = true;
520 border
521 }
522
523 pub fn bottom(width: f32, color: Color) -> Self {
524 let mut border = Self::new(width, color);
525 border.bottom = true;
526 border
527 }
528
529 pub fn right(width: f32, color: Color) -> Self {
530 let mut border = Self::new(width, color);
531 border.right = true;
532 border
533 }
534
535 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
536 self.top = top;
537 self.left = left;
538 self.bottom = bottom;
539 self.right = right;
540 self
541 }
542
543 pub fn top_width(&self) -> f32 {
544 if self.top {
545 self.width
546 } else {
547 0.0
548 }
549 }
550
551 pub fn left_width(&self) -> f32 {
552 if self.left {
553 self.width
554 } else {
555 0.0
556 }
557 }
558}
559
560impl ToJson for Border {
561 fn to_json(&self) -> serde_json::Value {
562 let mut value = json!({});
563 if self.top {
564 value["top"] = json!(self.width);
565 }
566 if self.right {
567 value["right"] = json!(self.width);
568 }
569 if self.bottom {
570 value["bottom"] = json!(self.width);
571 }
572 if self.left {
573 value["left"] = json!(self.width);
574 }
575 value
576 }
577}
578
579impl MouseRegion {
580 pub fn id(&self) -> MouseRegionId {
581 self.id
582 }
583}
584
585fn can_draw(bounds: RectF) -> bool {
586 let size = bounds.size();
587 size.x() > 0. && size.y() > 0.
588}