mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Refactor font_cache into render_data; delete image layer type
This commit is contained in:
parent
7ab601c0c6
commit
beab0f01c6
41 changed files with 395 additions and 554 deletions
|
|
@ -1,12 +1,11 @@
|
|||
use crate::boolean_ops::composite_boolean_operation;
|
||||
use crate::intersection::Quad;
|
||||
use crate::layers::folder_layer::FolderLayer;
|
||||
use crate::layers::image_layer::ImageLayer;
|
||||
use crate::layers::layer_info::{Layer, LayerData, LayerDataType, LayerDataTypeDiscriminant};
|
||||
use crate::layers::nodegraph_layer::NodeGraphFrameLayer;
|
||||
use crate::layers::shape_layer::ShapeLayer;
|
||||
use crate::layers::style::RenderData;
|
||||
use crate::layers::text_layer::{Font, FontCache, TextLayer};
|
||||
use crate::layers::text_layer::{Font, TextLayer};
|
||||
use crate::{DocumentError, DocumentResponse, Operation};
|
||||
|
||||
use graphene_std::vector::subpath::Subpath;
|
||||
|
|
@ -49,7 +48,7 @@ impl Default for Document {
|
|||
|
||||
impl Document {
|
||||
/// Wrapper around render, that returns the whole document as a Response.
|
||||
pub fn render_root(&mut self, render_data: RenderData) -> String {
|
||||
pub fn render_root(&mut self, render_data: &RenderData) -> String {
|
||||
// Render and append to the defs section
|
||||
let mut svg_defs = String::from("<defs>");
|
||||
self.root.render(&mut vec![], &mut svg_defs, render_data);
|
||||
|
|
@ -62,7 +61,7 @@ impl Document {
|
|||
}
|
||||
|
||||
/// Renders everything below the given layer contained within its parent folder.
|
||||
pub fn render_layers_below(&mut self, below_layer_path: &[LayerId], render_data: RenderData) -> Option<String> {
|
||||
pub fn render_layers_below(&mut self, below_layer_path: &[LayerId], render_data: &RenderData) -> Option<String> {
|
||||
// Split the path into the layer ID and its parent folder
|
||||
let (layer_id_to_render_below, parent_folder_path) = below_layer_path.split_last()?;
|
||||
|
||||
|
|
@ -89,7 +88,7 @@ impl Document {
|
|||
}
|
||||
|
||||
/// Renders a layer and its children
|
||||
pub fn render_layer(&mut self, layer_path: &[LayerId], render_data: RenderData) -> Option<String> {
|
||||
pub fn render_layer(&mut self, layer_path: &[LayerId], render_data: &RenderData) -> Option<String> {
|
||||
// Note: it is bad practice to directly clone and modify the document structure, this is a temporary hack until this whole system is replaced by the node graph
|
||||
let mut temp_clone = self.layer_mut(layer_path).ok()?.clone();
|
||||
|
||||
|
|
@ -109,14 +108,14 @@ impl Document {
|
|||
}
|
||||
|
||||
/// Checks whether each layer under `path` intersects with the provided `quad` and adds all intersection layers as paths to `intersections`.
|
||||
pub fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, font_cache: &FontCache) {
|
||||
self.layer(path).unwrap().intersects_quad(quad, path, intersections, font_cache);
|
||||
pub fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, render_data: &RenderData) {
|
||||
self.layer(path).unwrap().intersects_quad(quad, path, intersections, render_data);
|
||||
}
|
||||
|
||||
/// Checks whether each layer under the root path intersects with the provided `quad` and returns the paths to all intersecting layers.
|
||||
pub fn intersects_quad_root(&self, quad: Quad, font_cache: &FontCache) -> Vec<Vec<LayerId>> {
|
||||
pub fn intersects_quad_root(&self, quad: Quad, render_data: &RenderData) -> Vec<Vec<LayerId>> {
|
||||
let mut intersections = Vec::new();
|
||||
self.intersects_quad(quad, &mut vec![], &mut intersections, font_cache);
|
||||
self.intersects_quad(quad, &mut vec![], &mut intersections, render_data);
|
||||
intersections
|
||||
}
|
||||
|
||||
|
|
@ -407,32 +406,32 @@ impl Document {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn viewport_bounding_box(&self, path: &[LayerId], font_cache: &FontCache) -> Result<Option<[DVec2; 2]>, DocumentError> {
|
||||
pub fn viewport_bounding_box(&self, path: &[LayerId], render_data: &RenderData) -> Result<Option<[DVec2; 2]>, DocumentError> {
|
||||
let layer = self.layer(path)?;
|
||||
let transform = self.multiply_transforms(path)?;
|
||||
Ok(layer.data.bounding_box(transform, font_cache))
|
||||
Ok(layer.data.bounding_box(transform, render_data))
|
||||
}
|
||||
|
||||
pub fn bounding_box_and_transform(&self, path: &[LayerId], font_cache: &FontCache) -> Result<Option<([DVec2; 2], DAffine2)>, DocumentError> {
|
||||
pub fn bounding_box_and_transform(&self, path: &[LayerId], render_data: &RenderData) -> Result<Option<([DVec2; 2], DAffine2)>, DocumentError> {
|
||||
let layer = self.layer(path)?;
|
||||
let transform = self.multiply_transforms(&path[..path.len() - 1])?;
|
||||
Ok(layer.data.bounding_box(layer.transform, font_cache).map(|bounds| (bounds, transform)))
|
||||
Ok(layer.data.bounding_box(layer.transform, render_data).map(|bounds| (bounds, transform)))
|
||||
}
|
||||
|
||||
/// Compute the center of transformation multiplied with `Document::multiply_transforms`.
|
||||
pub fn pivot(&self, path: &[LayerId], font_cache: &FontCache) -> Option<DVec2> {
|
||||
pub fn pivot(&self, path: &[LayerId], render_data: &RenderData) -> Option<DVec2> {
|
||||
let layer = self.layer(path).ok()?;
|
||||
Some(self.multiply_transforms(path).unwrap_or_default().transform_point2(layer.layerspace_pivot(font_cache)))
|
||||
Some(self.multiply_transforms(path).unwrap_or_default().transform_point2(layer.layerspace_pivot(render_data)))
|
||||
}
|
||||
|
||||
pub fn visible_layers_bounding_box(&self, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
pub fn visible_layers_bounding_box(&self, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
let mut paths = vec![];
|
||||
self.visible_layers(&mut vec![], &mut paths).ok()?;
|
||||
self.combined_viewport_bounding_box(paths.iter().map(|x| x.as_slice()), font_cache)
|
||||
self.combined_viewport_bounding_box(paths.iter().map(|x| x.as_slice()), render_data)
|
||||
}
|
||||
|
||||
pub fn combined_viewport_bounding_box<'a>(&self, paths: impl Iterator<Item = &'a [LayerId]>, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
let boxes = paths.filter_map(|path| self.viewport_bounding_box(path, font_cache).ok()?);
|
||||
pub fn combined_viewport_bounding_box<'a>(&self, paths: impl Iterator<Item = &'a [LayerId]>, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
let boxes = paths.filter_map(|path| self.viewport_bounding_box(path, render_data).ok()?);
|
||||
boxes.reduce(|a, b| [a[0].min(b[0]), a[1].max(b[1])])
|
||||
}
|
||||
|
||||
|
|
@ -552,7 +551,7 @@ impl Document {
|
|||
|
||||
/// Mutate the document by applying the `operation` to it. If the operation necessitates a
|
||||
/// reaction from the frontend, responses may be returned.
|
||||
pub fn handle_operation(&mut self, operation: Operation, font_cache: &FontCache) -> Result<Option<Vec<DocumentResponse>>, DocumentError> {
|
||||
pub fn handle_operation(&mut self, operation: Operation, render_data: &RenderData) -> Result<Option<Vec<DocumentResponse>>, DocumentError> {
|
||||
use DocumentResponse::*;
|
||||
|
||||
operation.pseudo_hash().hash(&mut self.state_identifier);
|
||||
|
|
@ -590,7 +589,7 @@ impl Document {
|
|||
font_style,
|
||||
} => {
|
||||
let font = Font::new(font_name, font_style);
|
||||
let layer_text = TextLayer::new(text, style, size, font, font_cache);
|
||||
let layer_text = TextLayer::new(text, style, size, font, render_data);
|
||||
let layer_data = LayerDataType::Text(layer_text);
|
||||
let layer = Layer::new(layer_data, transform);
|
||||
|
||||
|
|
@ -598,20 +597,6 @@ impl Document {
|
|||
|
||||
Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
|
||||
}
|
||||
Operation::AddImage {
|
||||
path,
|
||||
transform,
|
||||
insert_index,
|
||||
image_data,
|
||||
mime,
|
||||
} => {
|
||||
let image_data = std::sync::Arc::new(image_data);
|
||||
let layer = Layer::new(LayerDataType::Image(ImageLayer::new(mime, image_data)), transform);
|
||||
|
||||
self.set_layer(&path, layer, insert_index)?;
|
||||
|
||||
Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
|
||||
}
|
||||
Operation::AddNodeGraphFrame {
|
||||
path,
|
||||
insert_index,
|
||||
|
|
@ -658,7 +643,7 @@ impl Document {
|
|||
.layer_mut(id)
|
||||
.ok_or_else(|| DocumentError::LayerNotFound(path.clone()))?
|
||||
.as_text_mut()?
|
||||
.update_text(new_text, font_cache);
|
||||
.update_text(new_text, render_data);
|
||||
|
||||
self.mark_as_dirty(&path)?;
|
||||
|
||||
|
|
@ -808,7 +793,7 @@ impl Document {
|
|||
|
||||
text.font = Font::new(font_family, font_style);
|
||||
text.size = size;
|
||||
text.cached_path = Some(text.generate_path(text.load_face(font_cache)));
|
||||
text.cached_path = Some(text.generate_path(text.load_face(render_data)));
|
||||
self.mark_as_dirty(&path)?;
|
||||
Some([vec![DocumentChanged, LayerChanged { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
|
||||
}
|
||||
|
|
@ -836,18 +821,14 @@ impl Document {
|
|||
Some([vec![DocumentChanged], update_thumbnails_upstream(&path)].concat())
|
||||
}
|
||||
Operation::SetLayerBlobUrl { layer_path, blob_url, resolution } => {
|
||||
let layer = self.layer_mut(&layer_path).unwrap_or_else(|_| panic!("Blob url for invalid layer with path '{:?}'", layer_path));
|
||||
match &mut layer.data {
|
||||
LayerDataType::Image(image) => {
|
||||
image.blob_url = Some(blob_url);
|
||||
image.dimensions = resolution.into();
|
||||
}
|
||||
LayerDataType::NodeGraphFrame(node_graph_frame) => {
|
||||
node_graph_frame.blob_url = Some(blob_url);
|
||||
node_graph_frame.dimensions = resolution.into();
|
||||
}
|
||||
_ => panic!("Incorrectly trying to set the image blob URL for a layer that is not an Image, NodeGraphFrame or Imaginate layer type"),
|
||||
}
|
||||
let layer = self.layer_mut(&layer_path).unwrap_or_else(|_| panic!("Blob URL for invalid layer with path '{:?}'", layer_path));
|
||||
|
||||
let LayerDataType::NodeGraphFrame(node_graph_frame) = &mut layer.data else {
|
||||
panic!("Incorrectly trying to set the image blob URL for a layer that is not a NodeGraphFrame layer type");
|
||||
};
|
||||
|
||||
node_graph_frame.blob_url = Some(blob_url);
|
||||
node_graph_frame.dimensions = resolution.into();
|
||||
|
||||
self.mark_as_dirty(&layer_path)?;
|
||||
Some([vec![DocumentChanged, LayerChanged { path: layer_path.clone() }], update_thumbnails_upstream(&layer_path)].concat())
|
||||
|
|
@ -1099,7 +1080,7 @@ impl Document {
|
|||
// Delete the layer if there are no longer any manipulator groups
|
||||
if (shape.manipulator_groups().len() - 1) == 0 {
|
||||
// Delegate deletion to DeleteLayer to update Layer Tree in frontend
|
||||
match self.handle_operation(Operation::DeleteLayer { path: layer_path.clone() }, font_cache) {
|
||||
match self.handle_operation(Operation::DeleteLayer { path: layer_path.clone() }, render_data) {
|
||||
Ok(Some(delete_responses)) => {
|
||||
responses.extend(delete_responses);
|
||||
responses.push(DocumentResponse::DeletedSelectedManipulatorPoints);
|
||||
|
|
@ -1169,8 +1150,8 @@ fn update_thumbnails_upstream(path: &[LayerId]) -> Vec<DocumentResponse> {
|
|||
responses
|
||||
}
|
||||
|
||||
pub fn pick_layer_safe_imaginate_resolution(layer: &Layer, font_cache: &FontCache) -> (u64, u64) {
|
||||
let layer_bounds = layer.bounding_transform(font_cache);
|
||||
pub fn pick_layer_safe_imaginate_resolution(layer: &Layer, render_data: &RenderData) -> (u64, u64) {
|
||||
let layer_bounds = layer.bounding_transform(render_data);
|
||||
let layer_bounds_size = (layer_bounds.transform_vector2((1., 0.).into()).length(), layer_bounds.transform_vector2((0., 1.).into()).length());
|
||||
|
||||
pick_safe_imaginate_resolution(layer_bounds_size)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use super::layer_info::{Layer, LayerData, LayerDataType};
|
||||
use super::style::RenderData;
|
||||
use crate::intersection::Quad;
|
||||
use crate::layers::text_layer::FontCache;
|
||||
use crate::{DocumentError, LayerId};
|
||||
|
||||
use glam::DVec2;
|
||||
|
|
@ -21,7 +20,7 @@ pub struct FolderLayer {
|
|||
}
|
||||
|
||||
impl LayerData for FolderLayer {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<glam::DAffine2>, render_data: RenderData) -> bool {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<glam::DAffine2>, render_data: &RenderData) -> bool {
|
||||
let mut any_child_requires_redraw = false;
|
||||
for layer in &mut self.layers {
|
||||
let (svg_value, requires_redraw) = layer.render(transforms, svg_defs, render_data);
|
||||
|
|
@ -31,18 +30,18 @@ impl LayerData for FolderLayer {
|
|||
any_child_requires_redraw
|
||||
}
|
||||
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, font_cache: &FontCache) {
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, render_data: &RenderData) {
|
||||
for (layer, layer_id) in self.layers().iter().zip(&self.layer_ids) {
|
||||
path.push(*layer_id);
|
||||
layer.intersects_quad(quad, path, intersections, font_cache);
|
||||
layer.intersects_quad(quad, path, intersections, render_data);
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
|
||||
fn bounding_box(&self, transform: glam::DAffine2, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
fn bounding_box(&self, transform: glam::DAffine2, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
self.layers
|
||||
.iter()
|
||||
.filter_map(|layer| layer.data.bounding_box(transform * layer.transform, font_cache))
|
||||
.filter_map(|layer| layer.data.bounding_box(transform * layer.transform, render_data))
|
||||
.reduce(|a, b| [a[0].min(b[0]), a[1].max(b[1])])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
use super::base64_serde;
|
||||
use super::layer_info::LayerData;
|
||||
use super::style::{RenderData, ViewMode};
|
||||
use crate::intersection::{intersect_quad_bez_path, Quad};
|
||||
use crate::layers::text_layer::FontCache;
|
||||
use crate::LayerId;
|
||||
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use kurbo::{Affine, BezPath, Shape as KurboShape};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Write;
|
||||
|
||||
#[derive(Clone, PartialEq, Deserialize, Serialize, specta::Type)]
|
||||
pub struct ImageLayer {
|
||||
pub mime: String,
|
||||
#[serde(serialize_with = "base64_serde::as_base64", deserialize_with = "base64_serde::from_base64")]
|
||||
#[specta(type = String)]
|
||||
pub image_data: std::sync::Arc<Vec<u8>>,
|
||||
// TODO: Have the browser dispose of this blob URL when this is dropped (like when the layer is deleted)
|
||||
#[serde(skip)]
|
||||
pub blob_url: Option<String>,
|
||||
#[serde(skip)]
|
||||
pub dimensions: DVec2,
|
||||
}
|
||||
|
||||
impl LayerData for ImageLayer {
|
||||
fn render(&mut self, svg: &mut String, _svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: RenderData) -> bool {
|
||||
let transform = self.transform(transforms, render_data.view_mode);
|
||||
let inverse = transform.inverse();
|
||||
|
||||
if !inverse.is_finite() {
|
||||
let _ = write!(svg, "<!-- SVG shape has an invalid transform -->");
|
||||
return false;
|
||||
}
|
||||
|
||||
let _ = writeln!(svg, r#"<g transform="matrix("#);
|
||||
inverse.to_cols_array().iter().enumerate().for_each(|(i, entry)| {
|
||||
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
|
||||
});
|
||||
let _ = svg.write_str(r#")">"#);
|
||||
|
||||
let svg_transform = transform
|
||||
.to_cols_array()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, entry)| entry.to_string() + if i == 5 { "" } else { "," })
|
||||
.collect::<String>();
|
||||
let _ = write!(
|
||||
svg,
|
||||
r#"<image width="{}" height="{}" transform="matrix({})" href="{}"/>"#,
|
||||
self.dimensions.x,
|
||||
self.dimensions.y,
|
||||
svg_transform,
|
||||
self.blob_url.as_ref().unwrap_or(&String::new())
|
||||
);
|
||||
let _ = svg.write_str("</g>");
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn bounding_box(&self, transform: glam::DAffine2, _font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
let mut path = self.bounds();
|
||||
|
||||
if transform.matrix2 == DMat2::ZERO {
|
||||
return None;
|
||||
}
|
||||
path.apply_affine(glam_to_kurbo(transform));
|
||||
|
||||
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
|
||||
Some([(x0, y0).into(), (x1, y1).into()])
|
||||
}
|
||||
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, _font_cache: &FontCache) {
|
||||
if intersect_quad_bez_path(quad, &self.bounds(), true) {
|
||||
intersections.push(path.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageLayer {
|
||||
pub fn new(mime: String, image_data: std::sync::Arc<Vec<u8>>) -> Self {
|
||||
Self {
|
||||
mime,
|
||||
image_data,
|
||||
blob_url: None,
|
||||
dimensions: DVec2::ONE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform(&self, transforms: &[DAffine2], mode: ViewMode) -> DAffine2 {
|
||||
let start = match mode {
|
||||
ViewMode::Outline => 0,
|
||||
_ => (transforms.len() as i32 - 1).max(0) as usize,
|
||||
};
|
||||
transforms.iter().skip(start).cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY)
|
||||
}
|
||||
|
||||
fn bounds(&self) -> BezPath {
|
||||
kurbo::Rect::from_origin_size(kurbo::Point::ZERO, kurbo::Size::new(self.dimensions.x, self.dimensions.y)).to_path(0.)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ImageLayer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ImageLayer")
|
||||
.field("mime", &self.mime)
|
||||
.field("image_data", &"...")
|
||||
.field("blob_url", &self.blob_url)
|
||||
.field("dimensions", &self.dimensions)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
fn glam_to_kurbo(transform: DAffine2) -> Affine {
|
||||
Affine::new(transform.to_cols_array())
|
||||
}
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
use super::blend_mode::BlendMode;
|
||||
use super::folder_layer::FolderLayer;
|
||||
use super::image_layer::ImageLayer;
|
||||
use super::nodegraph_layer::NodeGraphFrameLayer;
|
||||
use super::shape_layer::ShapeLayer;
|
||||
use super::style::{PathStyle, RenderData};
|
||||
use super::text_layer::TextLayer;
|
||||
use crate::intersection::Quad;
|
||||
use crate::layers::text_layer::FontCache;
|
||||
use crate::DocumentError;
|
||||
use crate::LayerId;
|
||||
|
||||
|
|
@ -26,8 +24,6 @@ pub enum LayerDataType {
|
|||
Shape(ShapeLayer),
|
||||
/// A layer that wraps a [TextLayer] struct.
|
||||
Text(TextLayer),
|
||||
/// A layer that wraps an [ImageLayer] struct.
|
||||
Image(ImageLayer),
|
||||
/// A layer that wraps an [NodeGraphFrameLayer] struct.
|
||||
NodeGraphFrame(NodeGraphFrameLayer),
|
||||
}
|
||||
|
|
@ -38,7 +34,6 @@ impl LayerDataType {
|
|||
LayerDataType::Shape(s) => s,
|
||||
LayerDataType::Folder(f) => f,
|
||||
LayerDataType::Text(t) => t,
|
||||
LayerDataType::Image(i) => i,
|
||||
LayerDataType::NodeGraphFrame(n) => n,
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +43,6 @@ impl LayerDataType {
|
|||
LayerDataType::Shape(s) => s,
|
||||
LayerDataType::Folder(f) => f,
|
||||
LayerDataType::Text(t) => t,
|
||||
LayerDataType::Image(i) => i,
|
||||
LayerDataType::NodeGraphFrame(n) => n,
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +77,6 @@ impl From<&LayerDataType> for LayerDataTypeDiscriminant {
|
|||
Folder(_) => LayerDataTypeDiscriminant::Folder,
|
||||
Shape(_) => LayerDataTypeDiscriminant::Shape,
|
||||
Text(_) => LayerDataTypeDiscriminant::Text,
|
||||
Image(_) => LayerDataTypeDiscriminant::Image,
|
||||
NodeGraphFrame(_) => LayerDataTypeDiscriminant::NodeGraphFrame,
|
||||
}
|
||||
}
|
||||
|
|
@ -133,8 +126,8 @@ pub trait LayerData {
|
|||
///
|
||||
/// // Render the shape without any transforms, in normal view mode
|
||||
/// # let font_cache = Default::default();
|
||||
/// let render_data = RenderData::new(ViewMode::Normal, &font_cache, None);
|
||||
/// shape.render(&mut svg, &mut String::new(), &mut vec![], render_data);
|
||||
/// let render_data = RenderData::new(&font_cache, ViewMode::Normal, None);
|
||||
/// shape.render(&mut svg, &mut String::new(), &mut vec![], &render_data);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// svg,
|
||||
|
|
@ -143,13 +136,13 @@ pub trait LayerData {
|
|||
/// </g>"
|
||||
/// );
|
||||
/// ```
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<glam::DAffine2>, render_data: RenderData) -> bool;
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<glam::DAffine2>, render_data: &RenderData) -> bool;
|
||||
|
||||
/// Determine the layers within this layer that intersect a given quad.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use graphite_document_legacy::layers::shape_layer::ShapeLayer;
|
||||
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle, ViewMode};
|
||||
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle, ViewMode, RenderData};
|
||||
/// # use graphite_document_legacy::layers::layer_info::LayerData;
|
||||
/// # use graphite_document_legacy::intersection::Quad;
|
||||
/// # use glam::f64::{DAffine2, DVec2};
|
||||
|
|
@ -162,18 +155,20 @@ pub trait LayerData {
|
|||
/// let quad = Quad::from_box([DVec2::ZERO, DVec2::ONE]);
|
||||
/// let mut intersections = vec![];
|
||||
///
|
||||
/// shape.intersects_quad(quad, &mut vec![shape_id], &mut intersections, &Default::default());
|
||||
/// let font_cache = Default::default();
|
||||
/// let render_data = RenderData::new(&font_cache, Default::default(), None);
|
||||
/// shape.intersects_quad(quad, &mut vec![shape_id], &mut intersections, &render_data);
|
||||
///
|
||||
/// assert_eq!(intersections, vec![vec![shape_id]]);
|
||||
/// ```
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, font_cache: &FontCache);
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, render_data: &RenderData);
|
||||
|
||||
// TODO: this doctest fails because 0 != 1e-32, maybe assert difference < epsilon?
|
||||
/// Calculate the bounding box for the layer's contents after applying a given transform.
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use graphite_document_legacy::layers::shape_layer::ShapeLayer;
|
||||
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
|
||||
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle, RenderData};
|
||||
/// # use graphite_document_legacy::layers::layer_info::LayerData;
|
||||
/// # use glam::f64::{DAffine2, DVec2};
|
||||
/// # use std::collections::HashMap;
|
||||
|
|
@ -182,24 +177,26 @@ pub trait LayerData {
|
|||
/// // Calculate the bounding box without applying any transformations.
|
||||
/// // (The identity transform maps every vector to itself.)
|
||||
/// let transform = DAffine2::IDENTITY;
|
||||
/// let bounding_box = shape.bounding_box(transform, &Default::default());
|
||||
/// let font_cache = Default::default();
|
||||
/// let render_data = RenderData::new(&font_cache, Default::default(), None);
|
||||
/// let bounding_box = shape.bounding_box(transform, &render_data);
|
||||
///
|
||||
/// assert_eq!(bounding_box, Some([DVec2::ZERO, DVec2::ONE]));
|
||||
/// ```
|
||||
fn bounding_box(&self, transform: glam::DAffine2, font_cache: &FontCache) -> Option<[DVec2; 2]>;
|
||||
fn bounding_box(&self, transform: glam::DAffine2, render_data: &RenderData) -> Option<[DVec2; 2]>;
|
||||
}
|
||||
|
||||
impl LayerData for LayerDataType {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<glam::DAffine2>, render_data: RenderData) -> bool {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<glam::DAffine2>, render_data: &RenderData) -> bool {
|
||||
self.inner_mut().render(svg, svg_defs, transforms, render_data)
|
||||
}
|
||||
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, font_cache: &FontCache) {
|
||||
self.inner().intersects_quad(quad, path, intersections, font_cache)
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, render_data: &RenderData) {
|
||||
self.inner().intersects_quad(quad, path, intersections, render_data)
|
||||
}
|
||||
|
||||
fn bounding_box(&self, transform: glam::DAffine2, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
self.inner().bounding_box(transform, font_cache)
|
||||
fn bounding_box(&self, transform: glam::DAffine2, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
self.inner().bounding_box(transform, render_data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +302,7 @@ impl Layer {
|
|||
}
|
||||
|
||||
/// Renders the layer, returning the result and if a redraw is required
|
||||
pub fn render(&mut self, transforms: &mut Vec<DAffine2>, svg_defs: &mut String, render_data: RenderData) -> (&str, bool) {
|
||||
pub fn render(&mut self, transforms: &mut Vec<DAffine2>, svg_defs: &mut String, render_data: &RenderData) -> (&str, bool) {
|
||||
if !self.visible {
|
||||
return ("", false);
|
||||
}
|
||||
|
|
@ -314,10 +311,7 @@ impl Layer {
|
|||
|
||||
// Skip rendering if outside the viewport bounds
|
||||
if let Some(viewport_bounds) = render_data.culling_bounds {
|
||||
if let Some(bounding_box) = self
|
||||
.data
|
||||
.bounding_box(transforms.iter().cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY), render_data.font_cache)
|
||||
{
|
||||
if let Some(bounding_box) = self.data.bounding_box(transforms.iter().cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY), render_data) {
|
||||
let is_overlapping =
|
||||
viewport_bounds[0].x < bounding_box[1].x && bounding_box[0].x < viewport_bounds[1].x && viewport_bounds[0].y < bounding_box[1].y && bounding_box[0].y < viewport_bounds[1].y;
|
||||
if !is_overlapping {
|
||||
|
|
@ -363,13 +357,13 @@ impl Layer {
|
|||
(self.cache.as_str(), requires_redraw)
|
||||
}
|
||||
|
||||
pub fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, font_cache: &FontCache) {
|
||||
pub fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, render_data: &RenderData) {
|
||||
if !self.visible {
|
||||
return;
|
||||
}
|
||||
|
||||
let transformed_quad = self.transform.inverse() * quad;
|
||||
self.data.intersects_quad(transformed_quad, path, intersections, font_cache)
|
||||
self.data.intersects_quad(transformed_quad, path, intersections, render_data)
|
||||
}
|
||||
|
||||
/// Compute the bounding box of the layer after applying a transform to it.
|
||||
|
|
@ -378,7 +372,7 @@ impl Layer {
|
|||
/// ```
|
||||
/// # use graphite_document_legacy::layers::shape_layer::ShapeLayer;
|
||||
/// # use graphite_document_legacy::layers::layer_info::Layer;
|
||||
/// # use graphite_document_legacy::layers::style::PathStyle;
|
||||
/// # use graphite_document_legacy::layers::style::{PathStyle, RenderData};
|
||||
/// # use glam::DVec2;
|
||||
/// # use glam::f64::DAffine2;
|
||||
/// # use std::collections::HashMap;
|
||||
|
|
@ -386,27 +380,30 @@ impl Layer {
|
|||
/// let layer: Layer = ShapeLayer::rectangle(PathStyle::default()).into();
|
||||
///
|
||||
/// // Apply the Identity transform, which leaves the points unchanged
|
||||
/// let transform = DAffine2::IDENTITY;
|
||||
/// let font_cache = Default::default();
|
||||
/// let render_data = RenderData::new(&font_cache, Default::default(), None);
|
||||
/// assert_eq!(
|
||||
/// layer.aabb_for_transform(DAffine2::IDENTITY, &Default::default()),
|
||||
/// layer.aabb_for_transform(transform, &render_data),
|
||||
/// Some([DVec2::ZERO, DVec2::ONE]),
|
||||
/// );
|
||||
///
|
||||
/// // Apply a transform that scales every point by a factor of two
|
||||
/// let transform = DAffine2::from_scale(DVec2::ONE * 2.);
|
||||
/// assert_eq!(
|
||||
/// layer.aabb_for_transform(transform, &Default::default()),
|
||||
/// layer.aabb_for_transform(transform, &render_data),
|
||||
/// Some([DVec2::ZERO, DVec2::ONE * 2.]),
|
||||
/// );
|
||||
pub fn aabb_for_transform(&self, transform: DAffine2, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
self.data.bounding_box(transform, font_cache)
|
||||
pub fn aabb_for_transform(&self, transform: DAffine2, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
self.data.bounding_box(transform, render_data)
|
||||
}
|
||||
|
||||
pub fn aabb(&self, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
self.aabb_for_transform(self.transform, font_cache)
|
||||
pub fn aabb(&self, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
self.aabb_for_transform(self.transform, render_data)
|
||||
}
|
||||
|
||||
pub fn bounding_transform(&self, font_cache: &FontCache) -> DAffine2 {
|
||||
let scale = match self.aabb_for_transform(DAffine2::IDENTITY, font_cache) {
|
||||
pub fn bounding_transform(&self, render_data: &RenderData) -> DAffine2 {
|
||||
let scale = match self.aabb_for_transform(DAffine2::IDENTITY, render_data) {
|
||||
Some([a, b]) => {
|
||||
let dimensions = b - a;
|
||||
DAffine2::from_scale(dimensions)
|
||||
|
|
@ -417,8 +414,8 @@ impl Layer {
|
|||
self.transform * scale
|
||||
}
|
||||
|
||||
pub fn layerspace_pivot(&self, font_cache: &FontCache) -> DVec2 {
|
||||
let [mut min, max] = self.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
pub fn layerspace_pivot(&self, render_data: &RenderData) -> DVec2 {
|
||||
let [mut min, max] = self.aabb_for_transform(DAffine2::IDENTITY, render_data).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
|
||||
// If the layer bounds are 0 in either axis then set them to one (to avoid div 0)
|
||||
if (max.x - min.x) < f64::EPSILON * 1000. {
|
||||
|
|
@ -560,12 +557,6 @@ impl From<TextLayer> for Layer {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ImageLayer> for Layer {
|
||||
fn from(from: ImageLayer) -> Layer {
|
||||
Layer::new(LayerDataType::Image(from), DAffine2::IDENTITY.to_cols_array())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Layer {
|
||||
type Item = &'a Layer;
|
||||
type IntoIter = LayerIter<'a>;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
//! * [Folder layers](folder_layer::FolderLayer), which encapsulate sub-layers
|
||||
//! * [Shape layers](shape_layer::ShapeLayer), which contain generic SVG [`<path>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)s
|
||||
//! * [Text layers](text_layer::TextLayer), which contain a description of laid out text
|
||||
//! * [Image layers](image_layer::ImageLayer), which contain a bitmap image
|
||||
//! * [Nodegraph layers](nodegraph_layer::NodegraphLayer), which contain a node graph frame
|
||||
//! * [Node Graph layers](nodegraph_layer::NodegraphLayer), which contain a node graph frame
|
||||
//!
|
||||
//! Refer to the module-level documentation for detailed information on each layer.
|
||||
//!
|
||||
|
|
@ -20,8 +19,6 @@ pub mod base64_serde;
|
|||
pub mod blend_mode;
|
||||
/// Contains the [FolderLayer](folder_layer::FolderLayer) type that encapsulates other layers, including more folders.
|
||||
pub mod folder_layer;
|
||||
/// Contains the [ImageLayer](image_layer::ImageLayer) type that contains a bitmap image.
|
||||
pub mod image_layer;
|
||||
/// Contains the base [Layer](layer_info::Layer) type, an abstraction over the different types of layers.
|
||||
pub mod layer_info;
|
||||
/// Contains the [NodegraphLayer](nodegraph_layer::NodegraphLayer) type that contains a node graph.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use super::base64_serde;
|
|||
use super::layer_info::LayerData;
|
||||
use super::style::{RenderData, ViewMode};
|
||||
use crate::intersection::{intersect_quad_bez_path, Quad};
|
||||
use crate::layers::text_layer::FontCache;
|
||||
use crate::LayerId;
|
||||
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
|
|
@ -34,7 +33,7 @@ pub struct ImageData {
|
|||
}
|
||||
|
||||
impl LayerData for NodeGraphFrameLayer {
|
||||
fn render(&mut self, svg: &mut String, _svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: RenderData) -> bool {
|
||||
fn render(&mut self, svg: &mut String, _svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: &RenderData) -> bool {
|
||||
let transform = self.transform(transforms, render_data.view_mode);
|
||||
let inverse = transform.inverse();
|
||||
|
||||
|
|
@ -81,7 +80,7 @@ impl LayerData for NodeGraphFrameLayer {
|
|||
false
|
||||
}
|
||||
|
||||
fn bounding_box(&self, transform: glam::DAffine2, _font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
fn bounding_box(&self, transform: glam::DAffine2, _render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
let mut path = self.bounds();
|
||||
|
||||
if transform.matrix2 == DMat2::ZERO {
|
||||
|
|
@ -93,7 +92,7 @@ impl LayerData for NodeGraphFrameLayer {
|
|||
Some([(x0, y0).into(), (x1, y1).into()])
|
||||
}
|
||||
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, _font_cache: &FontCache) {
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, _render_data: &RenderData) {
|
||||
if intersect_quad_bez_path(quad, &self.bounds(), true) {
|
||||
intersections.push(path.clone());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use super::layer_info::LayerData;
|
||||
use super::style::{self, PathStyle, RenderData, ViewMode};
|
||||
use crate::intersection::{intersect_quad_bez_path, Quad};
|
||||
use crate::layers::text_layer::FontCache;
|
||||
use crate::LayerId;
|
||||
|
||||
use graphene_std::vector::subpath::Subpath;
|
||||
|
|
@ -27,7 +26,7 @@ pub struct ShapeLayer {
|
|||
}
|
||||
|
||||
impl LayerData for ShapeLayer {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: RenderData) -> bool {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: &RenderData) -> bool {
|
||||
let mut subpath = self.shape.clone();
|
||||
|
||||
let layer_bounds = subpath.bounding_box().unwrap_or_default();
|
||||
|
|
@ -58,7 +57,7 @@ impl LayerData for ShapeLayer {
|
|||
false
|
||||
}
|
||||
|
||||
fn bounding_box(&self, transform: glam::DAffine2, _font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
fn bounding_box(&self, transform: glam::DAffine2, _render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
let mut subpath = self.shape.clone();
|
||||
if transform.matrix2 == DMat2::ZERO {
|
||||
return None;
|
||||
|
|
@ -68,7 +67,7 @@ impl LayerData for ShapeLayer {
|
|||
subpath.bounding_box()
|
||||
}
|
||||
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, _font_cache: &FontCache) {
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, _render_data: &RenderData) {
|
||||
let filled = self.style.fill().is_some() || self.shape.manipulator_groups().last().filter(|manipulator_group| manipulator_group.is_close()).is_some();
|
||||
if intersect_quad_bez_path(quad, &(&self.shape).into(), filled) {
|
||||
intersections.push(path.clone());
|
||||
|
|
|
|||
|
|
@ -35,16 +35,16 @@ pub enum ViewMode {
|
|||
/// Contains metadata for rendering the document as an svg
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RenderData<'a> {
|
||||
pub view_mode: ViewMode,
|
||||
pub font_cache: &'a FontCache,
|
||||
pub view_mode: ViewMode,
|
||||
pub culling_bounds: Option<[DVec2; 2]>,
|
||||
}
|
||||
|
||||
impl<'a> RenderData<'a> {
|
||||
pub fn new(view_mode: ViewMode, font_cache: &'a FontCache, culling_bounds: Option<[DVec2; 2]>) -> Self {
|
||||
pub fn new(font_cache: &'a FontCache, view_mode: ViewMode, culling_bounds: Option<[DVec2; 2]>) -> Self {
|
||||
Self {
|
||||
view_mode,
|
||||
font_cache,
|
||||
view_mode,
|
||||
culling_bounds,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub struct TextLayer {
|
|||
}
|
||||
|
||||
impl LayerData for TextLayer {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: RenderData) -> bool {
|
||||
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: &RenderData) -> bool {
|
||||
let transform = self.transform(transforms, render_data.view_mode);
|
||||
let inverse = transform.inverse();
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ impl LayerData for TextLayer {
|
|||
font.map(|_| r#" style="font-family: local-font;""#).unwrap_or_default()
|
||||
);
|
||||
} else {
|
||||
let buzz_face = self.load_face(render_data.font_cache);
|
||||
let buzz_face = self.load_face(render_data);
|
||||
|
||||
let mut path = self.to_subpath(buzz_face);
|
||||
|
||||
|
|
@ -89,8 +89,8 @@ impl LayerData for TextLayer {
|
|||
false
|
||||
}
|
||||
|
||||
fn bounding_box(&self, transform: glam::DAffine2, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
let buzz_face = Some(self.load_face(font_cache)?);
|
||||
fn bounding_box(&self, transform: glam::DAffine2, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
let buzz_face = Some(self.load_face(render_data)?);
|
||||
|
||||
if transform.matrix2 == DMat2::ZERO {
|
||||
return None;
|
||||
|
|
@ -99,8 +99,8 @@ impl LayerData for TextLayer {
|
|||
Some((transform * self.bounding_box(&self.text, buzz_face)).bounding_box())
|
||||
}
|
||||
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, font_cache: &FontCache) {
|
||||
let buzz_face = self.load_face(font_cache);
|
||||
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, render_data: &RenderData) {
|
||||
let buzz_face = self.load_face(render_data);
|
||||
|
||||
if intersect_quad_bez_path(quad, &self.bounding_box(&self.text, buzz_face).path(), true) {
|
||||
intersections.push(path.clone());
|
||||
|
|
@ -109,8 +109,8 @@ impl LayerData for TextLayer {
|
|||
}
|
||||
|
||||
impl TextLayer {
|
||||
pub fn load_face<'a>(&self, font_cache: &'a FontCache) -> Option<Face<'a>> {
|
||||
font_cache.get(&self.font).map(|data| rustybuzz::Face::from_slice(data, 0).expect("Loading font failed"))
|
||||
pub fn load_face<'a>(&self, render_data: &'a RenderData) -> Option<Face<'a>> {
|
||||
render_data.font_cache.get(&self.font).map(|data| rustybuzz::Face::from_slice(data, 0).expect("Loading font failed"))
|
||||
}
|
||||
|
||||
pub fn transform(&self, transforms: &[DAffine2], mode: ViewMode) -> DAffine2 {
|
||||
|
|
@ -121,7 +121,7 @@ impl TextLayer {
|
|||
transforms.iter().skip(start).cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY)
|
||||
}
|
||||
|
||||
pub fn new(text: String, style: PathStyle, size: f64, font: Font, font_cache: &FontCache) -> Self {
|
||||
pub fn new(text: String, style: PathStyle, size: f64, font: Font, render_data: &RenderData) -> Self {
|
||||
let mut new = Self {
|
||||
text,
|
||||
path_style: style,
|
||||
|
|
@ -132,7 +132,7 @@ impl TextLayer {
|
|||
cached_path: None,
|
||||
};
|
||||
|
||||
new.cached_path = Some(new.generate_path(new.load_face(font_cache)));
|
||||
new.cached_path = Some(new.generate_path(new.load_face(render_data)));
|
||||
|
||||
new
|
||||
}
|
||||
|
|
@ -150,8 +150,8 @@ impl TextLayer {
|
|||
|
||||
/// Converts to a [Subpath], without populating the cache.
|
||||
#[inline]
|
||||
pub fn to_subpath_nonmut(&self, font_cache: &FontCache) -> Subpath {
|
||||
let buzz_face = self.load_face(font_cache);
|
||||
pub fn to_subpath_nonmut(&self, render_data: &RenderData) -> Subpath {
|
||||
let buzz_face = self.load_face(render_data);
|
||||
|
||||
self.cached_path
|
||||
.clone()
|
||||
|
|
@ -170,8 +170,8 @@ impl TextLayer {
|
|||
Quad::from_box([DVec2::ZERO, far])
|
||||
}
|
||||
|
||||
pub fn update_text(&mut self, text: String, font_cache: &FontCache) {
|
||||
let buzz_face = self.load_face(font_cache);
|
||||
pub fn update_text(&mut self, text: String, render_data: &RenderData) {
|
||||
let buzz_face = self.load_face(render_data);
|
||||
|
||||
self.text = text;
|
||||
self.cached_path = Some(self.generate_path(buzz_face));
|
||||
|
|
|
|||
|
|
@ -45,13 +45,6 @@ pub enum Operation {
|
|||
font_name: String,
|
||||
font_style: String,
|
||||
},
|
||||
AddImage {
|
||||
path: Vec<LayerId>,
|
||||
insert_index: isize,
|
||||
transform: [f64; 6],
|
||||
mime: String,
|
||||
image_data: Vec<u8>,
|
||||
},
|
||||
AddNodeGraphFrame {
|
||||
path: Vec<LayerId>,
|
||||
insert_index: isize,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::application::generate_uuid;
|
||||
use crate::messages::portfolio::utility_types::PersistentData;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::color::Color;
|
||||
use document_legacy::document::Document as DocumentLegacy;
|
||||
use document_legacy::layers::style::{self, Fill, RenderData, ViewMode};
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::DocumentResponse;
|
||||
use document_legacy::LayerId;
|
||||
use document_legacy::Operation as DocumentOperation;
|
||||
|
|
@ -18,30 +18,34 @@ pub struct ArtboardMessageHandler {
|
|||
pub artboard_ids: Vec<LayerId>,
|
||||
}
|
||||
|
||||
impl MessageHandler<ArtboardMessage, &FontCache> for ArtboardMessageHandler {
|
||||
impl MessageHandler<ArtboardMessage, &PersistentData> for ArtboardMessageHandler {
|
||||
#[remain::check]
|
||||
fn process_message(&mut self, message: ArtboardMessage, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
fn process_message(&mut self, message: ArtboardMessage, responses: &mut VecDeque<Message>, persistent_data: &PersistentData) {
|
||||
use ArtboardMessage::*;
|
||||
|
||||
#[remain::sorted]
|
||||
match message {
|
||||
// Sub-messages
|
||||
#[remain::unsorted]
|
||||
DispatchOperation(operation) => match self.artboards_document.handle_operation(*operation, font_cache) {
|
||||
Ok(Some(document_responses)) => {
|
||||
for response in document_responses {
|
||||
match &response {
|
||||
DocumentResponse::LayerChanged { path } => responses.push_back(PropertiesPanelMessage::CheckSelectedWasUpdated { path: path.clone() }.into()),
|
||||
DocumentResponse::DeletedLayer { path } => responses.push_back(PropertiesPanelMessage::CheckSelectedWasDeleted { path: path.clone() }.into()),
|
||||
DocumentResponse::DocumentChanged => responses.push_back(ArtboardMessage::RenderArtboards.into()),
|
||||
_ => {}
|
||||
};
|
||||
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
|
||||
DispatchOperation(operation) => {
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None);
|
||||
|
||||
match self.artboards_document.handle_operation(*operation, &render_data) {
|
||||
Ok(Some(document_responses)) => {
|
||||
for response in document_responses {
|
||||
match &response {
|
||||
DocumentResponse::LayerChanged { path } => responses.push_back(PropertiesPanelMessage::CheckSelectedWasUpdated { path: path.clone() }.into()),
|
||||
DocumentResponse::DeletedLayer { path } => responses.push_back(PropertiesPanelMessage::CheckSelectedWasDeleted { path: path.clone() }.into()),
|
||||
DocumentResponse::DocumentChanged => responses.push_back(ArtboardMessage::RenderArtboards.into()),
|
||||
_ => {}
|
||||
};
|
||||
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
|
||||
}
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(e) => error!("Artboard Error: {:?}", e),
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(e) => error!("Artboard Error: {:?}", e),
|
||||
},
|
||||
}
|
||||
|
||||
// Messages
|
||||
AddArtboard { id, position, size } => {
|
||||
|
|
@ -85,10 +89,10 @@ impl MessageHandler<ArtboardMessage, &FontCache> for ArtboardMessageHandler {
|
|||
.into(),
|
||||
)
|
||||
} else {
|
||||
let render_data = RenderData::new(ViewMode::Normal, font_cache, None);
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None);
|
||||
responses.push_back(
|
||||
FrontendMessage::UpdateDocumentArtboards {
|
||||
svg: self.artboards_document.render_root(render_data),
|
||||
svg: self.artboards_document.render_root(&render_data),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use document_legacy::layers::blend_mode::BlendMode;
|
|||
use document_legacy::layers::folder_layer::FolderLayer;
|
||||
use document_legacy::layers::layer_info::{LayerDataType, LayerDataTypeDiscriminant};
|
||||
use document_legacy::layers::style::{Fill, RenderData, ViewMode};
|
||||
use document_legacy::layers::text_layer::{Font, FontCache};
|
||||
use document_legacy::layers::text_layer::Font;
|
||||
use document_legacy::{DocumentError, DocumentResponse, LayerId, Operation as DocumentOperation};
|
||||
use graph_craft::document::NodeId;
|
||||
use graphene_std::vector::subpath::Subpath;
|
||||
|
|
@ -114,70 +114,74 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
) {
|
||||
use DocumentMessage::*;
|
||||
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, self.view_mode, Some(ipp.document_bounds()));
|
||||
|
||||
#[remain::sorted]
|
||||
match message {
|
||||
// Sub-messages
|
||||
#[remain::unsorted]
|
||||
DispatchOperation(op) => match self.document_legacy.handle_operation(*op, &persistent_data.font_cache) {
|
||||
Ok(Some(document_responses)) => {
|
||||
for response in document_responses {
|
||||
match &response {
|
||||
DocumentResponse::FolderChanged { path } => responses.push_back(FolderChanged { affected_folder_path: path.clone() }.into()),
|
||||
DocumentResponse::DeletedLayer { path } => {
|
||||
self.layer_metadata.remove(path);
|
||||
}
|
||||
DocumentResponse::LayerChanged { path } => responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into()),
|
||||
DocumentResponse::CreatedLayer { path } => {
|
||||
if self.layer_metadata.contains_key(path) {
|
||||
warn!("CreatedLayer overrides existing layer metadata.");
|
||||
DispatchOperation(op) => {
|
||||
match self.document_legacy.handle_operation(*op, &render_data) {
|
||||
Ok(Some(document_responses)) => {
|
||||
for response in document_responses {
|
||||
match &response {
|
||||
DocumentResponse::FolderChanged { path } => responses.push_back(FolderChanged { affected_folder_path: path.clone() }.into()),
|
||||
DocumentResponse::DeletedLayer { path } => {
|
||||
self.layer_metadata.remove(path);
|
||||
}
|
||||
self.layer_metadata.insert(path.clone(), LayerMetadata::new(false));
|
||||
DocumentResponse::LayerChanged { path } => responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into()),
|
||||
DocumentResponse::CreatedLayer { path } => {
|
||||
if self.layer_metadata.contains_key(path) {
|
||||
warn!("CreatedLayer overrides existing layer metadata.");
|
||||
}
|
||||
self.layer_metadata.insert(path.clone(), LayerMetadata::new(false));
|
||||
|
||||
responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into());
|
||||
self.layer_range_selection_reference = path.clone();
|
||||
responses.push_back(
|
||||
AddSelectedLayers {
|
||||
additional_layers: vec![path.clone()],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
DocumentResponse::DocumentChanged => responses.push_back(RenderDocument.into()),
|
||||
DocumentResponse::DeletedSelectedManipulatorPoints => {
|
||||
// Clear Properties panel after deleting all points by updating backend widget state.
|
||||
responses.push_back(
|
||||
LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
|
||||
layout_target: LayoutTarget::PropertiesOptions,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
responses.push_back(
|
||||
LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
|
||||
layout_target: LayoutTarget::PropertiesSections,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
|
||||
responses.push_back(LayerChanged { affected_layer_path: path.clone() }.into());
|
||||
self.layer_range_selection_reference = path.clone();
|
||||
responses.push_back(
|
||||
AddSelectedLayers {
|
||||
additional_layers: vec![path.clone()],
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
DocumentResponse::DocumentChanged => responses.push_back(RenderDocument.into()),
|
||||
DocumentResponse::DeletedSelectedManipulatorPoints => {
|
||||
// Clear Properties panel after deleting all points by updating backend widget state.
|
||||
responses.push_back(
|
||||
LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
|
||||
layout_target: LayoutTarget::PropertiesOptions,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
responses.push_back(
|
||||
LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
|
||||
layout_target: LayoutTarget::PropertiesSections,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
|
||||
}
|
||||
}
|
||||
// Display boolean operation error to the user (except if it is a nothing done error).
|
||||
Err(DocumentError::BooleanOperationError(boolean_operation_error)) if boolean_operation_error != BooleanOperationError::NothingDone => responses.push_back(
|
||||
DialogMessage::DisplayDialogError {
|
||||
title: "Failed to calculate boolean operation".into(),
|
||||
description: format!("Unfortunately, this feature not that robust yet.\n\nError: {boolean_operation_error:?}"),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Err(e) => error!("DocumentError: {:?}", e),
|
||||
Ok(_) => (),
|
||||
}
|
||||
// Display boolean operation error to the user (except if it is a nothing done error).
|
||||
Err(DocumentError::BooleanOperationError(boolean_operation_error)) if boolean_operation_error != BooleanOperationError::NothingDone => responses.push_back(
|
||||
DialogMessage::DisplayDialogError {
|
||||
title: "Failed to calculate boolean operation".into(),
|
||||
description: format!("Unfortunately, this feature not that robust yet.\n\nError: {boolean_operation_error:?}"),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Err(e) => error!("DocumentError: {:?}", e),
|
||||
Ok(_) => (),
|
||||
},
|
||||
}
|
||||
#[remain::unsorted]
|
||||
Artboard(message) => {
|
||||
self.artboard_message_handler.process_message(message, responses, &persistent_data.font_cache);
|
||||
self.artboard_message_handler.process_message(message, responses, persistent_data);
|
||||
}
|
||||
#[remain::unsorted]
|
||||
Navigation(message) => {
|
||||
|
|
@ -185,13 +189,12 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
}
|
||||
#[remain::unsorted]
|
||||
Overlays(message) => {
|
||||
self.overlays_message_handler
|
||||
.process_message(message, responses, (self.overlays_visible, &persistent_data.font_cache, ipp));
|
||||
self.overlays_message_handler.process_message(message, responses, (self.overlays_visible, persistent_data, ipp));
|
||||
}
|
||||
#[remain::unsorted]
|
||||
TransformLayer(message) => {
|
||||
self.transform_layer_handler
|
||||
.process_message(message, responses, (&mut self.layer_metadata, &mut self.document_legacy, ipp, &persistent_data.font_cache));
|
||||
.process_message(message, responses, (&mut self.layer_metadata, &mut self.document_legacy, ipp, &render_data));
|
||||
}
|
||||
#[remain::unsorted]
|
||||
PropertiesPanel(message) => {
|
||||
|
|
@ -219,20 +222,20 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
}
|
||||
AddSelectedLayers { additional_layers } => {
|
||||
for layer_path in &additional_layers {
|
||||
responses.extend(self.select_layer(layer_path, &persistent_data.font_cache));
|
||||
responses.extend(self.select_layer(layer_path, &render_data));
|
||||
}
|
||||
|
||||
// TODO: Correctly update layer panel in clear_selection instead of here
|
||||
responses.push_back(FolderChanged { affected_folder_path: vec![] }.into());
|
||||
responses.push_back(BroadcastEvent::SelectionChanged.into());
|
||||
|
||||
self.update_layer_tree_options_bar_widgets(responses, &persistent_data.font_cache);
|
||||
self.update_layer_tree_options_bar_widgets(responses, &render_data);
|
||||
}
|
||||
AlignSelectedLayers { axis, aggregate } => {
|
||||
self.backup(responses);
|
||||
let (paths, boxes): (Vec<_>, Vec<_>) = self
|
||||
.selected_layers()
|
||||
.filter_map(|path| self.document_legacy.viewport_bounding_box(path, &persistent_data.font_cache).ok()?.map(|b| (path, b)))
|
||||
.filter_map(|path| self.document_legacy.viewport_bounding_box(path, &render_data).ok()?.map(|b| (path, b)))
|
||||
.unzip();
|
||||
|
||||
let axis = match axis {
|
||||
|
|
@ -240,7 +243,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
AlignAxis::Y => DVec2::Y,
|
||||
};
|
||||
let lerp = |bbox: &[DVec2; 2]| bbox[0].lerp(bbox[1], 0.5);
|
||||
if let Some(combined_box) = self.document_legacy.combined_viewport_bounding_box(self.selected_layers(), &persistent_data.font_cache) {
|
||||
if let Some(combined_box) = self.document_legacy.combined_viewport_bounding_box(self.selected_layers(), &render_data) {
|
||||
let aggregated = match aggregate {
|
||||
AlignAggregate::Min => combined_box[0],
|
||||
AlignAggregate::Max => combined_box[1],
|
||||
|
|
@ -376,14 +379,9 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
|
||||
// Calculate the bounding box of the region to be exported
|
||||
let bounds = match bounds {
|
||||
ExportBounds::AllArtwork => self.all_layer_bounds(&persistent_data.font_cache),
|
||||
ExportBounds::Selection => self.selected_visible_layers_bounding_box(&persistent_data.font_cache),
|
||||
ExportBounds::Artboard(id) => self
|
||||
.artboard_message_handler
|
||||
.artboards_document
|
||||
.layer(&[id])
|
||||
.ok()
|
||||
.and_then(|layer| layer.aabb(&persistent_data.font_cache)),
|
||||
ExportBounds::AllArtwork => self.all_layer_bounds(&render_data),
|
||||
ExportBounds::Selection => self.selected_visible_layers_bounding_box(&render_data),
|
||||
ExportBounds::Artboard(id) => self.artboard_message_handler.artboards_document.layer(&[id]).ok().and_then(|layer| layer.aabb(&render_data)),
|
||||
}
|
||||
.unwrap_or_default();
|
||||
let size = bounds[1] - bounds[0];
|
||||
|
|
@ -412,7 +410,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
FlipAxis::X => DVec2::new(-1., 1.),
|
||||
FlipAxis::Y => DVec2::new(1., -1.),
|
||||
};
|
||||
if let Some([min, max]) = self.document_legacy.combined_viewport_bounding_box(self.selected_layers(), &persistent_data.font_cache) {
|
||||
if let Some([min, max]) = self.document_legacy.combined_viewport_bounding_box(self.selected_layers(), &render_data) {
|
||||
let center = (max + min) / 2.;
|
||||
let bbox_trans = DAffine2::from_translation(-center);
|
||||
for path in self.selected_layers() {
|
||||
|
|
@ -483,11 +481,11 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
);
|
||||
}
|
||||
LayerChanged { affected_layer_path } => {
|
||||
if let Ok(layer_entry) = self.layer_panel_entry(affected_layer_path.clone(), &persistent_data.font_cache) {
|
||||
if let Ok(layer_entry) = self.layer_panel_entry(affected_layer_path.clone(), &render_data) {
|
||||
responses.push_back(FrontendMessage::UpdateDocumentLayerDetails { data: layer_entry }.into());
|
||||
}
|
||||
responses.push_back(PropertiesPanelMessage::CheckSelectedWasUpdated { path: affected_layer_path }.into());
|
||||
self.update_layer_tree_options_bar_widgets(responses, &persistent_data.font_cache);
|
||||
self.update_layer_tree_options_bar_widgets(responses, &render_data);
|
||||
}
|
||||
MoveSelectedLayersTo {
|
||||
folder_path,
|
||||
|
|
@ -632,10 +630,9 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
}
|
||||
RenameLayer { layer_path, new_name } => responses.push_back(DocumentOperation::RenameLayer { layer_path, new_name }.into()),
|
||||
RenderDocument => {
|
||||
let render_data = RenderData::new(self.view_mode, &persistent_data.font_cache, Some(ipp.document_bounds()));
|
||||
responses.push_back(
|
||||
FrontendMessage::UpdateDocumentArtwork {
|
||||
svg: self.document_legacy.render_root(render_data),
|
||||
svg: self.document_legacy.render_root(&render_data),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
|
@ -645,7 +642,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
let scale = 0.5 + ASYMPTOTIC_EFFECT + document_transform_scale * SCALE_EFFECT;
|
||||
let viewport_size = ipp.viewport_bounds.size();
|
||||
let viewport_mid = ipp.viewport_bounds.center();
|
||||
let [bounds1, bounds2] = self.document_bounds(&persistent_data.font_cache).unwrap_or([viewport_mid; 2]);
|
||||
let [bounds1, bounds2] = self.document_bounds(&render_data).unwrap_or([viewport_mid; 2]);
|
||||
let bounds1 = bounds1.min(viewport_mid) - viewport_size * scale;
|
||||
let bounds2 = bounds2.max(viewport_mid) + viewport_size * scale;
|
||||
let bounds_length = (bounds2 - bounds1) * (1. + SCROLLBAR_SPACING);
|
||||
|
|
@ -782,7 +779,6 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
responses.push_back(FrontendMessage::TriggerRevokeBlobUrl { url: url.clone() }.into());
|
||||
}
|
||||
}
|
||||
LayerDataType::Image(_) => {}
|
||||
other => panic!(
|
||||
"Setting blob URL for invalid layer type, which must be an `Imaginate`, `NodeGraphFrame` or `Image`. Found: `{:?}`",
|
||||
other
|
||||
|
|
@ -803,7 +799,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
responses.push_back(LayerChanged { affected_layer_path: layer_path }.into())
|
||||
}
|
||||
SetLayerName { layer_path, name } => {
|
||||
if let Some(layer) = self.layer_panel_entry_from_path(&layer_path, &persistent_data.font_cache) {
|
||||
if let Some(layer) = self.layer_panel_entry_from_path(&layer_path, &render_data) {
|
||||
// Only save the history state if the name actually changed to something different
|
||||
if layer.name != name {
|
||||
self.backup(responses);
|
||||
|
|
@ -926,7 +922,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|||
responses.push_front(NavigationMessage::SetCanvasZoom { zoom_factor: 2. }.into());
|
||||
}
|
||||
ZoomCanvasToFitAll => {
|
||||
if let Some(bounds) = self.document_bounds(&persistent_data.font_cache) {
|
||||
if let Some(bounds) = self.document_bounds(&render_data) {
|
||||
responses.push_back(
|
||||
NavigationMessage::FitViewportToBounds {
|
||||
bounds,
|
||||
|
|
@ -1057,14 +1053,14 @@ impl DocumentMessageHandler {
|
|||
pub fn render_document(&mut self, size: DVec2, transform: DAffine2, persistent_data: &PersistentData, render_mode: DocumentRenderMode) -> String {
|
||||
// Render the document SVG code
|
||||
|
||||
let render_data = RenderData::new(ViewMode::Normal, &persistent_data.font_cache, None);
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None);
|
||||
|
||||
let (artwork, outside) = match render_mode {
|
||||
DocumentRenderMode::Root => (self.document_legacy.render_root(render_data), None),
|
||||
DocumentRenderMode::OnlyBelowLayerInFolder(below_layer_path) => (self.document_legacy.render_layers_below(below_layer_path, render_data).unwrap(), None),
|
||||
DocumentRenderMode::LayerCutout(layer_path, background) => (self.document_legacy.render_layer(layer_path, render_data).unwrap(), Some(background)),
|
||||
DocumentRenderMode::Root => (self.document_legacy.render_root(&render_data), None),
|
||||
DocumentRenderMode::OnlyBelowLayerInFolder(below_layer_path) => (self.document_legacy.render_layers_below(below_layer_path, &render_data).unwrap(), None),
|
||||
DocumentRenderMode::LayerCutout(layer_path, background) => (self.document_legacy.render_layer(layer_path, &render_data).unwrap(), Some(background)),
|
||||
};
|
||||
let artboards = self.artboard_message_handler.artboards_document.render_root(render_data);
|
||||
let artboards = self.artboard_message_handler.artboards_document.render_root(&render_data);
|
||||
let outside_artboards_color = outside.map_or_else(
|
||||
|| if self.artboard_message_handler.artboard_ids.is_empty() { "ffffff" } else { "222222" }.to_string(),
|
||||
|col| col.rgba_hex(),
|
||||
|
|
@ -1129,12 +1125,14 @@ impl DocumentMessageHandler {
|
|||
&& self.name.starts_with(DEFAULT_DOCUMENT_NAME)
|
||||
}
|
||||
|
||||
fn select_layer(&mut self, path: &[LayerId], font_cache: &FontCache) -> Option<Message> {
|
||||
fn select_layer(&mut self, path: &[LayerId], render_data: &RenderData) -> Option<Message> {
|
||||
println!("Select_layer fail: {:?}", self.all_layers_sorted());
|
||||
|
||||
if let Some(layer) = self.layer_metadata.get_mut(path) {
|
||||
let render_data = RenderData::new(render_data.font_cache, self.view_mode, None);
|
||||
|
||||
layer.selected = true;
|
||||
let data = self.layer_panel_entry(path.to_vec(), font_cache).ok()?;
|
||||
let data = self.layer_panel_entry(path.to_vec(), &render_data).ok()?;
|
||||
(!path.is_empty()).then(|| FrontendMessage::UpdateDocumentLayerDetails { data }.into())
|
||||
} else {
|
||||
warn!("Tried to select non existing layer {:?}", path);
|
||||
|
|
@ -1142,13 +1140,13 @@ impl DocumentMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn selected_visible_layers_bounding_box(&self, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
pub fn selected_visible_layers_bounding_box(&self, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
let paths = self.selected_visible_layers();
|
||||
self.document_legacy.combined_viewport_bounding_box(paths, font_cache)
|
||||
self.document_legacy.combined_viewport_bounding_box(paths, render_data)
|
||||
}
|
||||
|
||||
pub fn artboard_bounding_box_and_transform(&self, path: &[LayerId], font_cache: &FontCache) -> Option<([DVec2; 2], DAffine2)> {
|
||||
self.artboard_message_handler.artboards_document.bounding_box_and_transform(path, font_cache).unwrap_or(None)
|
||||
pub fn artboard_bounding_box_and_transform(&self, path: &[LayerId], render_data: &RenderData) -> Option<([DVec2; 2], DAffine2)> {
|
||||
self.artboard_message_handler.artboards_document.bounding_box_and_transform(path, render_data).unwrap_or(None)
|
||||
}
|
||||
|
||||
pub fn selected_layers(&self) -> impl Iterator<Item = &[LayerId]> {
|
||||
|
|
@ -1220,16 +1218,16 @@ impl DocumentMessageHandler {
|
|||
}
|
||||
|
||||
/// Returns the bounding boxes for all visible layers and artboards, optionally excluding any paths.
|
||||
pub fn bounding_boxes<'a>(&'a self, ignore_document: Option<&'a Vec<Vec<LayerId>>>, ignore_artboard: Option<LayerId>, font_cache: &'a FontCache) -> impl Iterator<Item = [DVec2; 2]> + 'a {
|
||||
pub fn bounding_boxes<'a>(&'a self, ignore_document: Option<&'a Vec<Vec<LayerId>>>, ignore_artboard: Option<LayerId>, render_data: &'a RenderData) -> impl Iterator<Item = [DVec2; 2]> + 'a {
|
||||
self.visible_layers()
|
||||
.filter(move |path| ignore_document.map_or(true, |ignore_document| !ignore_document.iter().any(|ig| ig.as_slice() == *path)))
|
||||
.filter_map(|path| self.document_legacy.viewport_bounding_box(path, font_cache).ok()?)
|
||||
.filter_map(|path| self.document_legacy.viewport_bounding_box(path, render_data).ok()?)
|
||||
.chain(
|
||||
self.artboard_message_handler
|
||||
.artboard_ids
|
||||
.iter()
|
||||
.filter(move |&&id| Some(id) != ignore_artboard)
|
||||
.filter_map(|&path| self.artboard_message_handler.artboards_document.viewport_bounding_box(&[path], font_cache).ok()?),
|
||||
.filter_map(|&path| self.artboard_message_handler.artboards_document.viewport_bounding_box(&[path], render_data).ok()?),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1505,31 +1503,31 @@ impl DocumentMessageHandler {
|
|||
}
|
||||
|
||||
// TODO: This should probably take a slice not a vec, also why does this even exist when `layer_panel_entry_from_path` also exists?
|
||||
pub fn layer_panel_entry(&mut self, path: Vec<LayerId>, font_cache: &FontCache) -> Result<LayerPanelEntry, EditorError> {
|
||||
pub fn layer_panel_entry(&mut self, path: Vec<LayerId>, render_data: &RenderData) -> Result<LayerPanelEntry, EditorError> {
|
||||
let data: LayerMetadata = *self
|
||||
.layer_metadata
|
||||
.get_mut(&path)
|
||||
.ok_or_else(|| EditorError::Document(format!("Could not get layer metadata for {:?}", path)))?;
|
||||
let layer = self.document_legacy.layer(&path)?;
|
||||
let entry = LayerPanelEntry::new(&data, self.document_legacy.multiply_transforms(&path)?, layer, path, font_cache);
|
||||
let entry = LayerPanelEntry::new(&data, self.document_legacy.multiply_transforms(&path)?, layer, path, render_data);
|
||||
Ok(entry)
|
||||
}
|
||||
|
||||
/// Returns a list of `LayerPanelEntry`s intended for display purposes. These don't contain
|
||||
/// any actual data, but rather attributes such as visibility and names of the layers.
|
||||
pub fn layer_panel(&mut self, path: &[LayerId], font_cache: &FontCache) -> Result<Vec<LayerPanelEntry>, EditorError> {
|
||||
pub fn layer_panel(&mut self, path: &[LayerId], render_data: &RenderData) -> Result<Vec<LayerPanelEntry>, EditorError> {
|
||||
let folder = self.document_legacy.folder(path)?;
|
||||
let paths: Vec<Vec<LayerId>> = folder.layer_ids.iter().map(|id| [path, &[*id]].concat()).collect();
|
||||
let entries = paths.iter().rev().filter_map(|path| self.layer_panel_entry_from_path(path, font_cache)).collect();
|
||||
let entries = paths.iter().rev().filter_map(|path| self.layer_panel_entry_from_path(path, render_data)).collect();
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
pub fn layer_panel_entry_from_path(&self, path: &[LayerId], font_cache: &FontCache) -> Option<LayerPanelEntry> {
|
||||
pub fn layer_panel_entry_from_path(&self, path: &[LayerId], render_data: &RenderData) -> Option<LayerPanelEntry> {
|
||||
let layer_metadata = self.layer_metadata(path);
|
||||
let transform = self.document_legacy.generate_transform_across_scope(path, Some(self.document_legacy.root.transform.inverse())).ok()?;
|
||||
let layer = self.document_legacy.layer(path).ok()?;
|
||||
|
||||
Some(LayerPanelEntry::new(layer_metadata, transform, layer, path.to_vec(), font_cache))
|
||||
Some(LayerPanelEntry::new(layer_metadata, transform, layer, path.to_vec(), render_data))
|
||||
}
|
||||
|
||||
/// When working with an insert index, deleting the layers may cause the insert index to point to a different location (if the layer being deleted was located before the insert index).
|
||||
|
|
@ -1544,16 +1542,16 @@ impl DocumentMessageHandler {
|
|||
}
|
||||
|
||||
/// Calculates the bounding box of all layers in the document
|
||||
pub fn all_layer_bounds(&self, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
self.document_legacy.viewport_bounding_box(&[], font_cache).ok().flatten()
|
||||
pub fn all_layer_bounds(&self, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
self.document_legacy.viewport_bounding_box(&[], render_data).ok().flatten()
|
||||
}
|
||||
|
||||
/// Calculates the document bounds used for scrolling and centring (the layer bounds or the artboard (if applicable))
|
||||
pub fn document_bounds(&self, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
||||
pub fn document_bounds(&self, render_data: &RenderData) -> Option<[DVec2; 2]> {
|
||||
if self.artboard_message_handler.is_infinite_canvas() {
|
||||
self.all_layer_bounds(font_cache)
|
||||
self.all_layer_bounds(render_data)
|
||||
} else {
|
||||
self.artboard_message_handler.artboards_document.viewport_bounding_box(&[], font_cache).ok().flatten()
|
||||
self.artboard_message_handler.artboards_document.viewport_bounding_box(&[], render_data).ok().flatten()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1581,11 +1579,6 @@ impl DocumentMessageHandler {
|
|||
LayerDataType::Text(text) => {
|
||||
fonts.insert(text.font.clone());
|
||||
}
|
||||
LayerDataType::Image(image) => image_data.push(FrontendImageData {
|
||||
path: path.clone(),
|
||||
image_data: image.image_data.clone(),
|
||||
mime: image.mime.clone(),
|
||||
}),
|
||||
LayerDataType::NodeGraphFrame(node_graph_frame) => {
|
||||
if let Some(data) = &node_graph_frame.image_data {
|
||||
image_data.push(FrontendImageData {
|
||||
|
|
@ -1829,7 +1822,7 @@ impl DocumentMessageHandler {
|
|||
);
|
||||
}
|
||||
|
||||
pub fn update_layer_tree_options_bar_widgets(&self, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
pub fn update_layer_tree_options_bar_widgets(&self, responses: &mut VecDeque<Message>, render_data: &RenderData) {
|
||||
let mut opacity = None;
|
||||
let mut opacity_is_mixed = false;
|
||||
|
||||
|
|
@ -1838,7 +1831,7 @@ impl DocumentMessageHandler {
|
|||
|
||||
self.layer_metadata
|
||||
.keys()
|
||||
.filter_map(|path| self.layer_panel_entry_from_path(path, font_cache))
|
||||
.filter_map(|path| self.layer_panel_entry_from_path(path, render_data))
|
||||
.filter(|layer_panel_entry| layer_panel_entry.layer_metadata.selected)
|
||||
.flat_map(|layer_panel_entry| self.document_legacy.layer(layer_panel_entry.path.as_slice()))
|
||||
.for_each(|layer| {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,31 @@
|
|||
use crate::messages::portfolio::utility_types::PersistentData;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::document::Document as DocumentLegacy;
|
||||
use document_legacy::layers::style::{RenderData, ViewMode};
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct OverlaysMessageHandler {
|
||||
pub overlays_document: DocumentLegacy,
|
||||
}
|
||||
|
||||
impl MessageHandler<OverlaysMessage, (bool, &FontCache, &InputPreprocessorMessageHandler)> for OverlaysMessageHandler {
|
||||
impl MessageHandler<OverlaysMessage, (bool, &PersistentData, &InputPreprocessorMessageHandler)> for OverlaysMessageHandler {
|
||||
#[remain::check]
|
||||
fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque<Message>, (overlays_visible, font_cache, ipp): (bool, &FontCache, &InputPreprocessorMessageHandler)) {
|
||||
fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque<Message>, (overlays_visible, persistent_data, ipp): (bool, &PersistentData, &InputPreprocessorMessageHandler)) {
|
||||
use OverlaysMessage::*;
|
||||
|
||||
#[remain::sorted]
|
||||
match message {
|
||||
// Sub-messages
|
||||
#[remain::unsorted]
|
||||
DispatchOperation(operation) => match self.overlays_document.handle_operation(*operation, font_cache) {
|
||||
Ok(_) => responses.push_back(OverlaysMessage::Rerender.into()),
|
||||
Err(e) => error!("OverlaysError: {:?}", e),
|
||||
},
|
||||
DispatchOperation(operation) => {
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, Some(ipp.document_bounds()));
|
||||
|
||||
match self.overlays_document.handle_operation(*operation, &render_data) {
|
||||
Ok(_) => responses.push_back(OverlaysMessage::Rerender.into()),
|
||||
Err(e) => error!("OverlaysError: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
// Messages
|
||||
ClearAllOverlays => {
|
||||
|
|
@ -33,8 +37,8 @@ impl MessageHandler<OverlaysMessage, (bool, &FontCache, &InputPreprocessorMessag
|
|||
responses.push_back(
|
||||
FrontendMessage::UpdateDocumentOverlays {
|
||||
svg: if overlays_visible {
|
||||
let render_data = RenderData::new(ViewMode::Normal, font_cache, Some(ipp.document_bounds()));
|
||||
self.overlays_document.render_root(render_data)
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, Some(ipp.document_bounds()));
|
||||
self.overlays_document.render_root(&render_data)
|
||||
} else {
|
||||
String::from("")
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::messages::portfolio::utility_types::PersistentData;
|
|||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::layers::layer_info::LayerDataTypeDiscriminant;
|
||||
use document_legacy::layers::style::{RenderData, ViewMode};
|
||||
use document_legacy::{LayerId, Operation};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -20,6 +21,8 @@ pub struct PropertiesPanelMessageHandler {
|
|||
impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPanelMessageHandlerData<'a>)> for PropertiesPanelMessageHandler {
|
||||
#[remain::check]
|
||||
fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque<Message>, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) {
|
||||
use PropertiesPanelMessage::*;
|
||||
|
||||
let PropertiesPanelMessageHandlerData {
|
||||
artwork_document,
|
||||
artboard_document,
|
||||
|
|
@ -30,7 +33,8 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
|||
TargetDocument::Artboard => artboard_document,
|
||||
TargetDocument::Artwork => artwork_document,
|
||||
};
|
||||
use PropertiesPanelMessage::*;
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::Normal, None);
|
||||
|
||||
match message {
|
||||
SetActiveLayers { paths, document } => {
|
||||
if paths.len() != 1 {
|
||||
|
|
@ -99,7 +103,7 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
|||
let (path, target_document) = self.active_selection.as_ref().expect("Received update for properties panel with no active layer");
|
||||
let layer = get_document(*target_document).layer(path).unwrap();
|
||||
|
||||
let transform = apply_transform_operation(layer, transform_op, value, &persistent_data.font_cache);
|
||||
let transform = apply_transform_operation(layer, transform_op, value, &render_data);
|
||||
|
||||
self.create_document_operation(Operation::SetLayerTransform { path: path.clone(), transform }, true, responses);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ use crate::messages::prelude::*;
|
|||
use document_legacy::color::Color;
|
||||
use document_legacy::document::Document;
|
||||
use document_legacy::layers::layer_info::{Layer, LayerDataType, LayerDataTypeDiscriminant};
|
||||
use document_legacy::layers::style::{Fill, Gradient, GradientType, LineCap, LineJoin, Stroke};
|
||||
use document_legacy::layers::text_layer::{FontCache, TextLayer};
|
||||
use document_legacy::layers::style::{Fill, Gradient, GradientType, LineCap, LineJoin, RenderData, Stroke, ViewMode};
|
||||
use document_legacy::layers::text_layer::TextLayer;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::f64::consts::PI;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn apply_transform_operation(layer: &Layer, transform_op: TransformOp, value: f64, font_cache: &FontCache) -> [f64; 6] {
|
||||
pub fn apply_transform_operation(layer: &Layer, transform_op: TransformOp, value: f64, render_data: &RenderData) -> [f64; 6] {
|
||||
let transformation = match transform_op {
|
||||
TransformOp::X => DAffine2::update_x,
|
||||
TransformOp::Y => DAffine2::update_y,
|
||||
|
|
@ -29,8 +29,8 @@ pub fn apply_transform_operation(layer: &Layer, transform_op: TransformOp, value
|
|||
};
|
||||
|
||||
let scale = match transform_op {
|
||||
TransformOp::Width => layer.bounding_transform(font_cache).scale_x() / layer.transform.scale_x(),
|
||||
TransformOp::Height => layer.bounding_transform(font_cache).scale_y() / layer.transform.scale_y(),
|
||||
TransformOp::Width => layer.bounding_transform(render_data).scale_x() / layer.transform.scale_x(),
|
||||
TransformOp::Height => layer.bounding_transform(render_data).scale_y() / layer.transform.scale_y(),
|
||||
_ => 1.,
|
||||
};
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub fn apply_transform_operation(layer: &Layer, transform_op: TransformOp, value
|
|||
}
|
||||
|
||||
// Find the layerspace pivot
|
||||
let pivot = DAffine2::from_translation(layer.transform.transform_point2(layer.layerspace_pivot(font_cache)));
|
||||
let pivot = DAffine2::from_translation(layer.transform.transform_point2(layer.layerspace_pivot(render_data)));
|
||||
|
||||
// Find the delta transform
|
||||
let mut delta = layer.transform.inverse() * transform;
|
||||
|
|
@ -94,17 +94,15 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
|
|||
}];
|
||||
|
||||
let properties_body = {
|
||||
let shape = if let LayerDataType::Shape(shape) = &layer.data {
|
||||
shape
|
||||
} else {
|
||||
let LayerDataType::Shape(shape) = &layer.data else {
|
||||
panic!("Artboards can only be shapes")
|
||||
};
|
||||
let color = if let Fill::Solid(color) = shape.style.fill() {
|
||||
color
|
||||
} else {
|
||||
let Fill::Solid(color) = shape.style.fill() else {
|
||||
panic!("Artboard must have a solid fill")
|
||||
};
|
||||
let pivot = layer.transform.transform_vector2(layer.layerspace_pivot(&persistent_data.font_cache));
|
||||
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::default(), None);
|
||||
let pivot = layer.transform.transform_vector2(layer.layerspace_pivot(&render_data));
|
||||
|
||||
vec![LayoutGroup::Section {
|
||||
name: "Artboard".into(),
|
||||
|
|
@ -167,7 +165,7 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
|
|||
WidgetHolder::related_separator(),
|
||||
WidgetHolder::unrelated_separator(),
|
||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
value: Some(layer.bounding_transform(&persistent_data.font_cache).scale_x()),
|
||||
value: Some(layer.bounding_transform(&render_data).scale_x()),
|
||||
label: "W".into(),
|
||||
unit: " px".into(),
|
||||
is_integer: true,
|
||||
|
|
@ -183,7 +181,7 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
|
|||
})),
|
||||
WidgetHolder::related_separator(),
|
||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
value: Some(layer.bounding_transform(&persistent_data.font_cache).scale_y()),
|
||||
value: Some(layer.bounding_transform(&render_data).scale_y()),
|
||||
label: "H".into(),
|
||||
unit: " px".into(),
|
||||
is_integer: true,
|
||||
|
|
@ -267,11 +265,6 @@ pub fn register_artwork_layer_properties(
|
|||
tooltip: "Text".into(),
|
||||
..Default::default()
|
||||
})),
|
||||
LayerDataType::Image(_) => WidgetHolder::new(Widget::IconLabel(IconLabel {
|
||||
icon: "NodeImage".into(),
|
||||
tooltip: "Image".into(),
|
||||
..Default::default()
|
||||
})),
|
||||
LayerDataType::NodeGraphFrame(_) => WidgetHolder::new(Widget::IconLabel(IconLabel {
|
||||
icon: "NodeNodes".into(),
|
||||
tooltip: "Node Graph Frame".into(),
|
||||
|
|
@ -321,9 +314,6 @@ pub fn register_artwork_layer_properties(
|
|||
node_section_stroke(&text.path_style.stroke().unwrap_or_default()),
|
||||
]
|
||||
}
|
||||
LayerDataType::Image(_) => {
|
||||
vec![node_section_transform(layer, persistent_data)]
|
||||
}
|
||||
LayerDataType::NodeGraphFrame(node_graph_frame) => {
|
||||
let mut properties_sections = vec![node_section_transform(layer, persistent_data)];
|
||||
|
||||
|
|
@ -360,7 +350,8 @@ pub fn register_artwork_layer_properties(
|
|||
}
|
||||
|
||||
fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> LayoutGroup {
|
||||
let pivot = layer.transform.transform_vector2(layer.layerspace_pivot(&persistent_data.font_cache));
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, ViewMode::default(), None);
|
||||
let pivot = layer.transform.transform_vector2(layer.layerspace_pivot(&render_data));
|
||||
LayoutGroup::Section {
|
||||
name: "Transform".into(),
|
||||
layout: vec![
|
||||
|
|
@ -492,7 +483,7 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
|
|||
WidgetHolder::unrelated_separator(), // TODO: Remove these when we have proper entry row formatting that includes room for Assists.
|
||||
WidgetHolder::unrelated_separator(),
|
||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
value: Some(layer.bounding_transform(&persistent_data.font_cache).scale_x()),
|
||||
value: Some(layer.bounding_transform(&render_data).scale_x()),
|
||||
label: "W".into(),
|
||||
unit: " px".into(),
|
||||
on_update: WidgetCallback::new(|number_input: &NumberInput| {
|
||||
|
|
@ -506,7 +497,7 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
|
|||
})),
|
||||
WidgetHolder::related_separator(),
|
||||
WidgetHolder::new(Widget::NumberInput(NumberInput {
|
||||
value: Some(layer.bounding_transform(&persistent_data.font_cache).scale_y()),
|
||||
value: Some(layer.bounding_transform(&render_data).scale_y()),
|
||||
label: "H".into(),
|
||||
unit: " px".into(),
|
||||
on_update: WidgetCallback::new(|number_input: &NumberInput| {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ use crate::messages::portfolio::document::utility_types::transformation::{Axis,
|
|||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::document::Document;
|
||||
use document_legacy::layers::style::RenderData;
|
||||
use document_legacy::LayerId;
|
||||
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use glam::DVec2;
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
|
|
@ -25,10 +25,10 @@ pub struct TransformLayerMessageHandler {
|
|||
pivot: DVec2,
|
||||
}
|
||||
|
||||
type TransformData<'a> = (&'a mut HashMap<Vec<LayerId>, LayerMetadata>, &'a mut Document, &'a InputPreprocessorMessageHandler, &'a FontCache);
|
||||
type TransformData<'a> = (&'a mut HashMap<Vec<LayerId>, LayerMetadata>, &'a mut Document, &'a InputPreprocessorMessageHandler, &'a RenderData<'a>);
|
||||
impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformLayerMessageHandler {
|
||||
#[remain::check]
|
||||
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, (layer_metadata, document, ipp, font_cache): TransformData) {
|
||||
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, (layer_metadata, document, ipp, render_data): TransformData) {
|
||||
use TransformLayerMessage::*;
|
||||
|
||||
let selected_layers = layer_metadata.iter().filter_map(|(layer_path, data)| data.selected.then_some(layer_path)).collect::<Vec<_>>();
|
||||
|
|
@ -39,7 +39,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
|||
selected.revert_operation();
|
||||
typing.clear();
|
||||
} else {
|
||||
*selected.pivot = selected.mean_average_of_pivots(font_cache);
|
||||
*selected.pivot = selected.mean_average_of_pivots(render_data);
|
||||
}
|
||||
|
||||
*mouse_position = ipp.mouse.position;
|
||||
|
|
@ -137,7 +137,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
|||
self.transform_operation.apply_transform_operation(&mut selected, self.snap);
|
||||
}
|
||||
TransformOperation::Rotating(rotation) => {
|
||||
let selected_pivot = selected.mean_average_of_pivots(font_cache);
|
||||
let selected_pivot = selected.mean_average_of_pivots(render_data);
|
||||
let angle = {
|
||||
let start_offset = self.mouse_position - selected_pivot;
|
||||
let end_offset = ipp.mouse.position - selected_pivot;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use document_legacy::layers::layer_info::{Layer, LayerData, LayerDataTypeDiscriminant};
|
||||
use document_legacy::layers::style::{RenderData, ViewMode};
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::RenderData;
|
||||
use document_legacy::LayerId;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
|
@ -65,7 +64,7 @@ pub struct LayerPanelEntry {
|
|||
}
|
||||
|
||||
impl LayerPanelEntry {
|
||||
pub fn new(layer_metadata: &LayerMetadata, transform: DAffine2, layer: &Layer, path: Vec<LayerId>, font_cache: &FontCache) -> Self {
|
||||
pub fn new(layer_metadata: &LayerMetadata, transform: DAffine2, layer: &Layer, path: Vec<LayerId>, render_data: &RenderData) -> Self {
|
||||
let name = layer.name.clone().unwrap_or_else(|| String::from(""));
|
||||
|
||||
let mut tooltip = name.clone();
|
||||
|
|
@ -75,11 +74,10 @@ impl LayerPanelEntry {
|
|||
tooltip = tooltip.trim().to_string();
|
||||
}
|
||||
|
||||
let arr = layer.data.bounding_box(transform, font_cache).unwrap_or([DVec2::ZERO, DVec2::ZERO]);
|
||||
let arr = layer.data.bounding_box(transform, render_data).unwrap_or([DVec2::ZERO, DVec2::ZERO]);
|
||||
let arr = arr.iter().map(|x| (*x).into()).collect::<Vec<(f64, f64)>>();
|
||||
let mut thumbnail = String::new();
|
||||
let mut svg_defs = String::new();
|
||||
let render_data = RenderData::new(ViewMode::Normal, font_cache, None);
|
||||
layer.data.clone().render(&mut thumbnail, &mut svg_defs, &mut vec![transform], render_data);
|
||||
let transform = transform.to_cols_array().iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
|
||||
let thumbnail = if let [(x_min, y_min), (x_max, y_max)] = arr.as_slice() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::consts::{ROTATE_SNAP_ANGLE, SCALE_SNAP_INTERVAL};
|
|||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::document::Document;
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::RenderData;
|
||||
use document_legacy::LayerId;
|
||||
use document_legacy::Operation as DocumentOperation;
|
||||
|
||||
|
|
@ -206,20 +206,20 @@ impl<'a> Selected<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mean_average_of_pivots(&mut self, font_cache: &FontCache) -> DVec2 {
|
||||
let xy_summation = self.selected.iter().filter_map(|path| self.document.pivot(path, font_cache)).reduce(|a, b| a + b).unwrap_or_default();
|
||||
pub fn mean_average_of_pivots(&mut self, render_data: &RenderData) -> DVec2 {
|
||||
let xy_summation = self.selected.iter().filter_map(|path| self.document.pivot(path, render_data)).reduce(|a, b| a + b).unwrap_or_default();
|
||||
|
||||
xy_summation / self.selected.len() as f64
|
||||
}
|
||||
|
||||
pub fn center_of_aabb(&mut self, font_cache: &FontCache) -> DVec2 {
|
||||
pub fn center_of_aabb(&mut self, render_data: &RenderData) -> DVec2 {
|
||||
let [min, max] = self
|
||||
.selected
|
||||
.iter()
|
||||
.filter_map(|path| {
|
||||
let multiplied_transform = self.document.multiply_transforms(path).unwrap();
|
||||
|
||||
self.document.layer(path).unwrap().aabb_for_transform(multiplied_transform, font_cache)
|
||||
self.document.layer(path).unwrap().aabb_for_transform(multiplied_transform, render_data)
|
||||
})
|
||||
.reduce(|a, b| [a[0].min(b[0]), a[1].max(b[1])])
|
||||
.unwrap_or_default();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use crate::messages::prelude::*;
|
|||
use crate::messages::tool::utility_types::{HintData, HintGroup};
|
||||
use document_legacy::document::pick_safe_imaginate_resolution;
|
||||
use document_legacy::layers::layer_info::{LayerDataType, LayerDataTypeDiscriminant};
|
||||
use document_legacy::layers::style::RenderData;
|
||||
use document_legacy::layers::text_layer::Font;
|
||||
use document_legacy::{LayerId, Operation as DocumentOperation};
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
|
|
@ -635,19 +636,21 @@ impl PortfolioMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO Fix how this doesn't preserve tab order upon loading new document from *File > Load*
|
||||
// TODO: Fix how this doesn't preserve tab order upon loading new document from *File > Load*
|
||||
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, responses: &mut VecDeque<Message>) {
|
||||
let render_data = RenderData::new(&self.persistent_data.font_cache, new_document.view_mode, None);
|
||||
|
||||
self.document_ids.push(document_id);
|
||||
|
||||
responses.extend(
|
||||
new_document
|
||||
.layer_metadata
|
||||
.keys()
|
||||
.filter_map(|path| new_document.layer_panel_entry_from_path(path, &self.persistent_data.font_cache))
|
||||
.filter_map(|path| new_document.layer_panel_entry_from_path(path, &render_data))
|
||||
.map(|entry| FrontendMessage::UpdateDocumentLayerDetails { data: entry }.into())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
new_document.update_layer_tree_options_bar_widgets(responses, &self.persistent_data.font_cache);
|
||||
new_document.update_layer_tree_options_bar_widgets(responses, &render_data);
|
||||
|
||||
self.documents.insert(document_id, new_document);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ use crate::messages::prelude::*;
|
|||
|
||||
use document_legacy::intersection::Quad;
|
||||
use document_legacy::layers::layer_info::LayerDataType;
|
||||
use document_legacy::layers::style::{self, Fill, Stroke};
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::{self, Fill, RenderData, Stroke};
|
||||
use document_legacy::{LayerId, Operation};
|
||||
use graphene_std::vector::subpath::Subpath;
|
||||
|
||||
|
|
@ -26,7 +25,7 @@ impl PathOutline {
|
|||
overlay_path: Option<Vec<LayerId>>,
|
||||
document: &DocumentMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
font_cache: &FontCache,
|
||||
render_data: &RenderData,
|
||||
) -> Option<Vec<LayerId>> {
|
||||
// Get layer data
|
||||
let document_layer = document.document_legacy.layer(&document_layer_path).ok()?;
|
||||
|
|
@ -35,8 +34,8 @@ impl PathOutline {
|
|||
// Get the bezpath from the shape or text
|
||||
let subpath = match &document_layer.data {
|
||||
LayerDataType::Shape(layer_shape) => Some(layer_shape.shape.clone()),
|
||||
LayerDataType::Text(text) => Some(text.to_subpath_nonmut(font_cache)),
|
||||
_ => document_layer.aabb_for_transform(DAffine2::IDENTITY, font_cache).map(|[p1, p2]| Subpath::new_rect(p1, p2)),
|
||||
LayerDataType::Text(text) => Some(text.to_subpath_nonmut(render_data)),
|
||||
_ => document_layer.aabb_for_transform(DAffine2::IDENTITY, render_data).map(|[p1, p2]| Subpath::new_rect(p1, p2)),
|
||||
}?;
|
||||
|
||||
// Generate a new overlay layer if necessary
|
||||
|
|
@ -74,16 +73,16 @@ impl PathOutline {
|
|||
|
||||
/// Creates an outline of a layer either with a pre-existing overlay or by generating a new one
|
||||
///
|
||||
/// Creates an outline, discarding the overlay on failiure
|
||||
/// Creates an outline, discarding the overlay on failure
|
||||
fn create_outline(
|
||||
document_layer_path: Vec<LayerId>,
|
||||
overlay_path: Option<Vec<LayerId>>,
|
||||
document: &DocumentMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
font_cache: &FontCache,
|
||||
render_data: &RenderData,
|
||||
) -> Option<Vec<LayerId>> {
|
||||
let copied_overlay_path = overlay_path.clone();
|
||||
let result = Self::try_create_outline(document_layer_path, overlay_path, document, responses, font_cache);
|
||||
let result = Self::try_create_outline(document_layer_path, overlay_path, document, responses, render_data);
|
||||
if result.is_none() {
|
||||
// Discard the overlay layer if it exists
|
||||
if let Some(overlay_path) = copied_overlay_path {
|
||||
|
|
@ -104,17 +103,17 @@ impl PathOutline {
|
|||
}
|
||||
|
||||
/// Performs an intersect test and generates a hovered overlay if necessary
|
||||
pub fn intersect_test_hovered(&mut self, input: &InputPreprocessorMessageHandler, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
pub fn intersect_test_hovered(&mut self, input: &InputPreprocessorMessageHandler, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, render_data: &RenderData) {
|
||||
// Get the layer the user is hovering over
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
||||
let mut intersection = document.document_legacy.intersects_quad_root(quad, font_cache);
|
||||
let mut intersection = document.document_legacy.intersects_quad_root(quad, render_data);
|
||||
|
||||
// If the user is hovering over a layer they have not already selected, then update outline
|
||||
if let Some(path) = intersection.pop() {
|
||||
if !document.selected_visible_layers().any(|visible| visible == path.as_slice()) {
|
||||
// Updates the overlay, generating a new one if necessary
|
||||
self.hovered_overlay_path = Self::create_outline(path.clone(), self.hovered_overlay_path.take(), document, responses, font_cache);
|
||||
self.hovered_overlay_path = Self::create_outline(path.clone(), self.hovered_overlay_path.take(), document, responses, render_data);
|
||||
if self.hovered_overlay_path.is_none() {
|
||||
self.clear_hovered(responses);
|
||||
}
|
||||
|
|
@ -137,11 +136,11 @@ impl PathOutline {
|
|||
}
|
||||
|
||||
/// Updates the selected overlays, generating or removing overlays if necessary
|
||||
pub fn update_selected<'a>(&mut self, selected: impl Iterator<Item = &'a [LayerId]>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
pub fn update_selected<'a>(&mut self, selected: impl Iterator<Item = &'a [LayerId]>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, render_data: &RenderData) {
|
||||
let mut old_overlay_paths = std::mem::take(&mut self.selected_overlay_paths);
|
||||
|
||||
for document_layer_path in selected {
|
||||
if let Some(overlay_path) = Self::create_outline(document_layer_path.to_vec(), old_overlay_paths.pop(), document, responses, font_cache) {
|
||||
if let Some(overlay_path) = Self::create_outline(document_layer_path.to_vec(), old_overlay_paths.pop(), document, responses, render_data) {
|
||||
self.selected_overlay_paths.push(overlay_path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ use crate::consts::{COLOR_ACCENT, PIVOT_INNER, PIVOT_OUTER, PIVOT_OUTER_OUTLINE_
|
|||
use crate::messages::layout::utility_types::widgets::assist_widgets::PivotPosition;
|
||||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::layers::style;
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::{self, RenderData};
|
||||
use document_legacy::{LayerId, Operation};
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
|
@ -40,8 +39,8 @@ impl Default for Pivot {
|
|||
|
||||
impl Pivot {
|
||||
/// Calculates the transform that gets from normalized pivot to viewspace.
|
||||
fn get_layer_pivot_transform(layer_path: &[LayerId], layer: &document_legacy::layers::layer_info::Layer, document: &DocumentMessageHandler, font_cache: &FontCache) -> DAffine2 {
|
||||
let [mut min, max] = layer.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
fn get_layer_pivot_transform(layer_path: &[LayerId], layer: &document_legacy::layers::layer_info::Layer, document: &DocumentMessageHandler, render_data: &RenderData) -> DAffine2 {
|
||||
let [mut min, max] = layer.aabb_for_transform(DAffine2::IDENTITY, render_data).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
|
||||
// If the layer bounds are 0 in either axis then set them to one (to avoid div 0)
|
||||
if (max.x - min.x) < f64::EPSILON * 1000. {
|
||||
|
|
@ -56,7 +55,7 @@ impl Pivot {
|
|||
}
|
||||
|
||||
/// Recomputes the pivot position and transform.
|
||||
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler, font_cache: &FontCache) {
|
||||
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler, render_data: &RenderData) {
|
||||
let mut layers = document.selected_visible_layers();
|
||||
if let Some(first) = layers.next() {
|
||||
// Add one because the first item is consumed above.
|
||||
|
|
@ -66,20 +65,20 @@ impl Pivot {
|
|||
if selected_layers_count == 1 {
|
||||
if let Ok(layer) = document.document_legacy.layer(first) {
|
||||
self.normalized_pivot = layer.pivot;
|
||||
self.transform_from_normalized = Self::get_layer_pivot_transform(first, layer, document, font_cache);
|
||||
self.transform_from_normalized = Self::get_layer_pivot_transform(first, layer, document, render_data);
|
||||
self.pivot = Some(self.transform_from_normalized.transform_point2(layer.pivot));
|
||||
}
|
||||
} else {
|
||||
// If more than one layer is selected we use the AABB with the mean of the pivots
|
||||
let xy_summation = document
|
||||
.selected_visible_layers()
|
||||
.filter_map(|path| document.document_legacy.pivot(path, font_cache))
|
||||
.filter_map(|path| document.document_legacy.pivot(path, render_data))
|
||||
.reduce(|a, b| a + b)
|
||||
.unwrap_or_default();
|
||||
|
||||
let pivot = xy_summation / selected_layers_count as f64;
|
||||
self.pivot = Some(pivot);
|
||||
let [min, max] = document.selected_visible_layers_bounding_box(font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
let [min, max] = document.selected_visible_layers_bounding_box(render_data).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
self.normalized_pivot = (pivot - min) / (max - min);
|
||||
|
||||
self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
|
||||
|
|
@ -147,8 +146,8 @@ impl Pivot {
|
|||
responses.push_back(DocumentMessage::Overlays(Operation::TransformLayerInViewport { path: inner, transform }.into()).into());
|
||||
}
|
||||
|
||||
pub fn update_pivot(&mut self, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) {
|
||||
self.recalculate_pivot(document, font_cache);
|
||||
pub fn update_pivot(&mut self, document: &DocumentMessageHandler, render_data: &RenderData, responses: &mut VecDeque<Message>) {
|
||||
self.recalculate_pivot(document, render_data);
|
||||
self.redraw_pivot(responses);
|
||||
}
|
||||
|
||||
|
|
@ -165,10 +164,10 @@ impl Pivot {
|
|||
}
|
||||
|
||||
/// Sets the viewport position of the pivot for all selected layers.
|
||||
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) {
|
||||
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, render_data: &RenderData, responses: &mut VecDeque<Message>) {
|
||||
for layer_path in document.selected_visible_layers() {
|
||||
if let Ok(layer) = document.document_legacy.layer(layer_path) {
|
||||
let transform = Self::get_layer_pivot_transform(layer_path, layer, document, font_cache);
|
||||
let transform = Self::get_layer_pivot_transform(layer_path, layer, document, render_data);
|
||||
let pivot = transform.inverse().transform_point2(position);
|
||||
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
||||
if pivot.is_finite() {
|
||||
|
|
@ -180,8 +179,8 @@ impl Pivot {
|
|||
}
|
||||
|
||||
/// Set the pivot using the normalized transform that is set above.
|
||||
pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) {
|
||||
self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, font_cache, responses);
|
||||
pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, render_data: &RenderData, responses: &mut VecDeque<Message>) {
|
||||
self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, render_data, responses);
|
||||
}
|
||||
|
||||
/// Answers if the pointer is currently positioned over the pivot.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
|||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::RenderData;
|
||||
use document_legacy::LayerId;
|
||||
use document_legacy::Operation;
|
||||
|
||||
|
|
@ -18,8 +18,8 @@ pub struct Resize {
|
|||
|
||||
impl Resize {
|
||||
/// Starts a resize, assigning the snap targets and snapping the starting position.
|
||||
pub fn start(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, font_cache: &FontCache) {
|
||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
pub fn start(&mut self, responses: &mut VecDeque<Message>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, render_data: &RenderData) {
|
||||
self.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
|
||||
self.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
let root_transform = document.document_legacy.root.transform;
|
||||
self.drag_start = root_transform.inverse().transform_point2(self.snap_manager.snap_position(responses, document, input.mouse.position));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use crate::messages::prelude::*;
|
|||
use crate::messages::tool::utility_types::ToolType;
|
||||
|
||||
use document_legacy::color::Color;
|
||||
use document_legacy::layers::style::RenderData;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ToolMessageHandler {
|
||||
|
|
@ -21,6 +22,8 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, u64, &InputPreprocess
|
|||
responses: &mut VecDeque<Message>,
|
||||
(document, document_id, input, persistent_data): (&DocumentMessageHandler, u64, &InputPreprocessorMessageHandler, &PersistentData),
|
||||
) {
|
||||
let render_data = RenderData::new(&persistent_data.font_cache, document.view_mode, None);
|
||||
|
||||
#[remain::sorted]
|
||||
match message {
|
||||
// Messages
|
||||
|
|
@ -73,12 +76,12 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, u64, &InputPreprocess
|
|||
let mut send_abort_to_tool = |tool_type, update_hints_and_cursor: bool| {
|
||||
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
|
||||
if let Some(tool_abort_message) = tool.event_to_message_map().tool_abort {
|
||||
tool.process_message(tool_abort_message, responses, (document, document_id, document_data, input, &persistent_data.font_cache));
|
||||
tool.process_message(tool_abort_message, responses, (document, document_id, document_data, input, &render_data));
|
||||
}
|
||||
|
||||
if update_hints_and_cursor {
|
||||
tool.process_message(ToolMessage::UpdateHints, responses, (document, document_id, document_data, input, &persistent_data.font_cache));
|
||||
tool.process_message(ToolMessage::UpdateCursor, responses, (document, document_id, document_data, input, &persistent_data.font_cache));
|
||||
tool.process_message(ToolMessage::UpdateHints, responses, (document, document_id, document_data, input, &render_data));
|
||||
tool.process_message(ToolMessage::UpdateCursor, responses, (document, document_id, document_data, input, &render_data));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -134,10 +137,10 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, u64, &InputPreprocess
|
|||
// Set initial hints and cursor
|
||||
tool_data
|
||||
.active_tool_mut()
|
||||
.process_message(ToolMessage::UpdateHints, responses, (document, document_id, document_data, input, &persistent_data.font_cache));
|
||||
.process_message(ToolMessage::UpdateHints, responses, (document, document_id, document_data, input, &render_data));
|
||||
tool_data
|
||||
.active_tool_mut()
|
||||
.process_message(ToolMessage::UpdateCursor, responses, (document, document_id, document_data, input, &persistent_data.font_cache));
|
||||
.process_message(ToolMessage::UpdateCursor, responses, (document, document_id, document_data, input, &render_data));
|
||||
}
|
||||
ToolMessage::RefreshToolOptions => {
|
||||
let tool_data = &mut self.tool_state.tool_data;
|
||||
|
|
@ -196,7 +199,7 @@ impl MessageHandler<ToolMessage, (&DocumentMessageHandler, u64, &InputPreprocess
|
|||
|
||||
if let Some(tool) = tool_data.tools.get_mut(&tool_type) {
|
||||
if tool_type == tool_data.active_tool_type {
|
||||
tool.process_message(tool_message, responses, (document, document_id, document_data, input, &persistent_data.font_cache));
|
||||
tool.process_message(tool_message, responses, (document, document_id, document_data, input, &render_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,14 +112,14 @@ impl Fsm for ArtboardToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, _global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
if let ToolMessage::Artboard(event) = event {
|
||||
match (self, event) {
|
||||
(state, ArtboardToolMessage::DocumentIsDirty) if state != ArtboardToolFsmState::Drawing => {
|
||||
let current_artboard = tool_data.selected_artboard.and_then(|path| document.artboard_bounding_box_and_transform(&[path], font_cache));
|
||||
let current_artboard = tool_data.selected_artboard.and_then(|path| document.artboard_bounding_box_and_transform(&[path], render_data));
|
||||
match (current_artboard, tool_data.bounding_box_overlays.take()) {
|
||||
(None, Some(bounding_box_overlays)) => bounding_box_overlays.delete(responses),
|
||||
(Some((bounds, transform)), paths) => {
|
||||
|
|
@ -173,11 +173,11 @@ impl Fsm for ArtboardToolFsmState {
|
|||
let artboard = tool_data.selected_artboard.unwrap();
|
||||
tool_data
|
||||
.snap_manager
|
||||
.start_snap(document, input, document.bounding_boxes(None, Some(artboard), font_cache), snap_x, snap_y);
|
||||
.start_snap(document, input, document.bounding_boxes(None, Some(artboard), render_data), snap_x, snap_y);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_overlays {
|
||||
let pivot = document.artboard_message_handler.artboards_document.pivot(&[artboard], font_cache).unwrap_or_default();
|
||||
let pivot = document.artboard_message_handler.artboards_document.pivot(&[artboard], render_data).unwrap_or_default();
|
||||
let root = document.document_legacy.root.transform;
|
||||
let pivot = root.inverse().transform_point2(pivot);
|
||||
bounds.center_of_transformation = pivot;
|
||||
|
|
@ -188,7 +188,7 @@ impl Fsm for ArtboardToolFsmState {
|
|||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
||||
let intersection = document.artboard_message_handler.artboards_document.intersects_quad_root(quad, font_cache);
|
||||
let intersection = document.artboard_message_handler.artboards_document.intersects_quad_root(quad, render_data);
|
||||
|
||||
responses.push_back(BroadcastEvent::DocumentIsDirty.into());
|
||||
if let Some(intersection) = intersection.last() {
|
||||
|
|
@ -196,7 +196,7 @@ impl Fsm for ArtboardToolFsmState {
|
|||
|
||||
tool_data
|
||||
.snap_manager
|
||||
.start_snap(document, input, document.bounding_boxes(None, Some(intersection[0]), font_cache), true, true);
|
||||
.start_snap(document, input, document.bounding_boxes(None, Some(intersection[0]), render_data), true, true);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
responses.push_back(
|
||||
|
|
@ -304,7 +304,7 @@ impl Fsm for ArtboardToolFsmState {
|
|||
let id = generate_uuid();
|
||||
tool_data.selected_artboard = Some(id);
|
||||
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, Some(id), font_cache), true, true);
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, Some(id), render_data), true, true);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
responses.push_back(
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ impl Fsm for EllipseToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -112,7 +112,7 @@ impl Fsm for EllipseToolFsmState {
|
|||
if let ToolMessage::Ellipse(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input, font_cache);
|
||||
shape_data.start(responses, document, input, render_data);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ impl Fsm for EyedropperToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
_tool_data: &mut Self::ToolData,
|
||||
(_document, _document_id, global_tool_data, input, _font_cache): ToolActionHandlerData,
|
||||
(_document, _document_id, global_tool_data, input, _render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl Fsm for FillToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
_tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -98,7 +98,7 @@ impl Fsm for FillToolFsmState {
|
|||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
|
||||
|
||||
if let Some(path) = document.document_legacy.intersects_quad_root(quad, font_cache).last() {
|
||||
if let Some(path) = document.document_legacy.intersects_quad_root(quad, render_data).last() {
|
||||
let color = match lmb_or_rmb {
|
||||
LeftPointerDown => global_tool_data.primary_color,
|
||||
RightPointerDown => global_tool_data.secondary_color,
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ impl Fsm for FreehandToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, _font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, _render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,10 @@ use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
|||
use document_legacy::color::Color;
|
||||
use document_legacy::intersection::Quad;
|
||||
use document_legacy::layers::layer_info::Layer;
|
||||
use document_legacy::layers::style::{Fill, Gradient, GradientType, PathStyle, Stroke};
|
||||
use document_legacy::layers::style::{Fill, Gradient, GradientType, PathStyle, RenderData, Stroke};
|
||||
use document_legacy::LayerId;
|
||||
use document_legacy::Operation;
|
||||
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -130,8 +129,8 @@ enum GradientToolFsmState {
|
|||
}
|
||||
|
||||
/// Computes the transform from gradient space to layer space (where gradient space is 0..1 in layer space)
|
||||
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, font_cache: &FontCache) -> DAffine2 {
|
||||
let bounds = layer.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap();
|
||||
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, render_data: &RenderData) -> DAffine2 {
|
||||
let bounds = layer.aabb_for_transform(DAffine2::IDENTITY, render_data).unwrap();
|
||||
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
|
||||
|
||||
let multiplied = document.document_legacy.multiply_transforms(path).unwrap();
|
||||
|
|
@ -195,9 +194,9 @@ impl GradientOverlay {
|
|||
layer: &Layer,
|
||||
document: &DocumentMessageHandler,
|
||||
responses: &mut VecDeque<Message>,
|
||||
font_cache: &FontCache,
|
||||
render_data: &RenderData,
|
||||
) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document, font_cache);
|
||||
let transform = gradient_space_transform(path, layer, document, render_data);
|
||||
let Gradient { start, end, positions, .. } = fill;
|
||||
let [start, end] = [transform.transform_point2(*start), transform.transform_point2(*end)];
|
||||
|
||||
|
|
@ -261,8 +260,8 @@ struct SelectedGradient {
|
|||
}
|
||||
|
||||
impl SelectedGradient {
|
||||
pub fn new(gradient: Gradient, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, font_cache: &FontCache) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document, font_cache);
|
||||
pub fn new(gradient: Gradient, path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler, render_data: &RenderData) -> Self {
|
||||
let transform = gradient_space_transform(path, layer, document, render_data);
|
||||
Self {
|
||||
path: path.to_vec(),
|
||||
transform,
|
||||
|
|
@ -272,7 +271,7 @@ impl SelectedGradient {
|
|||
}
|
||||
|
||||
/// Update the selected gradient, checking for removal or change of gradient.
|
||||
pub fn update(gradient: &mut Option<Self>, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) {
|
||||
pub fn update(gradient: &mut Option<Self>, document: &DocumentMessageHandler, render_data: &RenderData, responses: &mut VecDeque<Message>) {
|
||||
let Some(inner_gradient) = gradient else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -285,7 +284,7 @@ impl SelectedGradient {
|
|||
};
|
||||
|
||||
// Update transform
|
||||
inner_gradient.transform = gradient_space_transform(&inner_gradient.path, layer, document, font_cache);
|
||||
inner_gradient.transform = gradient_space_transform(&inner_gradient.path, layer, document, render_data);
|
||||
|
||||
// Clear if no longer a gradient
|
||||
let Some(gradient) = layer.style().ok().and_then(|style|style.fill().as_gradient()) else {
|
||||
|
|
@ -384,8 +383,8 @@ struct GradientToolData {
|
|||
drag_start: DVec2,
|
||||
}
|
||||
|
||||
pub fn start_snap(snap_manager: &mut SnapManager, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, font_cache: &FontCache) {
|
||||
snap_manager.start_snap(document, input, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
pub fn start_snap(snap_manager: &mut SnapManager, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, render_data: &RenderData) {
|
||||
snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
|
||||
snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
}
|
||||
|
||||
|
|
@ -397,7 +396,7 @@ impl Fsm for GradientToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -409,7 +408,7 @@ impl Fsm for GradientToolFsmState {
|
|||
}
|
||||
|
||||
if self != GradientToolFsmState::Drawing {
|
||||
SelectedGradient::update(&mut tool_data.selected_gradient, document, font_cache, responses);
|
||||
SelectedGradient::update(&mut tool_data.selected_gradient, document, render_data, responses);
|
||||
}
|
||||
|
||||
for path in document.selected_visible_layers() {
|
||||
|
|
@ -423,7 +422,9 @@ impl Fsm for GradientToolFsmState {
|
|||
.selected_gradient
|
||||
.as_ref()
|
||||
.and_then(|selected| if selected.path == path { Some(selected.dragging) } else { None });
|
||||
tool_data.gradient_overlays.push(GradientOverlay::new(gradient, dragging, path, layer, document, responses, font_cache))
|
||||
tool_data
|
||||
.gradient_overlays
|
||||
.push(GradientOverlay::new(gradient, dragging, path, layer, document, responses, render_data))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -493,7 +494,7 @@ impl Fsm for GradientToolFsmState {
|
|||
|
||||
let layer = document.document_legacy.layer(&overlay.path);
|
||||
if let Ok(layer) = layer {
|
||||
let mut selected_gradient = SelectedGradient::new(gradient, &overlay.path, layer, document, font_cache);
|
||||
let mut selected_gradient = SelectedGradient::new(gradient, &overlay.path, layer, document, render_data);
|
||||
|
||||
// Select the new point
|
||||
selected_gradient.dragging = GradientDragTarget::Step(index);
|
||||
|
|
@ -541,7 +542,7 @@ impl Fsm for GradientToolFsmState {
|
|||
] {
|
||||
if pos.distance_squared(mouse) < tolerance {
|
||||
dragging = true;
|
||||
start_snap(&mut tool_data.snap_manager, document, input, font_cache);
|
||||
start_snap(&mut tool_data.snap_manager, document, input, render_data);
|
||||
tool_data.selected_gradient = Some(SelectedGradient {
|
||||
path: overlay.path.clone(),
|
||||
transform: overlay.transform,
|
||||
|
|
@ -557,7 +558,7 @@ impl Fsm for GradientToolFsmState {
|
|||
} else {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
let quad = Quad::from_box([input.mouse.position - tolerance, input.mouse.position + tolerance]);
|
||||
let intersection = document.document_legacy.intersects_quad_root(quad, font_cache).pop();
|
||||
let intersection = document.document_legacy.intersects_quad_root(quad, render_data).pop();
|
||||
|
||||
if let Some(intersection) = intersection {
|
||||
if !document.selected_layers_contains(&intersection) {
|
||||
|
|
@ -585,11 +586,11 @@ impl Fsm for GradientToolFsmState {
|
|||
tool_options.gradient_type,
|
||||
)
|
||||
};
|
||||
let selected_gradient = SelectedGradient::new(gradient, &intersection, layer, document, font_cache).with_gradient_start(input.mouse.position);
|
||||
let selected_gradient = SelectedGradient::new(gradient, &intersection, layer, document, render_data).with_gradient_start(input.mouse.position);
|
||||
|
||||
tool_data.selected_gradient = Some(selected_gradient);
|
||||
|
||||
start_snap(&mut tool_data.snap_manager, document, input, font_cache);
|
||||
start_snap(&mut tool_data.snap_manager, document, input, render_data);
|
||||
|
||||
GradientToolFsmState::Drawing
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ impl Fsm for ImaginateToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, _global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -112,7 +112,7 @@ impl Fsm for ImaginateToolFsmState {
|
|||
if let ToolMessage::Imaginate(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input, font_cache);
|
||||
shape_data.start(responses, document, input, render_data);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
responses.push_back(NodeGraphMessage::SetDrawing { new_drawing: true }.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ impl Fsm for LineToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -147,7 +147,7 @@ impl Fsm for LineToolFsmState {
|
|||
if let ToolMessage::Line(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
tool_data.drag_start = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl Fsm for NavigateToolFsmState {
|
|||
self,
|
||||
message: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(_document, _document_id, _global_tool_data, input, _font_cache): ToolActionHandlerData,
|
||||
(_document, _document_id, _global_tool_data, input, _render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
messages: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl Fsm for NodeGraphToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, _global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -111,7 +111,7 @@ impl Fsm for NodeGraphToolFsmState {
|
|||
if let ToolMessage::NodeGraphFrame(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input, font_cache);
|
||||
shape_data.start(responses, document, input, render_data);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
responses.push_back(NodeGraphMessage::SetDrawing { new_drawing: true }.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl Fsm for PathToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, _global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -166,7 +166,7 @@ impl Fsm for PathToolFsmState {
|
|||
let ignore_document = tool_data.shape_editor.selected_layers().clone();
|
||||
tool_data
|
||||
.snap_manager
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&ignore_document), None, font_cache), true, true);
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&ignore_document), None, render_data), true, true);
|
||||
|
||||
// Do not snap against handles when anchor is selected
|
||||
let mut extension = Vec::new();
|
||||
|
|
@ -196,7 +196,7 @@ impl Fsm for PathToolFsmState {
|
|||
// Select shapes directly under our mouse
|
||||
let intersection = document
|
||||
.document_legacy
|
||||
.intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]), font_cache);
|
||||
.intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]), render_data);
|
||||
if !intersection.is_empty() {
|
||||
if toggle_add_to_selection {
|
||||
responses.push_back(DocumentMessage::AddSelectedLayers { additional_layers: intersection }.into());
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ impl Fsm for PenToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -190,7 +190,7 @@ impl Fsm for PenToolFsmState {
|
|||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
|
||||
// Initialize snapping
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
// Disable this tool's mirroring
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ impl Fsm for RectangleToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -112,7 +112,7 @@ impl Fsm for RectangleToolFsmState {
|
|||
if let ToolMessage::Rectangle(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input, font_cache);
|
||||
shape_data.start(responses, document, input, render_data);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ impl Fsm for SelectToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, _global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, _global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
_tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -295,7 +295,7 @@ impl Fsm for SelectToolFsmState {
|
|||
if let ToolMessage::Select(event) = event {
|
||||
match (self, event) {
|
||||
(_, DocumentIsDirty | SelectionChanged) => {
|
||||
match (document.selected_visible_layers_bounding_box(font_cache), tool_data.bounding_box_overlays.take()) {
|
||||
match (document.selected_visible_layers_bounding_box(render_data), tool_data.bounding_box_overlays.take()) {
|
||||
(None, Some(bounding_box_overlays)) => bounding_box_overlays.delete(responses),
|
||||
(Some(bounds), paths) => {
|
||||
let mut bounding_box_overlays = paths.unwrap_or_else(|| BoundingBoxOverlays::new(responses));
|
||||
|
|
@ -310,9 +310,9 @@ impl Fsm for SelectToolFsmState {
|
|||
(_, _) => {}
|
||||
};
|
||||
|
||||
tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, font_cache);
|
||||
tool_data.path_outlines.intersect_test_hovered(input, document, responses, font_cache);
|
||||
tool_data.pivot.update_pivot(document, font_cache, responses);
|
||||
tool_data.path_outlines.update_selected(document.selected_visible_layers(), document, responses, render_data);
|
||||
tool_data.path_outlines.intersect_test_hovered(input, document, responses, render_data);
|
||||
tool_data.pivot.update_pivot(document, render_data, responses);
|
||||
|
||||
self
|
||||
}
|
||||
|
|
@ -325,7 +325,7 @@ impl Fsm for SelectToolFsmState {
|
|||
let quad = Quad::from_box([mouse_pos - tolerance, mouse_pos + tolerance]);
|
||||
|
||||
// Check the last (top most) intersection layer.
|
||||
if let Some(intersect_layer_path) = document.document_legacy.intersects_quad_root(quad, font_cache).last() {
|
||||
if let Some(intersect_layer_path) = document.document_legacy.intersects_quad_root(quad, render_data).last() {
|
||||
if let Ok(intersect) = document.document_legacy.layer(intersect_layer_path) {
|
||||
match intersect.data {
|
||||
LayerDataType::Text(_) => {
|
||||
|
|
@ -376,7 +376,7 @@ impl Fsm for SelectToolFsmState {
|
|||
|
||||
let mut selected: Vec<_> = document.selected_visible_layers().map(|path| path.to_vec()).collect();
|
||||
let quad = tool_data.selection_quad();
|
||||
let mut intersection = document.document_legacy.intersects_quad_root(quad, font_cache);
|
||||
let mut intersection = document.document_legacy.intersects_quad_root(quad, render_data);
|
||||
// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
|
||||
// If the user is dragging the rotate trigger, go into RotatingBounds mode.
|
||||
// If the user clicks on a layer that is in their current selection, go into the dragging mode.
|
||||
|
|
@ -385,7 +385,7 @@ impl Fsm for SelectToolFsmState {
|
|||
let state = if tool_data.pivot.is_over(input.mouse.position) {
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
|
||||
DraggingPivot
|
||||
|
|
@ -397,7 +397,7 @@ impl Fsm for SelectToolFsmState {
|
|||
|
||||
tool_data
|
||||
.snap_manager
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&selected), None, font_cache), snap_x, snap_y);
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&selected), None, render_data), snap_x, snap_y);
|
||||
tool_data
|
||||
.snap_manager
|
||||
.add_all_document_handles(document, input, &[], &selected.iter().map(|x| x.as_slice()).collect::<Vec<_>>(), &[]);
|
||||
|
|
@ -409,7 +409,7 @@ impl Fsm for SelectToolFsmState {
|
|||
|
||||
let selected = &tool_data.layers_dragging.iter().collect::<Vec<_>>();
|
||||
let mut selected = Selected::new(&mut bounds.original_transforms, &mut bounds.center_of_transformation, selected, responses, document);
|
||||
bounds.center_of_transformation = selected.mean_average_of_pivots(font_cache);
|
||||
bounds.center_of_transformation = selected.mean_average_of_pivots(render_data);
|
||||
}
|
||||
|
||||
ResizingBounds
|
||||
|
|
@ -420,7 +420,7 @@ impl Fsm for SelectToolFsmState {
|
|||
let selected = selected.iter().collect::<Vec<_>>();
|
||||
let mut selected = Selected::new(&mut bounds.original_transforms, &mut bounds.center_of_transformation, &selected, responses, &document.document_legacy);
|
||||
|
||||
bounds.center_of_transformation = selected.mean_average_of_pivots(font_cache);
|
||||
bounds.center_of_transformation = selected.mean_average_of_pivots(render_data);
|
||||
}
|
||||
|
||||
tool_data.layers_dragging = selected;
|
||||
|
|
@ -433,7 +433,7 @@ impl Fsm for SelectToolFsmState {
|
|||
|
||||
tool_data
|
||||
.snap_manager
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&tool_data.layers_dragging), None, font_cache), true, true);
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&tool_data.layers_dragging), None, render_data), true, true);
|
||||
|
||||
Dragging
|
||||
} else {
|
||||
|
|
@ -449,7 +449,7 @@ impl Fsm for SelectToolFsmState {
|
|||
tool_data.layers_dragging.append(&mut selected);
|
||||
tool_data
|
||||
.snap_manager
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&tool_data.layers_dragging), None, font_cache), true, true);
|
||||
.start_snap(document, input, document.bounding_boxes(Some(&tool_data.layers_dragging), None, render_data), true, true);
|
||||
|
||||
Dragging
|
||||
} else {
|
||||
|
|
@ -472,7 +472,7 @@ impl Fsm for SelectToolFsmState {
|
|||
let snap = tool_data
|
||||
.layers_dragging
|
||||
.iter()
|
||||
.filter_map(|path| document.document_legacy.viewport_bounding_box(path, font_cache).ok()?)
|
||||
.filter_map(|path| document.document_legacy.viewport_bounding_box(path, render_data).ok()?)
|
||||
.flat_map(snapping::expand_bounds)
|
||||
.collect();
|
||||
|
||||
|
|
@ -546,7 +546,7 @@ impl Fsm for SelectToolFsmState {
|
|||
(DraggingPivot, PointerMove { .. }) => {
|
||||
let mouse_position = input.mouse.position;
|
||||
let snapped_mouse_position = tool_data.snap_manager.snap_position(responses, document, mouse_position);
|
||||
tool_data.pivot.set_viewport_position(snapped_mouse_position, document, font_cache, responses);
|
||||
tool_data.pivot.set_viewport_position(snapped_mouse_position, document, render_data, responses);
|
||||
|
||||
DraggingPivot
|
||||
}
|
||||
|
|
@ -575,7 +575,7 @@ impl Fsm for SelectToolFsmState {
|
|||
|
||||
// Generate the select outline (but not if the user is going to use the bound overlays)
|
||||
if cursor == MouseCursorIcon::Default {
|
||||
tool_data.path_outlines.intersect_test_hovered(input, document, responses, font_cache);
|
||||
tool_data.path_outlines.intersect_test_hovered(input, document, responses, render_data);
|
||||
} else {
|
||||
tool_data.path_outlines.clear_hovered(responses);
|
||||
}
|
||||
|
|
@ -639,7 +639,7 @@ impl Fsm for SelectToolFsmState {
|
|||
let quad = tool_data.selection_quad();
|
||||
responses.push_front(
|
||||
DocumentMessage::AddSelectedLayers {
|
||||
additional_layers: document.document_legacy.intersects_quad_root(quad, font_cache),
|
||||
additional_layers: document.document_legacy.intersects_quad_root(quad, render_data),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
|
|
@ -708,7 +708,7 @@ impl Fsm for SelectToolFsmState {
|
|||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
|
||||
let pos: Option<DVec2> = position.into();
|
||||
tool_data.pivot.set_normalized_position(pos.unwrap(), document, font_cache, responses);
|
||||
tool_data.pivot.set_normalized_position(pos.unwrap(), document, render_data, responses);
|
||||
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ impl Fsm for ShapeToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -151,7 +151,7 @@ impl Fsm for ShapeToolFsmState {
|
|||
if let ToolMessage::Shape(event) = event {
|
||||
match (self, event) {
|
||||
(Ready, DragStart) => {
|
||||
shape_data.start(responses, document, input, font_cache);
|
||||
shape_data.start(responses, document, input, render_data);
|
||||
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||
shape_data.path = Some(document.get_path_for_new_layer());
|
||||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ impl Fsm for SplineToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -162,7 +162,7 @@ impl Fsm for SplineToolFsmState {
|
|||
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||
tool_data.path = Some(document.get_path_for_new_layer());
|
||||
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, font_cache), true, true);
|
||||
tool_data.snap_manager.start_snap(document, input, document.bounding_boxes(None, None, render_data), true, true);
|
||||
tool_data.snap_manager.add_all_document_handles(document, input, &[], &[], &[]);
|
||||
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHan
|
|||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||
|
||||
use document_legacy::intersection::Quad;
|
||||
use document_legacy::layers::style::{self, Fill, Stroke};
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::{self, Fill, RenderData, Stroke};
|
||||
use document_legacy::LayerId;
|
||||
use document_legacy::Operation;
|
||||
|
||||
|
|
@ -213,7 +212,7 @@ fn resize_overlays(overlays: &mut Vec<Vec<LayerId>>, responses: &mut VecDeque<Me
|
|||
}
|
||||
}
|
||||
|
||||
fn update_overlays(document: &DocumentMessageHandler, tool_data: &mut TextToolData, responses: &mut VecDeque<Message>, font_cache: &FontCache) {
|
||||
fn update_overlays(document: &DocumentMessageHandler, tool_data: &mut TextToolData, responses: &mut VecDeque<Message>, render_data: &RenderData) {
|
||||
let visible_text_layers = document.selected_visible_text_layers().collect::<Vec<_>>();
|
||||
resize_overlays(&mut tool_data.overlays, responses, visible_text_layers.len());
|
||||
|
||||
|
|
@ -225,7 +224,7 @@ fn update_overlays(document: &DocumentMessageHandler, tool_data: &mut TextToolDa
|
|||
.document_legacy
|
||||
.layer(layer_path)
|
||||
.unwrap()
|
||||
.aabb_for_transform(document.document_legacy.multiply_transforms(layer_path).unwrap(), font_cache)
|
||||
.aabb_for_transform(document.document_legacy.multiply_transforms(layer_path).unwrap(), render_data)
|
||||
.map(|bounds| (bounds, overlay_path))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
|
@ -250,7 +249,7 @@ impl Fsm for TextToolFsmState {
|
|||
self,
|
||||
event: ToolMessage,
|
||||
tool_data: &mut Self::ToolData,
|
||||
(document, _document_id, global_tool_data, input, font_cache): ToolActionHandlerData,
|
||||
(document, _document_id, global_tool_data, input, render_data): ToolActionHandlerData,
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
|
|
@ -260,7 +259,7 @@ impl Fsm for TextToolFsmState {
|
|||
if let ToolMessage::Text(event) = event {
|
||||
match (self, event) {
|
||||
(state, DocumentIsDirty) => {
|
||||
update_overlays(document, tool_data, responses, font_cache);
|
||||
update_overlays(document, tool_data, responses, render_data);
|
||||
|
||||
state
|
||||
}
|
||||
|
|
@ -272,7 +271,7 @@ impl Fsm for TextToolFsmState {
|
|||
// Check if the user has selected an existing text layer
|
||||
let new_state = if let Some(clicked_text_layer_path) = document
|
||||
.document_legacy
|
||||
.intersects_quad_root(quad, font_cache)
|
||||
.intersects_quad_root(quad, render_data)
|
||||
.last()
|
||||
.filter(|l| document.document_legacy.layer(l).map(|l| l.as_text().is_ok()).unwrap_or(false))
|
||||
{
|
||||
|
|
@ -367,7 +366,7 @@ impl Fsm for TextToolFsmState {
|
|||
(Editing, UpdateBounds { new_text }) => {
|
||||
resize_overlays(&mut tool_data.overlays, responses, 1);
|
||||
let text = document.document_legacy.layer(&tool_data.layer_path).unwrap().as_text().unwrap();
|
||||
let quad = text.bounding_box(&new_text, text.load_face(font_cache));
|
||||
let quad = text.bounding_box(&new_text, text.load_face(render_data));
|
||||
|
||||
let transformed_quad = document.document_legacy.multiply_transforms(&tool_data.layer_path).unwrap() * quad;
|
||||
let bounds = transformed_quad.bounding_box();
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ use crate::messages::layout::utility_types::widgets::label_widgets::{Separator,
|
|||
use crate::messages::prelude::*;
|
||||
|
||||
use document_legacy::color::Color;
|
||||
use document_legacy::layers::text_layer::FontCache;
|
||||
use document_legacy::layers::style::RenderData;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
pub type ToolActionHandlerData<'a> = (&'a DocumentMessageHandler, u64, &'a DocumentToolData, &'a InputPreprocessorMessageHandler, &'a FontCache);
|
||||
pub type ToolActionHandlerData<'a> = (&'a DocumentMessageHandler, u64, &'a DocumentToolData, &'a InputPreprocessorMessageHandler, &'a RenderData<'a>);
|
||||
|
||||
pub trait ToolCommon: for<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> + PropertyHolder + ToolTransition + ToolMetadata {}
|
||||
impl<T> ToolCommon for T where T: for<'a> MessageHandler<ToolMessage, ToolActionHandlerData<'a>> + PropertyHolder + ToolTransition + ToolMetadata {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue