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