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