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