mod mouse_event; mod mouse_region; mod region; #[cfg(debug_assertions)] use collections::HashSet; use derive_more::Mul; use schemars::JsonSchema; use serde::Deserialize; use serde_derive::Serialize; use std::{ any::{Any, TypeId}, borrow::Cow, rc::Rc, sync::Arc, }; use crate::{ color::Color, fonts::{FontId, GlyphId}, geometry::{rect::RectF, vector::Vector2F}, platform::{current::Surface, CursorStyle}, ImageData, WindowContext, }; pub use mouse_event::*; pub use mouse_region::*; pub struct SceneBuilder { stacking_contexts: Vec, active_stacking_context_stack: Vec, /// Used by the gpui2 crate. pub event_handlers: Vec, #[cfg(debug_assertions)] mouse_region_ids: HashSet, } pub struct Scene { scale_factor: f32, stacking_contexts: Vec, event_handlers: Vec, } struct StackingContext { layers: Vec, active_layer_stack: Vec, z_index: usize, } #[derive(Default)] pub struct Layer { clip_bounds: Option, quads: Vec, underlines: Vec, images: Vec, surfaces: Vec, shadows: Vec, glyphs: Vec, image_glyphs: Vec, icons: Vec, paths: Vec, cursor_regions: Vec, mouse_regions: Vec, } #[derive(Copy, Clone)] pub struct CursorRegion { pub bounds: RectF, pub style: CursorStyle, } #[derive(Default, Debug)] pub struct Quad { pub bounds: RectF, pub background: Option, pub border: Border, pub corner_radii: CornerRadii, } #[derive(Default, Debug, Mul, Clone, Copy, Serialize, JsonSchema)] pub struct CornerRadii { pub top_left: f32, pub top_right: f32, pub bottom_right: f32, pub bottom_left: f32, } impl<'de> Deserialize<'de> for CornerRadii { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { #[derive(Deserialize)] pub struct CornerRadiiHelper { pub top_left: Option, pub top_right: Option, pub bottom_right: Option, pub bottom_left: Option, } #[derive(Deserialize)] #[serde(untagged)] enum RadiusOrRadii { Radius(f32), Radii(CornerRadiiHelper), } let json = RadiusOrRadii::deserialize(deserializer)?; let result = match json { RadiusOrRadii::Radius(radius) => CornerRadii::from(radius), RadiusOrRadii::Radii(CornerRadiiHelper { top_left, top_right, bottom_right, bottom_left, }) => CornerRadii { top_left: top_left.unwrap_or(0.0), top_right: top_right.unwrap_or(0.0), bottom_right: bottom_right.unwrap_or(0.0), bottom_left: bottom_left.unwrap_or(0.0), }, }; Ok(result) } } impl From for CornerRadii { fn from(radius: f32) -> Self { Self { top_left: radius, top_right: radius, bottom_right: radius, bottom_left: radius, } } } #[derive(Debug)] pub struct Shadow { pub bounds: RectF, pub corner_radii: CornerRadii, pub sigma: f32, pub color: Color, } #[derive(Debug, Clone, Copy)] pub struct Glyph { pub font_id: FontId, pub font_size: f32, pub id: GlyphId, pub origin: Vector2F, pub color: Color, } #[derive(Debug)] pub struct ImageGlyph { pub font_id: FontId, pub font_size: f32, pub id: GlyphId, pub origin: Vector2F, } pub struct Icon { pub bounds: RectF, pub svg: usvg::Tree, pub path: Cow<'static, str>, pub color: Color, } #[derive(Clone, Copy, Default, Debug)] pub struct Border { pub color: Color, pub top: f32, pub right: f32, pub bottom: f32, pub left: f32, } #[derive(Clone, Copy, Default, Debug)] pub struct Underline { pub origin: Vector2F, pub width: f32, pub thickness: f32, pub color: Color, pub squiggly: bool, } #[derive(Debug)] pub struct Path { pub bounds: RectF, pub color: Color, pub vertices: Vec, } #[derive(Debug)] pub struct PathVertex { pub xy_position: Vector2F, pub st_position: Vector2F, } pub struct Image { pub bounds: RectF, pub border: Border, pub corner_radii: CornerRadii, pub grayscale: bool, pub data: Arc, } impl Scene { pub fn scale_factor(&self) -> f32 { self.scale_factor } pub fn layers(&self) -> impl Iterator { self.stacking_contexts.iter().flat_map(|s| &s.layers) } pub fn cursor_regions(&self) -> Vec { self.layers() .flat_map(|layer| &layer.cursor_regions) .copied() .collect() } pub fn mouse_regions(&self) -> Vec<(MouseRegion, usize)> { self.stacking_contexts .iter() .flat_map(|context| { context .layers .iter() .flat_map(|layer| &layer.mouse_regions) .map(|region| (region.clone(), context.z_index)) }) .collect() } pub fn take_event_handlers(&mut self) -> Vec { self.event_handlers .sort_by(|a, b| a.order.cmp(&b.order).reverse()); std::mem::take(&mut self.event_handlers) } } impl SceneBuilder { pub fn new() -> Self { let mut this = SceneBuilder { stacking_contexts: Vec::new(), active_stacking_context_stack: Vec::new(), #[cfg(debug_assertions)] mouse_region_ids: HashSet::default(), event_handlers: Vec::new(), }; this.clear(); this } pub fn clear(&mut self) { self.stacking_contexts.clear(); self.stacking_contexts.push(StackingContext::new(None, 0)); self.active_stacking_context_stack.clear(); self.active_stacking_context_stack.push(0); #[cfg(debug_assertions)] self.mouse_region_ids.clear(); } pub fn build(&mut self, scale_factor: f32) -> Scene { let mut stacking_contexts = std::mem::take(&mut self.stacking_contexts); stacking_contexts.sort_by_key(|context| context.z_index); let event_handlers = std::mem::take(&mut self.event_handlers); self.clear(); Scene { scale_factor, stacking_contexts, event_handlers, } } pub fn push_stacking_context(&mut self, clip_bounds: Option, z_index: Option) { let z_index = z_index.unwrap_or_else(|| self.active_stacking_context().z_index + 1); self.active_stacking_context_stack .push(self.stacking_contexts.len()); self.stacking_contexts .push(StackingContext::new(clip_bounds, z_index)) } pub fn pop_stacking_context(&mut self) { self.active_stacking_context_stack.pop(); assert!(!self.active_stacking_context_stack.is_empty()); } pub fn push_layer(&mut self, clip_bounds: Option) { self.active_stacking_context().push_layer(clip_bounds); } pub fn pop_layer(&mut self) { self.active_stacking_context().pop_layer(); } pub fn push_quad(&mut self, quad: Quad) { self.active_layer().push_quad(quad) } pub fn push_cursor_region(&mut self, region: CursorRegion) { if can_draw(region.bounds) { self.active_layer().push_cursor_region(region); } } pub fn push_mouse_region(&mut self, region: MouseRegion) { if can_draw(region.bounds) { // Ensure that Regions cannot be added to a scene with the same region id. #[cfg(debug_assertions)] let region_id; #[cfg(debug_assertions)] { region_id = region.id(); } if self.active_layer().push_mouse_region(region) { #[cfg(debug_assertions)] { if !self.mouse_region_ids.insert(region_id) { let tag_name = region_id.tag_type_name(); panic!("Same MouseRegionId: {region_id:?} inserted multiple times to the same scene. \ Will cause problems! Look for MouseRegion that uses Tag: {tag_name}"); } } } } } pub fn push_image(&mut self, image: Image) { self.active_layer().push_image(image) } pub fn push_surface(&mut self, surface: Surface) { self.active_layer().push_surface(surface) } pub fn push_underline(&mut self, underline: Underline) { self.active_layer().push_underline(underline) } pub fn push_shadow(&mut self, shadow: Shadow) { self.active_layer().push_shadow(shadow) } pub fn push_glyph(&mut self, glyph: Glyph) { self.active_layer().push_glyph(glyph) } pub fn push_image_glyph(&mut self, image_glyph: ImageGlyph) { self.active_layer().push_image_glyph(image_glyph) } pub fn push_icon(&mut self, icon: Icon) { self.active_layer().push_icon(icon) } pub fn push_path(&mut self, path: Path) { self.active_layer().push_path(path); } fn active_stacking_context(&mut self) -> &mut StackingContext { let ix = *self.active_stacking_context_stack.last().unwrap(); &mut self.stacking_contexts[ix] } fn active_layer(&mut self) -> &mut Layer { self.active_stacking_context().active_layer() } } impl StackingContext { fn new(clip_bounds: Option, z_index: usize) -> Self { Self { layers: vec![Layer::new(clip_bounds)], active_layer_stack: vec![0], z_index, } } fn active_layer(&mut self) -> &mut Layer { &mut self.layers[*self.active_layer_stack.last().unwrap()] } fn push_layer(&mut self, clip_bounds: Option) { let parent_clip_bounds = self.active_layer().clip_bounds(); let clip_bounds = clip_bounds .map(|clip_bounds| { clip_bounds .intersection(parent_clip_bounds.unwrap_or(clip_bounds)) .unwrap_or_else(|| { if !clip_bounds.is_empty() { log::warn!("specified clip bounds are disjoint from parent layer"); } RectF::default() }) }) .or(parent_clip_bounds); let ix = self.layers.len(); self.layers.push(Layer::new(clip_bounds)); self.active_layer_stack.push(ix); } fn pop_layer(&mut self) { self.active_layer_stack.pop().unwrap(); assert!(!self.active_layer_stack.is_empty()); } } impl Layer { pub fn new(clip_bounds: Option) -> Self { Self { clip_bounds, quads: Default::default(), underlines: Default::default(), images: Default::default(), surfaces: Default::default(), shadows: Default::default(), image_glyphs: Default::default(), glyphs: Default::default(), icons: Default::default(), paths: Default::default(), cursor_regions: Default::default(), mouse_regions: Default::default(), } } pub fn clip_bounds(&self) -> Option { self.clip_bounds } fn push_quad(&mut self, quad: Quad) { if can_draw(quad.bounds) { self.quads.push(quad); } } pub fn quads(&self) -> &[Quad] { self.quads.as_slice() } fn push_cursor_region(&mut self, region: CursorRegion) { if let Some(bounds) = region .bounds .intersection(self.clip_bounds.unwrap_or(region.bounds)) { if can_draw(bounds) { self.cursor_regions.push(region); } } } fn push_mouse_region(&mut self, region: MouseRegion) -> bool { if let Some(bounds) = region .bounds .intersection(self.clip_bounds.unwrap_or(region.bounds)) { if can_draw(bounds) { self.mouse_regions.push(region); return true; } } false } fn push_underline(&mut self, underline: Underline) { if underline.width > 0. { self.underlines.push(underline); } } pub fn underlines(&self) -> &[Underline] { self.underlines.as_slice() } fn push_image(&mut self, image: Image) { if can_draw(image.bounds) { self.images.push(image); } } pub fn images(&self) -> &[Image] { self.images.as_slice() } fn push_surface(&mut self, surface: Surface) { if can_draw(surface.bounds) { self.surfaces.push(surface); } } pub fn surfaces(&self) -> &[Surface] { self.surfaces.as_slice() } fn push_shadow(&mut self, shadow: Shadow) { if can_draw(shadow.bounds) { self.shadows.push(shadow); } } pub fn shadows(&self) -> &[Shadow] { self.shadows.as_slice() } fn push_image_glyph(&mut self, glyph: ImageGlyph) { self.image_glyphs.push(glyph); } pub fn image_glyphs(&self) -> &[ImageGlyph] { self.image_glyphs.as_slice() } fn push_glyph(&mut self, glyph: Glyph) { self.glyphs.push(glyph); } pub fn glyphs(&self) -> &[Glyph] { self.glyphs.as_slice() } pub fn push_icon(&mut self, icon: Icon) { if can_draw(icon.bounds) { self.icons.push(icon); } } pub fn icons(&self) -> &[Icon] { self.icons.as_slice() } fn push_path(&mut self, path: Path) { if can_draw(path.bounds) { self.paths.push(path); } } pub fn paths(&self) -> &[Path] { self.paths.as_slice() } } impl MouseRegion { pub fn id(&self) -> MouseRegionId { self.id } } pub struct EventHandler { pub order: u32, // The &dyn Any parameter below expects an event. pub handler: Rc bool>, pub event_type: TypeId, } fn can_draw(bounds: RectF) -> bool { let size = bounds.size(); size.x() > 0. && size.y() > 0. }