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