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