mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-18 16:38:14 +08:00
Remove the whole document-legacy crate (#1524)
Remove the whole document-legacy crate Closes #1520
This commit is contained in:
679
Cargo.lock
generated
679
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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 }
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod document;
|
||||
pub mod document_metadata;
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<_>>();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = ¤t_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();
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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}");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
})
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
] }
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user