|
|
|
@@ -21,15 +21,15 @@ use crate::messages::portfolio::document::utility_types::vectorize_layer_metadat
|
|
|
|
|
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::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::{DocumentError, DocumentResponse, LayerId, Operation as DocumentOperation};
|
|
|
|
|
use graph_craft::document::NodeId;
|
|
|
|
|
use graphene::color::Color;
|
|
|
|
|
use graphene::document::Document as GrapheneDocument;
|
|
|
|
|
use graphene::layers::blend_mode::BlendMode;
|
|
|
|
|
use graphene::layers::folder_layer::FolderLayer;
|
|
|
|
|
use graphene::layers::layer_info::{LayerDataType, LayerDataTypeDiscriminant};
|
|
|
|
|
use graphene::layers::style::{Fill, RenderData, ViewMode};
|
|
|
|
|
use graphene::layers::text_layer::{Font, FontCache};
|
|
|
|
|
use graphene::{DocumentError, DocumentResponse, LayerId, Operation as DocumentOperation};
|
|
|
|
|
use graphene_std::vector::subpath::Subpath;
|
|
|
|
|
|
|
|
|
|
use glam::{DAffine2, DVec2};
|
|
|
|
@@ -37,7 +37,7 @@ use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
|
pub struct DocumentMessageHandler {
|
|
|
|
|
pub graphene_document: GrapheneDocument,
|
|
|
|
|
pub document_legacy: DocumentLegacy,
|
|
|
|
|
pub saved_document_identifier: u64,
|
|
|
|
|
pub auto_saved_document_identifier: u64,
|
|
|
|
|
pub name: String,
|
|
|
|
@@ -71,7 +71,7 @@ pub struct DocumentMessageHandler {
|
|
|
|
|
impl Default for DocumentMessageHandler {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
graphene_document: GrapheneDocument::default(),
|
|
|
|
|
document_legacy: DocumentLegacy::default(),
|
|
|
|
|
saved_document_identifier: 0,
|
|
|
|
|
auto_saved_document_identifier: 0,
|
|
|
|
|
name: String::from("Untitled Document"),
|
|
|
|
@@ -112,7 +112,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
match message {
|
|
|
|
|
// Sub-messages
|
|
|
|
|
#[remain::unsorted]
|
|
|
|
|
DispatchOperation(op) => match self.graphene_document.handle_operation(*op, &persistent_data.font_cache) {
|
|
|
|
|
DispatchOperation(op) => match self.document_legacy.handle_operation(*op, &persistent_data.font_cache) {
|
|
|
|
|
Ok(Some(document_responses)) => {
|
|
|
|
|
for response in document_responses {
|
|
|
|
|
match &response {
|
|
|
|
@@ -150,7 +150,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
}
|
|
|
|
|
#[remain::unsorted]
|
|
|
|
|
Navigation(message) => {
|
|
|
|
|
self.navigation_handler.process_message(message, (&self.graphene_document, ipp), responses);
|
|
|
|
|
self.navigation_handler.process_message(message, (&self.document_legacy, ipp), responses);
|
|
|
|
|
}
|
|
|
|
|
#[remain::unsorted]
|
|
|
|
|
Overlays(message) => {
|
|
|
|
@@ -160,13 +160,13 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
#[remain::unsorted]
|
|
|
|
|
TransformLayer(message) => {
|
|
|
|
|
self.transform_layer_handler
|
|
|
|
|
.process_message(message, (&mut self.layer_metadata, &mut self.graphene_document, ipp, &persistent_data.font_cache), responses);
|
|
|
|
|
.process_message(message, (&mut self.layer_metadata, &mut self.document_legacy, ipp, &persistent_data.font_cache), responses);
|
|
|
|
|
}
|
|
|
|
|
#[remain::unsorted]
|
|
|
|
|
PropertiesPanel(message) => {
|
|
|
|
|
let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData {
|
|
|
|
|
artwork_document: &self.graphene_document,
|
|
|
|
|
artboard_document: &self.artboard_message_handler.artboards_graphene_document,
|
|
|
|
|
artwork_document: &self.document_legacy,
|
|
|
|
|
artboard_document: &self.artboard_message_handler.artboards_document,
|
|
|
|
|
selected_layers: &mut self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice())),
|
|
|
|
|
node_graph_message_handler: &self.node_graph_handler,
|
|
|
|
|
};
|
|
|
|
@@ -175,7 +175,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
}
|
|
|
|
|
#[remain::unsorted]
|
|
|
|
|
NodeGraph(message) => {
|
|
|
|
|
self.node_graph_handler.process_message(message, (&mut self.graphene_document, ipp), responses);
|
|
|
|
|
self.node_graph_handler.process_message(message, (&mut self.document_legacy, ipp), responses);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Messages
|
|
|
|
@@ -198,7 +198,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
self.backup(responses);
|
|
|
|
|
let (paths, boxes): (Vec<_>, Vec<_>) = self
|
|
|
|
|
.selected_layers()
|
|
|
|
|
.filter_map(|path| self.graphene_document.viewport_bounding_box(path, &persistent_data.font_cache).ok()?.map(|b| (path, b)))
|
|
|
|
|
.filter_map(|path| self.document_legacy.viewport_bounding_box(path, &persistent_data.font_cache).ok()?.map(|b| (path, b)))
|
|
|
|
|
.unzip();
|
|
|
|
|
|
|
|
|
|
let axis = match axis {
|
|
|
|
@@ -206,7 +206,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.graphene_document.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(), &persistent_data.font_cache) {
|
|
|
|
|
let aggregated = match aggregate {
|
|
|
|
|
AlignAggregate::Min => combined_box[0],
|
|
|
|
|
AlignAggregate::Max => combined_box[1],
|
|
|
|
@@ -261,7 +261,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
let initial_level = log::max_level();
|
|
|
|
|
log::set_max_level(log::LevelFilter::Trace);
|
|
|
|
|
|
|
|
|
|
trace!("{:#?}\n{:#?}", self.graphene_document, self.layer_metadata);
|
|
|
|
|
trace!("{:#?}\n{:#?}", self.document_legacy, self.layer_metadata);
|
|
|
|
|
|
|
|
|
|
log::set_max_level(initial_level);
|
|
|
|
|
}
|
|
|
|
@@ -301,7 +301,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
}
|
|
|
|
|
DirtyRenderDocument => {
|
|
|
|
|
// Mark all non-overlay caches as dirty
|
|
|
|
|
GrapheneDocument::mark_children_as_dirty(&mut self.graphene_document.root);
|
|
|
|
|
DocumentLegacy::mark_children_as_dirty(&mut self.document_legacy.root);
|
|
|
|
|
responses.push_back(DocumentMessage::RenderDocument.into());
|
|
|
|
|
}
|
|
|
|
|
DirtyRenderDocumentInOutlineView => {
|
|
|
|
@@ -335,7 +335,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
ExportBounds::Selection => self.selected_visible_layers_bounding_box(&persistent_data.font_cache),
|
|
|
|
|
ExportBounds::Artboard(id) => self
|
|
|
|
|
.artboard_message_handler
|
|
|
|
|
.artboards_graphene_document
|
|
|
|
|
.artboards_document
|
|
|
|
|
.layer(&[id])
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(|layer| layer.aabb(&persistent_data.font_cache)),
|
|
|
|
@@ -367,7 +367,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.graphene_document.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(), &persistent_data.font_cache) {
|
|
|
|
|
let center = (max + min) / 2.;
|
|
|
|
|
let bbox_trans = DAffine2::from_translation(-center);
|
|
|
|
|
for path in self.selected_layers() {
|
|
|
|
@@ -397,7 +397,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
}
|
|
|
|
|
let layer_path = layer_path.unwrap();
|
|
|
|
|
|
|
|
|
|
let layer = self.graphene_document.layer(layer_path).expect("Clearing NodeGraphFrame image for invalid layer");
|
|
|
|
|
let layer = self.document_legacy.layer(layer_path).expect("Clearing NodeGraphFrame image for invalid layer");
|
|
|
|
|
let previous_blob_url = match &layer.data {
|
|
|
|
|
LayerDataType::NodeGraphFrame(node_graph_frame) => &node_graph_frame.blob_url,
|
|
|
|
|
x => panic!("Cannot find blob url for layer type {}", LayerDataTypeDiscriminant::from(x)),
|
|
|
|
@@ -409,7 +409,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
responses.push_back(DocumentOperation::ClearBlobURL { path: layer_path.into() }.into());
|
|
|
|
|
}
|
|
|
|
|
GroupSelectedLayers => {
|
|
|
|
|
let mut new_folder_path = self.graphene_document.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
|
|
|
|
let mut new_folder_path = self.document_legacy.shallowest_common_folder(self.selected_layers()).unwrap_or(&[]).to_vec();
|
|
|
|
|
|
|
|
|
|
// Required for grouping parent folders with their own children
|
|
|
|
|
if !new_folder_path.is_empty() && self.selected_layers_contains(&new_folder_path) {
|
|
|
|
@@ -470,7 +470,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
MoveSelectedManipulatorPoints { layer_path, delta } => {
|
|
|
|
|
if let Ok(_layer) = self.graphene_document.layer(&layer_path) {
|
|
|
|
|
if let Ok(_layer) = self.document_legacy.layer(&layer_path) {
|
|
|
|
|
responses.push_back(DocumentOperation::MoveSelectedManipulatorPoints { layer_path, delta }.into());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -562,7 +562,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
let render_data = RenderData::new(self.view_mode, &persistent_data.font_cache, Some(ipp.document_bounds()));
|
|
|
|
|
responses.push_back(
|
|
|
|
|
FrontendMessage::UpdateDocumentArtwork {
|
|
|
|
|
svg: self.graphene_document.render_root(render_data),
|
|
|
|
|
svg: self.document_legacy.render_root(render_data),
|
|
|
|
|
}
|
|
|
|
|
.into(),
|
|
|
|
|
);
|
|
|
|
@@ -584,7 +584,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
let ruler_interval = if log < 0. { 100. * 2_f64.powf(-log.ceil()) } else { 100. / 2_f64.powf(log.ceil()) };
|
|
|
|
|
let ruler_spacing = ruler_interval * document_transform_scale;
|
|
|
|
|
|
|
|
|
|
let ruler_origin = self.graphene_document.root.transform.transform_point2(DVec2::ZERO);
|
|
|
|
|
let ruler_origin = self.document_legacy.root.transform.transform_point2(DVec2::ZERO);
|
|
|
|
|
|
|
|
|
|
responses.push_back(
|
|
|
|
|
FrontendMessage::UpdateDocumentScrollbars {
|
|
|
|
@@ -654,7 +654,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
// Fill the selection range
|
|
|
|
|
self.layer_metadata
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|(target, _)| self.graphene_document.layer_is_between(target, &layer_path, &self.layer_range_selection_reference))
|
|
|
|
|
.filter(|(target, _)| self.document_legacy.layer_is_between(target, &layer_path, &self.layer_range_selection_reference))
|
|
|
|
|
.for_each(|(layer_path, _)| {
|
|
|
|
|
paths.push(layer_path.clone());
|
|
|
|
|
});
|
|
|
|
@@ -700,7 +700,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
resolution,
|
|
|
|
|
document_id,
|
|
|
|
|
} => {
|
|
|
|
|
let layer = self.graphene_document.layer(&layer_path).expect("Setting blob URL for invalid layer");
|
|
|
|
|
let layer = self.document_legacy.layer(&layer_path).expect("Setting blob URL for invalid layer");
|
|
|
|
|
|
|
|
|
|
// Revoke the old blob URL
|
|
|
|
|
match &layer.data {
|
|
|
|
@@ -764,7 +764,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
self.snapping_enabled = snap;
|
|
|
|
|
}
|
|
|
|
|
SetTextboxEditability { path, editable } => {
|
|
|
|
|
let text = self.graphene_document.layer(&path).unwrap().as_text().unwrap();
|
|
|
|
|
let text = self.document_legacy.layer(&path).unwrap().as_text().unwrap();
|
|
|
|
|
responses.push_back(DocumentOperation::SetTextEditability { path, editable }.into());
|
|
|
|
|
if editable {
|
|
|
|
|
let color = if let Fill::Solid(solid_color) = text.path_style.fill() { *solid_color } else { Color::BLACK };
|
|
|
|
@@ -818,7 +818,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
}
|
|
|
|
|
UngroupLayers { folder_path } => {
|
|
|
|
|
// Select all the children of the folder
|
|
|
|
|
let select = self.graphene_document.folder_children_paths(&folder_path);
|
|
|
|
|
let select = self.document_legacy.folder_children_paths(&folder_path);
|
|
|
|
|
|
|
|
|
|
let message_buffer = [
|
|
|
|
|
// Select them
|
|
|
|
@@ -843,7 +843,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
|
|
|
|
}
|
|
|
|
|
UngroupSelectedLayers => {
|
|
|
|
|
responses.push_back(DocumentMessage::StartTransaction.into());
|
|
|
|
|
let folder_paths = self.graphene_document.sorted_folders_by_depth(self.selected_layers());
|
|
|
|
|
let folder_paths = self.document_legacy.sorted_folders_by_depth(self.selected_layers());
|
|
|
|
|
for folder_path in folder_paths {
|
|
|
|
|
responses.push_back(DocumentMessage::UngroupLayers { folder_path: folder_path.to_vec() }.into());
|
|
|
|
|
}
|
|
|
|
@@ -929,7 +929,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
// Calculate the size of the region to be exported
|
|
|
|
|
|
|
|
|
|
let old_transforms = self.remove_document_transform();
|
|
|
|
|
let transform = self.graphene_document.multiply_transforms(&layer_path).unwrap();
|
|
|
|
|
let transform = self.document_legacy.multiply_transforms(&layer_path).unwrap();
|
|
|
|
|
let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
|
|
|
|
|
|
|
|
|
|
let svg = self.render_document(size, transform.inverse(), persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path));
|
|
|
|
@@ -949,24 +949,24 @@ impl DocumentMessageHandler {
|
|
|
|
|
|
|
|
|
|
/// Remove the artwork and artboard pan/tilt/zoom to render it without the user's viewport navigation, and save it to be restored at the end
|
|
|
|
|
pub(crate) fn remove_document_transform(&mut self) -> [DAffine2; 2] {
|
|
|
|
|
let old_artwork_transform = self.graphene_document.root.transform;
|
|
|
|
|
self.graphene_document.root.transform = DAffine2::IDENTITY;
|
|
|
|
|
GrapheneDocument::mark_children_as_dirty(&mut self.graphene_document.root);
|
|
|
|
|
let old_artwork_transform = self.document_legacy.root.transform;
|
|
|
|
|
self.document_legacy.root.transform = DAffine2::IDENTITY;
|
|
|
|
|
DocumentLegacy::mark_children_as_dirty(&mut self.document_legacy.root);
|
|
|
|
|
|
|
|
|
|
let old_artboard_transform = self.artboard_message_handler.artboards_graphene_document.root.transform;
|
|
|
|
|
self.artboard_message_handler.artboards_graphene_document.root.transform = DAffine2::IDENTITY;
|
|
|
|
|
GrapheneDocument::mark_children_as_dirty(&mut self.artboard_message_handler.artboards_graphene_document.root);
|
|
|
|
|
let old_artboard_transform = self.artboard_message_handler.artboards_document.root.transform;
|
|
|
|
|
self.artboard_message_handler.artboards_document.root.transform = DAffine2::IDENTITY;
|
|
|
|
|
DocumentLegacy::mark_children_as_dirty(&mut self.artboard_message_handler.artboards_document.root);
|
|
|
|
|
|
|
|
|
|
[old_artwork_transform, old_artboard_transform]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Transform the artwork and artboard back to their original scales
|
|
|
|
|
pub(crate) fn restore_document_transform(&mut self, [old_artwork_transform, old_artboard_transform]: [DAffine2; 2]) {
|
|
|
|
|
self.graphene_document.root.transform = old_artwork_transform;
|
|
|
|
|
GrapheneDocument::mark_children_as_dirty(&mut self.graphene_document.root);
|
|
|
|
|
self.document_legacy.root.transform = old_artwork_transform;
|
|
|
|
|
DocumentLegacy::mark_children_as_dirty(&mut self.document_legacy.root);
|
|
|
|
|
|
|
|
|
|
self.artboard_message_handler.artboards_graphene_document.root.transform = old_artboard_transform;
|
|
|
|
|
GrapheneDocument::mark_children_as_dirty(&mut self.artboard_message_handler.artboards_graphene_document.root);
|
|
|
|
|
self.artboard_message_handler.artboards_document.root.transform = old_artboard_transform;
|
|
|
|
|
DocumentLegacy::mark_children_as_dirty(&mut self.artboard_message_handler.artboards_document.root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn render_document(&mut self, size: DVec2, transform: DAffine2, persistent_data: &PersistentData, render_mode: DocumentRenderMode) -> String {
|
|
|
|
@@ -975,11 +975,11 @@ impl DocumentMessageHandler {
|
|
|
|
|
let render_data = RenderData::new(ViewMode::Normal, &persistent_data.font_cache, None);
|
|
|
|
|
|
|
|
|
|
let (artwork, outside) = match render_mode {
|
|
|
|
|
DocumentRenderMode::Root => (self.graphene_document.render_root(render_data), None),
|
|
|
|
|
DocumentRenderMode::OnlyBelowLayerInFolder(below_layer_path) => (self.graphene_document.render_layers_below(below_layer_path, render_data).unwrap(), None),
|
|
|
|
|
DocumentRenderMode::LayerCutout(layer_path, background) => (self.graphene_document.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_graphene_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(),
|
|
|
|
@@ -1021,8 +1021,8 @@ impl DocumentMessageHandler {
|
|
|
|
|
pub fn with_name(name: String, ipp: &InputPreprocessorMessageHandler) -> Self {
|
|
|
|
|
let mut document = Self { name, ..Self::default() };
|
|
|
|
|
let starting_root_transform = document.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2.);
|
|
|
|
|
document.graphene_document.root.transform = starting_root_transform;
|
|
|
|
|
document.artboard_message_handler.artboards_graphene_document.root.transform = starting_root_transform;
|
|
|
|
|
document.document_legacy.root.transform = starting_root_transform;
|
|
|
|
|
document.artboard_message_handler.artboards_document.root.transform = starting_root_transform;
|
|
|
|
|
document
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1059,11 +1059,11 @@ impl DocumentMessageHandler {
|
|
|
|
|
|
|
|
|
|
pub fn selected_visible_layers_bounding_box(&self, font_cache: &FontCache) -> Option<[DVec2; 2]> {
|
|
|
|
|
let paths = self.selected_visible_layers();
|
|
|
|
|
self.graphene_document.combined_viewport_bounding_box(paths, font_cache)
|
|
|
|
|
self.document_legacy.combined_viewport_bounding_box(paths, font_cache)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn artboard_bounding_box_and_transform(&self, path: &[LayerId], font_cache: &FontCache) -> Option<([DVec2; 2], DAffine2)> {
|
|
|
|
|
self.artboard_message_handler.artboards_graphene_document.bounding_box_and_transform(path, font_cache).unwrap_or(None)
|
|
|
|
|
self.artboard_message_handler.artboards_document.bounding_box_and_transform(path, font_cache).unwrap_or(None)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn selected_layers(&self) -> impl Iterator<Item = &[LayerId]> {
|
|
|
|
@@ -1072,7 +1072,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
|
|
|
|
|
pub fn selected_layers_with_type(&self, discriminant: LayerDataTypeDiscriminant) -> impl Iterator<Item = &[LayerId]> {
|
|
|
|
|
self.selected_layers().filter(move |path| {
|
|
|
|
|
self.graphene_document
|
|
|
|
|
self.document_legacy
|
|
|
|
|
.layer(path)
|
|
|
|
|
.map(|layer| LayerDataTypeDiscriminant::from(&layer.data) == discriminant)
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
@@ -1084,7 +1084,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn selected_layers_without_children(&self) -> Vec<&[LayerId]> {
|
|
|
|
|
let unique_layers = GrapheneDocument::shallowest_unique_layers(self.selected_layers());
|
|
|
|
|
let unique_layers = DocumentLegacy::shallowest_unique_layers(self.selected_layers());
|
|
|
|
|
|
|
|
|
|
// We need to maintain layer ordering
|
|
|
|
|
self.sort_layers(unique_layers.iter().copied())
|
|
|
|
@@ -1095,14 +1095,14 @@ impl DocumentMessageHandler {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn selected_visible_layers(&self) -> impl Iterator<Item = &[LayerId]> {
|
|
|
|
|
self.selected_layers().filter(|path| match self.graphene_document.layer(path) {
|
|
|
|
|
self.selected_layers().filter(|path| match self.document_legacy.layer(path) {
|
|
|
|
|
Ok(layer) => layer.visible,
|
|
|
|
|
Err(_) => false,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn selected_visible_text_layers(&self) -> impl Iterator<Item = &[LayerId]> {
|
|
|
|
|
self.selected_layers().filter(|path| match self.graphene_document.layer(path) {
|
|
|
|
|
self.selected_layers().filter(|path| match self.document_legacy.layer(path) {
|
|
|
|
|
Ok(layer) => {
|
|
|
|
|
let discriminant: LayerDataTypeDiscriminant = (&layer.data).into();
|
|
|
|
|
layer.visible && discriminant == LayerDataTypeDiscriminant::Text
|
|
|
|
@@ -1112,7 +1112,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn visible_layers(&self) -> impl Iterator<Item = &[LayerId]> {
|
|
|
|
|
self.all_layers().filter(|path| match self.graphene_document.layer(path) {
|
|
|
|
|
self.all_layers().filter(|path| match self.document_legacy.layer(path) {
|
|
|
|
|
Ok(layer) => layer.visible,
|
|
|
|
|
Err(_) => false,
|
|
|
|
|
})
|
|
|
|
@@ -1121,7 +1121,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
/// Returns a copy of all the currently selected [Subpath]s.
|
|
|
|
|
pub fn selected_subpaths(&self) -> Vec<Subpath> {
|
|
|
|
|
self.selected_visible_layers()
|
|
|
|
|
.flat_map(|layer| self.graphene_document.layer(layer))
|
|
|
|
|
.flat_map(|layer| self.document_legacy.layer(layer))
|
|
|
|
|
.flat_map(|layer| layer.as_subpath_copy())
|
|
|
|
|
.collect::<Vec<Subpath>>()
|
|
|
|
|
}
|
|
|
|
@@ -1129,7 +1129,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
/// Returns references to all the currently selected [Subpath]s.
|
|
|
|
|
pub fn selected_subpaths_ref(&self) -> Vec<&Subpath> {
|
|
|
|
|
self.selected_visible_layers()
|
|
|
|
|
.flat_map(|layer| self.graphene_document.layer(layer))
|
|
|
|
|
.flat_map(|layer| self.document_legacy.layer(layer))
|
|
|
|
|
.flat_map(|layer| layer.as_subpath())
|
|
|
|
|
.collect::<Vec<&Subpath>>()
|
|
|
|
|
}
|
|
|
|
@@ -1138,13 +1138,13 @@ impl DocumentMessageHandler {
|
|
|
|
|
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 {
|
|
|
|
|
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.graphene_document.viewport_bounding_box(path, font_cache).ok()?)
|
|
|
|
|
.filter_map(|path| self.document_legacy.viewport_bounding_box(path, font_cache).ok()?)
|
|
|
|
|
.chain(
|
|
|
|
|
self.artboard_message_handler
|
|
|
|
|
.artboard_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(move |&&id| Some(id) != ignore_artboard)
|
|
|
|
|
.filter_map(|&path| self.artboard_message_handler.artboards_graphene_document.viewport_bounding_box(&[path], font_cache).ok()?),
|
|
|
|
|
.filter_map(|&path| self.artboard_message_handler.artboards_document.viewport_bounding_box(&[path], font_cache).ok()?),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1200,7 +1200,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn serialize_root(&self) -> Vec<u64> {
|
|
|
|
|
let (mut structure, mut data) = (vec![0], Vec::new());
|
|
|
|
|
self.serialize_structure(self.graphene_document.root.as_folder().unwrap(), &mut structure, &mut data, &mut vec![]);
|
|
|
|
|
self.serialize_structure(self.document_legacy.root.as_folder().unwrap(), &mut structure, &mut data, &mut vec![]);
|
|
|
|
|
structure[0] = structure.len() as u64 - 1;
|
|
|
|
|
structure.extend(data);
|
|
|
|
|
|
|
|
|
@@ -1220,7 +1220,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
.filter_map(|path| (!path.is_empty()).then_some(path))
|
|
|
|
|
.filter_map(|path| {
|
|
|
|
|
// TODO: `indices_for_path` can return an error. We currently skip these layers and log a warning. Once this problem is solved this code can be simplified.
|
|
|
|
|
match self.graphene_document.indices_for_path(path) {
|
|
|
|
|
match self.document_legacy.indices_for_path(path) {
|
|
|
|
|
Err(err) => {
|
|
|
|
|
warn!("layers_sorted: Could not get indices for the layer {:?}: {:?}", path, err);
|
|
|
|
|
None
|
|
|
|
@@ -1266,7 +1266,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
|
|
|
|
|
pub fn backup(&mut self, responses: &mut VecDeque<Message>) {
|
|
|
|
|
self.document_redo_history.clear();
|
|
|
|
|
self.document_undo_history.push_back((self.graphene_document.clone(), self.layer_metadata.clone()));
|
|
|
|
|
self.document_undo_history.push_back((self.document_legacy.clone(), self.layer_metadata.clone()));
|
|
|
|
|
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
|
|
|
|
|
self.document_undo_history.pop_front();
|
|
|
|
|
}
|
|
|
|
@@ -1298,10 +1298,10 @@ impl DocumentMessageHandler {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keeping the root is required if the bounds of the viewport have changed during the operation
|
|
|
|
|
let old_root = self.graphene_document.root.transform;
|
|
|
|
|
let document = std::mem::replace(&mut self.graphene_document, document);
|
|
|
|
|
self.graphene_document.root.transform = old_root;
|
|
|
|
|
self.graphene_document.root.cache_dirty = true;
|
|
|
|
|
let old_root = self.document_legacy.root.transform;
|
|
|
|
|
let document = std::mem::replace(&mut self.document_legacy, document);
|
|
|
|
|
self.document_legacy.root.transform = old_root;
|
|
|
|
|
self.document_legacy.root.cache_dirty = true;
|
|
|
|
|
|
|
|
|
|
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
|
|
|
|
self.document_redo_history.push_back((document, layer_metadata));
|
|
|
|
@@ -1336,10 +1336,10 @@ impl DocumentMessageHandler {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keeping the root is required if the bounds of the viewport have changed during the operation
|
|
|
|
|
let old_root = self.graphene_document.root.transform;
|
|
|
|
|
let document = std::mem::replace(&mut self.graphene_document, document);
|
|
|
|
|
self.graphene_document.root.transform = old_root;
|
|
|
|
|
self.graphene_document.root.cache_dirty = true;
|
|
|
|
|
let old_root = self.document_legacy.root.transform;
|
|
|
|
|
let document = std::mem::replace(&mut self.document_legacy, document);
|
|
|
|
|
self.document_legacy.root.transform = old_root;
|
|
|
|
|
self.document_legacy.root.cache_dirty = true;
|
|
|
|
|
|
|
|
|
|
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
|
|
|
|
self.document_undo_history.push_back((document, layer_metadata));
|
|
|
|
@@ -1363,7 +1363,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
self.document_undo_history
|
|
|
|
|
.iter()
|
|
|
|
|
.last()
|
|
|
|
|
.map(|(graphene_document, _)| graphene_document.current_state_identifier())
|
|
|
|
|
.map(|(document_legacy, _)| document_legacy.current_state_identifier())
|
|
|
|
|
.unwrap_or(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1397,15 +1397,15 @@ impl DocumentMessageHandler {
|
|
|
|
|
.layer_metadata
|
|
|
|
|
.get_mut(&path)
|
|
|
|
|
.ok_or_else(|| EditorError::Document(format!("Could not get layer metadata for {:?}", path)))?;
|
|
|
|
|
let layer = self.graphene_document.layer(&path)?;
|
|
|
|
|
let entry = LayerPanelEntry::new(&data, self.graphene_document.multiply_transforms(&path)?, layer, path, font_cache);
|
|
|
|
|
let layer = self.document_legacy.layer(&path)?;
|
|
|
|
|
let entry = LayerPanelEntry::new(&data, self.document_legacy.multiply_transforms(&path)?, layer, path, font_cache);
|
|
|
|
|
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> {
|
|
|
|
|
let folder = self.graphene_document.folder(path)?;
|
|
|
|
|
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();
|
|
|
|
|
Ok(entries)
|
|
|
|
@@ -1413,11 +1413,8 @@ impl DocumentMessageHandler {
|
|
|
|
|
|
|
|
|
|
pub fn layer_panel_entry_from_path(&self, path: &[LayerId], font_cache: &FontCache) -> Option<LayerPanelEntry> {
|
|
|
|
|
let layer_metadata = self.layer_metadata(path);
|
|
|
|
|
let transform = self
|
|
|
|
|
.graphene_document
|
|
|
|
|
.generate_transform_across_scope(path, Some(self.graphene_document.root.transform.inverse()))
|
|
|
|
|
.ok()?;
|
|
|
|
|
let layer = self.graphene_document.layer(path).ok()?;
|
|
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
@@ -1426,7 +1423,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
///
|
|
|
|
|
/// This function updates the insert index so that it points to the same place after the specified `layers` are deleted.
|
|
|
|
|
fn update_insert_index<'a>(&self, layers: &[&'a [LayerId]], path: &[LayerId], insert_index: isize, reverse_index: bool) -> Result<isize, DocumentError> {
|
|
|
|
|
let folder = self.graphene_document.folder(path)?;
|
|
|
|
|
let folder = self.document_legacy.folder(path)?;
|
|
|
|
|
let insert_index = if reverse_index { folder.layer_ids.len() as isize - insert_index } else { insert_index };
|
|
|
|
|
let layer_ids_above = if insert_index < 0 { &folder.layer_ids } else { &folder.layer_ids[..(insert_index as usize)] };
|
|
|
|
|
|
|
|
|
@@ -1435,7 +1432,7 @@ 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.graphene_document.viewport_bounding_box(&[], font_cache).ok().flatten()
|
|
|
|
|
self.document_legacy.viewport_bounding_box(&[], font_cache).ok().flatten()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Calculates the document bounds used for scrolling and centring (the layer bounds or the artboard (if applicable))
|
|
|
|
@@ -1443,7 +1440,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
if self.artboard_message_handler.is_infinite_canvas() {
|
|
|
|
|
self.all_layer_bounds(font_cache)
|
|
|
|
|
} else {
|
|
|
|
|
self.artboard_message_handler.artboards_graphene_document.viewport_bounding_box(&[], font_cache).ok().flatten()
|
|
|
|
|
self.artboard_message_handler.artboards_document.viewport_bounding_box(&[], font_cache).ok().flatten()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1452,7 +1449,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
pub fn get_path_for_new_layer(&self) -> Vec<u64> {
|
|
|
|
|
// If the selected layers don't actually exist, a new uuid for the
|
|
|
|
|
// root folder will be returned
|
|
|
|
|
let mut path = self.graphene_document.shallowest_common_folder(self.selected_layers()).map_or(vec![], |v| v.to_vec());
|
|
|
|
|
let mut path = self.document_legacy.shallowest_common_folder(self.selected_layers()).map_or(vec![], |v| v.to_vec());
|
|
|
|
|
path.push(generate_uuid());
|
|
|
|
|
path
|
|
|
|
|
}
|
|
|
|
@@ -1727,7 +1724,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
.keys()
|
|
|
|
|
.filter_map(|path| self.layer_panel_entry_from_path(path, font_cache))
|
|
|
|
|
.filter(|layer_panel_entry| layer_panel_entry.layer_metadata.selected)
|
|
|
|
|
.flat_map(|layer_panel_entry| self.graphene_document.layer(layer_panel_entry.path.as_slice()))
|
|
|
|
|
.flat_map(|layer_panel_entry| self.document_legacy.layer(layer_panel_entry.path.as_slice()))
|
|
|
|
|
.for_each(|layer| {
|
|
|
|
|
match opacity {
|
|
|
|
|
None => opacity = Some(layer.opacity),
|
|
|
|
@@ -1871,7 +1868,7 @@ impl DocumentMessageHandler {
|
|
|
|
|
if let Some(neighbor_path) = existing_layer_to_insert_beside {
|
|
|
|
|
let (neighbor_id, folder_path) = neighbor_path.split_last().expect("Can't move the root folder");
|
|
|
|
|
|
|
|
|
|
if let Some(folder) = self.graphene_document.layer(folder_path).ok().and_then(|layer| layer.as_folder().ok()) {
|
|
|
|
|
if let Some(folder) = self.document_legacy.layer(folder_path).ok().and_then(|layer| layer.as_folder().ok()) {
|
|
|
|
|
let neighbor_layer_index = folder.layer_ids.iter().position(|id| id == neighbor_id).unwrap() as isize;
|
|
|
|
|
|
|
|
|
|
// If moving down, insert below this layer. If moving up, insert above this layer.
|
|
|
|
|