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