1use serde::Deserialize;
2use serde_json::json;
3use std::{any::TypeId, borrow::Cow, rc::Rc, sync::Arc};
4
5use crate::{
6 color::Color,
7 fonts::{FontId, GlyphId},
8 geometry::{rect::RectF, vector::Vector2F},
9 json::ToJson,
10 platform::CursorStyle,
11 EventContext, ImageData,
12};
13
14pub struct Scene {
15 scale_factor: f32,
16 stacking_contexts: Vec<StackingContext>,
17 active_stacking_context_stack: Vec<usize>,
18}
19
20struct StackingContext {
21 layers: Vec<Layer>,
22 active_layer_stack: Vec<usize>,
23 depth: usize,
24}
25
26#[derive(Default)]
27pub struct Layer {
28 clip_bounds: Option<RectF>,
29 quads: Vec<Quad>,
30 underlines: Vec<Underline>,
31 images: Vec<Image>,
32 shadows: Vec<Shadow>,
33 glyphs: Vec<Glyph>,
34 image_glyphs: Vec<ImageGlyph>,
35 icons: Vec<Icon>,
36 paths: Vec<Path>,
37 cursor_regions: Vec<CursorRegion>,
38 mouse_regions: Vec<MouseRegion>,
39}
40
41#[derive(Copy, Clone)]
42pub struct CursorRegion {
43 pub bounds: RectF,
44 pub style: CursorStyle,
45}
46
47#[derive(Clone, Default)]
48pub struct MouseRegion {
49 pub view_id: usize,
50 pub discriminant: Option<(TypeId, usize)>,
51 pub bounds: RectF,
52 pub hover: Option<Rc<dyn Fn(Vector2F, bool, &mut EventContext)>>,
53 pub mouse_down: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
54 pub click: Option<Rc<dyn Fn(Vector2F, usize, &mut EventContext)>>,
55 pub right_mouse_down: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
56 pub right_click: Option<Rc<dyn Fn(Vector2F, usize, &mut EventContext)>>,
57 pub drag: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
58 pub mouse_down_out: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
59 pub right_mouse_down_out: Option<Rc<dyn Fn(Vector2F, &mut EventContext)>>,
60}
61
62#[derive(Copy, Clone, Eq, PartialEq, Hash)]
63pub struct MouseRegionId {
64 pub view_id: usize,
65 pub discriminant: (TypeId, usize),
66}
67
68#[derive(Default, Debug)]
69pub struct Quad {
70 pub bounds: RectF,
71 pub background: Option<Color>,
72 pub border: Border,
73 pub corner_radius: f32,
74}
75
76#[derive(Debug)]
77pub struct Shadow {
78 pub bounds: RectF,
79 pub corner_radius: f32,
80 pub sigma: f32,
81 pub color: Color,
82}
83
84#[derive(Debug)]
85pub struct Glyph {
86 pub font_id: FontId,
87 pub font_size: f32,
88 pub id: GlyphId,
89 pub origin: Vector2F,
90 pub color: Color,
91}
92
93#[derive(Debug)]
94pub struct ImageGlyph {
95 pub font_id: FontId,
96 pub font_size: f32,
97 pub id: GlyphId,
98 pub origin: Vector2F,
99}
100
101pub struct Icon {
102 pub bounds: RectF,
103 pub svg: usvg::Tree,
104 pub path: Cow<'static, str>,
105 pub color: Color,
106}
107
108#[derive(Clone, Copy, Default, Debug)]
109pub struct Border {
110 pub width: f32,
111 pub color: Color,
112 pub overlay: bool,
113 pub top: bool,
114 pub right: bool,
115 pub bottom: bool,
116 pub left: bool,
117}
118
119#[derive(Clone, Copy, Default, Debug)]
120pub struct Underline {
121 pub origin: Vector2F,
122 pub width: f32,
123 pub thickness: f32,
124 pub color: Color,
125 pub squiggly: bool,
126}
127
128impl<'de> Deserialize<'de> for Border {
129 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130 where
131 D: serde::Deserializer<'de>,
132 {
133 #[derive(Deserialize)]
134 struct BorderData {
135 pub width: f32,
136 pub color: Color,
137 #[serde(default)]
138 pub overlay: bool,
139 #[serde(default)]
140 pub top: bool,
141 #[serde(default)]
142 pub right: bool,
143 #[serde(default)]
144 pub bottom: bool,
145 #[serde(default)]
146 pub left: bool,
147 }
148
149 let data = BorderData::deserialize(deserializer)?;
150 let mut border = Border {
151 width: data.width,
152 color: data.color,
153 overlay: data.overlay,
154 top: data.top,
155 bottom: data.bottom,
156 left: data.left,
157 right: data.right,
158 };
159 if !border.top && !border.bottom && !border.left && !border.right {
160 border.top = true;
161 border.bottom = true;
162 border.left = true;
163 border.right = true;
164 }
165 Ok(border)
166 }
167}
168
169#[derive(Debug)]
170pub struct Path {
171 pub bounds: RectF,
172 pub color: Color,
173 pub vertices: Vec<PathVertex>,
174}
175
176#[derive(Debug)]
177pub struct PathVertex {
178 pub xy_position: Vector2F,
179 pub st_position: Vector2F,
180}
181
182pub struct Image {
183 pub bounds: RectF,
184 pub border: Border,
185 pub corner_radius: f32,
186 pub data: Arc<ImageData>,
187}
188
189impl Scene {
190 pub fn new(scale_factor: f32) -> Self {
191 let stacking_context = StackingContext::new(0, None);
192 Scene {
193 scale_factor,
194 stacking_contexts: vec![stacking_context],
195 active_stacking_context_stack: vec![0],
196 }
197 }
198
199 pub fn scale_factor(&self) -> f32 {
200 self.scale_factor
201 }
202
203 pub fn layers(&self) -> impl Iterator<Item = &Layer> {
204 self.stacking_contexts.iter().flat_map(|s| &s.layers)
205 }
206
207 pub fn cursor_regions(&self) -> Vec<CursorRegion> {
208 self.layers()
209 .flat_map(|layer| &layer.cursor_regions)
210 .copied()
211 .collect()
212 }
213
214 pub fn mouse_regions(&self) -> Vec<(MouseRegion, usize)> {
215 let mut regions = Vec::new();
216 for stacking_context in self.stacking_contexts.iter() {
217 for layer in &stacking_context.layers {
218 for mouse_region in &layer.mouse_regions {
219 regions.push((mouse_region.clone(), stacking_context.depth));
220 }
221 }
222 }
223 regions.sort_by_key(|(_, depth)| *depth);
224 regions
225 }
226
227 pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
228 let depth = self.active_stacking_context().depth + 1;
229 self.active_stacking_context_stack
230 .push(self.stacking_contexts.len());
231 self.stacking_contexts
232 .push(StackingContext::new(depth, clip_bounds))
233 }
234
235 pub fn pop_stacking_context(&mut self) {
236 self.active_stacking_context_stack.pop();
237 assert!(!self.active_stacking_context_stack.is_empty());
238 }
239
240 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
241 self.active_stacking_context().push_layer(clip_bounds);
242 }
243
244 pub fn pop_layer(&mut self) {
245 self.active_stacking_context().pop_layer();
246 }
247
248 pub fn push_quad(&mut self, quad: Quad) {
249 self.active_layer().push_quad(quad)
250 }
251
252 pub fn push_cursor_region(&mut self, region: CursorRegion) {
253 self.active_layer().push_cursor_region(region);
254 }
255
256 pub fn push_mouse_region(&mut self, region: MouseRegion) {
257 self.active_layer().push_mouse_region(region);
258 }
259
260 pub fn push_image(&mut self, image: Image) {
261 self.active_layer().push_image(image)
262 }
263
264 pub fn push_underline(&mut self, underline: Underline) {
265 self.active_layer().push_underline(underline)
266 }
267
268 pub fn push_shadow(&mut self, shadow: Shadow) {
269 self.active_layer().push_shadow(shadow)
270 }
271
272 pub fn push_glyph(&mut self, glyph: Glyph) {
273 self.active_layer().push_glyph(glyph)
274 }
275
276 pub fn push_image_glyph(&mut self, image_glyph: ImageGlyph) {
277 self.active_layer().push_image_glyph(image_glyph)
278 }
279
280 pub fn push_icon(&mut self, icon: Icon) {
281 self.active_layer().push_icon(icon)
282 }
283
284 pub fn push_path(&mut self, path: Path) {
285 self.active_layer().push_path(path);
286 }
287
288 fn active_stacking_context(&mut self) -> &mut StackingContext {
289 let ix = *self.active_stacking_context_stack.last().unwrap();
290 &mut self.stacking_contexts[ix]
291 }
292
293 fn active_layer(&mut self) -> &mut Layer {
294 self.active_stacking_context().active_layer()
295 }
296}
297
298impl StackingContext {
299 fn new(depth: usize, clip_bounds: Option<RectF>) -> Self {
300 Self {
301 layers: vec![Layer::new(clip_bounds)],
302 active_layer_stack: vec![0],
303 depth,
304 }
305 }
306
307 fn active_layer(&mut self) -> &mut Layer {
308 &mut self.layers[*self.active_layer_stack.last().unwrap()]
309 }
310
311 fn push_layer(&mut self, clip_bounds: Option<RectF>) {
312 let parent_clip_bounds = self.active_layer().clip_bounds();
313 let clip_bounds = clip_bounds
314 .map(|clip_bounds| {
315 clip_bounds
316 .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
317 .unwrap_or_else(|| {
318 if !clip_bounds.is_empty() {
319 log::warn!("specified clip bounds are disjoint from parent layer");
320 }
321 RectF::default()
322 })
323 })
324 .or(parent_clip_bounds);
325
326 let ix = self.layers.len();
327 self.layers.push(Layer::new(clip_bounds));
328 self.active_layer_stack.push(ix);
329 }
330
331 fn pop_layer(&mut self) {
332 self.active_layer_stack.pop().unwrap();
333 assert!(!self.active_layer_stack.is_empty());
334 }
335}
336
337impl Layer {
338 pub fn new(clip_bounds: Option<RectF>) -> Self {
339 Self {
340 clip_bounds,
341 quads: Default::default(),
342 underlines: Default::default(),
343 images: Default::default(),
344 shadows: Default::default(),
345 image_glyphs: Default::default(),
346 glyphs: Default::default(),
347 icons: Default::default(),
348 paths: Default::default(),
349 cursor_regions: Default::default(),
350 mouse_regions: Default::default(),
351 }
352 }
353
354 pub fn clip_bounds(&self) -> Option<RectF> {
355 self.clip_bounds
356 }
357
358 fn push_quad(&mut self, quad: Quad) {
359 if can_draw(quad.bounds) {
360 self.quads.push(quad);
361 }
362 }
363
364 pub fn quads(&self) -> &[Quad] {
365 self.quads.as_slice()
366 }
367
368 fn push_cursor_region(&mut self, region: CursorRegion) {
369 if let Some(bounds) = region
370 .bounds
371 .intersection(self.clip_bounds.unwrap_or(region.bounds))
372 {
373 if can_draw(bounds) {
374 self.cursor_regions.push(region);
375 }
376 }
377 }
378
379 fn push_mouse_region(&mut self, region: MouseRegion) {
380 if let Some(bounds) = region
381 .bounds
382 .intersection(self.clip_bounds.unwrap_or(region.bounds))
383 {
384 if can_draw(bounds) {
385 self.mouse_regions.push(region);
386 }
387 }
388 }
389
390 fn push_underline(&mut self, underline: Underline) {
391 if underline.width > 0. {
392 self.underlines.push(underline);
393 }
394 }
395
396 pub fn underlines(&self) -> &[Underline] {
397 self.underlines.as_slice()
398 }
399
400 fn push_image(&mut self, image: Image) {
401 if can_draw(image.bounds) {
402 self.images.push(image);
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}