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 }
265
266 pub fn build(&mut self, scale_factor: f32) -> Scene {
267 let mut stacking_contexts = std::mem::take(&mut self.stacking_contexts);
268 stacking_contexts.sort_by_key(|context| context.z_index);
269 let event_handlers = std::mem::take(&mut self.event_handlers);
270 self.clear();
271
272 Scene {
273 scale_factor,
274 stacking_contexts,
275 event_handlers,
276 }
277 }
278
279 pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>, z_index: Option<usize>) {
280 let z_index = z_index.unwrap_or_else(|| self.active_stacking_context().z_index + 1);
281 self.active_stacking_context_stack
282 .push(self.stacking_contexts.len());
283 self.stacking_contexts
284 .push(StackingContext::new(clip_bounds, z_index))
285 }
286
287 pub fn pop_stacking_context(&mut self) {
288 self.active_stacking_context_stack.pop();
289 assert!(!self.active_stacking_context_stack.is_empty());
290 }
291
292 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
293 self.active_stacking_context().push_layer(clip_bounds);
294 }
295
296 pub fn pop_layer(&mut self) {
297 self.active_stacking_context().pop_layer();
298 }
299
300 pub fn push_quad(&mut self, quad: Quad) {
301 self.active_layer().push_quad(quad)
302 }
303
304 pub fn push_cursor_region(&mut self, region: CursorRegion) {
305 if can_draw(region.bounds) {
306 self.active_layer().push_cursor_region(region);
307 }
308 }
309
310 pub fn push_mouse_region(&mut self, region: MouseRegion) {
311 if can_draw(region.bounds) {
312 // Ensure that Regions cannot be added to a scene with the same region id.
313 #[cfg(debug_assertions)]
314 let region_id;
315 #[cfg(debug_assertions)]
316 {
317 region_id = region.id();
318 }
319
320 if self.active_layer().push_mouse_region(region) {
321 #[cfg(debug_assertions)]
322 {
323 if !self.mouse_region_ids.insert(region_id) {
324 let tag_name = region_id.tag_type_name();
325 panic!("Same MouseRegionId: {region_id:?} inserted multiple times to the same scene. \
326 Will cause problems! Look for MouseRegion that uses Tag: {tag_name}");
327 }
328 }
329 }
330 }
331 }
332
333 pub fn push_image(&mut self, image: Image) {
334 self.active_layer().push_image(image)
335 }
336
337 pub fn push_surface(&mut self, surface: Surface) {
338 self.active_layer().push_surface(surface)
339 }
340
341 pub fn push_underline(&mut self, underline: Underline) {
342 self.active_layer().push_underline(underline)
343 }
344
345 pub fn push_shadow(&mut self, shadow: Shadow) {
346 self.active_layer().push_shadow(shadow)
347 }
348
349 pub fn push_glyph(&mut self, glyph: Glyph) {
350 self.active_layer().push_glyph(glyph)
351 }
352
353 pub fn push_image_glyph(&mut self, image_glyph: ImageGlyph) {
354 self.active_layer().push_image_glyph(image_glyph)
355 }
356
357 pub fn push_icon(&mut self, icon: Icon) {
358 self.active_layer().push_icon(icon)
359 }
360
361 pub fn push_path(&mut self, path: Path) {
362 self.active_layer().push_path(path);
363 }
364
365 fn active_stacking_context(&mut self) -> &mut StackingContext {
366 let ix = *self.active_stacking_context_stack.last().unwrap();
367 &mut self.stacking_contexts[ix]
368 }
369
370 fn active_layer(&mut self) -> &mut Layer {
371 self.active_stacking_context().active_layer()
372 }
373}
374
375impl StackingContext {
376 fn new(clip_bounds: Option<RectF>, z_index: usize) -> Self {
377 Self {
378 layers: vec![Layer::new(clip_bounds)],
379 active_layer_stack: vec![0],
380 z_index,
381 }
382 }
383
384 fn active_layer(&mut self) -> &mut Layer {
385 &mut self.layers[*self.active_layer_stack.last().unwrap()]
386 }
387
388 fn push_layer(&mut self, clip_bounds: Option<RectF>) {
389 let parent_clip_bounds = self.active_layer().clip_bounds();
390 let clip_bounds = clip_bounds
391 .map(|clip_bounds| {
392 clip_bounds
393 .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
394 .unwrap_or_else(|| {
395 if !clip_bounds.is_empty() {
396 log::warn!("specified clip bounds are disjoint from parent layer");
397 }
398 RectF::default()
399 })
400 })
401 .or(parent_clip_bounds);
402
403 let ix = self.layers.len();
404 self.layers.push(Layer::new(clip_bounds));
405 self.active_layer_stack.push(ix);
406 }
407
408 fn pop_layer(&mut self) {
409 self.active_layer_stack.pop().unwrap();
410 assert!(!self.active_layer_stack.is_empty());
411 }
412}
413
414impl Layer {
415 pub fn new(clip_bounds: Option<RectF>) -> Self {
416 Self {
417 clip_bounds,
418 quads: Default::default(),
419 underlines: Default::default(),
420 images: Default::default(),
421 surfaces: Default::default(),
422 shadows: Default::default(),
423 image_glyphs: Default::default(),
424 glyphs: Default::default(),
425 icons: Default::default(),
426 paths: Default::default(),
427 cursor_regions: Default::default(),
428 mouse_regions: Default::default(),
429 }
430 }
431
432 pub fn clip_bounds(&self) -> Option<RectF> {
433 self.clip_bounds
434 }
435
436 fn push_quad(&mut self, quad: Quad) {
437 if can_draw(quad.bounds) {
438 self.quads.push(quad);
439 }
440 }
441
442 pub fn quads(&self) -> &[Quad] {
443 self.quads.as_slice()
444 }
445
446 fn push_cursor_region(&mut self, region: CursorRegion) {
447 if let Some(bounds) = region
448 .bounds
449 .intersection(self.clip_bounds.unwrap_or(region.bounds))
450 {
451 if can_draw(bounds) {
452 self.cursor_regions.push(region);
453 }
454 }
455 }
456
457 fn push_mouse_region(&mut self, region: MouseRegion) -> bool {
458 if let Some(bounds) = region
459 .bounds
460 .intersection(self.clip_bounds.unwrap_or(region.bounds))
461 {
462 if can_draw(bounds) {
463 self.mouse_regions.push(region);
464 return true;
465 }
466 }
467 false
468 }
469
470 fn push_underline(&mut self, underline: Underline) {
471 if underline.width > 0. {
472 self.underlines.push(underline);
473 }
474 }
475
476 pub fn underlines(&self) -> &[Underline] {
477 self.underlines.as_slice()
478 }
479
480 fn push_image(&mut self, image: Image) {
481 if can_draw(image.bounds) {
482 self.images.push(image);
483 }
484 }
485
486 pub fn images(&self) -> &[Image] {
487 self.images.as_slice()
488 }
489
490 fn push_surface(&mut self, surface: Surface) {
491 if can_draw(surface.bounds) {
492 self.surfaces.push(surface);
493 }
494 }
495
496 pub fn surfaces(&self) -> &[Surface] {
497 self.surfaces.as_slice()
498 }
499
500 fn push_shadow(&mut self, shadow: Shadow) {
501 if can_draw(shadow.bounds) {
502 self.shadows.push(shadow);
503 }
504 }
505
506 pub fn shadows(&self) -> &[Shadow] {
507 self.shadows.as_slice()
508 }
509
510 fn push_image_glyph(&mut self, glyph: ImageGlyph) {
511 self.image_glyphs.push(glyph);
512 }
513
514 pub fn image_glyphs(&self) -> &[ImageGlyph] {
515 self.image_glyphs.as_slice()
516 }
517
518 fn push_glyph(&mut self, glyph: Glyph) {
519 self.glyphs.push(glyph);
520 }
521
522 pub fn glyphs(&self) -> &[Glyph] {
523 self.glyphs.as_slice()
524 }
525
526 pub fn push_icon(&mut self, icon: Icon) {
527 if can_draw(icon.bounds) {
528 self.icons.push(icon);
529 }
530 }
531
532 pub fn icons(&self) -> &[Icon] {
533 self.icons.as_slice()
534 }
535
536 fn push_path(&mut self, path: Path) {
537 if can_draw(path.bounds) {
538 self.paths.push(path);
539 }
540 }
541
542 pub fn paths(&self) -> &[Path] {
543 self.paths.as_slice()
544 }
545}
546
547impl MouseRegion {
548 pub fn id(&self) -> MouseRegionId {
549 self.id
550 }
551}
552
553pub struct EventHandler {
554 pub order: u32,
555 // The &dyn Any parameter below expects an event.
556 pub handler: Rc<dyn Fn(&dyn Any, &mut WindowContext) -> bool>,
557 pub event_type: TypeId,
558}
559
560fn can_draw(bounds: RectF) -> bool {
561 let size = bounds.size();
562 size.x() > 0. && size.y() > 0.
563}