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