Remove the whole document-legacy crate (#1524)

Remove the whole document-legacy crate

Closes #1520
This commit is contained in:
Keavon Chambers
2023-12-20 05:45:54 -08:00
committed by GitHub
parent dcd38f2e4c
commit 92203f3576
62 changed files with 1288 additions and 1215 deletions

679
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
[workspace]
members = [
"editor",
"document-legacy",
"proc-macros",
"frontend/wasm",
"frontend/src-tauri",
@@ -38,7 +37,6 @@ rustc-hash = "1.1.0"
# wasm-bindgen upgrades may break various things so we pin the version
wasm-bindgen = "=0.2.87"
dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam"] }
document-legacy = { path = "document-legacy", package = "graphite-document-legacy" }
graphene-core = { path = "node-graph/gcore" }
graph-craft = { path = "node-graph/graph-craft", features = ["serde"] }
spirv-std = { version = "0.9" }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,25 +0,0 @@
[package]
name = "graphite-document-legacy"
publish = false
version = "0.0.0"
rust-version = "1.66.0"
authors = ["Graphite Authors <contact@graphite.rs>"]
edition = "2021"
readme = "../README.md"
homepage = "https://graphite.rs"
repository = "https://github.com/GraphiteEditor/Graphite"
license = "Apache-2.0"
[dependencies]
graph-craft = { path = "../node-graph/graph-craft", features = ["serde"] }
graphene-std = { path = "../node-graph/gstd", features = ["serde"] }
graphene-core = { workspace = true, features = ["serde"] }
image = { workspace = true, default-features = false }
log = { workspace = true }
bezier-rs = { workspace = true }
kurbo = { workspace = true }
specta = { workspace = true }
serde = { workspace = true }
base64 = { workspace = true }
glam = { workspace = true }
rustybuzz = { workspace = true }

View File

@@ -1,148 +0,0 @@
use crate::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier};
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeNetwork, NodeOutput};
use graphene_core::renderer::ClickTarget;
use graphene_core::transform::Footprint;
use graphene_core::{concrete, generic, ProtoNodeIdentifier};
use graphene_std::wasm_application_io::WasmEditorApi;
use glam::DVec2;
use serde::{Deserialize, Serialize};
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::vec;
/// A number that identifies a layer.
/// This does not technically need to be unique globally, only within a folder.
pub type LayerId = u64;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Document {
#[serde(default)]
pub document_network: NodeNetwork,
/// The state_identifier serves to provide a way to uniquely identify a particular state that the document is in.
/// This identifier is not a hash and is not guaranteed to be equal for equivalent documents.
#[serde(skip)]
pub state_identifier: DefaultHasher,
#[serde(skip)]
pub metadata: DocumentMetadata,
}
impl PartialEq for Document {
fn eq(&self, other: &Self) -> bool {
self.state_identifier.finish() == other.state_identifier.finish()
}
}
impl Default for Document {
fn default() -> Self {
Self {
state_identifier: DefaultHasher::new(),
document_network: {
use graph_craft::document::{value::TaggedValue, NodeInput};
let mut network = NodeNetwork::default();
let node = graph_craft::document::DocumentNode {
name: "Output".into(),
inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true), NodeInput::Network(concrete!(WasmEditorApi))],
implementation: graph_craft::document::DocumentNodeImplementation::Network(NodeNetwork {
inputs: vec![3, 0],
outputs: vec![NodeOutput::new(3, 0)],
nodes: [
DocumentNode {
name: "EditorApi".to_string(),
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")),
..Default::default()
},
DocumentNode {
name: "Create Canvas".to_string(),
inputs: vec![NodeInput::node(0, 0)],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
skip_deduplication: true,
..Default::default()
},
DocumentNode {
name: "Cache".to_string(),
manual_composition: Some(concrete!(())),
inputs: vec![NodeInput::node(1, 0)],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
..Default::default()
},
DocumentNode {
name: "RenderNode".to_string(),
inputs: vec![
NodeInput::node(0, 0),
NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(generic!(T)))),
NodeInput::node(2, 0),
],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RenderNode<_, _, _>")),
..Default::default()
},
]
.into_iter()
.enumerate()
.map(|(id, node)| (id as NodeId, node))
.collect(),
..Default::default()
}),
metadata: graph_craft::document::DocumentNodeMetadata::position((8, 4)),
..Default::default()
};
network.push_node(node);
network
},
metadata: Default::default(),
}
}
}
impl Document {
pub fn layer_visible(&self, layer: LayerNodeIdentifier) -> bool {
!layer.ancestors(&self.metadata).any(|layer| self.document_network.disabled.contains(&layer.to_node()))
}
pub fn selected_visible_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.metadata.selected_layers().filter(|&layer| self.layer_visible(layer))
}
/// Runs an intersection test with all layers and a viewport space quad
pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_core::renderer::Quad, network: &'a NodeNetwork) -> impl Iterator<Item = LayerNodeIdentifier> + 'a {
let document_quad = self.metadata.document_to_viewport.inverse() * viewport_quad;
self.metadata
.root()
.decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer))
.filter(|&layer| !is_artboard(layer, network))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(move |target| target.intersect_rectangle(document_quad, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find all of the layers that were clicked on from a viewport space location
pub fn click_xray(&self, viewport_location: DVec2) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
let point = self.metadata.document_to_viewport.inverse().transform_point2(viewport_location);
self.metadata
.root()
.decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find the layer that has been clicked on from a viewport space location
pub fn click(&self, viewport_location: DVec2, network: &NodeNetwork) -> Option<LayerNodeIdentifier> {
self.click_xray(viewport_location).find(|&layer| !is_artboard(layer, network))
}
/// Get the combined bounding box of the click targets of the selected visible layers in viewport space
pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_visible_layers()
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
.reduce(graphene_core::renderer::Quad::combine_bounds)
}
pub fn current_state_identifier(&self) -> u64 {
self.state_identifier.finish()
}
}

View File

@@ -1,2 +0,0 @@
pub mod document;
pub mod document_metadata;

View File

@@ -44,11 +44,10 @@ gpu-executor = { path = "../node-graph/gpu-executor", optional = true }
interpreted-executor = { path = "../node-graph/interpreted-executor" }
dyn-any = { workspace = true }
graphene-core = { path = "../node-graph/gcore" }
graphene-std = { path = "../node-graph/gstd" }
graphene-std = { path = "../node-graph/gstd", features = ["serde"] }
num_enum = "0.6.1"
wasm-bindgen = { workspace = true, optional = true }
wasm-bindgen-futures = { workspace = true, optional = true }
document-legacy = { workspace = true }
# Remove when `core::cell::LazyCell` is stabilized (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>)
once_cell = "1.13.0"
web-sys = { workspace = true, features = [
@@ -61,5 +60,4 @@ web-sys = { workspace = true, features = [
[dev-dependencies]
env_logger = "0.10"
test-case = "3.1"
futures = { workspace = true }

View File

@@ -79,7 +79,7 @@ pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";
pub const DEFAULT_FONT_STYLE: &str = "Normal (400)";
// Document
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.1.0"; // Remember to update the demo artwork in /demos with both this version number and the contents so it remains editable
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.1.1"; // Remember to update the demo artwork in /demos with both this version number and the contents so it remains editable
pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
pub const MAX_UNDO_HISTORY_LEN: usize = 100; // TODO: Add this to user preferences

View File

@@ -257,12 +257,11 @@ impl Dispatcher {
mod test {
use crate::application::Editor;
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::portfolio::document::utility_types::document_metadata::{self, LayerNodeIdentifier};
use crate::messages::prelude::*;
use crate::messages::tool::tool_messages::tool_prelude::ToolType;
use crate::test_utils::EditorTestUtils;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::raster::color::Color;
fn init_logger() {
@@ -299,14 +298,14 @@ mod test {
fn copy_paste_single_layer() {
let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
editor.handle_message(PortfolioMessage::PasteIntoFolder {
clipboard: Clipboard::Internal,
parent: LayerNodeIdentifier::ROOT,
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();
@@ -330,7 +329,7 @@ mod test {
fn copy_paste_single_layer_from_middle() {
let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let shape_id = document_before_copy.metadata.all_layers().nth(1).unwrap();
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![shape_id.to_node()] });
@@ -341,7 +340,7 @@ mod test {
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();
@@ -370,15 +369,15 @@ mod test {
});
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![FOLDER_ID] });
let document_before_added_shapes = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let folder_layer = LayerNodeIdentifier::new(FOLDER_ID, &document_before_added_shapes.document_network);
let document_before_added_shapes = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let folder_layer = LayerNodeIdentifier::new(FOLDER_ID, &document_before_added_shapes.network);
editor.drag_tool(ToolType::Line, 0., 0., 10., 10.);
editor.drag_tool(ToolType::Freehand, 10., 20., 30., 40.);
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![FOLDER_ID] });
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
editor.handle_message(PortfolioMessage::PasteIntoFolder {
@@ -387,7 +386,7 @@ mod test {
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_added_shapes = document_before_added_shapes.metadata.all_layers().collect::<Vec<_>>();
let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
@@ -416,7 +415,7 @@ mod test {
fn copy_paste_deleted_layers() {
let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let mut layers = document_before_copy.metadata.all_layers();
let rect_id = layers.next().expect("rectangle");
let shape_id = layers.next().expect("shape");
@@ -439,7 +438,7 @@ mod test {
insert_index: -1,
});
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();

View File

@@ -75,10 +75,9 @@ impl MessageHandler<DialogMessage, DialogData<'_>> for DialogMessageHandler {
if let Some(document) = portfolio.active_document() {
let mut index = 0;
let artboards = document
.document_legacy
.metadata
.all_layers()
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.document_legacy, "Artboard"))
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Artboard"))
.map(|layer| {
(
layer,

View File

@@ -1,9 +1,8 @@
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
use document_legacy::document_metadata::LayerNodeIdentifier;
/// A dialog to allow users to customize their file export.
#[derive(Debug, Clone, Default)]
pub struct ExportDialogMessageHandler {

View File

@@ -1,5 +1,6 @@
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::LayerId;
use serde::{Deserialize, Serialize};
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, specta::Type)]

View File

@@ -6,11 +6,10 @@ use crate::messages::input_mapper::utility_types::macros::*;
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
use document_legacy::document_metadata::LayerNodeIdentifier;
use glam::DVec2;
impl From<MappingVariant> for Mapping {

View File

@@ -40,8 +40,7 @@ pub enum Message {
}
/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`.
/// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this
/// struct.
/// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this struct.
#[derive(specta::Type)]
#[specta(inline, remote = "MessageDiscriminant")]
pub struct MessageDiscriminantDef(u8);

View File

@@ -1,16 +1,15 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::portfolio::document::utility_types::layer_panel::LayerMetadata;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeId;
use graphene_core::raster::BlendMode;
use graphene_core::raster::Image;
use graphene_core::vector::style::ViewMode;
use graphene_core::Color;
use serde::{Deserialize, Serialize};
#[remain::sorted]
@@ -41,8 +40,7 @@ pub enum DocumentMessage {
aggregate: AlignAggregate,
},
BackupDocument {
document: DocumentLegacy,
layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
document: DocumentMessageHandler,
},
ClearLayerTree,
CommitTransaction,

View File

@@ -7,26 +7,31 @@ use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData;
use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData;
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::portfolio::document::utility_types::layer_panel::{LayerMetadata, RawBuffer};
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, DocumentSave, FlipAxis};
use crate::messages::portfolio::document::utility_types::vectorize_layer_metadata;
use crate::messages::portfolio::document::utility_types::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::layer_panel::RawBuffer;
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
use crate::messages::tool::utility_types::ToolType;
use crate::node_graph_executor::NodeGraphExecutor;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeInput, NodeNetwork};
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, DocumentNodeMetadata, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::raster::BlendMode;
use graphene_core::raster::ImageFrame;
use graphene_core::renderer::ClickTarget;
use graphene_core::transform::Footprint;
use graphene_core::vector::style::ViewMode;
use graphene_core::{concrete, generic, ProtoNodeIdentifier};
use graphene_std::wasm_application_io::WasmEditorApi;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::vec;
/// Utility function for providing a default boolean value to serde.
#[inline(always)]
@@ -36,52 +41,71 @@ fn return_true() -> bool {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DocumentMessageHandler {
pub document_legacy: DocumentLegacy,
pub saved_document_identifier: u64,
pub auto_saved_document_identifier: u64,
pub name: String,
pub version: String,
#[serde(default)]
pub commit_hash: String,
#[serde(default)]
pub collapsed_folders: Vec<LayerNodeIdentifier>,
pub document_mode: DocumentMode,
pub view_mode: ViewMode,
#[serde(skip)]
pub snapping_state: SnappingState,
pub overlays_visible: bool,
#[serde(default = "return_true")]
pub rulers_visible: bool,
#[serde(skip)]
pub document_undo_history: VecDeque<DocumentSave>,
#[serde(skip)]
pub document_redo_history: VecDeque<DocumentSave>,
/// Don't allow aborting transactions whilst undoing to avoid #559
#[serde(skip)]
undo_in_progress: bool,
#[serde(with = "vectorize_layer_metadata")]
pub layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
#[serde(skip)]
layer_range_selection_reference: Option<LayerNodeIdentifier>,
// Child message handlers
navigation_handler: NavigationMessageHandler,
#[serde(skip)]
node_graph_handler: NodeGraphMessageHandler,
#[serde(skip)]
overlays_message_handler: OverlaysMessageHandler,
#[serde(skip)]
properties_panel_message_handler: PropertiesPanelMessageHandler,
// Fields that are saved in the document format
//
pub name: String,
pub version: String,
pub network: NodeNetwork,
pub saved_document_identifier: u64,
pub auto_saved_document_identifier: u64,
// Fields that can be non-fatally missing from the saved document format
//
#[serde(default)]
pub document_mode: DocumentMode,
#[serde(default)]
pub view_mode: ViewMode,
#[serde(default = "return_true")]
pub overlays_visible: bool,
#[serde(default = "return_true")]
pub rulers_visible: bool,
#[serde(default)]
pub commit_hash: String,
#[serde(default)]
pub collapsed: Vec<LayerNodeIdentifier>,
#[serde(default)]
pub selected: HashMap<Vec<LayerId>, bool>,
// Fields omitted from the saved document format
//
#[serde(skip)]
node_graph_handler: NodeGraphMessageHandler,
pub document_undo_history: VecDeque<DocumentMessageHandler>,
#[serde(skip)]
pub document_redo_history: VecDeque<DocumentMessageHandler>,
/// Don't allow aborting transactions whilst undoing to avoid #559
#[serde(skip)]
undo_in_progress: bool,
#[serde(skip)]
pub snapping_state: SnappingState,
#[serde(skip)]
layer_range_selection_reference: Option<LayerNodeIdentifier>,
#[serde(skip)]
pub metadata: DocumentMetadata,
/// The state_identifier serves to provide a way to uniquely identify a particular state that the document is in.
/// This identifier is not a hash and is not guaranteed to be equal for equivalent documents.
#[serde(skip)]
pub state_identifier: DefaultHasher,
}
impl Default for DocumentMessageHandler {
fn default() -> Self {
Self {
document_legacy: DocumentLegacy::default(),
network: root_network(),
saved_document_identifier: 0,
auto_saved_document_identifier: 0,
name: DEFAULT_DOCUMENT_NAME.to_string(),
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
commit_hash: crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string(),
collapsed_folders: Vec::new(),
collapsed: Vec::new(),
document_mode: DocumentMode::DesignMode,
view_mode: ViewMode::default(),
snapping_state: SnappingState::default(),
@@ -90,16 +114,79 @@ impl Default for DocumentMessageHandler {
document_undo_history: VecDeque::new(),
document_redo_history: VecDeque::new(),
undo_in_progress: false,
layer_metadata: vec![(vec![], LayerMetadata::new(true))].into_iter().collect(),
selected: vec![(vec![], true)].into_iter().collect(),
layer_range_selection_reference: None,
navigation_handler: NavigationMessageHandler::default(),
overlays_message_handler: OverlaysMessageHandler::default(),
properties_panel_message_handler: PropertiesPanelMessageHandler::default(),
node_graph_handler: Default::default(),
state_identifier: DefaultHasher::new(),
metadata: Default::default(),
}
}
}
fn root_network() -> NodeNetwork {
{
let mut network = NodeNetwork::default();
let node = graph_craft::document::DocumentNode {
name: "Output".into(),
inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true), NodeInput::Network(concrete!(WasmEditorApi))],
implementation: graph_craft::document::DocumentNodeImplementation::Network(NodeNetwork {
inputs: vec![3, 0],
outputs: vec![NodeOutput::new(3, 0)],
nodes: [
DocumentNode {
name: "EditorApi".to_string(),
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")),
..Default::default()
},
DocumentNode {
name: "Create Canvas".to_string(),
inputs: vec![NodeInput::node(0, 0)],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
skip_deduplication: true,
..Default::default()
},
DocumentNode {
name: "Cache".to_string(),
manual_composition: Some(concrete!(())),
inputs: vec![NodeInput::node(1, 0)],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
..Default::default()
},
DocumentNode {
name: "RenderNode".to_string(),
inputs: vec![
NodeInput::node(0, 0),
NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(generic!(T)))),
NodeInput::node(2, 0),
],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RenderNode<_, _, _>")),
..Default::default()
},
]
.into_iter()
.enumerate()
.map(|(id, node)| (id as NodeId, node))
.collect(),
..Default::default()
}),
metadata: DocumentNodeMetadata::position((8, 4)),
..Default::default()
};
network.push_node(node);
network
}
}
impl PartialEq for DocumentMessageHandler {
fn eq(&self, other: &Self) -> bool {
self.state_identifier.finish() == other.state_identifier.finish()
}
}
pub struct DocumentInputs<'a> {
pub document_id: u64,
pub ipp: &'a InputPreprocessorMessageHandler,
@@ -126,11 +213,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
#[remain::unsorted]
Navigation(message) => {
let document_bounds = self.metadata().document_bounds_viewport_space();
self.navigation_handler.process_message(
message,
responses,
(&self.document_legacy, document_bounds, ipp, self.document_legacy.selected_visible_layers_bounding_box_viewport()),
);
self.navigation_handler
.process_message(message, responses, (&self.metadata, document_bounds, ipp, self.selected_visible_layers_bounding_box_viewport()));
}
#[remain::unsorted]
Overlays(message) => {
@@ -139,11 +223,12 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
#[remain::unsorted]
PropertiesPanel(message) => {
let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData {
document_name: self.name.as_str(),
artwork_document: &self.document_legacy,
selected_layers: &mut self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice())),
selected_layers: &mut self.selected.iter().filter_map(|(path, selected)| selected.then_some(path.as_slice())),
node_graph_message_handler: &self.node_graph_handler,
executor,
document_name: self.name.as_str(),
document_network: &mut self.network,
document_metadata: &mut self.metadata,
};
self.properties_panel_message_handler
.process_message(message, responses, (persistent_data, properties_panel_message_handler_data));
@@ -154,17 +239,18 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
message,
responses,
NodeGraphHandlerData {
document: &mut self.document_legacy,
document_network: &mut self.network,
document_metadata: &mut self.metadata,
document_id,
document_name: self.name.as_str(),
collapsed_folders: &mut self.collapsed_folders,
collapsed: &mut self.collapsed,
input: ipp,
graph_view_overlay_open,
},
);
}
#[remain::unsorted]
GraphOperation(message) => GraphOperationMessageHandler.process_message(message, responses, (&mut self.document_legacy, &mut self.collapsed_folders, &mut self.node_graph_handler)),
GraphOperation(message) => GraphOperationMessageHandler.process_message(message, responses, (&mut self.network, &mut self.metadata, &mut self.collapsed, &mut self.node_graph_handler)),
// Messages
AbortTransaction => {
@@ -180,7 +266,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
AlignAxis::X => DVec2::X,
AlignAxis::Y => DVec2::Y,
};
let Some(combined_box) = self.document_legacy.selected_visible_layers_bounding_box_viewport() else {
let Some(combined_box) = self.selected_visible_layers_bounding_box_viewport() else {
return;
};
@@ -208,7 +294,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
responses.add(BroadcastEvent::DocumentIsDirty);
}
BackupDocument { document, layer_metadata } => self.backup_with_document(document, layer_metadata, responses),
BackupDocument { document } => self.backup_with_document(document, responses),
ClearLayerTree => {
// Send an empty layer tree
let data_buffer: RawBuffer = Self::default().serialize_root().as_slice().into();
@@ -233,7 +319,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
}
DebugPrintDocument => {
info!("{:#?}\n{:#?}", self.document_legacy, self.layer_metadata);
info!("{:#?}\n{:#?}", self.network, self.selected);
}
DeleteLayer { layer_path } => {
responses.add(GraphOperationMessage::DeleteLayer { id: layer_path[0] });
@@ -277,7 +363,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
FlipAxis::X => DVec2::new(-1., 1.),
FlipAxis::Y => DVec2::new(1., -1.),
};
if let Some([min, max]) = self.document_legacy.selected_visible_layers_bounding_box_viewport() {
if let Some([min, max]) = self.selected_visible_layers_bounding_box_viewport() {
let center = (max + min) / 2.;
let bbox_trans = DAffine2::from_translation(-center);
for layer in self.metadata().selected_layers() {
@@ -379,7 +465,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
});
}
// Nudge resize
else if let Some([existing_top_left, existing_bottom_right]) = self.document_legacy.metadata.bounding_box_document(layer) {
else if let Some([existing_top_left, existing_bottom_right]) = self.metadata.bounding_box_document(layer) {
let size = existing_bottom_right - existing_top_left;
let new_size = size + if opposite_corner { -delta } else { delta };
let enlargement_factor = new_size / size;
@@ -620,10 +706,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
StartTransaction => self.backup(responses),
ToggleLayerExpansion { layer } => {
let layer = LayerNodeIdentifier::new(layer, self.network());
if self.collapsed_folders.contains(&layer) {
self.collapsed_folders.retain(|&collapsed_layer| collapsed_layer != layer);
if self.collapsed.contains(&layer) {
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
} else {
self.collapsed_folders.push(layer);
self.collapsed.push(layer);
}
responses.add(NodeGraphMessage::RunDocumentGraph);
}
@@ -663,7 +749,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(DocumentMessage::CommitTransaction);
}
UpdateDocumentTransform { transform } => {
self.document_legacy.metadata.document_to_viewport = transform;
self.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::RenderRulers);
responses.add(DocumentMessage::RenderScrollbars);
responses.add(NodeGraphMessage::RunDocumentGraph);
@@ -692,49 +778,61 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
impl DocumentMessageHandler {
pub fn actions_with_graph_open(&self, graph_open: bool) -> ActionList {
let mut common = actions!(DocumentMessageDiscriminant;
Undo,
Redo,
SelectAllLayers,
DeselectAllLayers,
RenderDocument,
SaveDocument,
SetSnapping,
DebugPrintDocument,
ZoomCanvasToFitAll,
ZoomCanvasTo100Percent,
ZoomCanvasTo200Percent,
CreateEmptyFolder,
);
if self.metadata().selected_layers().next().is_some() {
let select = actions!(DocumentMessageDiscriminant;
DeleteSelectedLayers,
DuplicateSelectedLayers,
NudgeSelectedLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
GroupSelectedLayers,
UngroupSelectedLayers,
);
common.extend(select);
}
common.extend(self.navigation_handler.actions());
common.extend(self.node_graph_handler.actions_with_node_graph_open(graph_open));
common
pub fn layer_visible(&self, layer: LayerNodeIdentifier) -> bool {
!layer.ancestors(&self.metadata).any(|layer| self.network.disabled.contains(&layer.to_node()))
}
pub fn selected_visible_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.metadata.selected_layers().filter(|&layer| self.layer_visible(layer))
}
/// Runs an intersection test with all layers and a viewport space quad
pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_core::renderer::Quad, network: &'a NodeNetwork) -> impl Iterator<Item = LayerNodeIdentifier> + 'a {
let document_quad = self.metadata.document_to_viewport.inverse() * viewport_quad;
self.metadata
.root()
.decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer))
.filter(|&layer| !is_artboard(layer, network))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(move |target| target.intersect_rectangle(document_quad, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find all of the layers that were clicked on from a viewport space location
pub fn click_xray(&self, viewport_location: DVec2) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
let point = self.metadata.document_to_viewport.inverse().transform_point2(viewport_location);
self.metadata
.root()
.decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find the layer that has been clicked on from a viewport space location
pub fn click(&self, viewport_location: DVec2, network: &NodeNetwork) -> Option<LayerNodeIdentifier> {
self.click_xray(viewport_location).find(|&layer| !is_artboard(layer, network))
}
/// Get the combined bounding box of the click targets of the selected visible layers in viewport space
pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_visible_layers()
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
.reduce(graphene_core::renderer::Quad::combine_bounds)
}
pub fn current_state_identifier(&self) -> u64 {
self.state_identifier.finish()
}
}
impl DocumentMessageHandler {
pub fn network(&self) -> &NodeNetwork {
&self.document_legacy.document_network
&self.network
}
pub fn metadata(&self) -> &document_legacy::document_metadata::DocumentMetadata {
&self.document_legacy.metadata
pub fn metadata(&self) -> &DocumentMetadata {
&self.metadata
}
pub fn serialize_document(&self) -> String {
@@ -760,7 +858,7 @@ impl DocumentMessageHandler {
pub fn with_name(name: String, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Self {
let mut document = Self { name, ..Self::default() };
let transform = document.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2.);
document.document_legacy.metadata.document_to_viewport = transform;
document.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::UpdateDocumentTransform { transform });
document
@@ -773,7 +871,7 @@ impl DocumentMessageHandler {
}
pub fn selected_layers(&self) -> impl Iterator<Item = &[LayerId]> {
self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice()))
self.selected.iter().filter_map(|(path, selected)| selected.then_some(path.as_slice()))
}
/// Returns the bounding boxes for all visible layers.
@@ -788,7 +886,7 @@ impl DocumentMessageHandler {
for layer_node in folder.children(self.metadata()) {
data.push(layer_node.to_node());
space += 1;
if layer_node.has_children(self.metadata()) && !self.collapsed_folders.contains(&layer_node) {
if layer_node.has_children(self.metadata()) && !self.collapsed.contains(&layer_node) {
path.push(layer_node.to_node());
// TODO: Skip if folder is not expanded.
@@ -843,14 +941,10 @@ impl DocumentMessageHandler {
structure
}
pub fn layer_metadata(&self, path: &[LayerId]) -> &LayerMetadata {
self.layer_metadata.get(path).unwrap_or_else(|| panic!("Editor's layer metadata for {path:?} does not exist"))
}
/// Places a document into the history system
fn backup_with_document(&mut self, document: DocumentLegacy, layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>, responses: &mut VecDeque<Message>) {
fn backup_with_document(&mut self, document: DocumentMessageHandler, responses: &mut VecDeque<Message>) {
self.document_redo_history.clear();
self.document_undo_history.push_back(DocumentSave { document, layer_metadata });
self.document_undo_history.push_back(document);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
@@ -861,27 +955,23 @@ impl DocumentMessageHandler {
/// Copies the entire document into the history system
pub fn backup(&mut self, responses: &mut VecDeque<Message>) {
self.backup_with_document(self.document_legacy.clone(), self.layer_metadata.clone(), responses);
self.backup_with_document(self.clone(), responses);
}
// TODO: Is this now redundant?
/// Push a message backing up the document in its current state
pub fn backup_nonmut(&self, responses: &mut VecDeque<Message>) {
responses.add(DocumentMessage::BackupDocument {
document: self.document_legacy.clone(),
layer_metadata: self.layer_metadata.clone(),
});
responses.add(DocumentMessage::BackupDocument { document: self.clone() });
}
/// Replace the document with a new document save, returning the document save.
pub fn replace_document(&mut self, DocumentSave { document, layer_metadata }: DocumentSave) -> DocumentSave {
// Keeping the root is required if the bounds of the viewport have changed during the operation
pub fn replace_document(&mut self, document: DocumentMessageHandler) -> DocumentMessageHandler {
// Replace the network. (Keeping the root is required if the bounds of the viewport have changed during the operation.)
let old_root = self.metadata().document_to_viewport;
let document = std::mem::replace(&mut self.document_legacy, document);
self.document_legacy.metadata.document_to_viewport = old_root;
let document = std::mem::replace(self, document);
self.metadata.document_to_viewport = old_root;
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
DocumentSave { document, layer_metadata }
document
}
pub fn undo(&mut self, responses: &mut VecDeque<Message>) {
@@ -890,25 +980,27 @@ impl DocumentMessageHandler {
let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();
if let Some(DocumentSave { document, layer_metadata }) = self.document_undo_history.pop_back() {
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();
let Some(document) = self.document_undo_history.pop_back() else {
return;
};
if prev_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = self.selected.iter().filter_map(|(layer_id, selected)| selected.then_some(layer_id.clone())).collect();
let document_save = self.replace_document(DocumentSave { document, layer_metadata });
self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
if prev_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
let document_save = self.replace_document(document);
self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
pub fn redo(&mut self, responses: &mut VecDeque<Message>) {
@@ -917,34 +1009,30 @@ impl DocumentMessageHandler {
let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();
if let Some(DocumentSave { document, layer_metadata }) = self.document_redo_history.pop_back() {
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();
let Some(document) = self.document_redo_history.pop_back() else { return };
if next_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = self.selected.iter().filter_map(|(layer_id, selected)| selected.then_some(layer_id.clone())).collect();
let document_save = self.replace_document(DocumentSave { document, layer_metadata });
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
if next_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
let document_save = self.replace_document(document);
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
pub fn current_identifier(&self) -> u64 {
// We can use the last state of the document to serve as the identifier to compare against
// This is useful since when the document is empty the identifier will be 0
self.document_undo_history
.iter()
.last()
.map(|DocumentSave { document, .. }| document.current_state_identifier())
.unwrap_or(0)
self.document_undo_history.iter().last().map(|document| document.state_identifier.finish()).unwrap_or(0)
}
pub fn is_auto_saved(&self) -> bool {
@@ -990,7 +1078,7 @@ impl DocumentMessageHandler {
/// Loads layer resources such as creating the blob URLs for the images and loading all of the fonts in the document
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>) {
let mut fonts = HashSet::new();
for (_node_id, node) in self.document_legacy.document_network.recursive_nodes() {
for (_node_id, node) in self.network.recursive_nodes() {
for input in &node.inputs {
if let NodeInput::Value {
tagged_value: TaggedValue::Font(font),
@@ -1191,12 +1279,7 @@ impl DocumentMessageHandler {
let selected_layers_except_artboards = self.metadata().selected_layers_except_artboards();
// Look up the current opacity and blend mode of the selected layers (if any), and split the iterator into the first tuple and the rest.
let mut opacity_and_blend_mode = selected_layers_except_artboards.map(|layer| {
(
get_opacity(layer, &self.document_legacy).unwrap_or(100.),
get_blend_mode(layer, &self.document_legacy).unwrap_or_default(),
)
});
let mut opacity_and_blend_mode = selected_layers_except_artboards.map(|layer| (get_opacity(layer, &self.network).unwrap_or(100.), get_blend_mode(layer, &self.network).unwrap_or_default()));
let first_opacity_and_blend_mode = opacity_and_blend_mode.next();
let result_opacity_and_blend_mode = opacity_and_blend_mode;
@@ -1322,4 +1405,39 @@ impl DocumentMessageHandler {
responses.add(DocumentMessage::MoveSelectedLayersTo { parent, insert_index });
}
pub fn actions_with_graph_open(&self, graph_open: bool) -> ActionList {
let mut common = actions!(DocumentMessageDiscriminant;
Undo,
Redo,
SelectAllLayers,
DeselectAllLayers,
RenderDocument,
SaveDocument,
SetSnapping,
DebugPrintDocument,
ZoomCanvasToFitAll,
ZoomCanvasTo100Percent,
ZoomCanvasTo200Percent,
CreateEmptyFolder,
);
if self.metadata().selected_layers().next().is_some() {
let select = actions!(DocumentMessageDiscriminant;
DeleteSelectedLayers,
DuplicateSelectedLayers,
NudgeSelectedLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
GroupSelectedLayers,
UngroupSelectedLayers,
);
common.extend(select);
}
common.extend(self.navigation_handler.actions());
common.extend(self.node_graph_handler.actions_with_node_graph_open(graph_open));
common
}
}

View File

@@ -5,11 +5,10 @@ use crate::consts::{
use crate::messages::frontend::utility_types::MouseCursorIcon;
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion};
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::prelude::*;
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
use document_legacy::document::Document;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
@@ -59,13 +58,13 @@ impl Default for NavigationMessageHandler {
}
}
impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>)> for NavigationMessageHandler {
impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>)> for NavigationMessageHandler {
#[remain::check]
fn process_message(
&mut self,
message: NavigationMessage,
responses: &mut VecDeque<Message>,
(document, document_bounds, ipp, selection_bounds): (&Document, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>),
(document_metadata, document_bounds, ipp, selection_bounds): (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>),
) {
use NavigationMessage::*;
@@ -85,8 +84,8 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
padding_scale_factor,
prevent_zoom_past_100,
} => {
let v1 = document.metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
let v2 = document.metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size());
let v1 = document_metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
let v2 = document_metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size());
let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5);
let size = (pos2 - pos1) / (v2 - v1);
@@ -108,7 +107,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
}
FitViewportToSelection => {
if let Some(bounds) = selection_bounds {
let transform = document.metadata.document_to_viewport.inverse();
let transform = document_metadata.document_to_viewport.inverse();
responses.add(FitViewportToBounds {
bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])],
padding_scale_factor: Some(VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR),
@@ -270,7 +269,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
responses.add(TransformCanvasEnd { abort_transform });
}
TranslateCanvas { delta } => {
let transformed_delta = document.metadata.document_to_viewport.inverse().transform_vector2(delta);
let transformed_delta = document_metadata.document_to_viewport.inverse().transform_vector2(delta);
self.pan += transformed_delta;
responses.add(BroadcastEvent::CanvasTransformed);
@@ -288,7 +287,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
self.transform_operation = TransformOperation::Pan { pre_commit_pan: self.pan };
}
TranslateCanvasByViewportFraction { delta } => {
let transformed_delta = document.metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
let transformed_delta = document_metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
self.pan += transformed_delta;
responses.add(BroadcastEvent::DocumentIsDirty);

View File

@@ -1,7 +1,8 @@
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use bezier_rs::Subpath;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::DocumentNode;
use graph_craft::document::NodeId;
use graphene_core::raster::BlendMode;
@@ -15,7 +16,7 @@ use graphene_core::{Artboard, Color};
use glam::{DAffine2, DVec2, IVec2};
pub type LayerIdentifier = Vec<document_legacy::document::LayerId>;
pub type LayerIdentifier = Vec<LayerId>;
#[impl_message(Message, DocumentMessage, GraphOperation)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]

View File

@@ -1,10 +1,9 @@
use super::{resolve_document_node_type, VectorDataModification};
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use bezier_rs::Subpath;
use document_legacy::document::Document;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{generate_uuid, DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::raster::{BlendMode, ImageFrame};
@@ -23,35 +22,41 @@ pub mod transform_utils;
pub struct GraphOperationMessageHandler;
struct ModifyInputsContext<'a> {
network: &'a mut NodeNetwork,
document_metadata: &'a mut DocumentMetadata,
document_network: &'a mut NodeNetwork,
node_graph: &'a mut NodeGraphMessageHandler,
responses: &'a mut VecDeque<Message>,
layer: &'a [LayerId],
outwards_links: HashMap<NodeId, Vec<NodeId>>,
layer_node: Option<NodeId>,
document_metadata: &'a mut DocumentMetadata,
}
impl<'a> ModifyInputsContext<'a> {
/// Get the node network from the document
fn new(document: &'a mut Document, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque<Message>) -> Self {
fn new(document_network: &'a mut NodeNetwork, document_metadata: &'a mut DocumentMetadata, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque<Message>) -> Self {
Self {
outwards_links: document.document_network.collect_outwards_links(),
network: &mut document.document_network,
outwards_links: document_network.collect_outwards_links(),
document_network,
node_graph,
responses,
layer: &[],
layer_node: None,
document_metadata: &mut document.metadata,
document_metadata,
}
}
fn new_with_layer(layer: &'a [LayerId], document: &'a mut Document, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque<Message>) -> Option<Self> {
let mut document = Self::new(document, node_graph, responses);
fn new_with_layer(
layer: &'a [LayerId],
document_network: &'a mut NodeNetwork,
document_metadata: &'a mut DocumentMetadata,
node_graph: &'a mut NodeGraphMessageHandler,
responses: &'a mut VecDeque<Message>,
) -> Option<Self> {
let mut document = Self::new(document_network, document_metadata, node_graph, responses);
let Some(mut id) = layer.last().copied() else {
error!("Tried to modify root layer");
return None;
};
while !document.network.nodes.get(&id)?.is_layer() {
while !document.document_network.nodes.get(&id)?.is_layer() {
id = document.outwards_links.get(&id)?.first().copied()?;
}
document.layer_node = Some(id);
@@ -60,20 +65,20 @@ impl<'a> ModifyInputsContext<'a> {
/// Updates the input of an existing node
fn modify_existing_node_inputs(&mut self, node_id: NodeId, update_input: impl FnOnce(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let document_node = self.network.nodes.get_mut(&node_id).unwrap();
let document_node = self.document_network.nodes.get_mut(&node_id).unwrap();
update_input(&mut document_node.inputs, node_id, self.document_metadata);
}
pub fn insert_between(&mut self, id: NodeId, pre: NodeOutput, post: NodeOutput, mut node: DocumentNode, input: usize, output: usize, shift_upstream: IVec2) -> Option<NodeId> {
assert!(!self.network.nodes.contains_key(&id), "Creating already existing node");
let pre_node = self.network.nodes.get_mut(&pre.node_id)?;
assert!(!self.document_network.nodes.contains_key(&id), "Creating already existing node");
let pre_node = self.document_network.nodes.get_mut(&pre.node_id)?;
node.metadata.position = pre_node.metadata.position;
let post_node = self.network.nodes.get_mut(&post.node_id)?;
let post_node = self.document_network.nodes.get_mut(&post.node_id)?;
node.inputs[input] = NodeInput::node(pre.node_id, pre.node_output_index);
post_node.inputs[post.node_output_index] = NodeInput::node(id, output);
self.network.nodes.insert(id, node);
self.document_network.nodes.insert(id, node);
self.shift_upstream(id, shift_upstream);
@@ -81,19 +86,19 @@ impl<'a> ModifyInputsContext<'a> {
}
pub fn insert_node_before(&mut self, new_id: NodeId, node_id: NodeId, input_index: usize, mut document_node: DocumentNode, offset: IVec2) -> Option<NodeId> {
assert!(!self.network.nodes.contains_key(&new_id), "Creating already existing node");
let post_node = self.network.nodes.get_mut(&node_id)?;
assert!(!self.document_network.nodes.contains_key(&new_id), "Creating already existing node");
let post_node = self.document_network.nodes.get_mut(&node_id)?;
post_node.inputs[input_index] = NodeInput::node(new_id, 0);
document_node.metadata.position = post_node.metadata.position + offset;
self.network.nodes.insert(new_id, document_node);
self.document_network.nodes.insert(new_id, document_node);
Some(new_id)
}
pub fn skip_artboards(&self, output: &mut NodeOutput) -> Option<(NodeId, usize)> {
while let NodeInput::Node { node_id, output_index, .. } = &self.network.nodes.get(&output.node_id)?.inputs[output.node_output_index] {
let sibling_node = self.network.nodes.get(node_id)?;
while let NodeInput::Node { node_id, output_index, .. } = &self.document_network.nodes.get(&output.node_id)?.inputs[output.node_output_index] {
let sibling_node = self.document_network.nodes.get(node_id)?;
if sibling_node.name != "Artboard" {
return Some((*node_id, *output_index));
}
@@ -103,14 +108,14 @@ impl<'a> ModifyInputsContext<'a> {
}
pub fn create_layer(&mut self, new_id: NodeId, output_node_id: NodeId, input_index: usize, skip_layer_nodes: usize) -> Option<NodeId> {
assert!(!self.network.nodes.contains_key(&new_id), "Creating already existing layer");
assert!(!self.document_network.nodes.contains_key(&new_id), "Creating already existing layer");
let mut output = NodeOutput::new(output_node_id, input_index);
let mut sibling_layer = None;
let mut shift = IVec2::new(0, 3);
// Locate the node output of the first sibling layer to the new layer
if let Some((node_id, output_index)) = self.skip_artboards(&mut output) {
let sibling_node = self.network.nodes.get(&node_id)?;
let sibling_node = self.document_network.nodes.get(&node_id)?;
if sibling_node.is_layer() {
// There is already a layer node
sibling_layer = Some(NodeOutput::new(node_id, 0));
@@ -125,7 +130,7 @@ impl<'a> ModifyInputsContext<'a> {
for _ in 0..skip_layer_nodes {
if let Some(old_sibling) = &sibling_layer {
output = NodeOutput::new(old_sibling.node_id, 1);
sibling_layer = self.network.nodes.get(&old_sibling.node_id)?.inputs[1].as_node().map(|node| NodeOutput::new(node, 0));
sibling_layer = self.document_network.nodes.get(&old_sibling.node_id)?.inputs[1].as_node().map(|node| NodeOutput::new(node, 0));
shift = IVec2::new(0, 3);
}
}
@@ -145,12 +150,12 @@ impl<'a> ModifyInputsContext<'a> {
// Update the document metadata structure
if let Some(new_id) = new_id {
let parent = if self.network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
LayerNodeIdentifier::new(output_node_id, self.network)
let parent = if self.document_network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
LayerNodeIdentifier::new(output_node_id, self.document_network)
} else {
LayerNodeIdentifier::ROOT
};
let new_child = LayerNodeIdentifier::new(new_id, self.network);
let new_child = LayerNodeIdentifier::new(new_id, self.document_network);
parent.push_front_child(self.document_metadata, new_child);
self.responses.add(DocumentMessage::DocumentStructureChanged);
}
@@ -162,7 +167,7 @@ impl<'a> ModifyInputsContext<'a> {
let skip_layer_nodes = if insert_index < 0 { (-1 - insert_index) as usize } else { insert_index as usize };
let output_node_id = if parent == LayerNodeIdentifier::ROOT {
self.network.original_outputs()[0].node_id
self.document_network.original_outputs()[0].node_id
} else {
parent.to_node()
};
@@ -256,7 +261,7 @@ impl<'a> ModifyInputsContext<'a> {
let mut shift_nodes = HashSet::new();
let mut stack = vec![node_id];
while let Some(node_id) = stack.pop() {
let Some(node) = self.network.nodes.get(&node_id) else { continue };
let Some(node) = self.document_network.nodes.get(&node_id) else { continue };
for input in &node.inputs {
let NodeInput::Node { node_id, .. } = input else { continue };
if shift_nodes.insert(*node_id) {
@@ -266,7 +271,7 @@ impl<'a> ModifyInputsContext<'a> {
}
for node_id in shift_nodes {
if let Some(node) = self.network.nodes.get_mut(&node_id) {
if let Some(node) = self.document_network.nodes.get_mut(&node_id) {
node.metadata.position += shift;
}
}
@@ -274,8 +279,8 @@ impl<'a> ModifyInputsContext<'a> {
/// Inserts a new node and modifies the inputs
fn modify_new_node(&mut self, name: &'static str, update_input: impl FnOnce(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let output_node_id = self.layer_node.unwrap_or(self.network.outputs[0].node_id);
let Some(output_node) = self.network.nodes.get_mut(&output_node_id) else {
let output_node_id = self.layer_node.unwrap_or(self.document_network.outputs[0].node_id);
let Some(output_node) = self.document_network.nodes.get_mut(&output_node_id) else {
warn!("Output node doesn't exist");
return;
};
@@ -292,11 +297,11 @@ impl<'a> ModifyInputsContext<'a> {
};
let mut new_document_node = node_type.to_document_node_default_inputs([new_input], metadata);
update_input(&mut new_document_node.inputs, node_id, self.document_metadata);
self.network.nodes.insert(node_id, new_document_node);
self.document_network.nodes.insert(node_id, new_document_node);
let upstream_nodes = self.network.upstream_flow_back_from_nodes(vec![node_id], true).map(|(_, id)| id).collect::<Vec<_>>();
let upstream_nodes = self.document_network.upstream_flow_back_from_nodes(vec![node_id], true).map(|(_, id)| id).collect::<Vec<_>>();
for node_id in upstream_nodes {
let Some(node) = self.network.nodes.get_mut(&node_id) else { continue };
let Some(node) = self.document_network.nodes.get_mut(&node_id) else { continue };
node.metadata.position.x -= 8;
}
}
@@ -304,8 +309,12 @@ impl<'a> ModifyInputsContext<'a> {
/// Changes the inputs of a specific node
fn modify_inputs(&mut self, name: &'static str, skip_rerender: bool, update_input: impl FnOnce(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let existing_node_id = self
.network
.upstream_flow_back_from_nodes(self.layer_node.map_or_else(|| self.network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]), true)
.document_network
.upstream_flow_back_from_nodes(
self.layer_node
.map_or_else(|| self.document_network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]),
true,
)
.find(|(node, _)| node.name == name)
.map(|(_, id)| id);
if let Some(node_id) = existing_node_id {
@@ -331,8 +340,12 @@ impl<'a> ModifyInputsContext<'a> {
/// Changes the inputs of a all of the existing instances of a node name
fn modify_all_node_inputs(&mut self, name: &'static str, skip_rerender: bool, mut update_input: impl FnMut(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let existing_nodes: Vec<_> = self
.network
.upstream_flow_back_from_nodes(self.layer_node.map_or_else(|| self.network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]), true)
.document_network
.upstream_flow_back_from_nodes(
self.layer_node
.map_or_else(|| self.document_network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]),
true,
)
.filter(|(node, _)| node.name == name)
.map(|(_, id)| id)
.collect();
@@ -516,18 +529,18 @@ impl<'a> ModifyInputsContext<'a> {
}
fn delete_layer(&mut self, id: NodeId) {
let Some(node) = self.network.nodes.get(&id) else {
let Some(node) = self.document_network.nodes.get(&id) else {
warn!("Deleting layer node that does not exist");
return;
};
LayerNodeIdentifier::new(id, self.network).delete(self.document_metadata);
LayerNodeIdentifier::new(id, self.document_network).delete(self.document_metadata);
let new_input = node.inputs[1].clone();
let deleted_position = node.metadata.position;
for post_node in self.outwards_links.get(&id).unwrap_or(&Vec::new()) {
let Some(node) = self.network.nodes.get_mut(post_node) else {
let Some(node) = self.document_network.nodes.get_mut(post_node) else {
continue;
};
@@ -541,7 +554,7 @@ impl<'a> ModifyInputsContext<'a> {
}
let mut delete_nodes = vec![id];
for (_node, id) in self.network.upstream_flow_back_from_nodes(vec![id], true) {
for (_node, id) in self.document_network.upstream_flow_back_from_nodes(vec![id], true) {
// Don't delete the node if other layers depend on it.
if self.outwards_links.get(&id).is_some_and(|nodes| nodes.len() > 1) {
break;
@@ -552,13 +565,13 @@ impl<'a> ModifyInputsContext<'a> {
}
for node_id in &delete_nodes {
self.network.nodes.remove(node_id);
self.document_network.nodes.remove(node_id);
}
if let Some(node_id) = new_input.as_node() {
if let Some(shift) = self.network.nodes.get(&node_id).map(|node| deleted_position - node.metadata.position) {
for node_id in self.network.upstream_flow_back_from_nodes(vec![node_id], false).map(|(_, id)| id).collect::<Vec<_>>() {
let Some(node) = self.network.nodes.get_mut(&node_id) else { continue };
if let Some(shift) = self.document_network.nodes.get(&node_id).map(|node| deleted_position - node.metadata.position) {
for node_id in self.document_network.upstream_flow_back_from_nodes(vec![node_id], false).map(|(_, id)| id).collect::<Vec<_>>() {
let Some(node) = self.document_network.nodes.get_mut(&node_id) else { continue };
node.metadata.position += shift;
}
}
@@ -572,36 +585,36 @@ impl<'a> ModifyInputsContext<'a> {
}
}
impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler)> for GraphOperationMessageHandler {
impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler)> for GraphOperationMessageHandler {
fn process_message(
&mut self,
message: GraphOperationMessage,
responses: &mut VecDeque<Message>,
(document, collapsed_folders, node_graph): (&mut Document, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler),
(document_network, document_metadata, collapsed, node_graph): (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler),
) {
match message {
GraphOperationMessage::FillSet { layer, fill } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.fill_set(fill);
}
}
GraphOperationMessage::OpacitySet { layer, opacity } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.opacity_set(opacity);
}
}
GraphOperationMessage::BlendModeSet { layer, blend_mode } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.blend_mode_set(blend_mode);
}
}
GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.update_bounds(old_bounds, new_bounds);
}
}
GraphOperationMessage::StrokeSet { layer, stroke } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.stroke_set(stroke);
}
}
@@ -611,10 +624,10 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
transform_in,
skip_rerender,
} => {
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
let parent_transform = document.metadata.downstream_transform_to_viewport(layer_identifier);
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender);
}
}
@@ -624,37 +637,37 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
transform_in,
skip_rerender,
} => {
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
let parent_transform = document.metadata.downstream_transform_to_viewport(layer_identifier);
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
let current_transform = Some(document.metadata.transform_to_viewport(layer_identifier));
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
let current_transform = Some(document_metadata.transform_to_viewport(layer_identifier));
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender);
}
}
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.pivot_set(pivot, bounds);
}
}
GraphOperationMessage::Vector { layer, modification } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.vector_modify(modification);
}
}
GraphOperationMessage::Brush { layer, strokes } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.brush_modify(strokes);
}
}
GraphOperationMessage::NewArtboard { id, artboard } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.network.original_outputs()[0].node_id, 0, 0) {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.document_network.original_outputs()[0].node_id, 0, 0) {
modify_inputs.insert_artboard(artboard, layer);
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::NewBitmapLayer {
id,
@@ -662,7 +675,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
parent,
insert_index,
} => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_image_data(image_frame, layer);
}
@@ -670,7 +683,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index } => {
trace!("Inserting new layer {id} as a child of {parent:?} at index {insert_index}");
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
let new_ids: HashMap<_, _> = nodes.iter().map(|(&id, _)| (id, crate::application::generate_uuid())).collect();
@@ -679,7 +692,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
.get(&0)
.and_then(|node| {
modify_inputs
.network
.document_network
.nodes
.get(&layer)
.map(|layer| layer.metadata.position - node.metadata.position + IVec2::new(-8, 0))
@@ -695,10 +708,10 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
document_node = document_node.map_ids(NodeGraphMessageHandler::default_node_input, &new_ids);
// Insert node into network
modify_inputs.network.nodes.insert(node_id, document_node);
modify_inputs.document_network.nodes.insert(node_id, document_node);
}
if let Some(layer_node) = modify_inputs.network.nodes.get_mut(&layer) {
if let Some(layer_node) = modify_inputs.document_network.nodes.get_mut(&layer) {
if let Some(&input) = new_ids.get(&0) {
layer_node.inputs[0] = NodeInput::node(input, 0)
}
@@ -707,14 +720,14 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
modify_inputs.responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_vector_data(subpaths, layer);
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::NewTextLayer {
id,
@@ -724,31 +737,31 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
parent,
insert_index,
} => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_text(text, font, size, layer);
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::ResizeArtboard { id, location, dimensions } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&[id], document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&[id], document_network, document_metadata, node_graph, responses) {
modify_inputs.resize_artboard(location, dimensions);
}
}
GraphOperationMessage::DeleteLayer { id } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
modify_inputs.delete_layer(id);
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::ClearArtboards => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let layer_nodes = modify_inputs.network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
for layer in layer_nodes {
if modify_inputs.network.upstream_flow_back_from_nodes(vec![layer], true).any(|(node, _id)| node.is_artboard()) {
if modify_inputs.document_network.upstream_flow_back_from_nodes(vec![layer], true).any(|(node, _id)| node.is_artboard()) {
modify_inputs.delete_layer(layer);
}
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
}
}
@@ -758,7 +771,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
}
}
pub fn load_network_structure(document: &mut Document, collapsed_folders: &mut Vec<LayerNodeIdentifier>) {
document.metadata.load_structure(&document.document_network);
collapsed_folders.retain(|&layer| document.metadata.layer_exists(layer));
pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, collapsed: &mut Vec<LayerNodeIdentifier>) {
document_metadata.load_structure(document_network);
collapsed.retain(|&layer| document_metadata.layer_exists(layer));
}

View File

@@ -1,8 +1,8 @@
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use bezier_rs::{ManipulatorGroup, Subpath};
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graph_craft::document::{value::TaggedValue, NodeInput};
use graphene_core::uuid::ManipulatorGroupId;
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -53,12 +53,12 @@ pub struct LayerBounds {
impl LayerBounds {
/// Extract the layer bounds and their transform for a layer.
pub fn new(document: &Document, layer: &[u64]) -> Self {
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
pub fn new(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: &[u64]) -> Self {
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
Self {
bounds: document.metadata.nonzero_bounding_box(layer),
bounds: document_metadata.nonzero_bounding_box(layer),
bounds_transform: DAffine2::IDENTITY,
layer_transform: document.metadata.transform_to_document(layer),
layer_transform: document_metadata.transform_to_document(layer),
}
}

View File

@@ -1,6 +1,6 @@
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::LayerId;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNode, NodeId, NodeInput};

View File

@@ -2,12 +2,11 @@ pub use self::document_node_types::*;
use super::load_network_structure;
use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use crate::node_graph_executor::GraphIdentifier;
use document_legacy::document::Document;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::*;
@@ -157,19 +156,19 @@ impl NodeGraphMessageHandler {
}
/// Updates the buttons for disable and preview
fn update_selection_action_buttons(&mut self, document: &Document, responses: &mut VecDeque<Message>) {
if let Some(network) = document.document_network.nested_network(&self.network) {
fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) {
if let Some(network) = document_network.nested_network(&self.network) {
let mut widgets = Vec::new();
// Don't allow disabling input or output nodes
let mut selected_nodes = document.metadata.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id));
let mut selected_nodes = document_metadata.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id));
// If there is at least one other selected node then show the hide or show button
if selected_nodes.next().is_some() {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
// Check if any of the selected nodes are disabled
let is_hidden = document.metadata.selected_nodes().any(|id| network.disabled.contains(id));
let is_hidden = document_metadata.selected_nodes().any(|id| network.disabled.contains(id));
// Check if multiple nodes are selected
let multiple_nodes = selected_nodes.next().is_some();
@@ -186,7 +185,7 @@ impl NodeGraphMessageHandler {
}
// If only one node is selected then show the preview or stop previewing button
let mut selected_nodes = document.metadata.selected_nodes();
let mut selected_nodes = document_metadata.selected_nodes();
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
@@ -212,7 +211,6 @@ impl NodeGraphMessageHandler {
/// Collate the properties panel sections for a node graph
pub fn collate_properties(&self, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let mut network = context.network;
let document = context.document;
for segment in &self.network {
network = network.nodes.get(segment).and_then(|node| node.implementation.get_network()).unwrap();
@@ -225,7 +223,7 @@ impl NodeGraphMessageHandler {
// First, we filter all the selections into layers and nodes
let (mut layers, mut nodes) = (Vec::new(), Vec::new());
for node_id in document.metadata.selected_nodes() {
for node_id in context.metadata.selected_nodes() {
if let Some(layer_or_node) = network.nodes.get(node_id) {
if layer_or_node.is_layer() {
layers.push(*node_id);
@@ -341,10 +339,10 @@ impl NodeGraphMessageHandler {
}
/// Updates the frontend's selection state in line with the backend
fn update_selected(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document, responses);
fn update_selected(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document_network, document_metadata, responses);
responses.add(FrontendMessage::UpdateNodeGraphSelection {
selected: document.metadata.selected_nodes_ref().clone(),
selected: document_metadata.selected_nodes_ref().clone(),
});
}
@@ -415,15 +413,15 @@ impl NodeGraphMessageHandler {
}
/// Tries to remove a node from the network, returning true on success.
fn remove_node(&mut self, document: &mut Document, node_id: NodeId, responses: &mut VecDeque<Message>, reconnect: bool) -> bool {
let Some(network) = document.document_network.nested_network_mut(&self.network) else {
fn remove_node(&mut self, document_network: &mut NodeNetwork, document_metadata: &mut DocumentMetadata, node_id: NodeId, responses: &mut VecDeque<Message>, reconnect: bool) -> bool {
let Some(network) = document_network.nested_network_mut(&self.network) else {
return false;
};
if !Self::remove_references_from_network(network, node_id, reconnect) {
return false;
}
network.nodes.remove(&node_id);
document.metadata.retain_selected_nodes(|&id| id != node_id);
document_metadata.retain_selected_nodes(|&id| id != node_id);
responses.add(BroadcastEvent::SelectionChanged);
true
}
@@ -447,10 +445,11 @@ impl NodeGraphMessageHandler {
#[derive(Debug)]
pub struct NodeGraphHandlerData<'a> {
pub document: &'a mut Document,
pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub document_id: u64,
pub document_name: &'a str,
pub collapsed_folders: &'a mut Vec<LayerNodeIdentifier>,
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
pub input: &'a InputPreprocessorMessageHandler,
pub graph_view_overlay_open: bool,
}
@@ -458,9 +457,10 @@ pub struct NodeGraphHandlerData<'a> {
impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGraphMessageHandler {
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, data: NodeGraphHandlerData<'a>) {
let NodeGraphHandlerData {
document,
document_network,
document_metadata: metadata,
document_id,
collapsed_folders,
collapsed,
graph_view_overlay_open,
..
} = data;
@@ -471,15 +471,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
on: BroadcastEvent::SelectionChanged,
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
});
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, metadata, collapsed);
responses.add(DocumentMessage::DocumentStructureChanged);
}
NodeGraphMessage::SelectedNodesUpdated => {
self.update_selection_action_buttons(document, responses);
self.update_selected(document, responses);
if document.metadata.selected_layers().count() <= 1 {
self.update_selection_action_buttons(document_network, metadata, responses);
self.update_selected(document_network, metadata, responses);
if metadata.selected_layers().count() <= 1 {
responses.add(DocumentMessage::SetRangeSelectionLayer {
new_layer: document.metadata.selected_layers().next(),
new_layer: metadata.selected_layers().next(),
});
}
responses.add(NodeGraphMessage::RunDocumentGraph);
@@ -492,7 +492,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
} => {
let node_id = input_node;
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
error!("No network");
return;
};
@@ -515,13 +515,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender });
}
NodeGraphMessage::Copy => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
error!("No network");
return;
};
// Collect the selected nodes
let new_ids = &document.metadata.selected_nodes().copied().enumerate().map(|(new, old)| (old, new as NodeId)).collect();
let new_ids = &metadata.selected_nodes().copied().enumerate().map(|(new, old)| (old, new as NodeId)).collect();
let copied_nodes: Vec<_> = Self::copy_nodes(network, new_ids).collect();
// Prefix to show that this is nodes
@@ -556,20 +556,20 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
}
NodeGraphMessage::DeleteNode { node_id, reconnect } => {
self.remove_node(document, node_id, responses, reconnect);
self.remove_node(document_network, metadata, node_id, responses, reconnect);
}
NodeGraphMessage::DeleteSelectedNodes { reconnect } => {
responses.add(DocumentMessage::StartTransaction);
for node_id in document.metadata.selected_nodes().copied() {
for node_id in metadata.selected_nodes().copied() {
responses.add(NodeGraphMessage::DeleteNode { node_id, reconnect });
}
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
// Only generate node graph if one of the selected nodes is connected to the output
if document.metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
if metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
if let Some(layer_path) = self.layer_path.clone() {
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
} else {
@@ -579,7 +579,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::DisconnectNodes { node_id, input_index } => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
warn!("No network");
return;
};
@@ -607,30 +607,30 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender });
}
NodeGraphMessage::DoubleClickNode { node } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
if network.nodes.get(&node).and_then(|node| node.implementation.get_network()).is_some() {
self.network.push(node);
}
}
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
}
NodeGraphMessage::DuplicateSelectedNodes => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction);
let new_ids = &document.metadata.selected_nodes().map(|&id| (id, crate::application::generate_uuid())).collect();
let new_ids = &metadata.selected_nodes().map(|&id| (id, crate::application::generate_uuid())).collect();
document.metadata.clear_selected_nodes();
metadata.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
// Copy the selected nodes
let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>();
// Select the new nodes
document.metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
responses.add(BroadcastEvent::SelectionChanged);
for (node_id, mut document_node) in copied_nodes {
@@ -642,24 +642,24 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
}
}
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
document.metadata.clear_selected_nodes();
metadata.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
for _ in 0..depth_of_nesting {
self.network.pop();
}
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
}
NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
warn!("No network");
return;
};
@@ -689,17 +689,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(PropertiesPanelMessage::Refresh);
}
NodeGraphMessage::InsertNode { node_id, document_node } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
network.nodes.insert(node_id, document_node);
}
}
NodeGraphMessage::MoveSelectedNodes { displacement_x, displacement_y } => {
let Some(network) = document.document_network.nested_network_mut(&self.network) else {
let Some(network) = document_network.nested_network_mut(&self.network) else {
warn!("No network");
return;
};
for node_id in document.metadata.selected_nodes() {
for node_id in metadata.selected_nodes() {
if let Some(node) = network.nodes.get_mut(node_id) {
node.metadata.position += IVec2::new(displacement_x, displacement_y)
}
@@ -707,7 +707,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
NodeGraphMessage::PasteNodes { serialized_nodes } => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
warn!("No network");
return;
};
@@ -755,20 +755,20 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path: Vec::new() }),
NodeGraphMessage::SelectedNodesAdd { nodes } => {
document.metadata.add_selected_nodes(nodes);
metadata.add_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged);
}
NodeGraphMessage::SelectedNodesRemove { nodes } => {
document.metadata.retain_selected_nodes(|node| !nodes.contains(node));
metadata.retain_selected_nodes(|node| !nodes.contains(node));
responses.add(BroadcastEvent::SelectionChanged);
}
NodeGraphMessage::SelectedNodesSet { nodes } => {
document.metadata.set_selected_nodes(nodes);
metadata.set_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged);
responses.add(PropertiesPanelMessage::Refresh);
}
NodeGraphMessage::SendGraph { should_rerender } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
if should_rerender {
if let Some(layer_path) = self.layer_path.clone() {
@@ -780,7 +780,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::SetInputValue { node_id, input_index, value } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
if let Some(node) = network.nodes.get(&node_id) {
responses.add(DocumentMessage::StartTransaction);
@@ -798,7 +798,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::SetNodeInput { node_id, input_index, input } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
if let Some(node) = network.nodes.get_mut(&node_id) {
let Some(node_input) = node.inputs.get_mut(input_index) else {
error!("Tried to set input {input_index} to {input:?}, but the index was invalid. Node {node_id}:\n{node:#?}");
@@ -807,7 +807,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let structure_changed = node_input.as_node().is_some() || input.as_node().is_some();
*node_input = input;
if structure_changed {
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, metadata, collapsed);
}
}
}
@@ -823,7 +823,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
return;
};
let network = document.document_network.nested_network_mut(node_path);
let network = document_network.nested_network_mut(node_path);
if let Some(network) = network {
if let Some(node) = network.nodes.get_mut(node_id) {
@@ -839,7 +839,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::ShiftNode { node_id } => {
let Some(network) = document.document_network.nested_network_mut(&self.network) else {
let Some(network) = document_network.nested_network_mut(&self.network) else {
warn!("No network");
return;
};
@@ -887,23 +887,23 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
}
NodeGraphMessage::ToggleSelectedHidden => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction);
let new_hidden = !document.metadata.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in document.metadata.selected_nodes() {
let new_hidden = !metadata.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in metadata.selected_nodes() {
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
}
}
}
NodeGraphMessage::ToggleHidden { node_id } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
let new_hidden = !network.disabled.contains(&node_id);
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
}
}
NodeGraphMessage::SetHidden { node_id, hidden } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
if !hidden {
network.disabled.retain(|&id| node_id != id);
} else if !network.inputs.contains(&node_id) && !network.original_outputs().iter().any(|output| output.node_id == node_id) {
@@ -916,14 +916,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::RunDocumentGraph);
}
}
self.update_selection_action_buttons(document, responses);
self.update_selection_action_buttons(document_network, metadata, responses);
}
NodeGraphMessage::SetName { node_id, name } => {
responses.add(DocumentMessage::StartTransaction);
responses.add(NodeGraphMessage::SetNameImpl { node_id, name });
}
NodeGraphMessage::SetNameImpl { node_id, name } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
if let Some(node) = network.nodes.get_mut(&node_id) {
node.alias = name;
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
@@ -935,7 +935,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::TogglePreviewImpl { node_id });
}
NodeGraphMessage::TogglePreviewImpl { node_id } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
// Check if the node is not already being previewed
if !network.outputs_contain(node_id) {
network.previous_outputs = Some(network.previous_outputs.to_owned().unwrap_or_else(|| network.outputs.clone()));
@@ -947,7 +947,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
self.update_selection_action_buttons(document, responses);
self.update_selection_action_buttons(document_network, metadata, responses);
if let Some(layer_path) = self.layer_path.clone() {
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
} else {
@@ -955,8 +955,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::UpdateNewNodeGraph => {
if let Some(network) = document.document_network.nested_network(&self.network) {
document.metadata.clear_selected_nodes();
if let Some(network) = document_network.nested_network(&self.network) {
metadata.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
@@ -964,10 +964,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let node_types = document_node_types::collect_node_types();
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
}
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
}
}
self.has_selection = document.metadata.has_selected_nodes();
self.has_selection = metadata.has_selected_nodes();
}
fn actions(&self) -> ActionList {

View File

@@ -1,11 +1,15 @@
use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::Message;
use crate::node_graph_executor::NodeGraphExecutor;
use graph_craft::concrete;
use graph_craft::document::value::*;
use graph_craft::document::*;
use graph_craft::document::{value::*, DocumentNodeMetadata};
use graph_craft::imaginate_input::ImaginateSamplingMethod;
use graph_craft::ProtoNodeIdentifier;
#[cfg(feature = "gpu")]
@@ -68,13 +72,13 @@ impl DocumentOutputType {
}
pub struct NodePropertiesContext<'a> {
pub persistent_data: &'a crate::messages::portfolio::utility_types::PersistentData,
pub document: &'a document_legacy::document::Document,
pub responses: &'a mut VecDeque<crate::messages::prelude::Message>,
pub layer_path: &'a [document_legacy::document::LayerId],
pub persistent_data: &'a PersistentData,
pub responses: &'a mut VecDeque<Message>,
pub layer_path: &'a [LayerId],
pub nested_path: &'a [NodeId],
pub executor: &'a mut NodeGraphExecutor,
pub network: &'a NodeNetwork,
pub metadata: &'a mut DocumentMetadata,
}
#[derive(Clone)]
@@ -2493,7 +2497,7 @@ impl DocumentNodeDefinition {
}
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], based on the inputs from the graph (which must be the correct length) and the metadata
pub fn to_document_node(&self, inputs: impl IntoIterator<Item = NodeInput>, metadata: graph_craft::document::DocumentNodeMetadata) -> DocumentNode {
pub fn to_document_node(&self, inputs: impl IntoIterator<Item = NodeInput>, document_metadata: DocumentNodeMetadata) -> DocumentNode {
let inputs: Vec<_> = inputs.into_iter().collect();
assert_eq!(inputs.len(), self.inputs.len(), "Inputs passed from the graph must be equal to the number required");
DocumentNode {
@@ -2501,7 +2505,7 @@ impl DocumentNodeDefinition {
inputs,
has_primary_output: self.has_primary_output,
implementation: self.generate_implementation(),
metadata,
metadata: document_metadata,
manual_composition: self.manual_composition.clone(),
..Default::default()
}
@@ -2509,10 +2513,10 @@ impl DocumentNodeDefinition {
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], using the provided `input_override` and falling back to the default inputs.
/// `input_override` does not have to be the correct length.
pub fn to_document_node_default_inputs(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>, metadata: graph_craft::document::DocumentNodeMetadata) -> DocumentNode {
pub fn to_document_node_default_inputs(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>, document_metadata: DocumentNodeMetadata) -> DocumentNode {
let mut input_override = input_override.into_iter();
let inputs = self.inputs.iter().map(|default| input_override.next().unwrap_or_default().unwrap_or_else(|| default.default.clone()));
self.to_document_node(inputs, metadata)
self.to_document_node(inputs, document_metadata)
}
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], completely default

View File

@@ -26,7 +26,7 @@ pub fn overlay_canvas_context() -> web_sys::CanvasRenderingContext2d {
pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext) {
for layer in document.metadata().selected_layers() {
let Some(subpaths) = get_subpaths(layer, &document.document_legacy) else { continue };
let Some(subpaths) = get_subpaths(layer, &document.network) else { continue };
let transform = document.metadata().transform_to_viewport(layer);
let selected = shape_editor.selected_shape_state.get(&layer);
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));

View File

@@ -15,10 +15,11 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
use PropertiesPanelMessage::*;
let PropertiesPanelMessageHandlerData {
document_name,
artwork_document,
node_graph_message_handler,
executor,
document_network,
document_metadata,
document_name,
..
} = data;
@@ -36,12 +37,12 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
Refresh => {
let mut context = NodePropertiesContext {
persistent_data,
document: artwork_document,
responses,
nested_path: &node_graph_message_handler.network,
layer_path: &[],
executor,
network: &artwork_document.document_network,
network: document_network,
metadata: document_metadata,
};
let properties_sections = node_graph_message_handler.collate_properties(&mut context);

View File

@@ -1,11 +1,14 @@
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::NodeGraphMessageHandler;
use crate::node_graph_executor::NodeGraphExecutor;
use crate::{messages::prelude::NodeGraphMessageHandler, node_graph_executor::NodeGraphExecutor};
use graph_craft::document::NodeNetwork;
pub struct PropertiesPanelMessageHandlerData<'a> {
pub document_name: &'a str,
pub artwork_document: &'a DocumentLegacy,
pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub selected_layers: &'a mut dyn Iterator<Item = &'a [LayerId]>,
pub node_graph_message_handler: &'a NodeGraphMessageHandler,
pub executor: &'a mut NodeGraphExecutor,

View File

@@ -8,6 +8,10 @@ use glam::{DAffine2, DVec2};
use std::collections::{HashMap, HashSet};
use std::num::NonZeroU64;
// ================
// DocumentMetadata
// ================
#[derive(Debug, Clone)]
pub struct DocumentMetadata {
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
@@ -33,9 +37,11 @@ impl Default for DocumentMetadata {
}
}
}
pub struct SelectionChanged;
// layer iters
// =================================
// DocumentMetadata: Layer iterators
// =================================
impl DocumentMetadata {
/// Get the root layer from the document
pub const fn root(&self) -> LayerNodeIdentifier {
@@ -152,7 +158,10 @@ impl DocumentMetadata {
}
}
// selected layer modifications
// ==============================================
// DocumentMetadata: Selected layer modifications
// ==============================================
impl DocumentMetadata {
pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
self.selected_nodes.retain(f);
@@ -172,6 +181,10 @@ impl DocumentMetadata {
/// Loads the structure of layer nodes from a node graph.
pub fn load_structure(&mut self, graph: &NodeNetwork) {
fn first_child_layer<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
graph.upstream_flow_back_from_nodes(vec![node.inputs[0].as_node()?], true).find(|(node, _)| node.is_layer())
}
self.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]);
self.folders = HashSet::new();
self.artboards = HashSet::new();
@@ -204,7 +217,9 @@ impl DocumentMetadata {
}
}
current = sibling_below(graph, current_node);
// Get the sibling below
let construct_layer_node = &current_node.inputs[1];
current = construct_layer_node.as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.is_layer()).map(|node| (node, id)));
}
}
@@ -214,16 +229,10 @@ impl DocumentMetadata {
}
}
fn first_child_layer<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
graph.upstream_flow_back_from_nodes(vec![node.inputs[0].as_node()?], true).find(|(node, _)| node.is_layer())
}
// ============================
// DocumentMetadata: Transforms
// ============================
fn sibling_below<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
let construct_layer_node = &node.inputs[1];
construct_layer_node.as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.is_layer()).map(|node| (node, id)))
}
// transforms
impl DocumentMetadata {
/// Update the cached transforms of the layers
pub fn update_transforms(&mut self, new_upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>) {
@@ -258,19 +267,10 @@ impl DocumentMetadata {
}
}
pub fn is_artboard(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
network.upstream_flow_back_from_nodes(vec![layer.to_node()], true).any(|(node, _)| node.is_artboard())
}
// ===============================
// DocumentMetadata: Click targets
// ===============================
pub fn is_folder(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
network.nodes.get(&layer.to_node()).and_then(|node| node.inputs.first()).is_some_and(|input| input.as_node().is_none())
|| network
.upstream_flow_back_from_nodes(vec![layer.to_node()], true)
.skip(1)
.any(|(node, _)| node.is_artboard() || node.is_layer())
}
// click targets
impl DocumentMetadata {
/// Update the cached click targets of the layers
pub fn update_click_targets(&mut self, new_click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>) {
@@ -341,7 +341,11 @@ impl DocumentMetadata {
}
}
/// Id of a layer node
// ===================
// LayerNodeIdentifier
// ===================
/// ID of a layer node
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct LayerNodeIdentifier(NonZeroU64);
@@ -558,12 +562,16 @@ impl LayerNodeIdentifier {
}
}
// ========
// AxisIter
// ========
/// Iterator over specified axis.
#[derive(Clone)]
pub struct AxisIter<'a> {
layer_node: Option<LayerNodeIdentifier>,
next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>,
document_metadata: &'a DocumentMetadata,
pub layer_node: Option<LayerNodeIdentifier>,
pub next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>,
pub document_metadata: &'a DocumentMetadata,
}
impl<'a> Iterator for AxisIter<'a> {
@@ -576,6 +584,10 @@ impl<'a> Iterator for AxisIter<'a> {
}
}
// ==============
// DecendantsIter
// ==============
#[derive(Clone)]
pub struct DecendantsIter<'a> {
front: Option<LayerNodeIdentifier>,
@@ -620,8 +632,12 @@ impl<'a> DoubleEndedIterator for DecendantsIter<'a> {
}
}
// =============
// NodeRelations
// =============
#[derive(Debug, Clone, Copy, Default)]
pub struct NodeRelations {
struct NodeRelations {
parent: Option<LayerNodeIdentifier>,
previous_sibling: Option<LayerNodeIdentifier>,
next_sibling: Option<LayerNodeIdentifier>,
@@ -629,6 +645,22 @@ pub struct NodeRelations {
last_child: Option<LayerNodeIdentifier>,
}
// ================
// Helper functions
// ================
pub fn is_artboard(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
network.upstream_flow_back_from_nodes(vec![layer.to_node()], true).any(|(node, _)| node.is_artboard())
}
pub fn is_folder(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
network.nodes.get(&layer.to_node()).and_then(|node| node.inputs.first()).is_some_and(|input| input.as_node().is_none())
|| network
.upstream_flow_back_from_nodes(vec![layer.to_node()], true)
.skip(1)
.any(|(node, _)| node.is_artboard() || node.is_layer())
}
#[test]
fn test_tree() {
let mut document_metadata = DocumentMetadata::default();

View File

@@ -1,4 +1,4 @@
use document_legacy::document::LayerId;
use crate::messages::portfolio::document::utility_types::LayerId;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
@@ -29,18 +29,6 @@ impl Serialize for JsRawBuffer {
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Copy, specta::Type)]
pub struct LayerMetadata {
pub selected: bool,
pub expanded: bool,
}
impl LayerMetadata {
pub fn new(expanded: bool) -> Self {
Self { selected: false, expanded }
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub enum LayerClassification {
#[default]
@@ -55,8 +43,8 @@ pub struct LayerPanelEntry {
pub tooltip: String,
#[serde(rename = "layerClassification")]
pub layer_classification: LayerClassification,
#[serde(rename = "layerMetadata")]
pub layer_metadata: LayerMetadata,
pub selected: bool,
pub expanded: bool,
pub path: Vec<LayerId>,
pub thumbnail: String,
}

View File

@@ -1,18 +1,11 @@
pub use super::layer_panel::{LayerMetadata, LayerPanelEntry};
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
pub use super::layer_panel::LayerPanelEntry;
use crate::messages::portfolio::document::utility_types::LayerId;
use graphene_core::raster::color::Color;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct DocumentSave {
pub document: DocumentLegacy,
pub layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash)]
pub enum FlipAxis {
X,
@@ -32,8 +25,9 @@ pub enum AlignAggregate {
Center,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
pub enum DocumentMode {
#[default]
DesignMode,
SelectMode,
GuideMode,

View File

@@ -1,6 +1,11 @@
pub mod clipboards;
pub mod document_metadata;
pub mod error;
pub mod layer_panel;
pub mod misc;
pub mod transformation;
pub mod vectorize_layer_metadata;
// TODO: Remove this entirely
/// A number that identifies a layer.
/// This does not technically need to be unique globally, only within a folder.
pub type LayerId = u64;

View File

@@ -1,12 +1,12 @@
use crate::consts::{ROTATE_SNAP_ANGLE, SCALE_SNAP_INTERVAL};
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
use crate::messages::tool::utility_types::ToolType;
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graphene_core::renderer::Quad;
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -31,12 +31,12 @@ impl OriginalTransforms {
}
}
pub fn update<'a>(&mut self, selected: &'a [LayerNodeIdentifier], document: &'a Document, shape_editor: Option<&'a ShapeState>) {
pub fn update<'a>(&mut self, selected: &'a [LayerNodeIdentifier], document_network: &NodeNetwork, document_metadata: &DocumentMetadata, shape_editor: Option<&'a ShapeState>) {
match self {
OriginalTransforms::Layer(layer_map) => {
layer_map.retain(|layer, _| selected.contains(layer));
for &layer in selected {
layer_map.entry(layer).or_insert_with(|| document.metadata.upstream_transform(layer.to_node()));
layer_map.entry(layer).or_insert_with(|| document_metadata.upstream_transform(layer.to_node()));
}
}
OriginalTransforms::Path(path_map) => {
@@ -61,7 +61,7 @@ impl OriginalTransforms {
if path_map.contains_key(&layer) {
continue;
}
let Some(vector_data) = graph_modification_utils::get_subpaths(layer, document) else {
let Some(vector_data) = graph_modification_utils::get_subpaths(layer, document_network) else {
continue;
};
let get_manipulator_point_position = |point_id: ManipulatorPointId| {
@@ -312,7 +312,8 @@ impl TransformOperation {
pub struct Selected<'a> {
pub selected: &'a [LayerNodeIdentifier],
pub responses: &'a mut VecDeque<Message>,
pub document: &'a Document,
pub document_network: &'a NodeNetwork,
pub document_metadata: &'a DocumentMetadata,
pub original_transforms: &'a mut OriginalTransforms,
pub pivot: &'a mut DVec2,
pub shape_editor: Option<&'a ShapeState>,
@@ -325,7 +326,8 @@ impl<'a> Selected<'a> {
pivot: &'a mut DVec2,
selected: &'a [LayerNodeIdentifier],
responses: &'a mut VecDeque<Message>,
document: &'a Document,
document_network: &'a NodeNetwork,
document_metadata: &'a DocumentMetadata,
shape_editor: Option<&'a ShapeState>,
tool_type: &'a ToolType,
) -> Self {
@@ -334,12 +336,13 @@ impl<'a> Selected<'a> {
*original_transforms = OriginalTransforms::Layer(HashMap::new());
}
original_transforms.update(selected, document, shape_editor);
original_transforms.update(selected, document_network, document_metadata, shape_editor);
Self {
selected,
responses,
document,
document_network,
document_metadata,
original_transforms,
pivot,
shape_editor,
@@ -351,7 +354,7 @@ impl<'a> Selected<'a> {
let xy_summation = self
.selected
.iter()
.map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.document))
.map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.document_network, self.document_metadata))
.reduce(|a, b| a + b)
.unwrap_or_default();
@@ -362,15 +365,15 @@ impl<'a> Selected<'a> {
let [min, max] = self
.selected
.iter()
.filter_map(|&layer| self.document.metadata.bounding_box_viewport(layer))
.filter_map(|&layer| self.document_metadata.bounding_box_viewport(layer))
.reduce(Quad::combine_bounds)
.unwrap_or_default();
(min + max) / 2.
}
fn transform_layer(document: &Document, layer: LayerNodeIdentifier, original_transform: Option<&DAffine2>, transformation: DAffine2, responses: &mut VecDeque<Message>) {
fn transform_layer(document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier, original_transform: Option<&DAffine2>, transformation: DAffine2, responses: &mut VecDeque<Message>) {
let Some(&original_transform) = original_transform else { return };
let to = document.metadata.downstream_transform_to_viewport(layer);
let to = document_metadata.downstream_transform_to_viewport(layer);
let new = to.inverse() * transformation * to * original_transform;
responses.add(GraphOperationMessage::TransformSet {
layer: layer.to_path(),
@@ -380,8 +383,14 @@ impl<'a> Selected<'a> {
});
}
fn transform_path(document: &Document, layer: LayerNodeIdentifier, initial_points: Option<&Vec<(ManipulatorPointId, DVec2)>>, transformation: DAffine2, responses: &mut VecDeque<Message>) {
let viewspace = document.metadata.transform_to_viewport(layer);
fn transform_path(
document_metadata: &DocumentMetadata,
layer: LayerNodeIdentifier,
initial_points: Option<&Vec<(ManipulatorPointId, DVec2)>>,
transformation: DAffine2,
responses: &mut VecDeque<Message>,
) {
let viewspace = document_metadata.transform_to_viewport(layer);
let layerspace_rotation = viewspace.inverse() * transformation;
let Some(initial_points) = initial_points else {
@@ -404,12 +413,12 @@ impl<'a> Selected<'a> {
pub fn apply_transformation(&mut self, transformation: DAffine2) {
if !self.selected.is_empty() {
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
for layer_ancestors in self.document.metadata.shallowest_unique_layers(self.selected.iter().copied()) {
for layer_ancestors in self.document_metadata.shallowest_unique_layers(self.selected.iter().copied()) {
let layer = *layer_ancestors.last().unwrap();
match &self.original_transforms {
OriginalTransforms::Layer(layer_transforms) => Self::transform_layer(self.document, layer, layer_transforms.get(&layer), transformation, self.responses),
OriginalTransforms::Path(path_transforms) => Self::transform_path(self.document, layer, path_transforms.get(&layer), transformation, self.responses),
OriginalTransforms::Layer(layer_transforms) => Self::transform_layer(self.document_metadata, layer, layer_transforms.get(&layer), transformation, self.responses),
OriginalTransforms::Path(path_transforms) => Self::transform_path(&self.document_metadata, layer, path_transforms.get(&layer), transformation, self.responses),
}
}
self.responses.add(BroadcastEvent::DocumentIsDirty);

View File

@@ -1,25 +0,0 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::iter::FromIterator;
/// Necessary because serde can't serialize hashmaps when the keys don't implement display.
pub fn serialize<'a, T, K, V, S>(target: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: IntoIterator<Item = (&'a K, &'a V)>,
K: Serialize + 'a,
V: Serialize + 'a,
{
let container: Vec<_> = target.into_iter().collect();
serde::Serialize::serialize(&container, serializer)
}
pub fn deserialize<'de, T, K, V, D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromIterator<(K, V)>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
let container: Vec<_> = serde::Deserialize::deserialize(deserializer)?;
Ok(T::from_iter(container))
}

View File

@@ -1,8 +1,8 @@
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::text::Font;
use serde::{Deserialize, Serialize};

View File

@@ -676,10 +676,8 @@ impl PortfolioMessageHandler {
return;
};
self.executor
.poll_node_graph_evaluation(&mut active_document.document_legacy, &mut active_document.collapsed_folders, responses)
.unwrap_or_else(|e| {
log::error!("Error while evaluating node graph: {e}");
});
self.executor.poll_node_graph_evaluation(active_document, responses).unwrap_or_else(|e| {
log::error!("Error while evaluating node graph: {e}");
});
}
}

View File

@@ -1,8 +1,8 @@
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::prelude::*;
use bezier_rs::{ManipulatorGroup, Subpath};
use document_legacy::{document::Document, document_metadata::LayerNodeIdentifier};
use graph_craft::document::{value::TaggedValue, DocumentNode, NodeId, NodeInput, NodeNetwork};
use graphene_core::raster::{BlendMode, ImageFrame};
use graphene_core::text::Font;
@@ -48,8 +48,8 @@ pub fn set_manipulator_mirror_angle(manipulator_groups: &[ManipulatorGroup<Manip
}
/// Locate the subpaths from the shape nodes of a particular layer
pub fn get_subpaths(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<Subpath<ManipulatorGroupId>>> {
if let TaggedValue::Subpaths(subpaths) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 0)? {
pub fn get_subpaths(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<&Vec<Subpath<ManipulatorGroupId>>> {
if let TaggedValue::Subpaths(subpaths) = NodeGraphLayer::new(layer, document_network)?.find_input("Shape", 0)? {
Some(subpaths)
} else {
None
@@ -57,23 +57,23 @@ pub fn get_subpaths(layer: LayerNodeIdentifier, document: &Document) -> Option<&
}
/// Locate the final pivot from the transform (TODO: decide how the pivot should actually work)
pub fn get_pivot(layer: LayerNodeIdentifier, document: &Document) -> Option<DVec2> {
if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, document)?.find_input("Transform", 5)? {
pub fn get_pivot(layer: LayerNodeIdentifier, network: &NodeNetwork) -> Option<DVec2> {
if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network)?.find_input("Transform", 5)? {
Some(*pivot)
} else {
None
}
}
pub fn get_viewport_pivot(layer: LayerNodeIdentifier, document: &Document) -> DVec2 {
let [min, max] = document.metadata.nonzero_bounding_box(layer);
let pivot = get_pivot(layer, document).unwrap_or(DVec2::splat(0.5));
document.metadata.transform_to_viewport(layer).transform_point2(min + (max - min) * pivot)
pub fn get_viewport_pivot(layer: LayerNodeIdentifier, document_network: &NodeNetwork, document_metadata: &DocumentMetadata) -> DVec2 {
let [min, max] = document_metadata.nonzero_bounding_box(layer);
let pivot = get_pivot(layer, document_network).unwrap_or(DVec2::splat(0.5));
document_metadata.transform_to_viewport(layer).transform_point2(min + (max - min) * pivot)
}
/// Get the currently mirrored handles for a particular layer from the shape node
pub fn get_mirror_handles(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<ManipulatorGroupId>> {
if let TaggedValue::ManipulatorGroupIds(mirror_handles) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 1)? {
pub fn get_mirror_handles(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<&Vec<ManipulatorGroupId>> {
if let TaggedValue::ManipulatorGroupIds(mirror_handles) = NodeGraphLayer::new(layer, document_network)?.find_input("Shape", 1)? {
Some(mirror_handles)
} else {
None
@@ -81,8 +81,8 @@ pub fn get_mirror_handles(layer: LayerNodeIdentifier, document: &Document) -> Op
}
/// Get the current gradient of a layer from the closest Fill node
pub fn get_gradient(layer: LayerNodeIdentifier, document: &Document) -> Option<Gradient> {
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Fill")?;
pub fn get_gradient(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<Gradient> {
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Fill")?;
let TaggedValue::FillType(FillType::Gradient) = inputs.get(1)?.as_value()? else {
return None;
};
@@ -111,8 +111,8 @@ pub fn get_gradient(layer: LayerNodeIdentifier, document: &Document) -> Option<G
}
/// Get the current fill of a layer from the closest Fill node
pub fn get_fill_color(layer: LayerNodeIdentifier, document: &Document) -> Option<Color> {
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Fill")?;
pub fn get_fill_color(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<Color> {
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Fill")?;
let TaggedValue::Color(color) = inputs.get(2)?.as_value()? else {
return None;
};
@@ -120,8 +120,8 @@ pub fn get_fill_color(layer: LayerNodeIdentifier, document: &Document) -> Option
}
/// Get the current blend mode of a layer from the closest Blend Mode node
pub fn get_blend_mode(layer: LayerNodeIdentifier, document: &Document) -> Option<BlendMode> {
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Blend Mode")?;
pub fn get_blend_mode(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<BlendMode> {
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Blend Mode")?;
let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else {
return None;
};
@@ -135,25 +135,25 @@ pub fn get_blend_mode(layer: LayerNodeIdentifier, document: &Document) -> Option
/// - Already factored into the pixel alpha channel of an image
/// - The default value of 100% if no Opacity node is present, but this function returns None in that case
/// With those limitations in mind, the intention of this function is to show just the value already present in an upstream Opacity node so that value can be directly edited.
pub fn get_opacity(layer: LayerNodeIdentifier, document: &Document) -> Option<f32> {
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Opacity")?;
pub fn get_opacity(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<f32> {
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Opacity")?;
let TaggedValue::F32(opacity) = inputs.get(1)?.as_value()? else {
return None;
};
Some(*opacity)
}
pub fn get_fill_id(layer: LayerNodeIdentifier, document: &Document) -> Option<NodeId> {
NodeGraphLayer::new(layer, document)?.node_id("Fill")
pub fn get_fill_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<NodeId> {
NodeGraphLayer::new(layer, document_network)?.node_id("Fill")
}
pub fn get_text_id(layer: LayerNodeIdentifier, document: &Document) -> Option<NodeId> {
NodeGraphLayer::new(layer, document)?.node_id("Text")
pub fn get_text_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<NodeId> {
NodeGraphLayer::new(layer, document_network)?.node_id("Text")
}
/// Gets properties from the Text node
pub fn get_text(layer: LayerNodeIdentifier, document: &Document) -> Option<(&String, &Font, f64)> {
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Text")?;
pub fn get_text(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<(&String, &Font, f64)> {
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Text")?;
let NodeInput::Value {
tagged_value: TaggedValue::String(text),
..
@@ -182,8 +182,8 @@ pub fn get_text(layer: LayerNodeIdentifier, document: &Document) -> Option<(&Str
}
/// Checks if a specified layer uses an upstream node matching the given name.
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, document: &Document, node_name: &str) -> bool {
NodeGraphLayer::new(layer, document).is_some_and(|layer| layer.find_node_inputs(node_name).is_some())
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, document_network: &NodeNetwork, node_name: &str) -> bool {
NodeGraphLayer::new(layer, document_network).is_some_and(|layer| layer.find_node_inputs(node_name).is_some())
}
/// Convert subpaths to an iterator of manipulator groups
@@ -205,12 +205,11 @@ pub struct NodeGraphLayer<'a> {
impl<'a> NodeGraphLayer<'a> {
/// Get the layer node from the document
pub fn new(layer: LayerNodeIdentifier, document: &'a document_legacy::document::Document) -> Option<Self> {
let node_graph = &document.document_network;
let outwards_links = document.document_network.collect_outwards_links();
pub fn new(layer: LayerNodeIdentifier, network: &'a NodeNetwork) -> Option<Self> {
let outwards_links = network.collect_outwards_links();
Some(Self {
node_graph,
node_graph: network,
_outwards_links: outwards_links,
layer_node: layer.to_node(),
})

View File

@@ -4,10 +4,9 @@ use super::graph_modification_utils;
use crate::consts::PIVOT_OUTER;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
use document_legacy::document_metadata::LayerNodeIdentifier;
use glam::{DAffine2, DVec2};
use std::collections::VecDeque;
@@ -46,7 +45,7 @@ impl Pivot {
/// Recomputes the pivot position and transform.
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
let mut layers = document.document_legacy.selected_visible_layers();
let mut layers = document.selected_visible_layers();
let Some(first) = layers.next() else {
// If no layers are selected then we revert things back to default
self.normalized_pivot = DVec2::splat(0.5);
@@ -59,22 +58,21 @@ impl Pivot {
// If just one layer is selected we can use its inner transform (as it accounts for rotation)
if selected_layers_count == 1 {
let normalized_pivot = graph_modification_utils::get_pivot(first, &document.document_legacy).unwrap_or(DVec2::splat(0.5));
let normalized_pivot = graph_modification_utils::get_pivot(first, &document.network).unwrap_or(DVec2::splat(0.5));
self.normalized_pivot = normalized_pivot;
self.transform_from_normalized = Self::get_layer_pivot_transform(first, document);
self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot));
} else {
// If more than one layer is selected we use the AABB with the mean of the pivots
let xy_summation = document
.document_legacy
.selected_visible_layers()
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.document_legacy))
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.metadata))
.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.document_legacy.selected_visible_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]);
let [min, max] = document.selected_visible_layers_bounding_box_viewport().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);
@@ -102,7 +100,7 @@ impl Pivot {
/// Sets the viewport position of the pivot for all selected layers.
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
for layer in document.document_legacy.selected_visible_layers() {
for layer in document.selected_visible_layers() {
let transform = Self::get_layer_pivot_transform(layer, document);
let pivot = transform.inverse().transform_point2(position);
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.

View File

@@ -1,10 +1,9 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use document_legacy::document_metadata::LayerNodeIdentifier;
use glam::{DAffine2, DVec2, Vec2Swizzles};
#[derive(Clone, Debug, Default)]

View File

@@ -1,12 +1,12 @@
use super::graph_modification_utils;
use crate::consts::DRAG_THRESHOLD;
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils::{get_manipulator_from_id, get_manipulator_groups, get_mirror_handles, get_subpaths};
use bezier_rs::{Bezier, ManipulatorGroup, TValue};
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graphene_core::uuid::ManipulatorGroupId;
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -66,15 +66,22 @@ pub type OpposingHandleLengths = HashMap<LayerNodeIdentifier, HashMap<Manipulato
impl ShapeState {
/// Select the first point within the selection threshold.
/// Returns a tuple of the points if found and the offset, or `None` otherwise.
pub fn select_point(&mut self, document: &Document, mouse_position: DVec2, select_threshold: f64, add_to_selection: bool) -> Option<SelectedPointsInfo> {
pub fn select_point(
&mut self,
document_network: &NodeNetwork,
document_metadata: &DocumentMetadata,
mouse_position: DVec2,
select_threshold: f64,
add_to_selection: bool,
) -> Option<SelectedPointsInfo> {
if self.selected_shape_state.is_empty() {
return None;
}
if let Some((layer, manipulator_point_id)) = self.find_nearest_point_indices(document, mouse_position, select_threshold) {
if let Some((layer, manipulator_point_id)) = self.find_nearest_point_indices(document_network, document_metadata, mouse_position, select_threshold) {
trace!("Selecting... manipulator point: {manipulator_point_id:?}");
let subpaths = get_subpaths(layer, document)?;
let subpaths = get_subpaths(layer, document_network)?;
let manipulator_group = get_manipulator_groups(subpaths).find(|group| group.id == manipulator_point_id.group)?;
let point_position = manipulator_point_id.manipulator_type.get_position(manipulator_group)?;
@@ -96,7 +103,7 @@ impl ShapeState {
selected_shape_state.select_point(manipulator_point_id);
// Offset to snap the selected point to the cursor
let offset = mouse_position - document.metadata.transform_to_viewport(layer).transform_point2(point_position);
let offset = mouse_position - document_metadata.transform_to_viewport(layer).transform_point2(point_position);
let points = self
.selected_shape_state
@@ -115,9 +122,9 @@ impl ShapeState {
None
}
pub fn select_all_points(&mut self, document: &Document) {
pub fn select_all_points(&mut self, document_network: &NodeNetwork) {
for (layer, state) in self.selected_shape_state.iter_mut() {
let Some(subpaths) = get_subpaths(*layer, document) else { return };
let Some(subpaths) = get_subpaths(*layer, document_network) else { return };
for manipulator in get_manipulator_groups(subpaths) {
state.select_point(ManipulatorPointId::new(manipulator.id, SelectedType::Anchor));
for selected_type in &[SelectedType::InHandle, SelectedType::OutHandle] {
@@ -148,13 +155,13 @@ impl ShapeState {
}
/// A mutable iterator of all the manipulators, regardless of selection.
pub fn manipulator_groups<'a>(&'a self, document: &'a Document) -> impl Iterator<Item = &'a ManipulatorGroup<ManipulatorGroupId>> {
self.iter(document).flat_map(|subpaths| get_manipulator_groups(subpaths))
pub fn manipulator_groups<'a>(&'a self, document_network: &'a NodeNetwork) -> impl Iterator<Item = &'a ManipulatorGroup<ManipulatorGroupId>> {
self.iter(document_network).flat_map(|subpaths| get_manipulator_groups(subpaths))
}
// Sets the selected points to all points for the corresponding intersection
pub fn select_all_anchors(&mut self, document: &Document, layer: LayerNodeIdentifier) {
let Some(subpaths) = get_subpaths(layer, document) else { return };
pub fn select_all_anchors(&mut self, document_network: &NodeNetwork, layer: LayerNodeIdentifier) {
let Some(subpaths) = get_subpaths(layer, document_network) else { return };
let Some(state) = self.selected_shape_state.get_mut(&layer) else { return };
for manipulator in get_manipulator_groups(subpaths) {
state.select_point(ManipulatorPointId::new(manipulator.id, SelectedType::Anchor))
@@ -168,9 +175,17 @@ impl ShapeState {
/// Moves a control point to a `new_position` in document space.
/// Returns `Some(())` if successful and `None` otherwise.
pub fn reposition_control_point(&self, point: &ManipulatorPointId, responses: &mut VecDeque<Message>, document: &Document, new_position: DVec2, layer: LayerNodeIdentifier) -> Option<()> {
let subpaths = get_subpaths(layer, document)?;
let transform = document.metadata.transform_to_viewport(layer).inverse();
pub fn reposition_control_point(
&self,
point: &ManipulatorPointId,
responses: &mut VecDeque<Message>,
document_network: &NodeNetwork,
document_metadata: &DocumentMetadata,
new_position: DVec2,
layer: LayerNodeIdentifier,
) -> Option<()> {
let subpaths = get_subpaths(layer, document_network)?;
let transform = document_metadata.transform_to_viewport(layer).inverse();
let position = transform.transform_point2(new_position);
let group = graph_modification_utils::get_manipulator_from_id(subpaths, point.group)?;
let delta = position - point.manipulator_type.get_position(group)?;
@@ -203,12 +218,12 @@ impl ShapeState {
// Iterates over the selected manipulator groups, returning whether they have mixed, sharp, or smooth angles.
// If there are no points selected this function returns mixed.
pub fn selected_manipulator_angles(&self, document: &Document) -> ManipulatorAngle {
pub fn selected_manipulator_angles(&self, document_network: &NodeNetwork) -> ManipulatorAngle {
// This iterator contains a bool indicating whether or not every selected point has a smooth manipulator angle.
let mut point_smoothness_status = self
.selected_shape_state
.iter()
.filter_map(|(&layer, selection_state)| Some((graph_modification_utils::get_mirror_handles(layer, document)?, selection_state)))
.filter_map(|(&layer, selection_state)| Some((graph_modification_utils::get_mirror_handles(layer, document_network)?, selection_state)))
.flat_map(|(mirror, selection_state)| selection_state.selected_points.iter().map(|selected_point| mirror.contains(&selected_point.group)));
let Some(first_is_smooth) = point_smoothness_status.next() else { return ManipulatorAngle::Mixed };
@@ -291,11 +306,11 @@ impl ShapeState {
}
/// Smooths the set of selected control points, assuming that the selected set is homogeneously sharp.
pub fn smooth_selected_groups(&self, responses: &mut VecDeque<Message>, document: &Document) -> Option<()> {
pub fn smooth_selected_groups(&self, responses: &mut VecDeque<Message>, document_network: &NodeNetwork) -> Option<()> {
let mut skip_set = HashSet::new();
for (&layer, layer_state) in self.selected_shape_state.iter() {
let subpaths = get_subpaths(layer, document)?;
let subpaths = get_subpaths(layer, document_network)?;
for point in layer_state.selected_points.iter() {
if skip_set.contains(&point.group) {
@@ -357,12 +372,12 @@ impl ShapeState {
}
/// Move the selected points by dragging the mouse.
pub fn move_selected_points(&self, document: &Document, delta: DVec2, mirror_distance: bool, responses: &mut VecDeque<Message>) {
pub fn move_selected_points(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, delta: DVec2, mirror_distance: bool, responses: &mut VecDeque<Message>) {
for (&layer, state) in &self.selected_shape_state {
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document) else { continue };
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document_network) else { continue };
let transform = document.metadata.transform_to_viewport(layer);
let transform = document_metadata.transform_to_viewport(layer);
let delta = transform.inverse().transform_vector2(delta);
for &point in state.selected_points.iter() {
@@ -423,14 +438,20 @@ impl ShapeState {
}
/// Delete selected and mirrored handles with zero length when the drag stops.
pub fn delete_selected_handles_with_zero_length(&self, document: &Document, opposing_handle_lengths: &Option<OpposingHandleLengths>, responses: &mut VecDeque<Message>) {
pub fn delete_selected_handles_with_zero_length(
&self,
document_network: &NodeNetwork,
document_metadata: &DocumentMetadata,
opposing_handle_lengths: &Option<OpposingHandleLengths>,
responses: &mut VecDeque<Message>,
) {
for (&layer, state) in &self.selected_shape_state {
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document) else { continue };
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document_network) else { continue };
let opposing_handle_lengths = opposing_handle_lengths.as_ref().and_then(|lengths| lengths.get(&layer));
let transform = document.metadata.transform_to_viewport(layer);
let transform = document_metadata.transform_to_viewport(layer);
for &point in state.selected_points.iter() {
let anchor = ManipulatorPointId::new(point.group, SelectedType::Anchor);
@@ -472,11 +493,11 @@ impl ShapeState {
}
/// The opposing handle lengths.
pub fn opposing_handle_lengths(&self, document: &Document) -> OpposingHandleLengths {
pub fn opposing_handle_lengths(&self, document_network: &NodeNetwork) -> OpposingHandleLengths {
self.selected_shape_state
.iter()
.filter_map(|(&layer, state)| {
let subpaths = get_subpaths(layer, document)?;
let subpaths = get_subpaths(layer, document_network)?;
let opposing_handle_lengths = subpaths
.iter()
.flat_map(|subpath| {
@@ -514,10 +535,10 @@ impl ShapeState {
}
/// Reset the opposing handle lengths.
pub fn reset_opposing_handle_lengths(&self, document: &Document, opposing_handle_lengths: &OpposingHandleLengths, responses: &mut VecDeque<Message>) {
pub fn reset_opposing_handle_lengths(&self, document_network: &NodeNetwork, opposing_handle_lengths: &OpposingHandleLengths, responses: &mut VecDeque<Message>) {
for (&layer, state) in &self.selected_shape_state {
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document) else { continue };
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
let Some(mirror_angle) = get_mirror_handles(layer, document_network) else { continue };
let Some(opposing_handle_lengths) = opposing_handle_lengths.get(&layer) else { continue };
for subpath in subpaths {
@@ -610,12 +631,18 @@ impl ShapeState {
}
/// Iterate over the shapes.
pub fn iter<'a>(&'a self, document: &'a Document) -> impl Iterator<Item = &'a Vec<bezier_rs::Subpath<ManipulatorGroupId>>> + 'a {
self.selected_shape_state.keys().filter_map(|&layer| get_subpaths(layer, document))
pub fn iter<'a>(&'a self, document_network: &'a NodeNetwork) -> impl Iterator<Item = &'a Vec<bezier_rs::Subpath<ManipulatorGroupId>>> + 'a {
self.selected_shape_state.keys().filter_map(|&layer| get_subpaths(layer, document_network))
}
/// Find a [ManipulatorPoint] that is within the selection threshold and return the layer path, an index to the [ManipulatorGroup], and an enum index for [ManipulatorPoint].
pub fn find_nearest_point_indices(&mut self, document: &Document, mouse_position: DVec2, select_threshold: f64) -> Option<(LayerNodeIdentifier, ManipulatorPointId)> {
pub fn find_nearest_point_indices(
&mut self,
document_network: &NodeNetwork,
document_metadata: &DocumentMetadata,
mouse_position: DVec2,
select_threshold: f64,
) -> Option<(LayerNodeIdentifier, ManipulatorPointId)> {
if self.selected_shape_state.is_empty() {
return None;
}
@@ -623,7 +650,7 @@ impl ShapeState {
let select_threshold_squared = select_threshold * select_threshold;
// Find the closest control point among all elements of shapes_to_modify
for &layer in self.selected_shape_state.keys() {
if let Some((manipulator_point_id, distance_squared)) = Self::closest_point_in_layer(document, layer, mouse_position) {
if let Some((manipulator_point_id, distance_squared)) = Self::closest_point_in_layer(document_network, document_metadata, layer, mouse_position) {
// Choose the first point under the threshold
if distance_squared < select_threshold_squared {
trace!("Selecting... manipulator point: {manipulator_point_id:?}");
@@ -639,12 +666,12 @@ impl ShapeState {
/// Find the closest manipulator, manipulator point, and distance so we can select path elements.
/// Brute force comparison to determine which manipulator (handle or anchor) we want to select taking O(n) time.
/// Return value is an `Option` of the tuple representing `(ManipulatorPointId, distance squared)`.
fn closest_point_in_layer(document: &Document, layer: LayerNodeIdentifier, pos: glam::DVec2) -> Option<(ManipulatorPointId, f64)> {
fn closest_point_in_layer(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier, pos: glam::DVec2) -> Option<(ManipulatorPointId, f64)> {
let mut closest_distance_squared: f64 = f64::MAX;
let mut result = None;
let subpaths = get_subpaths(layer, document)?;
let viewspace = document.metadata.transform_to_viewport(layer);
let subpaths = get_subpaths(layer, document_network)?;
let viewspace = document_metadata.transform_to_viewport(layer);
for manipulator in get_manipulator_groups(subpaths) {
let (selected, distance_squared) = SelectedType::closest_widget(manipulator, viewspace, pos, crate::consts::HIDE_HANDLE_DISTANCE);
@@ -658,15 +685,22 @@ impl ShapeState {
}
/// Find the `t` value along the path segment we have clicked upon, together with that segment ID.
fn closest_segment(&self, document: &Document, layer: LayerNodeIdentifier, position: glam::DVec2, tolerance: f64) -> Option<(ManipulatorGroupId, ManipulatorGroupId, Bezier, f64)> {
let transform = document.metadata.transform_to_viewport(layer);
fn closest_segment(
&self,
document_network: &NodeNetwork,
document_metadata: &DocumentMetadata,
layer: LayerNodeIdentifier,
position: glam::DVec2,
tolerance: f64,
) -> Option<(ManipulatorGroupId, ManipulatorGroupId, Bezier, f64)> {
let transform = document_metadata.transform_to_viewport(layer);
let layer_pos = transform.inverse().transform_point2(position);
let projection_options = bezier_rs::ProjectionOptions { lut_size: 5, ..Default::default() };
let mut result = None;
let mut closest_distance_squared: f64 = tolerance * tolerance;
let subpaths = get_subpaths(layer, document)?;
let subpaths = get_subpaths(layer, document_network)?;
for subpath in subpaths {
for (manipulator_index, bezier) in subpath.iter().enumerate() {
@@ -689,9 +723,9 @@ impl ShapeState {
}
/// Handles the splitting of a curve to insert new points (which can be activated by double clicking on a curve with the Path tool).
pub fn split(&self, document: &Document, position: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) {
pub fn split(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, position: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) {
for &layer in self.selected_layers() {
if let Some((start, end, bezier, t)) = self.closest_segment(document, layer, position, tolerance) {
if let Some((start, end, bezier, t)) = self.closest_segment(document_network, document_metadata, layer, position, tolerance) {
let [first, second] = bezier.split(TValue::Parametric(t));
// Adjust the first manipulator group's out handle
@@ -726,11 +760,11 @@ impl ShapeState {
}
/// Handles the flipping between sharp corner and smooth (which can be activated by double clicking on an anchor with the Path tool).
pub fn flip_sharp(&self, document: &Document, position: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) -> bool {
pub fn flip_sharp(&self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, position: glam::DVec2, tolerance: f64, responses: &mut VecDeque<Message>) -> bool {
let mut process_layer = |layer| {
let subpaths = get_subpaths(layer, document)?;
let subpaths = get_subpaths(layer, document_network)?;
let transform_to_screenspace = document.metadata.transform_to_viewport(layer);
let transform_to_screenspace = document_metadata.transform_to_viewport(layer);
let mut result = None;
let mut closest_distance_squared = tolerance * tolerance;
@@ -751,7 +785,7 @@ impl ShapeState {
let subpath = &subpaths[subpath_index];
// Check by comparing the handle positions to the anchor if this maniuplator group is a point
// Check by comparing the handle positions to the anchor if this manipulator group is a point
let already_sharp = match (manipulator.in_handle, manipulator.out_handle) {
(Some(in_handle), Some(out_handle)) => anchor_position.abs_diff_eq(in_handle, 1e-10) && anchor_position.abs_diff_eq(out_handle, 1e-10),
(Some(handle), None) | (None, Some(handle)) => anchor_position.abs_diff_eq(handle, 1e-10),
@@ -790,15 +824,15 @@ impl ShapeState {
false
}
pub fn select_all_in_quad(&mut self, document: &Document, quad: [DVec2; 2], clear_selection: bool) {
pub fn select_all_in_quad(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, quad: [DVec2; 2], clear_selection: bool) {
for (&layer, state) in &mut self.selected_shape_state {
if clear_selection {
state.clear_points()
}
let Some(subpaths) = get_subpaths(layer, document) else { continue };
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
let transform = document.metadata.transform_to_viewport(layer);
let transform = document_metadata.transform_to_viewport(layer);
for manipulator_group in get_manipulator_groups(subpaths) {
for selected_type in [SelectedType::Anchor, SelectedType::InHandle, SelectedType::OutHandle] {

View File

@@ -1,9 +1,8 @@
use super::shape_editor::ManipulatorPointInfo;
use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::LayerId;
use glam::DVec2;
/// Handles snapping and snap overlays

View File

@@ -1,12 +1,11 @@
use super::tool_prelude::*;
use crate::application::generate_uuid;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use crate::messages::tool::common_functionality::transformation_cage::*;
use document_legacy::document_metadata::LayerNodeIdentifier;
use glam::{IVec2, Vec2Swizzles};
#[derive(Default)]
@@ -132,9 +131,8 @@ impl ArtboardToolData {
responses.add(DocumentMessage::StartTransaction);
let mut intersections = document
.document_legacy
.click_xray(input.mouse.position)
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.document_legacy, "Artboard"));
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Artboard"));
responses.add(BroadcastEvent::DocumentIsDirty);
if let Some(intersection) = intersections.next() {

View File

@@ -1,9 +1,9 @@
use super::tool_prelude::*;
use crate::messages::portfolio::document::node_graph::resolve_document_node_type;
use crate::messages::portfolio::document::node_graph::transform_utils::{get_current_normalized_pivot, get_current_transform};
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNodeMetadata, NodeInput};
use graphene_core::raster::BlendMode;

View File

@@ -69,7 +69,7 @@ impl Fsm for FillToolFsmState {
let ToolMessage::Fill(event) = event else {
return self;
};
let Some(layer_identifier) = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network) else {
let Some(layer_identifier) = document.click(input.mouse.position, &document.network) else {
return self;
};
let layer = layer_identifier.to_path();

View File

@@ -1,9 +1,9 @@
use super::tool_prelude::*;
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::uuid::generate_uuid;
use graphene_core::vector::style::{Fill, Stroke};
use graphene_core::Color;

View File

@@ -2,10 +2,10 @@ use super::tool_prelude::*;
use crate::application::generate_uuid;
use crate::consts::{LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD};
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::graph_modification_utils::get_gradient;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::raster::color::Color;
use graphene_core::vector::style::{Fill, Gradient, GradientType};
@@ -170,7 +170,7 @@ impl SelectedGradient {
inner_gradient.transform = gradient_space_transform(inner_gradient.layer, document);
// Clear if no longer a gradient
let Some(gradient) = get_gradient(inner_gradient.layer, &document.document_legacy) else {
let Some(gradient) = get_gradient(inner_gradient.layer, &document.network) else {
responses.add(ToolMessage::RefreshToolOptions);
*gradient = None;
return;
@@ -296,8 +296,8 @@ impl Fsm for GradientToolFsmState {
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
let selected = tool_data.selected_gradient.as_ref();
for layer in document.document_legacy.selected_visible_layers() {
let Some(gradient) = get_gradient(layer, &document.document_legacy) else { continue };
for layer in document.selected_visible_layers() {
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document);
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
@@ -366,8 +366,8 @@ impl Fsm for GradientToolFsmState {
self
}
(_, GradientToolMessage::InsertStop) => {
for layer in document.document_legacy.selected_visible_layers() {
let Some(mut gradient) = get_gradient(layer, &document.document_legacy) else { continue };
for layer in document.selected_visible_layers() {
let Some(mut gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document);
let mouse = input.mouse.position;
@@ -407,8 +407,8 @@ impl Fsm for GradientToolFsmState {
let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
let mut dragging = false;
for layer in document.document_legacy.selected_visible_layers() {
let Some(gradient) = get_gradient(layer, &document.document_legacy) else { continue };
for layer in document.selected_visible_layers() {
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document);
// Check for dragging step
@@ -444,7 +444,7 @@ impl Fsm for GradientToolFsmState {
document.backup_nonmut(responses);
GradientToolFsmState::Drawing
} else {
let selected_layer = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network);
let selected_layer = document.click(input.mouse.position, &document.network);
// Apply the gradient to the selected layer
if let Some(layer) = selected_layer {
@@ -457,7 +457,7 @@ impl Fsm for GradientToolFsmState {
responses.add(DocumentMessage::StartTransaction);
// Use the already existing gradient if it exists
let gradient = if let Some(gradient) = get_gradient(layer, &document.document_legacy) {
let gradient = if let Some(gradient) = get_gradient(layer, &document.network) {
gradient.clone()
} else {
// Generate a new gradient

View File

@@ -1,9 +1,8 @@
use super::tool_prelude::*;
use crate::messages::portfolio::document::node_graph::{self, IMAGINATE_NODE};
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::resize::Resize;
use document_legacy::document_metadata::LayerNodeIdentifier;
use serde::{Deserialize, Serialize};
#[derive(Default)]

View File

@@ -1,10 +1,10 @@
use super::tool_prelude::*;
use crate::consts::LINE_ROTATE_SNAP_ANGLE;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::uuid::generate_uuid;
use graphene_core::vector::style::Stroke;
use graphene_core::Color;

View File

@@ -2,12 +2,12 @@ use super::tool_prelude::*;
use crate::consts::{DRAG_THRESHOLD, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::tool::common_functionality::graph_modification_utils::{get_manipulator_from_id, get_mirror_handles, get_subpaths};
use crate::messages::tool::common_functionality::shape_editor::{ManipulatorAngle, ManipulatorPointInfo, OpposingHandleLengths, SelectedPointsInfo, ShapeState};
use crate::messages::tool::common_functionality::snapping::SnapManager;
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graphene_core::renderer::Quad;
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -223,14 +223,14 @@ impl PathToolData {
let _selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
// Select the first point within the threshold (in pixels)
if let Some(selected_points) = shape_editor.select_point(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD, shift) {
if let Some(selected_points) = shape_editor.select_point(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD, shift) {
self.start_dragging_point(selected_points, input, document, responses);
responses.add(OverlaysMessage::Draw);
PathToolFsmState::Dragging
}
// We didn't find a point nearby, so consider selecting the nearest shape instead
else if let Some(layer) = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network) {
else if let Some(layer) = document.click(input.mouse.position, &document.network) {
if shift {
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] });
} else {
@@ -238,7 +238,7 @@ impl PathToolData {
}
self.drag_start_pos = input.mouse.position;
self.previous_mouse_position = input.mouse.position;
shape_editor.select_all_anchors(&document.document_legacy, layer);
shape_editor.select_all_anchors(&document.network, layer);
PathToolFsmState::Dragging
} else {
@@ -292,16 +292,16 @@ impl PathToolData {
if shift {
if self.opposing_handle_lengths.is_none() {
self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(&document.document_legacy));
self.opposing_handle_lengths = Some(shape_editor.opposing_handle_lengths(&document.network));
}
} else if let Some(opposing_handle_lengths) = &self.opposing_handle_lengths {
shape_editor.reset_opposing_handle_lengths(&document.document_legacy, opposing_handle_lengths, responses);
shape_editor.reset_opposing_handle_lengths(&document.network, opposing_handle_lengths, responses);
self.opposing_handle_lengths = None;
}
// Move the selected points with the mouse
let snapped_position = self.snap_manager.snap_position(responses, document, input.mouse.position);
shape_editor.move_selected_points(&document.document_legacy, snapped_position - self.previous_mouse_position, shift, responses);
shape_editor.move_selected_points(&document.network, &document.metadata, snapped_position - self.previous_mouse_position, shift, responses);
self.previous_mouse_position = snapped_position;
}
}
@@ -365,7 +365,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
} else {
shape_editor.select_all_in_quad(&document.document_legacy, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
}
responses.add(OverlaysMessage::Draw);
@@ -379,7 +379,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
} else {
shape_editor.select_all_in_quad(&document.document_legacy, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
}
responses.add(OverlaysMessage::Draw);
responses.add(PathToolMessage::SelectedPointUpdated);
@@ -391,16 +391,16 @@ impl Fsm for PathToolFsmState {
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
let nearest_point = shape_editor
.find_nearest_point_indices(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD)
.find_nearest_point_indices(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD)
.map(|(_, nearest_point)| nearest_point);
shape_editor.delete_selected_handles_with_zero_length(&document.document_legacy, &tool_data.opposing_handle_lengths, responses);
shape_editor.delete_selected_handles_with_zero_length(&document.network, &document.metadata, &tool_data.opposing_handle_lengths, responses);
if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD && !shift_pressed {
let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == Some(point));
if clicked_selected {
shape_editor.deselect_all();
shape_editor.select_point(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD, false);
shape_editor.select_point(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD, false);
responses.add(OverlaysMessage::Draw);
}
}
@@ -421,9 +421,9 @@ impl Fsm for PathToolFsmState {
}
(_, PathToolMessage::InsertPoint) => {
// First we try and flip the sharpness (if they have clicked on an anchor)
if !shape_editor.flip_sharp(&document.document_legacy, input.mouse.position, SELECTION_TOLERANCE, responses) {
if !shape_editor.flip_sharp(&document.network, &document.metadata, input.mouse.position, SELECTION_TOLERANCE, responses) {
// If not, then we try and split the path that may have been clicked upon
shape_editor.split(&document.document_legacy, input.mouse.position, SELECTION_TOLERANCE, responses);
shape_editor.split(&document.network, &document.metadata, input.mouse.position, SELECTION_TOLERANCE, responses);
}
responses.add(PathToolMessage::SelectedPointUpdated);
@@ -436,35 +436,35 @@ impl Fsm for PathToolFsmState {
}
(_, PathToolMessage::PointerMove { .. }) => self,
(_, PathToolMessage::NudgeSelectedPoints { delta_x, delta_y }) => {
shape_editor.move_selected_points(&document.document_legacy, (delta_x, delta_y).into(), true, responses);
shape_editor.move_selected_points(&document.network, &document.metadata, (delta_x, delta_y).into(), true, responses);
PathToolFsmState::Ready
}
(_, PathToolMessage::SelectAllPoints) => {
shape_editor.select_all_points(&document.document_legacy);
shape_editor.select_all_points(&document.network);
responses.add(OverlaysMessage::Draw);
PathToolFsmState::Ready
}
(_, PathToolMessage::SelectedPointXChanged { new_x }) => {
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
shape_editor.reposition_control_point(&id, responses, &document.document_legacy, DVec2::new(new_x, coordinates.y), layer);
shape_editor.reposition_control_point(&id, responses, &document.network, &document.metadata, DVec2::new(new_x, coordinates.y), layer);
}
PathToolFsmState::Ready
}
(_, PathToolMessage::SelectedPointYChanged { new_y }) => {
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
shape_editor.reposition_control_point(&id, responses, &document.document_legacy, DVec2::new(coordinates.x, new_y), layer);
shape_editor.reposition_control_point(&id, responses, &document.network, &document.metadata, DVec2::new(coordinates.x, new_y), layer);
}
PathToolFsmState::Ready
}
(_, PathToolMessage::SelectedPointUpdated) => {
tool_data.selection_status = get_selection_status(&document.document_legacy, shape_editor);
tool_data.selection_status = get_selection_status(&document.network, &document.metadata, shape_editor);
self
}
(_, PathToolMessage::ManipulatorAngleMakeSmooth) => {
responses.add(DocumentMessage::StartTransaction);
shape_editor.set_handle_mirroring_on_selected(true, responses);
shape_editor.smooth_selected_groups(responses, &document.document_legacy);
shape_editor.smooth_selected_groups(responses, &document.network);
responses.add(DocumentMessage::CommitTransaction);
PathToolFsmState::Ready
}
@@ -549,7 +549,7 @@ struct SingleSelectedPoint {
/// Sets the cumulative description of the selected points: if `None` are selected, if `One` is selected, or if `Multiple` are selected.
/// Applies to any selected points, whether they are anchors or handles; and whether they are from a single shape or across multiple shapes.
fn get_selection_status(document: &Document, shape_state: &mut ShapeState) -> SelectionStatus {
fn get_selection_status(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, shape_state: &mut ShapeState) -> SelectionStatus {
let mut selection_layers = shape_state.selected_shape_state.iter().map(|(k, v)| (*k, v.selected_points_count()));
let total_selected_points = selection_layers.clone().map(|(_, v)| v).sum::<usize>();
@@ -559,10 +559,10 @@ fn get_selection_status(document: &Document, shape_state: &mut ShapeState) -> Se
return SelectionStatus::None;
};
let Some(subpaths) = get_subpaths(layer, document) else {
let Some(subpaths) = get_subpaths(layer, document_network) else {
return SelectionStatus::None;
};
let Some(mirror) = get_mirror_handles(layer, document) else {
let Some(mirror) = get_mirror_handles(layer, document_network) else {
return SelectionStatus::None;
};
let Some(point) = shape_state.selected_points().next() else {
@@ -579,7 +579,7 @@ fn get_selection_status(document: &Document, shape_state: &mut ShapeState) -> Se
let manipulator_angle = if mirror.contains(&point.group) { ManipulatorAngle::Smooth } else { ManipulatorAngle::Sharp };
return SelectionStatus::One(SingleSelectedPoint {
coordinates: document.metadata.transform_to_document(layer).transform_point2(local_position),
coordinates: document_metadata.transform_to_document(layer).transform_point2(local_position),
layer,
id: *point,
manipulator_angle,
@@ -589,7 +589,7 @@ fn get_selection_status(document: &Document, shape_state: &mut ShapeState) -> Se
// Check to see if multiple manipulator groups are selected
if total_selected_points > 1 {
return SelectionStatus::Multiple(MultipleSelectedPoints {
manipulator_angle: shape_state.selected_manipulator_angles(document),
manipulator_angle: shape_state.selected_manipulator_angles(document_network),
});
}

View File

@@ -3,12 +3,12 @@ use crate::consts::LINE_ROTATE_SNAP_ANGLE;
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::graph_modification_utils::get_subpaths;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::uuid::{generate_uuid, ManipulatorGroupId};
use graphene_core::vector::style::{Fill, Stroke};
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -217,7 +217,7 @@ impl PenToolData {
self.subpath_index = subpath_index;
// Stop the handles on the first point from mirroring
let Some(subpaths) = get_subpaths(layer, &document.document_legacy) else {
let Some(subpaths) = get_subpaths(layer, &document.network) else {
return;
};
let manipulator_groups = subpaths[subpath_index].manipulator_groups();
@@ -277,7 +277,7 @@ impl PenToolData {
fn check_break(&mut self, document: &DocumentMessageHandler, transform: DAffine2, responses: &mut VecDeque<Message>) -> Option<()> {
// Get subpath
let layer = self.layer?;
let subpath = &get_subpaths(layer, &document.document_legacy)?[self.subpath_index];
let subpath = &get_subpaths(layer, &document.network)?[self.subpath_index];
// Get the last manipulator group and the one previous to that
let mut manipulator_groups = subpath.manipulator_groups().iter();
@@ -323,7 +323,7 @@ impl PenToolData {
fn finish_placing_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
// Get subpath
let layer = self.layer?;
let subpath = &get_subpaths(layer, &document.document_legacy)?[self.subpath_index];
let subpath = &get_subpaths(layer, &document.network)?[self.subpath_index];
// Get the last manipulator group and the one previous to that
let mut manipulator_groups = subpath.manipulator_groups().iter();
@@ -395,7 +395,7 @@ impl PenToolData {
fn drag_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
// Get subpath
let subpath = &get_subpaths(self.layer?, &document.document_legacy)?[self.subpath_index];
let subpath = &get_subpaths(self.layer?, &document.network)?[self.subpath_index];
// Get the last manipulator group
let manipulator_groups = subpath.manipulator_groups();
@@ -448,7 +448,7 @@ impl PenToolData {
fn place_anchor(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
// Get subpath
let layer = self.layer?;
let subpath = &get_subpaths(layer, &document.document_legacy)?[self.subpath_index];
let subpath = &get_subpaths(layer, &document.network)?[self.subpath_index];
// Get the last manipulator group and the one previous to that
let mut manipulator_groups = subpath.manipulator_groups().iter();
@@ -492,7 +492,7 @@ impl PenToolData {
fn finish_transaction(&mut self, fsm: PenToolFsmState, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Option<DocumentMessage> {
// Get subpath
let subpath = &get_subpaths(self.layer?, &document.document_legacy)?[self.subpath_index];
let subpath = &get_subpaths(self.layer?, &document.network)?[self.subpath_index];
// Abort if only one manipulator group has been placed
if fsm == PenToolFsmState::PlacingAnchor && subpath.len() < 3 {
@@ -724,7 +724,7 @@ fn should_extend(document: &DocumentMessageHandler, pos: DVec2, tolerance: f64)
for layer in document.metadata().selected_layers() {
let viewspace = document.metadata().transform_to_viewport(layer);
let subpaths = get_subpaths(layer, &document.document_legacy)?;
let subpaths = get_subpaths(layer, &document.network)?;
for (subpath_index, subpath) in subpaths.iter().enumerate() {
if subpath.closed() {
continue;

View File

@@ -4,6 +4,7 @@ use super::tool_prelude::*;
use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE};
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
use crate::messages::portfolio::document::utility_types::transformation::Selected;
use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name;
@@ -11,8 +12,7 @@ use crate::messages::tool::common_functionality::pivot::Pivot;
use crate::messages::tool::common_functionality::snapping::{self, SnapManager};
use crate::messages::tool::common_functionality::transformation_cage::*;
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graphene_core::renderer::Quad;
use std::fmt;
@@ -394,22 +394,21 @@ impl Fsm for SelectToolFsmState {
tool_data.selected_layers_count = selected_layers_count;
// Outline selected layers
for layer in document.document_legacy.selected_visible_layers() {
for layer in document.selected_visible_layers() {
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
}
// Get the layer the user is hovering over
let click = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network);
let click = document.click(input.mouse.position, &document.network);
let not_selected_click = click.filter(|&hovered_layer| !document.metadata().selected_layers_contains(hovered_layer));
if let Some(layer) = not_selected_click {
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
}
// Update bounds
let transform = document.document_legacy.selected_visible_layers().next().map(|layer| document.metadata().transform_to_viewport(layer));
let transform = document.selected_visible_layers().next().map(|layer| document.metadata().transform_to_viewport(layer));
let transform = transform.unwrap_or(DAffine2::IDENTITY);
let bounds = document
.document_legacy
.selected_visible_layers()
.filter_map(|layer| {
document
@@ -440,10 +439,10 @@ impl Fsm for SelectToolFsmState {
}
(_, SelectToolMessage::EditLayer) => {
// Edit the clicked layer
if let Some(intersect) = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network) {
if let Some(intersect) = document.click(input.mouse.position, &document.network) {
match tool_data.nested_selection_behavior {
NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect, responses),
NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, &document.document_legacy, responses),
NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, &document.network, responses),
}
}
@@ -471,8 +470,8 @@ impl Fsm for SelectToolFsmState {
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
.unwrap_or_default();
let mut selected: Vec<_> = document.document_legacy.selected_visible_layers().collect();
let intersection = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network);
let mut selected: Vec<_> = document.selected_visible_layers().collect();
let intersection = document.click(input.mouse.position, &document.network);
// 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.
@@ -502,16 +501,16 @@ impl Fsm for SelectToolFsmState {
tool_data.layers_dragging = selected;
if let Some(bounds) = &mut tool_data.bounding_box_manager {
let document = &document.document_legacy;
bounds.original_bound_transform = bounds.transform;
tool_data.layers_dragging.retain(|layer| document.document_network.nodes.contains_key(&layer.to_node()));
tool_data.layers_dragging.retain(|layer| document.network.nodes.contains_key(&layer.to_node()));
let mut selected = Selected::new(
&mut bounds.original_transforms,
&mut bounds.center_of_transformation,
&tool_data.layers_dragging,
responses,
document,
&document.network,
&document.metadata,
None,
&ToolType::Select,
);
@@ -529,7 +528,8 @@ impl Fsm for SelectToolFsmState {
&mut bounds.center_of_transformation,
&selected,
responses,
&document.document_legacy,
&document.network,
&document.metadata,
None,
&ToolType::Select,
);
@@ -639,7 +639,16 @@ impl Fsm for SelectToolFsmState {
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
let selected = &tool_data.layers_dragging;
let mut selected = Selected::new(&mut bounds.original_transforms, &mut pivot, selected, responses, &document.document_legacy, None, &ToolType::Select);
let mut selected = Selected::new(
&mut bounds.original_transforms,
&mut pivot,
selected,
responses,
&document.network,
&document.metadata,
None,
&ToolType::Select,
);
selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse());
}
@@ -670,7 +679,8 @@ impl Fsm for SelectToolFsmState {
&mut bounds.center_of_transformation,
&tool_data.layers_dragging,
responses,
&document.document_legacy,
&document.network,
&document.metadata,
None,
&ToolType::Select,
);
@@ -725,7 +735,7 @@ impl Fsm for SelectToolFsmState {
// Deselect layer if not snap dragging
if !tool_data.has_dragged && input.keyboard.key(remove_from_selection) && tool_data.layer_selected_on_start.is_none() {
let quad = tool_data.selection_quad();
let intersection = document.document_legacy.intersect_quad(quad, &document.document_legacy.document_network);
let intersection = document.intersect_quad(quad, &document.network);
if let Some(path) = intersection.last() {
let replacement_selected_layers: Vec<_> = document.metadata().selected_layers().filter(|&layer| !path.starts_with(layer, document.metadata())).collect();
@@ -795,7 +805,7 @@ impl Fsm for SelectToolFsmState {
}
(SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
let quad = tool_data.selection_quad();
let new_selected: HashSet<_> = document.document_legacy.intersect_quad(quad, &document.document_legacy.document_network).collect();
let new_selected: HashSet<_> = document.intersect_quad(quad, &document.network).collect();
let current_selected: HashSet<_> = document.metadata().selected_layers().collect();
if new_selected != current_selected {
tool_data.layers_dragging = new_selected.into_iter().collect();
@@ -813,7 +823,7 @@ impl Fsm for SelectToolFsmState {
if let Some(layer) = selected_layers.next() {
// Check that only one layer is selected
if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.document_legacy, "Text") {
if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network, "Text") {
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
responses.add(TextToolMessage::EditSelected);
}
@@ -836,7 +846,8 @@ impl Fsm for SelectToolFsmState {
&mut bounding_box_overlays.opposite_pivot,
&tool_data.layers_dragging,
responses,
&document.document_legacy,
&document.network,
&document.metadata,
None,
&ToolType::Select,
);
@@ -951,11 +962,11 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer:
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_selected.to_node()] });
}
fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, document: &Document, responses: &mut VecDeque<Message>) {
if is_layer_fed_by_node_of_name(layer, document, "Text") {
fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, document_network: &NodeNetwork, responses: &mut VecDeque<Message>) {
if is_layer_fed_by_node_of_name(layer, document_network, "Text") {
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
responses.add(TextToolMessage::EditSelected);
} else if is_layer_fed_by_node_of_name(layer, document, "Shape") {
} else if is_layer_fed_by_node_of_name(layer, document_network, "Shape") {
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path });
}
}

View File

@@ -1,11 +1,11 @@
use super::tool_prelude::*;
use crate::consts::DRAG_THRESHOLD;
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graphene_core::uuid::generate_uuid;
use graphene_core::vector::style::{Fill, Stroke};
use graphene_core::Color;

View File

@@ -3,10 +3,10 @@
use super::tool_prelude::*;
use crate::application::generate_uuid;
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name};
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graphene_core::renderer::Quad;
use graphene_core::text::{load_face, Font, FontCache};
@@ -225,7 +225,7 @@ struct TextToolData {
impl TextToolData {
/// Set the editing state of the currently modifying layer
fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.document_legacy) {
if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.network) {
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: editable });
}
@@ -245,8 +245,8 @@ impl TextToolData {
fn load_layer_text_node(&mut self, document: &DocumentMessageHandler) -> Option<()> {
let transform = document.metadata().transform_to_viewport(self.layer);
let color = graph_modification_utils::get_fill_color(self.layer, &document.document_legacy).unwrap_or(Color::BLACK);
let (text, font, font_size) = graph_modification_utils::get_text(self.layer, &document.document_legacy)?;
let color = graph_modification_utils::get_fill_color(self.layer, &document.network).unwrap_or(Color::BLACK);
let (text, font, font_size) = graph_modification_utils::get_text(self.layer, &document.network)?;
self.editing_text = Some(EditingText {
text: text.clone(),
font: font.clone(),
@@ -276,9 +276,8 @@ impl TextToolData {
fn interact(&mut self, state: TextToolFsmState, mouse: DVec2, document: &DocumentMessageHandler, font_cache: &FontCache, responses: &mut VecDeque<Message>) -> TextToolFsmState {
// Check if the user has selected an existing text layer
if let Some(clicked_text_layer_path) = document
.document_legacy
.click(mouse, document.network())
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.document_legacy, "Text"))
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Text"))
{
self.start_editing_layer(clicked_text_layer_path, state, document, font_cache, responses);
@@ -350,7 +349,7 @@ fn can_edit_selected(document: &DocumentMessageHandler) -> Option<LayerNodeIdent
return None;
}
if !is_layer_fed_by_node_of_name(layer, &document.document_legacy, "Text") {
if !is_layer_fed_by_node_of_name(layer, &document.network, "Text") {
return None;
}
@@ -391,7 +390,7 @@ impl Fsm for TextToolFsmState {
}
(_, TextToolMessage::Overlays(mut overlay_context)) => {
for layer in document.metadata().selected_layers() {
let Some((text, font, font_size)) = graph_modification_utils::get_text(layer, &document.document_legacy) else {
let Some((text, font, font_size)) = graph_modification_utils::get_text(layer, &document.network) else {
continue;
};
let buzz_face = font_cache.get(font).map(|data| load_face(data));
@@ -439,7 +438,7 @@ impl Fsm for TextToolFsmState {
tool_data.fix_text_bounds(&new_text, document, font_cache, responses);
responses.add(NodeGraphMessage::SetQualifiedInputValue {
layer_path: Vec::new(),
node_path: vec![graph_modification_utils::get_text_id(tool_data.layer, &document.document_legacy).unwrap()],
node_path: vec![graph_modification_utils::get_text_id(tool_data.layer, &document.network).unwrap()],
input_index: 1,
value: TaggedValue::String(new_text),
});

View File

@@ -55,7 +55,8 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
&mut self.pivot,
&selected_layers,
responses,
&document.document_legacy,
&document.network,
&document.metadata,
Some(shape_editor),
&tool_data.active_tool_type,
);
@@ -67,7 +68,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
}
if using_path_tool {
if let Some(subpaths) = selected_layers.first().and_then(|&layer| graph_modification_utils::get_subpaths(layer, &document.document_legacy)) {
if let Some(subpaths) = selected_layers.first().and_then(|&layer| graph_modification_utils::get_subpaths(layer, &document.network)) {
*selected.original_transforms = OriginalTransforms::default();
let viewspace = document.metadata().transform_to_viewport(selected_layers[0]);

View File

@@ -599,32 +599,3 @@ impl HintInfo {
self
}
}
#[cfg(test)]
mod tool_crash_on_layer_delete_tests {
use crate::application::{set_uuid_seed, Editor};
use crate::messages::portfolio::document::DocumentMessage;
use crate::messages::tool::utility_types::ToolType;
use crate::test_utils::EditorTestUtils;
use test_case::test_case;
#[test_case(ToolType::Pen; "while using Pen tool")]
#[test_case(ToolType::Freehand; "while using Freehand tool")]
#[test_case(ToolType::Spline; "while using Spline tool")]
#[test_case(ToolType::Line; "while using Line tool")]
#[test_case(ToolType::Rectangle; "while using Rectangle tool")]
#[test_case(ToolType::Ellipse; "while using Ellipse tool")]
#[test_case(ToolType::Polygon; "while using Polygon tool")]
#[test_case(ToolType::Path; "while using Path tool")]
fn should_not_crash_when_layer_is_deleted(tool: ToolType) {
set_uuid_seed(0);
let mut test_editor = Editor::new();
test_editor.select_tool(tool);
test_editor.lmb_mousedown(0.0, 0.0);
test_editor.move_mouse(100.0, 100.0);
test_editor.handle_message(DocumentMessage::DeleteSelectedLayers);
}
}

View File

@@ -2,13 +2,12 @@ use crate::consts::FILE_SAVE_SUFFIX;
use crate::messages::frontend::utility_types::FrontendImageData;
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
use crate::messages::portfolio::document::node_graph::wrap_network_in_scope;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::layer_panel::LayerClassification;
use crate::messages::portfolio::document::utility_types::misc::{LayerMetadata, LayerPanelEntry};
use crate::messages::portfolio::document::utility_types::misc::LayerPanelEntry;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
use graph_craft::graphene_compiler::Compiler;
@@ -493,7 +492,7 @@ impl NodeGraphExecutor {
let render_config = RenderConfig {
viewport: Footprint {
transform: document.document_legacy.metadata.document_to_viewport,
transform: document.metadata.document_to_viewport,
resolution: viewport_resolution,
..Default::default()
},
@@ -581,7 +580,14 @@ impl NodeGraphExecutor {
Ok(())
}
pub fn poll_node_graph_evaluation(&mut self, document: &mut DocumentLegacy, collapsed_folders: &mut Vec<LayerNodeIdentifier>, responses: &mut VecDeque<Message>) -> Result<(), String> {
pub fn poll_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Result<(), String> {
let DocumentMessageHandler {
network: document_network,
metadata: document_metadata,
collapsed,
..
} = document;
let results = self.receiver.try_iter().collect::<Vec<_>>();
for response in results {
match response {
@@ -602,34 +608,32 @@ impl NodeGraphExecutor {
}
for (&node_id, svg) in &new_thumbnails {
if !document.document_network.nodes.contains_key(&node_id) {
if !document_network.nodes.contains_key(&node_id) {
warn!("Missing node");
continue;
}
let layer = LayerNodeIdentifier::new(node_id, &document.document_network);
let layer = LayerNodeIdentifier::new(node_id, document_network);
responses.add(FrontendMessage::UpdateDocumentLayerDetails {
data: LayerPanelEntry {
name: document.document_network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(),
name: document_network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(),
tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() },
layer_classification: if document.metadata.is_artboard(layer) {
layer_classification: if document_metadata.is_artboard(layer) {
LayerClassification::Artboard
} else if document.metadata.is_folder(layer) {
} else if document_metadata.is_folder(layer) {
LayerClassification::Folder
} else {
LayerClassification::Layer
},
layer_metadata: LayerMetadata {
expanded: layer.has_children(&document.metadata) && !collapsed_folders.contains(&layer),
selected: document.metadata.selected_layers_contains(layer),
},
expanded: layer.has_children(document_metadata) && !collapsed.contains(&layer),
selected: document_metadata.selected_layers_contains(layer),
path: vec![node_id],
thumbnail: svg.to_string(),
},
});
}
self.thumbnails = new_thumbnails;
document.metadata.update_transforms(new_upstream_transforms);
document.metadata.update_click_targets(new_click_targets);
document_metadata.update_transforms(new_upstream_transforms);
document_metadata.update_click_targets(new_click_targets);
responses.extend(updates);
self.process_node_graph_output(node_graph_output, execution_context.layer_path.clone(), transform, responses)?;
responses.add(DocumentMessage::RenderDocument);

View File

@@ -209,11 +209,11 @@
async function dragStart(event: DragEvent, listing: LayerListingInfo) {
const layer = listing.entry;
dragInPanel = true;
if (!layer.layerMetadata.selected) {
if (!layer.selected) {
fakeHighlight = [layer.path];
}
const select = () => {
if (!layer.layerMetadata.selected) selectLayer(false, false, listing);
if (!layer.selected) selectLayer(false, false, listing);
};
const target = (event.target instanceof HTMLElement && event.target) || undefined;
@@ -309,7 +309,7 @@
<LayoutRow
class="layer"
classes={{
selected: fakeHighlight ? fakeHighlight.includes(listing.entry.path) : listing.entry.layerMetadata.selected,
selected: fakeHighlight ? fakeHighlight.includes(listing.entry.path) : listing.entry.selected,
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertFolder === listing.entry.path,
}}
styles={{ "--layer-indent-levels": `${listing.entry.path.length - 1}` }}
@@ -321,7 +321,7 @@
on:click={(e) => selectLayerWithModifiers(e, listing)}
>
{#if isNestingLayer(listing.entry.layerClassification)}
<button class="expand-arrow" class:expanded={listing.entry.layerMetadata.expanded} on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.path)} tabindex="0" />
<button class="expand-arrow" class:expanded={listing.entry.expanded} on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.path)} tabindex="0" />
{#if listing.entry.layerClassification === "Artboard"}
<IconLabel icon="Artboard" class={"layer-type-icon"} />
{:else if listing.entry.layerClassification === "Folder"}

View File

@@ -672,16 +672,11 @@ export class LayerPanelEntry {
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
path!: BigUint64Array;
@Type(() => LayerMetadata)
layerMetadata!: LayerMetadata;
thumbnail!: string;
}
export class LayerMetadata {
expanded!: boolean;
selected!: boolean;
thumbnail!: string;
}
export type LayerClassification = "Folder" | "Artboard" | "Layer";

View File

@@ -20,7 +20,6 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
editor = { path = "../../editor", package = "graphite-editor" }
document-legacy = { workspace = true }
graph-craft = { workspace = true }
log = { workspace = true }
graphene-core = { workspace = true, features = ["std", "alloc"] }

View File

@@ -6,13 +6,13 @@
use crate::helpers::translate_key;
use crate::{Error, EDITOR_HAS_CRASHED, EDITOR_INSTANCES, JS_EDITOR_HANDLES};
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use editor::application::generate_uuid;
use editor::application::Editor;
use editor::consts::{FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION};
use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use editor::messages::portfolio::document::utility_types::LayerId;
use editor::messages::portfolio::utility_types::Platform;
use editor::messages::prelude::*;
use graph_craft::document::NodeId;

View File

@@ -31,7 +31,7 @@ serde = { workspace = true }
serde_json = { workspace = true }
bezier-rs = { workspace = true }
glam = { workspace = true }
graphene-std = { path = "../gstd" }
graphene-std = { path = "../gstd", features = ["serde"] }
image = { workspace = true, default-features = false, features = [
"bmp",
"png",
@@ -49,8 +49,4 @@ chrono = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt"] }
wgpu = { workspace = true }
[dependencies.document-legacy]
path = "../../document-legacy"
package = "graphite-document-legacy"
[dev-dependencies]

View File

@@ -74,16 +74,8 @@ image-compare = { version = "0.3.0", optional = true }
vello = { workspace = true, optional = true }
vello_svg = { workspace = true, optional = true }
resvg = { workspace = true, optional = true }
[dependencies.serde]
workspace = true
optional = true
features = ["derive"]
[dependencies.web-sys]
workspace = true
optional = true
features = [
serde = { workspace = true, optional = true, features = ["derive"] }
web-sys = { workspace = true, optional = true, features = [
"Window",
"CanvasRenderingContext2d",
"ImageData",
@@ -93,4 +85,4 @@ features = [
"HtmlCanvasElement",
"HtmlImageElement",
"ImageBitmapRenderingContext",
]
] }

View File

@@ -14,7 +14,7 @@ quantization = ["graphene-std/quantization"]
[dependencies]
graphene-core = { workspace = true, features = ["std"] }
graphene-std = { path = "../gstd" }
graphene-std = { path = "../gstd", features = ["serde"] }
graph-craft = { path = "../graph-craft" }
gpu-executor = { path = "../gpu-executor" }
wgpu-executor = { path = "../wgpu-executor" }
@@ -23,5 +23,6 @@ num-traits = { workspace = true }
log = { workspace = true }
serde = { workspace = true, optional = true }
glam = { workspace = true }
once_cell = "1.18" # Remove when `core::cell::LazyCell` is stabilized (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>)
# Remove when `core::cell::LazyCell` is stabilized (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>)
once_cell = "1.18"
futures = { workspace = true }