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