use super::blend_mode::BlendMode; use super::folder_layer::FolderLayer; use super::image_layer::ImageLayer; use super::shape_layer::ShapeLayer; use super::style::{PathStyle, ViewMode}; use super::text_layer::TextLayer; use crate::intersection::Quad; use crate::DocumentError; use crate::LayerId; use glam::{DAffine2, DMat2, DVec2}; use serde::{Deserialize, Serialize}; use std::fmt::Write; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub enum LayerDataType { Folder(FolderLayer), Shape(ShapeLayer), Text(TextLayer), Image(ImageLayer), } impl LayerDataType { pub fn inner(&self) -> &dyn LayerData { match self { LayerDataType::Shape(s) => s, LayerDataType::Folder(f) => f, LayerDataType::Text(t) => t, LayerDataType::Image(i) => i, } } pub fn inner_mut(&mut self) -> &mut dyn LayerData { match self { LayerDataType::Shape(s) => s, LayerDataType::Folder(f) => f, LayerDataType::Text(t) => t, LayerDataType::Image(i) => i, } } } pub trait LayerData { fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec, view_mode: ViewMode); fn intersects_quad(&self, quad: Quad, path: &mut Vec, intersections: &mut Vec>); fn bounding_box(&self, transform: glam::DAffine2) -> Option<[DVec2; 2]>; } impl LayerData for LayerDataType { fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec, view_mode: ViewMode) { self.inner_mut().render(svg, svg_defs, transforms, view_mode) } fn intersects_quad(&self, quad: Quad, path: &mut Vec, intersections: &mut Vec>) { self.inner().intersects_quad(quad, path, intersections) } fn bounding_box(&self, transform: glam::DAffine2) -> Option<[DVec2; 2]> { self.inner().bounding_box(transform) } } #[derive(Serialize, Deserialize)] #[serde(remote = "glam::DAffine2")] struct DAffine2Ref { pub matrix2: DMat2, pub translation: DVec2, } fn return_true() -> bool { true } #[derive(Debug, PartialEq, Deserialize, Serialize)] pub struct Layer { pub visible: bool, pub name: Option, pub data: LayerDataType, #[serde(with = "DAffine2Ref")] pub transform: glam::DAffine2, #[serde(skip)] pub cache: String, #[serde(skip)] pub thumbnail_cache: String, #[serde(skip)] pub svg_defs_cache: String, #[serde(skip, default = "return_true")] pub cache_dirty: bool, pub blend_mode: BlendMode, pub opacity: f64, } impl Layer { pub fn new(data: LayerDataType, transform: [f64; 6]) -> Self { Self { visible: true, name: None, data, transform: glam::DAffine2::from_cols_array(&transform), cache: String::new(), thumbnail_cache: String::new(), svg_defs_cache: String::new(), cache_dirty: true, blend_mode: BlendMode::Normal, opacity: 1., } } pub fn iter(&self) -> LayerIter<'_> { LayerIter { stack: vec![self] } } pub fn render(&mut self, transforms: &mut Vec, view_mode: ViewMode, svg_defs: &mut String) -> &str { if !self.visible { return ""; } if self.cache_dirty { transforms.push(self.transform); self.thumbnail_cache.clear(); self.svg_defs_cache.clear(); self.data.render(&mut self.thumbnail_cache, &mut self.svg_defs_cache, transforms, view_mode); self.cache.clear(); let _ = writeln!(self.cache, r#"{}"#, self.blend_mode.to_svg_style_name(), self.opacity, self.thumbnail_cache.as_str() ); transforms.pop(); self.cache_dirty = false; } svg_defs.push_str(&self.svg_defs_cache); self.cache.as_str() } pub fn intersects_quad(&self, quad: Quad, path: &mut Vec, intersections: &mut Vec>) { if !self.visible { return; } let transformed_quad = self.transform.inverse() * quad; self.data.intersects_quad(transformed_quad, path, intersections) } pub fn aabounding_box_for_transform(&self, transform: DAffine2) -> Option<[DVec2; 2]> { self.data.bounding_box(transform) } pub fn aabounding_box(&self) -> Option<[DVec2; 2]> { self.aabounding_box_for_transform(self.transform) } pub fn bounding_transform(&self) -> DAffine2 { let scale = match self.aabounding_box_for_transform(DAffine2::IDENTITY) { Some([a, b]) => { let dimensions = b - a; DAffine2::from_scale(dimensions) } _ => DAffine2::IDENTITY, }; self.transform * scale } pub fn as_folder_mut(&mut self) -> Result<&mut FolderLayer, DocumentError> { match &mut self.data { LayerDataType::Folder(f) => Ok(f), _ => Err(DocumentError::NotAFolder), } } pub fn as_folder(&self) -> Result<&FolderLayer, DocumentError> { match &self.data { LayerDataType::Folder(f) => Ok(f), _ => Err(DocumentError::NotAFolder), } } pub fn as_text_mut(&mut self) -> Result<&mut TextLayer, DocumentError> { match &mut self.data { LayerDataType::Text(t) => Ok(t), _ => Err(DocumentError::NotText), } } pub fn as_text(&self) -> Result<&TextLayer, DocumentError> { match &self.data { LayerDataType::Text(t) => Ok(t), _ => Err(DocumentError::NotText), } } pub fn as_image_mut(&mut self) -> Result<&mut ImageLayer, DocumentError> { match &mut self.data { LayerDataType::Image(img) => Ok(img), _ => Err(DocumentError::NotAnImage), } } pub fn style(&self) -> Result<&PathStyle, DocumentError> { match &self.data { LayerDataType::Shape(s) => Ok(&s.style), LayerDataType::Text(t) => Ok(&t.style), _ => Err(DocumentError::NotAShape), } } pub fn style_mut(&mut self) -> Result<&mut PathStyle, DocumentError> { match &mut self.data { LayerDataType::Shape(s) => Ok(&mut s.style), LayerDataType::Text(t) => Ok(&mut t.style), _ => Err(DocumentError::NotAShape), } } } impl Clone for Layer { fn clone(&self) -> Self { Self { visible: self.visible, name: self.name.clone(), data: self.data.clone(), transform: self.transform, cache: String::new(), thumbnail_cache: String::new(), svg_defs_cache: String::new(), cache_dirty: true, blend_mode: self.blend_mode, opacity: self.opacity, } } } impl<'a> IntoIterator for &'a Layer { type Item = &'a Layer; type IntoIter = LayerIter<'a>; fn into_iter(self) -> Self::IntoIter { self.iter() } } #[derive(Debug, Default)] pub struct LayerIter<'a> { pub stack: Vec<&'a Layer>, } impl<'a> Iterator for LayerIter<'a> { type Item = &'a Layer; fn next(&mut self) -> Option { match self.stack.pop() { Some(layer) => { if let LayerDataType::Folder(folder) = &layer.data { let layers = folder.layers(); self.stack.extend(layers); }; Some(layer) } None => None, } } }