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 pub fn images(&self) -> &[Image] {
401 self.images.as_slice()
402 }
403
404 fn push_surface(&mut self, surface: Surface) {
405 if can_draw(surface.bounds) {
406 self.surfaces.push(surface);
407 }
408 }
409
410 pub fn surfaces(&self) -> &[Surface] {
411 self.surfaces.as_slice()
412 }
413
414 fn push_shadow(&mut self, shadow: Shadow) {
415 if can_draw(shadow.bounds) {
416 self.shadows.push(shadow);
417 }
418 }
419
420 pub fn shadows(&self) -> &[Shadow] {
421 self.shadows.as_slice()
422 }
423
424 fn push_image_glyph(&mut self, glyph: ImageGlyph) {
425 self.image_glyphs.push(glyph);
426 }
427
428 pub fn image_glyphs(&self) -> &[ImageGlyph] {
429 self.image_glyphs.as_slice()
430 }
431
432 fn push_glyph(&mut self, glyph: Glyph) {
433 self.glyphs.push(glyph);
434 }
435
436 pub fn glyphs(&self) -> &[Glyph] {
437 self.glyphs.as_slice()
438 }
439
440 pub fn push_icon(&mut self, icon: Icon) {
441 if can_draw(icon.bounds) {
442 self.icons.push(icon);
443 }
444 }
445
446 pub fn icons(&self) -> &[Icon] {
447 self.icons.as_slice()
448 }
449
450 fn push_path(&mut self, path: Path) {
451 if can_draw(path.bounds) {
452 self.paths.push(path);
453 }
454 }
455
456 pub fn paths(&self) -> &[Path] {
457 self.paths.as_slice()
458 }
459}
460
461impl Border {
462 pub fn new(width: f32, color: Color) -> Self {
463 Self {
464 width,
465 color,
466 overlay: false,
467 top: false,
468 left: false,
469 bottom: false,
470 right: false,
471 }
472 }
473
474 pub fn all(width: f32, color: Color) -> Self {
475 Self {
476 width,
477 color,
478 overlay: false,
479 top: true,
480 left: true,
481 bottom: true,
482 right: true,
483 }
484 }
485
486 pub fn top(width: f32, color: Color) -> Self {
487 let mut border = Self::new(width, color);
488 border.top = true;
489 border
490 }
491
492 pub fn left(width: f32, color: Color) -> Self {
493 let mut border = Self::new(width, color);
494 border.left = true;
495 border
496 }
497
498 pub fn bottom(width: f32, color: Color) -> Self {
499 let mut border = Self::new(width, color);
500 border.bottom = true;
501 border
502 }
503
504 pub fn right(width: f32, color: Color) -> Self {
505 let mut border = Self::new(width, color);
506 border.right = true;
507 border
508 }
509
510 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
511 self.top = top;
512 self.left = left;
513 self.bottom = bottom;
514 self.right = right;
515 self
516 }
517
518 pub fn top_width(&self) -> f32 {
519 if self.top {
520 self.width
521 } else {
522 0.0
523 }
524 }
525
526 pub fn left_width(&self) -> f32 {
527 if self.left {
528 self.width
529 } else {
530 0.0
531 }
532 }
533}
534
535impl ToJson for Border {
536 fn to_json(&self) -> serde_json::Value {
537 let mut value = json!({});
538 if self.top {
539 value["top"] = json!(self.width);
540 }
541 if self.right {
542 value["right"] = json!(self.width);
543 }
544 if self.bottom {
545 value["bottom"] = json!(self.width);
546 }
547 if self.left {
548 value["left"] = json!(self.width);
549 }
550 value
551 }
552}
553
554impl MouseRegion {
555 pub fn id(&self) -> Option<MouseRegionId> {
556 self.discriminant.map(|discriminant| MouseRegionId {
557 view_id: self.view_id,
558 discriminant,
559 })
560 }
561}
562
563fn can_draw(bounds: RectF) -> bool {
564 let size = bounds.size();
565 size.x() > 0. && size.y() > 0.
566}