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, Clone, Copy)]
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 if can_draw(region.bounds) {
254 self.active_layer().push_cursor_region(region);
255 }
256 }
257
258 pub fn push_mouse_region(&mut self, region: MouseRegion) {
259 if can_draw(region.bounds) {
260 self.active_layer().push_mouse_region(region);
261 }
262 }
263
264 pub fn push_image(&mut self, image: Image) {
265 self.active_layer().push_image(image)
266 }
267
268 pub fn push_underline(&mut self, underline: Underline) {
269 self.active_layer().push_underline(underline)
270 }
271
272 pub fn push_shadow(&mut self, shadow: Shadow) {
273 self.active_layer().push_shadow(shadow)
274 }
275
276 pub fn push_glyph(&mut self, glyph: Glyph) {
277 self.active_layer().push_glyph(glyph)
278 }
279
280 pub fn push_image_glyph(&mut self, image_glyph: ImageGlyph) {
281 self.active_layer().push_image_glyph(image_glyph)
282 }
283
284 pub fn push_icon(&mut self, icon: Icon) {
285 self.active_layer().push_icon(icon)
286 }
287
288 pub fn push_path(&mut self, path: Path) {
289 self.active_layer().push_path(path);
290 }
291
292 fn active_stacking_context(&mut self) -> &mut StackingContext {
293 let ix = *self.active_stacking_context_stack.last().unwrap();
294 &mut self.stacking_contexts[ix]
295 }
296
297 fn active_layer(&mut self) -> &mut Layer {
298 self.active_stacking_context().active_layer()
299 }
300}
301
302impl StackingContext {
303 fn new(depth: usize, clip_bounds: Option<RectF>) -> Self {
304 Self {
305 layers: vec![Layer::new(clip_bounds)],
306 active_layer_stack: vec![0],
307 depth,
308 }
309 }
310
311 fn active_layer(&mut self) -> &mut Layer {
312 &mut self.layers[*self.active_layer_stack.last().unwrap()]
313 }
314
315 fn push_layer(&mut self, clip_bounds: Option<RectF>) {
316 let parent_clip_bounds = self.active_layer().clip_bounds();
317 let clip_bounds = clip_bounds
318 .map(|clip_bounds| {
319 clip_bounds
320 .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
321 .unwrap_or_else(|| {
322 if !clip_bounds.is_empty() {
323 log::warn!("specified clip bounds are disjoint from parent layer");
324 }
325 RectF::default()
326 })
327 })
328 .or(parent_clip_bounds);
329
330 let ix = self.layers.len();
331 self.layers.push(Layer::new(clip_bounds));
332 self.active_layer_stack.push(ix);
333 }
334
335 fn pop_layer(&mut self) {
336 self.active_layer_stack.pop().unwrap();
337 assert!(!self.active_layer_stack.is_empty());
338 }
339}
340
341impl Layer {
342 pub fn new(clip_bounds: Option<RectF>) -> Self {
343 Self {
344 clip_bounds,
345 quads: Default::default(),
346 underlines: Default::default(),
347 images: Default::default(),
348 shadows: Default::default(),
349 image_glyphs: Default::default(),
350 glyphs: Default::default(),
351 icons: Default::default(),
352 paths: Default::default(),
353 cursor_regions: Default::default(),
354 mouse_regions: Default::default(),
355 }
356 }
357
358 pub fn clip_bounds(&self) -> Option<RectF> {
359 self.clip_bounds
360 }
361
362 fn push_quad(&mut self, quad: Quad) {
363 if can_draw(quad.bounds) {
364 self.quads.push(quad);
365 }
366 }
367
368 pub fn quads(&self) -> &[Quad] {
369 self.quads.as_slice()
370 }
371
372 fn push_cursor_region(&mut self, region: CursorRegion) {
373 if let Some(bounds) = region
374 .bounds
375 .intersection(self.clip_bounds.unwrap_or(region.bounds))
376 {
377 if can_draw(bounds) {
378 self.cursor_regions.push(region);
379 }
380 }
381 }
382
383 fn push_mouse_region(&mut self, region: MouseRegion) {
384 if let Some(bounds) = region
385 .bounds
386 .intersection(self.clip_bounds.unwrap_or(region.bounds))
387 {
388 if can_draw(bounds) {
389 self.mouse_regions.push(region);
390 }
391 }
392 }
393
394 fn push_underline(&mut self, underline: Underline) {
395 if underline.width > 0. {
396 self.underlines.push(underline);
397 }
398 }
399
400 pub fn underlines(&self) -> &[Underline] {
401 self.underlines.as_slice()
402 }
403
404 fn push_image(&mut self, image: Image) {
405 if can_draw(image.bounds) {
406 self.images.push(image);
407 }
408 }
409
410 pub fn images(&self) -> &[Image] {
411 self.images.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}