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