mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 10:18:11 +08:00
Remove the whole document-legacy crate (#1524)
Remove the whole document-legacy crate Closes #1520
This commit is contained in:
Generated
+401
-278
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"editor",
|
"editor",
|
||||||
"document-legacy",
|
|
||||||
"proc-macros",
|
"proc-macros",
|
||||||
"frontend/wasm",
|
"frontend/wasm",
|
||||||
"frontend/src-tauri",
|
"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 upgrades may break various things so we pin the version
|
||||||
wasm-bindgen = "=0.2.87"
|
wasm-bindgen = "=0.2.87"
|
||||||
dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam"] }
|
dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam"] }
|
||||||
document-legacy = { path = "document-legacy", package = "graphite-document-legacy" }
|
|
||||||
graphene-core = { path = "node-graph/gcore" }
|
graphene-core = { path = "node-graph/gcore" }
|
||||||
graph-craft = { path = "node-graph/graph-craft", features = ["serde"] }
|
graph-craft = { path = "node-graph/graph-craft", features = ["serde"] }
|
||||||
spirv-std = { version = "0.9" }
|
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;
|
|
||||||
+1
-3
@@ -44,11 +44,10 @@ gpu-executor = { path = "../node-graph/gpu-executor", optional = true }
|
|||||||
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
||||||
dyn-any = { workspace = true }
|
dyn-any = { workspace = true }
|
||||||
graphene-core = { path = "../node-graph/gcore" }
|
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"
|
num_enum = "0.6.1"
|
||||||
wasm-bindgen = { workspace = true, optional = true }
|
wasm-bindgen = { workspace = true, optional = true }
|
||||||
wasm-bindgen-futures = { 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>)
|
# Remove when `core::cell::LazyCell` is stabilized (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>)
|
||||||
once_cell = "1.13.0"
|
once_cell = "1.13.0"
|
||||||
web-sys = { workspace = true, features = [
|
web-sys = { workspace = true, features = [
|
||||||
@@ -61,5 +60,4 @@ web-sys = { workspace = true, features = [
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
test-case = "3.1"
|
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";
|
|||||||
pub const DEFAULT_FONT_STYLE: &str = "Normal (400)";
|
pub const DEFAULT_FONT_STYLE: &str = "Normal (400)";
|
||||||
|
|
||||||
// Document
|
// 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 DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
|
||||||
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
|
pub const FILE_SAVE_SUFFIX: &str = ".graphite";
|
||||||
pub const MAX_UNDO_HISTORY_LEN: usize = 100; // TODO: Add this to user preferences
|
pub const MAX_UNDO_HISTORY_LEN: usize = 100; // TODO: Add this to user preferences
|
||||||
|
|||||||
+11
-12
@@ -257,12 +257,11 @@ impl Dispatcher {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::application::Editor;
|
use crate::application::Editor;
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
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::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::tool_prelude::ToolType;
|
use crate::messages::tool::tool_messages::tool_prelude::ToolType;
|
||||||
use crate::test_utils::EditorTestUtils;
|
use crate::test_utils::EditorTestUtils;
|
||||||
|
|
||||||
use document_legacy::document::LayerId;
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
|
|
||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
@@ -299,14 +298,14 @@ mod test {
|
|||||||
fn copy_paste_single_layer() {
|
fn copy_paste_single_layer() {
|
||||||
let mut editor = create_editor_with_three_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();
|
||||||
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
|
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
clipboard: Clipboard::Internal,
|
clipboard: Clipboard::Internal,
|
||||||
parent: LayerNodeIdentifier::ROOT,
|
parent: LayerNodeIdentifier::ROOT,
|
||||||
insert_index: -1,
|
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_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
|
||||||
let layers_after_copy = document_after_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() {
|
fn copy_paste_single_layer_from_middle() {
|
||||||
let mut editor = create_editor_with_three_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 shape_id = document_before_copy.metadata.all_layers().nth(1).unwrap();
|
let shape_id = document_before_copy.metadata.all_layers().nth(1).unwrap();
|
||||||
|
|
||||||
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![shape_id.to_node()] });
|
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![shape_id.to_node()] });
|
||||||
@@ -341,7 +340,7 @@ mod test {
|
|||||||
insert_index: -1,
|
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_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
|
||||||
let layers_after_copy = document_after_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] });
|
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 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.document_network);
|
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::Line, 0., 0., 10., 10.);
|
||||||
editor.drag_tool(ToolType::Freehand, 10., 20., 30., 40.);
|
editor.drag_tool(ToolType::Freehand, 10., 20., 30., 40.);
|
||||||
|
|
||||||
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![FOLDER_ID] });
|
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::Copy { clipboard: Clipboard::Internal });
|
||||||
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
editor.handle_message(PortfolioMessage::PasteIntoFolder {
|
||||||
@@ -387,7 +386,7 @@ mod test {
|
|||||||
insert_index: -1,
|
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_added_shapes = document_before_added_shapes.metadata.all_layers().collect::<Vec<_>>();
|
||||||
let layers_before_copy = document_before_copy.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() {
|
fn copy_paste_deleted_layers() {
|
||||||
let mut editor = create_editor_with_three_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 mut layers = document_before_copy.metadata.all_layers();
|
||||||
let rect_id = layers.next().expect("rectangle");
|
let rect_id = layers.next().expect("rectangle");
|
||||||
let shape_id = layers.next().expect("shape");
|
let shape_id = layers.next().expect("shape");
|
||||||
@@ -439,7 +438,7 @@ mod test {
|
|||||||
insert_index: -1,
|
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_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
|
||||||
let layers_after_copy = document_after_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() {
|
if let Some(document) = portfolio.active_document() {
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
let artboards = document
|
let artboards = document
|
||||||
.document_legacy
|
|
||||||
.metadata
|
.metadata
|
||||||
.all_layers()
|
.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| {
|
.map(|layer| {
|
||||||
(
|
(
|
||||||
layer,
|
layer,
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
|
|
||||||
/// A dialog to allow users to customize their file export.
|
/// A dialog to allow users to customize their file export.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct ExportDialogMessageHandler {
|
pub struct ExportDialogMessageHandler {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use document_legacy::document::LayerId;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, specta::Type)]
|
#[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::MappingEntry;
|
||||||
use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping};
|
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::clipboards::Clipboard;
|
||||||
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
|
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
impl From<MappingVariant> for Mapping {
|
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`.
|
/// 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
|
/// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this struct.
|
||||||
/// struct.
|
|
||||||
#[derive(specta::Type)]
|
#[derive(specta::Type)]
|
||||||
#[specta(inline, remote = "MessageDiscriminant")]
|
#[specta(inline, remote = "MessageDiscriminant")]
|
||||||
pub struct MessageDiscriminantDef(u8);
|
pub struct MessageDiscriminantDef(u8);
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
|
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::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
||||||
|
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||||
use crate::messages::prelude::*;
|
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 graph_craft::document::NodeId;
|
||||||
use graphene_core::raster::BlendMode;
|
use graphene_core::raster::BlendMode;
|
||||||
use graphene_core::raster::Image;
|
use graphene_core::raster::Image;
|
||||||
use graphene_core::vector::style::ViewMode;
|
use graphene_core::vector::style::ViewMode;
|
||||||
use graphene_core::Color;
|
use graphene_core::Color;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
@@ -41,8 +40,7 @@ pub enum DocumentMessage {
|
|||||||
aggregate: AlignAggregate,
|
aggregate: AlignAggregate,
|
||||||
},
|
},
|
||||||
BackupDocument {
|
BackupDocument {
|
||||||
document: DocumentLegacy,
|
document: DocumentMessageHandler,
|
||||||
layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
|
|
||||||
},
|
},
|
||||||
ClearLayerTree,
|
ClearLayerTree,
|
||||||
CommitTransaction,
|
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::node_graph::NodeGraphHandlerData;
|
||||||
use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData;
|
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::clipboards::Clipboard;
|
||||||
use crate::messages::portfolio::document::utility_types::layer_panel::{LayerMetadata, RawBuffer};
|
use crate::messages::portfolio::document::utility_types::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier};
|
||||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, DocumentSave, FlipAxis};
|
use crate::messages::portfolio::document::utility_types::layer_panel::RawBuffer;
|
||||||
use crate::messages::portfolio::document::utility_types::vectorize_layer_metadata;
|
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::portfolio::utility_types::PersistentData;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
|
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
|
||||||
use crate::messages::tool::utility_types::ToolType;
|
use crate::messages::tool::utility_types::ToolType;
|
||||||
use crate::node_graph_executor::NodeGraphExecutor;
|
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::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::BlendMode;
|
||||||
use graphene_core::raster::ImageFrame;
|
use graphene_core::raster::ImageFrame;
|
||||||
|
use graphene_core::renderer::ClickTarget;
|
||||||
|
use graphene_core::transform::Footprint;
|
||||||
use graphene_core::vector::style::ViewMode;
|
use graphene_core::vector::style::ViewMode;
|
||||||
|
use graphene_core::{concrete, generic, ProtoNodeIdentifier};
|
||||||
|
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use serde::{Deserialize, Serialize};
|
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.
|
/// Utility function for providing a default boolean value to serde.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -36,52 +41,71 @@ fn return_true() -> bool {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct DocumentMessageHandler {
|
pub struct DocumentMessageHandler {
|
||||||
pub document_legacy: DocumentLegacy,
|
// Child message handlers
|
||||||
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>,
|
|
||||||
navigation_handler: NavigationMessageHandler,
|
navigation_handler: NavigationMessageHandler,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
node_graph_handler: NodeGraphMessageHandler,
|
||||||
|
#[serde(skip)]
|
||||||
overlays_message_handler: OverlaysMessageHandler,
|
overlays_message_handler: OverlaysMessageHandler,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
properties_panel_message_handler: PropertiesPanelMessageHandler,
|
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)]
|
#[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 {
|
impl Default for DocumentMessageHandler {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
document_legacy: DocumentLegacy::default(),
|
network: root_network(),
|
||||||
saved_document_identifier: 0,
|
saved_document_identifier: 0,
|
||||||
auto_saved_document_identifier: 0,
|
auto_saved_document_identifier: 0,
|
||||||
name: DEFAULT_DOCUMENT_NAME.to_string(),
|
name: DEFAULT_DOCUMENT_NAME.to_string(),
|
||||||
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
|
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
|
||||||
commit_hash: crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string(),
|
commit_hash: crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string(),
|
||||||
collapsed_folders: Vec::new(),
|
collapsed: Vec::new(),
|
||||||
document_mode: DocumentMode::DesignMode,
|
document_mode: DocumentMode::DesignMode,
|
||||||
view_mode: ViewMode::default(),
|
view_mode: ViewMode::default(),
|
||||||
snapping_state: SnappingState::default(),
|
snapping_state: SnappingState::default(),
|
||||||
@@ -90,16 +114,79 @@ impl Default for DocumentMessageHandler {
|
|||||||
document_undo_history: VecDeque::new(),
|
document_undo_history: VecDeque::new(),
|
||||||
document_redo_history: VecDeque::new(),
|
document_redo_history: VecDeque::new(),
|
||||||
undo_in_progress: false,
|
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,
|
layer_range_selection_reference: None,
|
||||||
navigation_handler: NavigationMessageHandler::default(),
|
navigation_handler: NavigationMessageHandler::default(),
|
||||||
overlays_message_handler: OverlaysMessageHandler::default(),
|
overlays_message_handler: OverlaysMessageHandler::default(),
|
||||||
properties_panel_message_handler: PropertiesPanelMessageHandler::default(),
|
properties_panel_message_handler: PropertiesPanelMessageHandler::default(),
|
||||||
node_graph_handler: Default::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 struct DocumentInputs<'a> {
|
||||||
pub document_id: u64,
|
pub document_id: u64,
|
||||||
pub ipp: &'a InputPreprocessorMessageHandler,
|
pub ipp: &'a InputPreprocessorMessageHandler,
|
||||||
@@ -126,11 +213,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
Navigation(message) => {
|
Navigation(message) => {
|
||||||
let document_bounds = self.metadata().document_bounds_viewport_space();
|
let document_bounds = self.metadata().document_bounds_viewport_space();
|
||||||
self.navigation_handler.process_message(
|
self.navigation_handler
|
||||||
message,
|
.process_message(message, responses, (&self.metadata, document_bounds, ipp, self.selected_visible_layers_bounding_box_viewport()));
|
||||||
responses,
|
|
||||||
(&self.document_legacy, document_bounds, ipp, self.document_legacy.selected_visible_layers_bounding_box_viewport()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
Overlays(message) => {
|
Overlays(message) => {
|
||||||
@@ -139,11 +223,12 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
#[remain::unsorted]
|
#[remain::unsorted]
|
||||||
PropertiesPanel(message) => {
|
PropertiesPanel(message) => {
|
||||||
let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData {
|
let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData {
|
||||||
document_name: self.name.as_str(),
|
selected_layers: &mut self.selected.iter().filter_map(|(path, selected)| selected.then_some(path.as_slice())),
|
||||||
artwork_document: &self.document_legacy,
|
|
||||||
selected_layers: &mut self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice())),
|
|
||||||
node_graph_message_handler: &self.node_graph_handler,
|
node_graph_message_handler: &self.node_graph_handler,
|
||||||
executor,
|
executor,
|
||||||
|
document_name: self.name.as_str(),
|
||||||
|
document_network: &mut self.network,
|
||||||
|
document_metadata: &mut self.metadata,
|
||||||
};
|
};
|
||||||
self.properties_panel_message_handler
|
self.properties_panel_message_handler
|
||||||
.process_message(message, responses, (persistent_data, properties_panel_message_handler_data));
|
.process_message(message, responses, (persistent_data, properties_panel_message_handler_data));
|
||||||
@@ -154,17 +239,18 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
message,
|
message,
|
||||||
responses,
|
responses,
|
||||||
NodeGraphHandlerData {
|
NodeGraphHandlerData {
|
||||||
document: &mut self.document_legacy,
|
document_network: &mut self.network,
|
||||||
|
document_metadata: &mut self.metadata,
|
||||||
document_id,
|
document_id,
|
||||||
document_name: self.name.as_str(),
|
document_name: self.name.as_str(),
|
||||||
collapsed_folders: &mut self.collapsed_folders,
|
collapsed: &mut self.collapsed,
|
||||||
input: ipp,
|
input: ipp,
|
||||||
graph_view_overlay_open,
|
graph_view_overlay_open,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[remain::unsorted]
|
#[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
|
// Messages
|
||||||
AbortTransaction => {
|
AbortTransaction => {
|
||||||
@@ -180,7 +266,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
AlignAxis::X => DVec2::X,
|
AlignAxis::X => DVec2::X,
|
||||||
AlignAxis::Y => DVec2::Y,
|
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;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,7 +294,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
}
|
}
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
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 => {
|
ClearLayerTree => {
|
||||||
// Send an empty layer tree
|
// Send an empty layer tree
|
||||||
let data_buffer: RawBuffer = Self::default().serialize_root().as_slice().into();
|
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] });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
|
||||||
}
|
}
|
||||||
DebugPrintDocument => {
|
DebugPrintDocument => {
|
||||||
info!("{:#?}\n{:#?}", self.document_legacy, self.layer_metadata);
|
info!("{:#?}\n{:#?}", self.network, self.selected);
|
||||||
}
|
}
|
||||||
DeleteLayer { layer_path } => {
|
DeleteLayer { layer_path } => {
|
||||||
responses.add(GraphOperationMessage::DeleteLayer { id: layer_path[0] });
|
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::X => DVec2::new(-1., 1.),
|
||||||
FlipAxis::Y => 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 center = (max + min) / 2.;
|
||||||
let bbox_trans = DAffine2::from_translation(-center);
|
let bbox_trans = DAffine2::from_translation(-center);
|
||||||
for layer in self.metadata().selected_layers() {
|
for layer in self.metadata().selected_layers() {
|
||||||
@@ -379,7 +465,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Nudge resize
|
// 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 size = existing_bottom_right - existing_top_left;
|
||||||
let new_size = size + if opposite_corner { -delta } else { delta };
|
let new_size = size + if opposite_corner { -delta } else { delta };
|
||||||
let enlargement_factor = new_size / size;
|
let enlargement_factor = new_size / size;
|
||||||
@@ -620,10 +706,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
StartTransaction => self.backup(responses),
|
StartTransaction => self.backup(responses),
|
||||||
ToggleLayerExpansion { layer } => {
|
ToggleLayerExpansion { layer } => {
|
||||||
let layer = LayerNodeIdentifier::new(layer, self.network());
|
let layer = LayerNodeIdentifier::new(layer, self.network());
|
||||||
if self.collapsed_folders.contains(&layer) {
|
if self.collapsed.contains(&layer) {
|
||||||
self.collapsed_folders.retain(|&collapsed_layer| collapsed_layer != layer);
|
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
|
||||||
} else {
|
} else {
|
||||||
self.collapsed_folders.push(layer);
|
self.collapsed.push(layer);
|
||||||
}
|
}
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
}
|
}
|
||||||
@@ -663,7 +749,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
responses.add(DocumentMessage::CommitTransaction);
|
responses.add(DocumentMessage::CommitTransaction);
|
||||||
}
|
}
|
||||||
UpdateDocumentTransform { transform } => {
|
UpdateDocumentTransform { transform } => {
|
||||||
self.document_legacy.metadata.document_to_viewport = transform;
|
self.metadata.document_to_viewport = transform;
|
||||||
responses.add(DocumentMessage::RenderRulers);
|
responses.add(DocumentMessage::RenderRulers);
|
||||||
responses.add(DocumentMessage::RenderScrollbars);
|
responses.add(DocumentMessage::RenderScrollbars);
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
@@ -692,49 +778,61 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DocumentMessageHandler {
|
impl DocumentMessageHandler {
|
||||||
pub fn actions_with_graph_open(&self, graph_open: bool) -> ActionList {
|
pub fn layer_visible(&self, layer: LayerNodeIdentifier) -> bool {
|
||||||
let mut common = actions!(DocumentMessageDiscriminant;
|
!layer.ancestors(&self.metadata).any(|layer| self.network.disabled.contains(&layer.to_node()))
|
||||||
Undo,
|
}
|
||||||
Redo,
|
|
||||||
SelectAllLayers,
|
|
||||||
DeselectAllLayers,
|
|
||||||
RenderDocument,
|
|
||||||
SaveDocument,
|
|
||||||
SetSnapping,
|
|
||||||
DebugPrintDocument,
|
|
||||||
ZoomCanvasToFitAll,
|
|
||||||
ZoomCanvasTo100Percent,
|
|
||||||
ZoomCanvasTo200Percent,
|
|
||||||
CreateEmptyFolder,
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.metadata().selected_layers().next().is_some() {
|
pub fn selected_visible_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||||
let select = actions!(DocumentMessageDiscriminant;
|
self.metadata.selected_layers().filter(|&layer| self.layer_visible(layer))
|
||||||
DeleteSelectedLayers,
|
}
|
||||||
DuplicateSelectedLayers,
|
|
||||||
NudgeSelectedLayers,
|
/// Runs an intersection test with all layers and a viewport space quad
|
||||||
SelectedLayersLower,
|
pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_core::renderer::Quad, network: &'a NodeNetwork) -> impl Iterator<Item = LayerNodeIdentifier> + 'a {
|
||||||
SelectedLayersLowerToBack,
|
let document_quad = self.metadata.document_to_viewport.inverse() * viewport_quad;
|
||||||
SelectedLayersRaise,
|
self.metadata
|
||||||
SelectedLayersRaiseToFront,
|
.root()
|
||||||
GroupSelectedLayers,
|
.decendants(&self.metadata)
|
||||||
UngroupSelectedLayers,
|
.filter(|&layer| self.layer_visible(layer))
|
||||||
);
|
.filter(|&layer| !is_artboard(layer, network))
|
||||||
common.extend(select);
|
.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))))
|
||||||
common.extend(self.navigation_handler.actions());
|
.map(|(layer, _)| layer)
|
||||||
common.extend(self.node_graph_handler.actions_with_node_graph_open(graph_open));
|
}
|
||||||
common
|
|
||||||
|
/// 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 {
|
pub fn network(&self) -> &NodeNetwork {
|
||||||
&self.document_legacy.document_network
|
&self.network
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metadata(&self) -> &document_legacy::document_metadata::DocumentMetadata {
|
pub fn metadata(&self) -> &DocumentMetadata {
|
||||||
&self.document_legacy.metadata
|
&self.metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_document(&self) -> String {
|
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 {
|
pub fn with_name(name: String, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Self {
|
||||||
let mut document = Self { name, ..Self::default() };
|
let mut document = Self { name, ..Self::default() };
|
||||||
let transform = document.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2.);
|
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 });
|
responses.add(DocumentMessage::UpdateDocumentTransform { transform });
|
||||||
|
|
||||||
document
|
document
|
||||||
@@ -773,7 +871,7 @@ impl DocumentMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn selected_layers(&self) -> impl Iterator<Item = &[LayerId]> {
|
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.
|
/// Returns the bounding boxes for all visible layers.
|
||||||
@@ -788,7 +886,7 @@ impl DocumentMessageHandler {
|
|||||||
for layer_node in folder.children(self.metadata()) {
|
for layer_node in folder.children(self.metadata()) {
|
||||||
data.push(layer_node.to_node());
|
data.push(layer_node.to_node());
|
||||||
space += 1;
|
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());
|
path.push(layer_node.to_node());
|
||||||
|
|
||||||
// TODO: Skip if folder is not expanded.
|
// TODO: Skip if folder is not expanded.
|
||||||
@@ -843,14 +941,10 @@ impl DocumentMessageHandler {
|
|||||||
structure
|
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
|
/// 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_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 {
|
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
|
||||||
self.document_undo_history.pop_front();
|
self.document_undo_history.pop_front();
|
||||||
}
|
}
|
||||||
@@ -861,27 +955,23 @@ impl DocumentMessageHandler {
|
|||||||
|
|
||||||
/// Copies the entire document into the history system
|
/// Copies the entire document into the history system
|
||||||
pub fn backup(&mut self, responses: &mut VecDeque<Message>) {
|
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
|
/// Push a message backing up the document in its current state
|
||||||
pub fn backup_nonmut(&self, responses: &mut VecDeque<Message>) {
|
pub fn backup_nonmut(&self, responses: &mut VecDeque<Message>) {
|
||||||
responses.add(DocumentMessage::BackupDocument {
|
responses.add(DocumentMessage::BackupDocument { document: self.clone() });
|
||||||
document: self.document_legacy.clone(),
|
|
||||||
layer_metadata: self.layer_metadata.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace the document with a new document save, returning the document save.
|
/// Replace the document with a new document save, returning the document save.
|
||||||
pub fn replace_document(&mut self, DocumentSave { document, layer_metadata }: DocumentSave) -> DocumentSave {
|
pub fn replace_document(&mut self, document: DocumentMessageHandler) -> DocumentMessageHandler {
|
||||||
// Keeping the root is required if the bounds of the viewport have changed during the operation
|
// 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 old_root = self.metadata().document_to_viewport;
|
||||||
let document = std::mem::replace(&mut self.document_legacy, document);
|
let document = std::mem::replace(self, document);
|
||||||
self.document_legacy.metadata.document_to_viewport = old_root;
|
self.metadata.document_to_viewport = old_root;
|
||||||
|
|
||||||
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
|
document
|
||||||
|
|
||||||
DocumentSave { document, layer_metadata }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo(&mut self, responses: &mut VecDeque<Message>) {
|
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();
|
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() {
|
let Some(document) = self.document_undo_history.pop_back() else {
|
||||||
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
|
return;
|
||||||
// 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();
|
|
||||||
|
|
||||||
if prev_selected_paths != selected_paths {
|
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
// 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 });
|
if prev_selected_paths != selected_paths {
|
||||||
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>) {
|
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();
|
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() {
|
let Some(document) = self.document_redo_history.pop_back() else { return };
|
||||||
// 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();
|
|
||||||
|
|
||||||
if next_selected_paths != selected_paths {
|
// Update currently displayed layer on property panel if selection changes after redo action
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
// 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 });
|
if next_selected_paths != selected_paths {
|
||||||
self.document_undo_history.push_back(document_save);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
pub fn current_identifier(&self) -> u64 {
|
||||||
// We can use the last state of the document to serve as the identifier to compare against
|
// 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
|
// This is useful since when the document is empty the identifier will be 0
|
||||||
self.document_undo_history
|
self.document_undo_history.iter().last().map(|document| document.state_identifier.finish()).unwrap_or(0)
|
||||||
.iter()
|
|
||||||
.last()
|
|
||||||
.map(|DocumentSave { document, .. }| document.current_state_identifier())
|
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_auto_saved(&self) -> bool {
|
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
|
/// 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>) {
|
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>) {
|
||||||
let mut fonts = HashSet::new();
|
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 {
|
for input in &node.inputs {
|
||||||
if let NodeInput::Value {
|
if let NodeInput::Value {
|
||||||
tagged_value: TaggedValue::Font(font),
|
tagged_value: TaggedValue::Font(font),
|
||||||
@@ -1191,12 +1279,7 @@ impl DocumentMessageHandler {
|
|||||||
let selected_layers_except_artboards = self.metadata().selected_layers_except_artboards();
|
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.
|
// 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| {
|
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()));
|
||||||
(
|
|
||||||
get_opacity(layer, &self.document_legacy).unwrap_or(100.),
|
|
||||||
get_blend_mode(layer, &self.document_legacy).unwrap_or_default(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
let first_opacity_and_blend_mode = opacity_and_blend_mode.next();
|
let first_opacity_and_blend_mode = opacity_and_blend_mode.next();
|
||||||
let result_opacity_and_blend_mode = opacity_and_blend_mode;
|
let result_opacity_and_blend_mode = opacity_and_blend_mode;
|
||||||
|
|
||||||
@@ -1322,4 +1405,39 @@ impl DocumentMessageHandler {
|
|||||||
|
|
||||||
responses.add(DocumentMessage::MoveSelectedLayersTo { parent, insert_index });
|
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::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion};
|
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::input_mapper::utility_types::input_mouse::ViewportPosition;
|
||||||
|
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||||
|
|
||||||
use document_legacy::document::Document;
|
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use serde::{Deserialize, Serialize};
|
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]
|
#[remain::check]
|
||||||
fn process_message(
|
fn process_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: NavigationMessage,
|
message: NavigationMessage,
|
||||||
responses: &mut VecDeque<Message>,
|
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::*;
|
use NavigationMessage::*;
|
||||||
|
|
||||||
@@ -85,8 +84,8 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||||||
padding_scale_factor,
|
padding_scale_factor,
|
||||||
prevent_zoom_past_100,
|
prevent_zoom_past_100,
|
||||||
} => {
|
} => {
|
||||||
let v1 = document.metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
|
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 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 center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5);
|
||||||
let size = (pos2 - pos1) / (v2 - v1);
|
let size = (pos2 - pos1) / (v2 - v1);
|
||||||
@@ -108,7 +107,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
|
|||||||
}
|
}
|
||||||
FitViewportToSelection => {
|
FitViewportToSelection => {
|
||||||
if let Some(bounds) = selection_bounds {
|
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 {
|
responses.add(FitViewportToBounds {
|
||||||
bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])],
|
bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])],
|
||||||
padding_scale_factor: Some(VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR),
|
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 });
|
responses.add(TransformCanvasEnd { abort_transform });
|
||||||
}
|
}
|
||||||
TranslateCanvas { delta } => {
|
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;
|
self.pan += transformed_delta;
|
||||||
responses.add(BroadcastEvent::CanvasTransformed);
|
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 };
|
self.transform_operation = TransformOperation::Pan { pre_commit_pan: self.pan };
|
||||||
}
|
}
|
||||||
TranslateCanvasByViewportFraction { delta } => {
|
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;
|
self.pan += transformed_delta;
|
||||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
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 crate::messages::prelude::*;
|
||||||
|
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graph_craft::document::DocumentNode;
|
use graph_craft::document::DocumentNode;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graphene_core::raster::BlendMode;
|
use graphene_core::raster::BlendMode;
|
||||||
@@ -15,7 +16,7 @@ use graphene_core::{Artboard, Color};
|
|||||||
|
|
||||||
use glam::{DAffine2, DVec2, IVec2};
|
use glam::{DAffine2, DVec2, IVec2};
|
||||||
|
|
||||||
pub type LayerIdentifier = Vec<document_legacy::document::LayerId>;
|
pub type LayerIdentifier = Vec<LayerId>;
|
||||||
|
|
||||||
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
#[impl_message(Message, DocumentMessage, GraphOperation)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
|||||||
+104
-91
@@ -1,10 +1,9 @@
|
|||||||
use super::{resolve_document_node_type, VectorDataModification};
|
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 crate::messages::prelude::*;
|
||||||
|
|
||||||
use bezier_rs::Subpath;
|
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::value::TaggedValue;
|
||||||
use graph_craft::document::{generate_uuid, DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
|
use graph_craft::document::{generate_uuid, DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
|
||||||
use graphene_core::raster::{BlendMode, ImageFrame};
|
use graphene_core::raster::{BlendMode, ImageFrame};
|
||||||
@@ -23,35 +22,41 @@ pub mod transform_utils;
|
|||||||
pub struct GraphOperationMessageHandler;
|
pub struct GraphOperationMessageHandler;
|
||||||
|
|
||||||
struct ModifyInputsContext<'a> {
|
struct ModifyInputsContext<'a> {
|
||||||
network: &'a mut NodeNetwork,
|
document_metadata: &'a mut DocumentMetadata,
|
||||||
|
document_network: &'a mut NodeNetwork,
|
||||||
node_graph: &'a mut NodeGraphMessageHandler,
|
node_graph: &'a mut NodeGraphMessageHandler,
|
||||||
responses: &'a mut VecDeque<Message>,
|
responses: &'a mut VecDeque<Message>,
|
||||||
layer: &'a [LayerId],
|
layer: &'a [LayerId],
|
||||||
outwards_links: HashMap<NodeId, Vec<NodeId>>,
|
outwards_links: HashMap<NodeId, Vec<NodeId>>,
|
||||||
layer_node: Option<NodeId>,
|
layer_node: Option<NodeId>,
|
||||||
document_metadata: &'a mut DocumentMetadata,
|
|
||||||
}
|
}
|
||||||
impl<'a> ModifyInputsContext<'a> {
|
impl<'a> ModifyInputsContext<'a> {
|
||||||
/// Get the node network from the document
|
/// 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 {
|
Self {
|
||||||
outwards_links: document.document_network.collect_outwards_links(),
|
outwards_links: document_network.collect_outwards_links(),
|
||||||
network: &mut document.document_network,
|
document_network,
|
||||||
node_graph,
|
node_graph,
|
||||||
responses,
|
responses,
|
||||||
layer: &[],
|
layer: &[],
|
||||||
layer_node: None,
|
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> {
|
fn new_with_layer(
|
||||||
let mut document = Self::new(document, node_graph, responses);
|
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 {
|
let Some(mut id) = layer.last().copied() else {
|
||||||
error!("Tried to modify root layer");
|
error!("Tried to modify root layer");
|
||||||
return None;
|
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()?;
|
id = document.outwards_links.get(&id)?.first().copied()?;
|
||||||
}
|
}
|
||||||
document.layer_node = Some(id);
|
document.layer_node = Some(id);
|
||||||
@@ -60,20 +65,20 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
|
|
||||||
/// Updates the input of an existing node
|
/// 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)) {
|
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);
|
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> {
|
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");
|
assert!(!self.document_network.nodes.contains_key(&id), "Creating already existing node");
|
||||||
let pre_node = self.network.nodes.get_mut(&pre.node_id)?;
|
let pre_node = self.document_network.nodes.get_mut(&pre.node_id)?;
|
||||||
node.metadata.position = pre_node.metadata.position;
|
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);
|
node.inputs[input] = NodeInput::node(pre.node_id, pre.node_output_index);
|
||||||
post_node.inputs[post.node_output_index] = NodeInput::node(id, output);
|
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);
|
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> {
|
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");
|
assert!(!self.document_network.nodes.contains_key(&new_id), "Creating already existing node");
|
||||||
let post_node = self.network.nodes.get_mut(&node_id)?;
|
let post_node = self.document_network.nodes.get_mut(&node_id)?;
|
||||||
|
|
||||||
post_node.inputs[input_index] = NodeInput::node(new_id, 0);
|
post_node.inputs[input_index] = NodeInput::node(new_id, 0);
|
||||||
document_node.metadata.position = post_node.metadata.position + offset;
|
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)
|
Some(new_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_artboards(&self, output: &mut NodeOutput) -> Option<(NodeId, usize)> {
|
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] {
|
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.network.nodes.get(node_id)?;
|
let sibling_node = self.document_network.nodes.get(node_id)?;
|
||||||
if sibling_node.name != "Artboard" {
|
if sibling_node.name != "Artboard" {
|
||||||
return Some((*node_id, *output_index));
|
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> {
|
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 output = NodeOutput::new(output_node_id, input_index);
|
||||||
let mut sibling_layer = None;
|
let mut sibling_layer = None;
|
||||||
let mut shift = IVec2::new(0, 3);
|
let mut shift = IVec2::new(0, 3);
|
||||||
// Locate the node output of the first sibling layer to the new layer
|
// 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) {
|
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() {
|
if sibling_node.is_layer() {
|
||||||
// There is already a layer node
|
// There is already a layer node
|
||||||
sibling_layer = Some(NodeOutput::new(node_id, 0));
|
sibling_layer = Some(NodeOutput::new(node_id, 0));
|
||||||
@@ -125,7 +130,7 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
for _ in 0..skip_layer_nodes {
|
for _ in 0..skip_layer_nodes {
|
||||||
if let Some(old_sibling) = &sibling_layer {
|
if let Some(old_sibling) = &sibling_layer {
|
||||||
output = NodeOutput::new(old_sibling.node_id, 1);
|
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);
|
shift = IVec2::new(0, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,12 +150,12 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
|
|
||||||
// Update the document metadata structure
|
// Update the document metadata structure
|
||||||
if let Some(new_id) = new_id {
|
if let Some(new_id) = new_id {
|
||||||
let parent = if self.network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
|
let parent = if self.document_network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
|
||||||
LayerNodeIdentifier::new(output_node_id, self.network)
|
LayerNodeIdentifier::new(output_node_id, self.document_network)
|
||||||
} else {
|
} else {
|
||||||
LayerNodeIdentifier::ROOT
|
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);
|
parent.push_front_child(self.document_metadata, new_child);
|
||||||
self.responses.add(DocumentMessage::DocumentStructureChanged);
|
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 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 {
|
let output_node_id = if parent == LayerNodeIdentifier::ROOT {
|
||||||
self.network.original_outputs()[0].node_id
|
self.document_network.original_outputs()[0].node_id
|
||||||
} else {
|
} else {
|
||||||
parent.to_node()
|
parent.to_node()
|
||||||
};
|
};
|
||||||
@@ -256,7 +261,7 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
let mut shift_nodes = HashSet::new();
|
let mut shift_nodes = HashSet::new();
|
||||||
let mut stack = vec![node_id];
|
let mut stack = vec![node_id];
|
||||||
while let Some(node_id) = stack.pop() {
|
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 {
|
for input in &node.inputs {
|
||||||
let NodeInput::Node { node_id, .. } = input else { continue };
|
let NodeInput::Node { node_id, .. } = input else { continue };
|
||||||
if shift_nodes.insert(*node_id) {
|
if shift_nodes.insert(*node_id) {
|
||||||
@@ -266,7 +271,7 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for node_id in shift_nodes {
|
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;
|
node.metadata.position += shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,8 +279,8 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
|
|
||||||
/// Inserts a new node and modifies the inputs
|
/// 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)) {
|
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 output_node_id = self.layer_node.unwrap_or(self.document_network.outputs[0].node_id);
|
||||||
let Some(output_node) = self.network.nodes.get_mut(&output_node_id) else {
|
let Some(output_node) = self.document_network.nodes.get_mut(&output_node_id) else {
|
||||||
warn!("Output node doesn't exist");
|
warn!("Output node doesn't exist");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -292,11 +297,11 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
};
|
};
|
||||||
let mut new_document_node = node_type.to_document_node_default_inputs([new_input], metadata);
|
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);
|
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 {
|
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;
|
node.metadata.position.x -= 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,8 +309,12 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
/// Changes the inputs of a specific node
|
/// 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)) {
|
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
|
let existing_node_id = self
|
||||||
.network
|
.document_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)
|
.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)
|
.find(|(node, _)| node.name == name)
|
||||||
.map(|(_, id)| id);
|
.map(|(_, id)| id);
|
||||||
if let Some(node_id) = existing_node_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
|
/// 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)) {
|
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
|
let existing_nodes: Vec<_> = self
|
||||||
.network
|
.document_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)
|
.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)
|
.filter(|(node, _)| node.name == name)
|
||||||
.map(|(_, id)| id)
|
.map(|(_, id)| id)
|
||||||
.collect();
|
.collect();
|
||||||
@@ -516,18 +529,18 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn delete_layer(&mut self, id: NodeId) {
|
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");
|
warn!("Deleting layer node that does not exist");
|
||||||
return;
|
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 new_input = node.inputs[1].clone();
|
||||||
let deleted_position = node.metadata.position;
|
let deleted_position = node.metadata.position;
|
||||||
|
|
||||||
for post_node in self.outwards_links.get(&id).unwrap_or(&Vec::new()) {
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -541,7 +554,7 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut delete_nodes = vec![id];
|
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.
|
// Don't delete the node if other layers depend on it.
|
||||||
if self.outwards_links.get(&id).is_some_and(|nodes| nodes.len() > 1) {
|
if self.outwards_links.get(&id).is_some_and(|nodes| nodes.len() > 1) {
|
||||||
break;
|
break;
|
||||||
@@ -552,13 +565,13 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for node_id in &delete_nodes {
|
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(node_id) = new_input.as_node() {
|
||||||
if let Some(shift) = self.network.nodes.get(&node_id).map(|node| deleted_position - node.metadata.position) {
|
if let Some(shift) = self.document_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<_>>() {
|
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.network.nodes.get_mut(&node_id) else { continue };
|
let Some(node) = self.document_network.nodes.get_mut(&node_id) else { continue };
|
||||||
node.metadata.position += shift;
|
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(
|
fn process_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
message: GraphOperationMessage,
|
message: GraphOperationMessage,
|
||||||
responses: &mut VecDeque<Message>,
|
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 {
|
match message {
|
||||||
GraphOperationMessage::FillSet { layer, fill } => {
|
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);
|
modify_inputs.fill_set(fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::OpacitySet { layer, opacity } => {
|
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);
|
modify_inputs.opacity_set(opacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::BlendModeSet { layer, blend_mode } => {
|
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);
|
modify_inputs.blend_mode_set(blend_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => {
|
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);
|
modify_inputs.update_bounds(old_bounds, new_bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::StrokeSet { layer, stroke } => {
|
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);
|
modify_inputs.stroke_set(stroke);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -611,10 +624,10 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
|
|||||||
transform_in,
|
transform_in,
|
||||||
skip_rerender,
|
skip_rerender,
|
||||||
} => {
|
} => {
|
||||||
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
|
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
||||||
let parent_transform = document.metadata.downstream_transform_to_viewport(layer_identifier);
|
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
|
||||||
let bounds = LayerBounds::new(document, &layer);
|
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
||||||
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.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender);
|
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,
|
transform_in,
|
||||||
skip_rerender,
|
skip_rerender,
|
||||||
} => {
|
} => {
|
||||||
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
|
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
||||||
let parent_transform = document.metadata.downstream_transform_to_viewport(layer_identifier);
|
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
|
||||||
|
|
||||||
let current_transform = Some(document.metadata.transform_to_viewport(layer_identifier));
|
let current_transform = Some(document_metadata.transform_to_viewport(layer_identifier));
|
||||||
let bounds = LayerBounds::new(document, &layer);
|
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
||||||
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.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender);
|
modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
|
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
|
||||||
let bounds = LayerBounds::new(document, &layer);
|
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
|
||||||
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.pivot_set(pivot, bounds);
|
modify_inputs.pivot_set(pivot, bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::Vector { layer, modification } => {
|
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);
|
modify_inputs.vector_modify(modification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::Brush { layer, strokes } => {
|
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);
|
modify_inputs.brush_modify(strokes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::NewArtboard { id, artboard } => {
|
GraphOperationMessage::NewArtboard { id, artboard } => {
|
||||||
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(id, modify_inputs.network.original_outputs()[0].node_id, 0, 0) {
|
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);
|
modify_inputs.insert_artboard(artboard, layer);
|
||||||
}
|
}
|
||||||
load_network_structure(document, collapsed_folders);
|
load_network_structure(document_network, document_metadata, collapsed);
|
||||||
}
|
}
|
||||||
GraphOperationMessage::NewBitmapLayer {
|
GraphOperationMessage::NewBitmapLayer {
|
||||||
id,
|
id,
|
||||||
@@ -662,7 +675,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
|
|||||||
parent,
|
parent,
|
||||||
insert_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) {
|
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
|
||||||
modify_inputs.insert_image_data(image_frame, layer);
|
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 } => {
|
GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index } => {
|
||||||
trace!("Inserting new layer {id} as a child of {parent:?} at index {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) {
|
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();
|
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)
|
.get(&0)
|
||||||
.and_then(|node| {
|
.and_then(|node| {
|
||||||
modify_inputs
|
modify_inputs
|
||||||
.network
|
.document_network
|
||||||
.nodes
|
.nodes
|
||||||
.get(&layer)
|
.get(&layer)
|
||||||
.map(|layer| layer.metadata.position - node.metadata.position + IVec2::new(-8, 0))
|
.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);
|
document_node = document_node.map_ids(NodeGraphMessageHandler::default_node_input, &new_ids);
|
||||||
|
|
||||||
// Insert node into network
|
// 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) {
|
if let Some(&input) = new_ids.get(&0) {
|
||||||
layer_node.inputs[0] = NodeInput::node(input, 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 });
|
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 } => {
|
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) {
|
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
|
||||||
modify_inputs.insert_vector_data(subpaths, layer);
|
modify_inputs.insert_vector_data(subpaths, layer);
|
||||||
}
|
}
|
||||||
load_network_structure(document, collapsed_folders);
|
load_network_structure(document_network, document_metadata, collapsed);
|
||||||
}
|
}
|
||||||
GraphOperationMessage::NewTextLayer {
|
GraphOperationMessage::NewTextLayer {
|
||||||
id,
|
id,
|
||||||
@@ -724,31 +737,31 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
|
|||||||
parent,
|
parent,
|
||||||
insert_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) {
|
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
|
||||||
modify_inputs.insert_text(text, font, size, layer);
|
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 } => {
|
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);
|
modify_inputs.resize_artboard(location, dimensions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GraphOperationMessage::DeleteLayer { id } => {
|
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);
|
modify_inputs.delete_layer(id);
|
||||||
load_network_structure(document, collapsed_folders);
|
load_network_structure(document_network, document_metadata, collapsed);
|
||||||
}
|
}
|
||||||
GraphOperationMessage::ClearArtboards => {
|
GraphOperationMessage::ClearArtboards => {
|
||||||
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
|
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
|
||||||
let layer_nodes = modify_inputs.network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
|
let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
|
||||||
for layer in layer_nodes {
|
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);
|
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>) {
|
pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, collapsed: &mut Vec<LayerNodeIdentifier>) {
|
||||||
document.metadata.load_structure(&document.document_network);
|
document_metadata.load_structure(document_network);
|
||||||
collapsed_folders.retain(|&layer| document.metadata.layer_exists(layer));
|
collapsed.retain(|&layer| document_metadata.layer_exists(layer));
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -1,8 +1,8 @@
|
|||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
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 bezier_rs::{ManipulatorGroup, Subpath};
|
||||||
use document_legacy::document::Document;
|
use graph_craft::document::NodeNetwork;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graph_craft::document::{value::TaggedValue, NodeInput};
|
use graph_craft::document::{value::TaggedValue, NodeInput};
|
||||||
use graphene_core::uuid::ManipulatorGroupId;
|
use graphene_core::uuid::ManipulatorGroupId;
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
@@ -53,12 +53,12 @@ pub struct LayerBounds {
|
|||||||
|
|
||||||
impl LayerBounds {
|
impl LayerBounds {
|
||||||
/// Extract the layer bounds and their transform for a layer.
|
/// Extract the layer bounds and their transform for a layer.
|
||||||
pub fn new(document: &Document, layer: &[u64]) -> Self {
|
pub fn new(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: &[u64]) -> Self {
|
||||||
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
|
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
|
||||||
Self {
|
Self {
|
||||||
bounds: document.metadata.nonzero_bounding_box(layer),
|
bounds: document_metadata.nonzero_bounding_box(layer),
|
||||||
bounds_transform: DAffine2::IDENTITY,
|
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 crate::messages::prelude::*;
|
||||||
|
|
||||||
use document_legacy::document::LayerId;
|
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
|
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ pub use self::document_node_types::*;
|
|||||||
use super::load_network_structure;
|
use super::load_network_structure;
|
||||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
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::messages::prelude::*;
|
||||||
use crate::node_graph_executor::GraphIdentifier;
|
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::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
|
use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
|
||||||
use graphene_core::*;
|
use graphene_core::*;
|
||||||
@@ -157,19 +156,19 @@ impl NodeGraphMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the buttons for disable and preview
|
/// Updates the buttons for disable and preview
|
||||||
fn update_selection_action_buttons(&mut self, document: &Document, responses: &mut VecDeque<Message>) {
|
fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) {
|
||||||
if let Some(network) = document.document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
let mut widgets = Vec::new();
|
let mut widgets = Vec::new();
|
||||||
|
|
||||||
// Don't allow disabling input or output nodes
|
// 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 there is at least one other selected node then show the hide or show button
|
||||||
if selected_nodes.next().is_some() {
|
if selected_nodes.next().is_some() {
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
// Check if any of the selected nodes are disabled
|
// 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
|
// Check if multiple nodes are selected
|
||||||
let multiple_nodes = selected_nodes.next().is_some();
|
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
|
// 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()) {
|
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) {
|
||||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||||
|
|
||||||
@@ -212,7 +211,6 @@ impl NodeGraphMessageHandler {
|
|||||||
/// Collate the properties panel sections for a node graph
|
/// Collate the properties panel sections for a node graph
|
||||||
pub fn collate_properties(&self, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
pub fn collate_properties(&self, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||||
let mut network = context.network;
|
let mut network = context.network;
|
||||||
let document = context.document;
|
|
||||||
|
|
||||||
for segment in &self.network {
|
for segment in &self.network {
|
||||||
network = network.nodes.get(segment).and_then(|node| node.implementation.get_network()).unwrap();
|
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
|
// First, we filter all the selections into layers and nodes
|
||||||
let (mut layers, mut nodes) = (Vec::new(), Vec::new());
|
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 let Some(layer_or_node) = network.nodes.get(node_id) {
|
||||||
if layer_or_node.is_layer() {
|
if layer_or_node.is_layer() {
|
||||||
layers.push(*node_id);
|
layers.push(*node_id);
|
||||||
@@ -341,10 +339,10 @@ impl NodeGraphMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the frontend's selection state in line with the backend
|
/// Updates the frontend's selection state in line with the backend
|
||||||
fn update_selected(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
|
fn update_selected(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) {
|
||||||
self.update_selection_action_buttons(document, responses);
|
self.update_selection_action_buttons(document_network, document_metadata, responses);
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphSelection {
|
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.
|
/// 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 {
|
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.document_network.nested_network_mut(&self.network) else {
|
let Some(network) = document_network.nested_network_mut(&self.network) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if !Self::remove_references_from_network(network, node_id, reconnect) {
|
if !Self::remove_references_from_network(network, node_id, reconnect) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
network.nodes.remove(&node_id);
|
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);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -447,10 +445,11 @@ impl NodeGraphMessageHandler {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NodeGraphHandlerData<'a> {
|
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_id: u64,
|
||||||
pub document_name: &'a str,
|
pub document_name: &'a str,
|
||||||
pub collapsed_folders: &'a mut Vec<LayerNodeIdentifier>,
|
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
|
||||||
pub input: &'a InputPreprocessorMessageHandler,
|
pub input: &'a InputPreprocessorMessageHandler,
|
||||||
pub graph_view_overlay_open: bool,
|
pub graph_view_overlay_open: bool,
|
||||||
}
|
}
|
||||||
@@ -458,9 +457,10 @@ pub struct NodeGraphHandlerData<'a> {
|
|||||||
impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGraphMessageHandler {
|
impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGraphMessageHandler {
|
||||||
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, data: NodeGraphHandlerData<'a>) {
|
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, data: NodeGraphHandlerData<'a>) {
|
||||||
let NodeGraphHandlerData {
|
let NodeGraphHandlerData {
|
||||||
document,
|
document_network,
|
||||||
|
document_metadata: metadata,
|
||||||
document_id,
|
document_id,
|
||||||
collapsed_folders,
|
collapsed,
|
||||||
graph_view_overlay_open,
|
graph_view_overlay_open,
|
||||||
..
|
..
|
||||||
} = data;
|
} = data;
|
||||||
@@ -471,15 +471,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
on: BroadcastEvent::SelectionChanged,
|
on: BroadcastEvent::SelectionChanged,
|
||||||
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
|
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
|
||||||
});
|
});
|
||||||
load_network_structure(document, collapsed_folders);
|
load_network_structure(document_network, metadata, collapsed);
|
||||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SelectedNodesUpdated => {
|
NodeGraphMessage::SelectedNodesUpdated => {
|
||||||
self.update_selection_action_buttons(document, responses);
|
self.update_selection_action_buttons(document_network, metadata, responses);
|
||||||
self.update_selected(document, responses);
|
self.update_selected(document_network, metadata, responses);
|
||||||
if document.metadata.selected_layers().count() <= 1 {
|
if metadata.selected_layers().count() <= 1 {
|
||||||
responses.add(DocumentMessage::SetRangeSelectionLayer {
|
responses.add(DocumentMessage::SetRangeSelectionLayer {
|
||||||
new_layer: document.metadata.selected_layers().next(),
|
new_layer: metadata.selected_layers().next(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
@@ -492,7 +492,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
} => {
|
} => {
|
||||||
let node_id = input_node;
|
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");
|
error!("No network");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -515,13 +515,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender });
|
responses.add(NodeGraphMessage::SendGraph { should_rerender });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::Copy => {
|
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");
|
error!("No network");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Collect the selected nodes
|
// 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();
|
let copied_nodes: Vec<_> = Self::copy_nodes(network, new_ids).collect();
|
||||||
|
|
||||||
// Prefix to show that this is nodes
|
// 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 });
|
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::DeleteNode { node_id, reconnect } => {
|
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 } => {
|
NodeGraphMessage::DeleteSelectedNodes { reconnect } => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
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::DeleteNode { node_id, reconnect });
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
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
|
// 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() {
|
if let Some(layer_path) = self.layer_path.clone() {
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||||
} else {
|
} else {
|
||||||
@@ -579,7 +579,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::DisconnectNodes { node_id, input_index } => {
|
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");
|
warn!("No network");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -607,30 +607,30 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender });
|
responses.add(NodeGraphMessage::SendGraph { should_rerender });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::DoubleClickNode { node } => {
|
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() {
|
if network.nodes.get(&node).and_then(|node| node.implementation.get_network()).is_some() {
|
||||||
self.network.push(node);
|
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::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 => {
|
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);
|
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);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
|
||||||
// Copy the selected nodes
|
// Copy the selected nodes
|
||||||
let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>();
|
let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>();
|
||||||
|
|
||||||
// Select the new nodes
|
// 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);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
|
||||||
for (node_id, mut document_node) in copied_nodes {
|
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::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 });
|
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
|
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
|
||||||
document.metadata.clear_selected_nodes();
|
metadata.clear_selected_nodes();
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
|
||||||
for _ in 0..depth_of_nesting {
|
for _ in 0..depth_of_nesting {
|
||||||
self.network.pop();
|
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::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 } => {
|
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");
|
warn!("No network");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -689,17 +689,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::InsertNode { node_id, document_node } => {
|
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);
|
network.nodes.insert(node_id, document_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::MoveSelectedNodes { displacement_x, displacement_y } => {
|
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");
|
warn!("No network");
|
||||||
return;
|
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) {
|
if let Some(node) = network.nodes.get_mut(node_id) {
|
||||||
node.metadata.position += IVec2::new(displacement_x, displacement_y)
|
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);
|
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::PasteNodes { serialized_nodes } => {
|
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");
|
warn!("No network");
|
||||||
return;
|
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::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path: Vec::new() }),
|
||||||
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
NodeGraphMessage::SelectedNodesAdd { nodes } => {
|
||||||
document.metadata.add_selected_nodes(nodes);
|
metadata.add_selected_nodes(nodes);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SelectedNodesRemove { nodes } => {
|
NodeGraphMessage::SelectedNodesRemove { nodes } => {
|
||||||
document.metadata.retain_selected_nodes(|node| !nodes.contains(node));
|
metadata.retain_selected_nodes(|node| !nodes.contains(node));
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SelectedNodesSet { nodes } => {
|
NodeGraphMessage::SelectedNodesSet { nodes } => {
|
||||||
document.metadata.set_selected_nodes(nodes);
|
metadata.set_selected_nodes(nodes);
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SendGraph { should_rerender } => {
|
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);
|
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
||||||
if should_rerender {
|
if should_rerender {
|
||||||
if let Some(layer_path) = self.layer_path.clone() {
|
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 } => {
|
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) {
|
if let Some(node) = network.nodes.get(&node_id) {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
@@ -798,7 +798,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SetNodeInput { node_id, input_index, input } => {
|
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) {
|
if let Some(node) = network.nodes.get_mut(&node_id) {
|
||||||
let Some(node_input) = node.inputs.get_mut(input_index) else {
|
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:#?}");
|
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();
|
let structure_changed = node_input.as_node().is_some() || input.as_node().is_some();
|
||||||
*node_input = input;
|
*node_input = input;
|
||||||
if structure_changed {
|
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;
|
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(network) = network {
|
||||||
if let Some(node) = network.nodes.get_mut(node_id) {
|
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 } => {
|
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");
|
warn!("No network");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -887,23 +887,23 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ToggleSelectedHidden => {
|
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);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
let new_hidden = !document.metadata.selected_nodes().any(|id| network.disabled.contains(id));
|
let new_hidden = !metadata.selected_nodes().any(|id| network.disabled.contains(id));
|
||||||
for &node_id in document.metadata.selected_nodes() {
|
for &node_id in metadata.selected_nodes() {
|
||||||
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
|
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ToggleHidden { node_id } => {
|
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);
|
let new_hidden = !network.disabled.contains(&node_id);
|
||||||
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
|
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SetHidden { node_id, 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 {
|
if !hidden {
|
||||||
network.disabled.retain(|&id| node_id != id);
|
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) {
|
} 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);
|
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 } => {
|
NodeGraphMessage::SetName { node_id, name } => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
responses.add(NodeGraphMessage::SetNameImpl { node_id, name });
|
responses.add(NodeGraphMessage::SetNameImpl { node_id, name });
|
||||||
}
|
}
|
||||||
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) {
|
if let Some(node) = network.nodes.get_mut(&node_id) {
|
||||||
node.alias = name;
|
node.alias = name;
|
||||||
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
|
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 });
|
responses.add(NodeGraphMessage::TogglePreviewImpl { node_id });
|
||||||
}
|
}
|
||||||
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
|
// Check if the node is not already being previewed
|
||||||
if !network.outputs_contain(node_id) {
|
if !network.outputs_contain(node_id) {
|
||||||
network.previous_outputs = Some(network.previous_outputs.to_owned().unwrap_or_else(|| network.outputs.clone()));
|
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::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() {
|
if let Some(layer_path) = self.layer_path.clone() {
|
||||||
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
|
||||||
} else {
|
} else {
|
||||||
@@ -955,8 +955,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::UpdateNewNodeGraph => {
|
NodeGraphMessage::UpdateNewNodeGraph => {
|
||||||
if let Some(network) = document.document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
document.metadata.clear_selected_nodes();
|
metadata.clear_selected_nodes();
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
|
||||||
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
|
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();
|
let node_types = document_node_types::collect_node_types();
|
||||||
responses.add(FrontendMessage::UpdateNodeTypes { 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 {
|
fn actions(&self) -> ActionList {
|
||||||
|
|||||||
+13
-9
@@ -1,11 +1,15 @@
|
|||||||
use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
|
use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
|
||||||
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
|
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
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 crate::node_graph_executor::NodeGraphExecutor;
|
||||||
|
|
||||||
use graph_craft::concrete;
|
use graph_craft::concrete;
|
||||||
use graph_craft::document::value::*;
|
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
|
use graph_craft::document::{value::*, DocumentNodeMetadata};
|
||||||
use graph_craft::imaginate_input::ImaginateSamplingMethod;
|
use graph_craft::imaginate_input::ImaginateSamplingMethod;
|
||||||
use graph_craft::ProtoNodeIdentifier;
|
use graph_craft::ProtoNodeIdentifier;
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
@@ -68,13 +72,13 @@ impl DocumentOutputType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct NodePropertiesContext<'a> {
|
pub struct NodePropertiesContext<'a> {
|
||||||
pub persistent_data: &'a crate::messages::portfolio::utility_types::PersistentData,
|
pub persistent_data: &'a PersistentData,
|
||||||
pub document: &'a document_legacy::document::Document,
|
pub responses: &'a mut VecDeque<Message>,
|
||||||
pub responses: &'a mut VecDeque<crate::messages::prelude::Message>,
|
pub layer_path: &'a [LayerId],
|
||||||
pub layer_path: &'a [document_legacy::document::LayerId],
|
|
||||||
pub nested_path: &'a [NodeId],
|
pub nested_path: &'a [NodeId],
|
||||||
pub executor: &'a mut NodeGraphExecutor,
|
pub executor: &'a mut NodeGraphExecutor,
|
||||||
pub network: &'a NodeNetwork,
|
pub network: &'a NodeNetwork,
|
||||||
|
pub metadata: &'a mut DocumentMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[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
|
/// 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();
|
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");
|
assert_eq!(inputs.len(), self.inputs.len(), "Inputs passed from the graph must be equal to the number required");
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
@@ -2501,7 +2505,7 @@ impl DocumentNodeDefinition {
|
|||||||
inputs,
|
inputs,
|
||||||
has_primary_output: self.has_primary_output,
|
has_primary_output: self.has_primary_output,
|
||||||
implementation: self.generate_implementation(),
|
implementation: self.generate_implementation(),
|
||||||
metadata,
|
metadata: document_metadata,
|
||||||
manual_composition: self.manual_composition.clone(),
|
manual_composition: self.manual_composition.clone(),
|
||||||
..Default::default()
|
..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.
|
/// 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.
|
/// `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 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()));
|
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
|
/// 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) {
|
pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext) {
|
||||||
for layer in document.metadata().selected_layers() {
|
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 transform = document.metadata().transform_to_viewport(layer);
|
||||||
let selected = shape_editor.selected_shape_state.get(&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));
|
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
|
||||||
|
|||||||
+5
-4
@@ -15,10 +15,11 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
|||||||
use PropertiesPanelMessage::*;
|
use PropertiesPanelMessage::*;
|
||||||
|
|
||||||
let PropertiesPanelMessageHandlerData {
|
let PropertiesPanelMessageHandlerData {
|
||||||
document_name,
|
|
||||||
artwork_document,
|
|
||||||
node_graph_message_handler,
|
node_graph_message_handler,
|
||||||
executor,
|
executor,
|
||||||
|
document_network,
|
||||||
|
document_metadata,
|
||||||
|
document_name,
|
||||||
..
|
..
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
@@ -36,12 +37,12 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
|||||||
Refresh => {
|
Refresh => {
|
||||||
let mut context = NodePropertiesContext {
|
let mut context = NodePropertiesContext {
|
||||||
persistent_data,
|
persistent_data,
|
||||||
document: artwork_document,
|
|
||||||
responses,
|
responses,
|
||||||
nested_path: &node_graph_message_handler.network,
|
nested_path: &node_graph_message_handler.network,
|
||||||
layer_path: &[],
|
layer_path: &[],
|
||||||
executor,
|
executor,
|
||||||
network: &artwork_document.document_network,
|
network: document_network,
|
||||||
|
metadata: document_metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
let properties_sections = node_graph_message_handler.collate_properties(&mut context);
|
let properties_sections = node_graph_message_handler.collate_properties(&mut context);
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
use document_legacy::document::Document as DocumentLegacy;
|
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
|
||||||
use document_legacy::document::LayerId;
|
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 struct PropertiesPanelMessageHandlerData<'a> {
|
||||||
pub document_name: &'a str,
|
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 selected_layers: &'a mut dyn Iterator<Item = &'a [LayerId]>,
|
||||||
pub node_graph_message_handler: &'a NodeGraphMessageHandler,
|
pub node_graph_message_handler: &'a NodeGraphMessageHandler,
|
||||||
pub executor: &'a mut NodeGraphExecutor,
|
pub executor: &'a mut NodeGraphExecutor,
|
||||||
|
|||||||
+62
-30
@@ -8,6 +8,10 @@ use glam::{DAffine2, DVec2};
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
|
||||||
|
// ================
|
||||||
|
// DocumentMetadata
|
||||||
|
// ================
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DocumentMetadata {
|
pub struct DocumentMetadata {
|
||||||
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
||||||
@@ -33,9 +37,11 @@ impl Default for DocumentMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct SelectionChanged;
|
|
||||||
|
|
||||||
// layer iters
|
// =================================
|
||||||
|
// DocumentMetadata: Layer iterators
|
||||||
|
// =================================
|
||||||
|
|
||||||
impl DocumentMetadata {
|
impl DocumentMetadata {
|
||||||
/// Get the root layer from the document
|
/// Get the root layer from the document
|
||||||
pub const fn root(&self) -> LayerNodeIdentifier {
|
pub const fn root(&self) -> LayerNodeIdentifier {
|
||||||
@@ -152,7 +158,10 @@ impl DocumentMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// selected layer modifications
|
// ==============================================
|
||||||
|
// DocumentMetadata: Selected layer modifications
|
||||||
|
// ==============================================
|
||||||
|
|
||||||
impl DocumentMetadata {
|
impl DocumentMetadata {
|
||||||
pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
|
pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
|
||||||
self.selected_nodes.retain(f);
|
self.selected_nodes.retain(f);
|
||||||
@@ -172,6 +181,10 @@ impl DocumentMetadata {
|
|||||||
|
|
||||||
/// Loads the structure of layer nodes from a node graph.
|
/// Loads the structure of layer nodes from a node graph.
|
||||||
pub fn load_structure(&mut self, graph: &NodeNetwork) {
|
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.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]);
|
||||||
self.folders = HashSet::new();
|
self.folders = HashSet::new();
|
||||||
self.artboards = 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 {
|
impl DocumentMetadata {
|
||||||
/// Update the cached transforms of the layers
|
/// Update the cached transforms of the layers
|
||||||
pub fn update_transforms(&mut self, new_upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>) {
|
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 {
|
impl DocumentMetadata {
|
||||||
/// Update the cached click targets of the layers
|
/// Update the cached click targets of the layers
|
||||||
pub fn update_click_targets(&mut self, new_click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>) {
|
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)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct LayerNodeIdentifier(NonZeroU64);
|
pub struct LayerNodeIdentifier(NonZeroU64);
|
||||||
|
|
||||||
@@ -558,12 +562,16 @@ impl LayerNodeIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========
|
||||||
|
// AxisIter
|
||||||
|
// ========
|
||||||
|
|
||||||
/// Iterator over specified axis.
|
/// Iterator over specified axis.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AxisIter<'a> {
|
pub struct AxisIter<'a> {
|
||||||
layer_node: Option<LayerNodeIdentifier>,
|
pub layer_node: Option<LayerNodeIdentifier>,
|
||||||
next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>,
|
pub next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>,
|
||||||
document_metadata: &'a DocumentMetadata,
|
pub document_metadata: &'a DocumentMetadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for AxisIter<'a> {
|
impl<'a> Iterator for AxisIter<'a> {
|
||||||
@@ -576,6 +584,10 @@ impl<'a> Iterator for AxisIter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==============
|
||||||
|
// DecendantsIter
|
||||||
|
// ==============
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DecendantsIter<'a> {
|
pub struct DecendantsIter<'a> {
|
||||||
front: Option<LayerNodeIdentifier>,
|
front: Option<LayerNodeIdentifier>,
|
||||||
@@ -620,8 +632,12 @@ impl<'a> DoubleEndedIterator for DecendantsIter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============
|
||||||
|
// NodeRelations
|
||||||
|
// =============
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct NodeRelations {
|
struct NodeRelations {
|
||||||
parent: Option<LayerNodeIdentifier>,
|
parent: Option<LayerNodeIdentifier>,
|
||||||
previous_sibling: Option<LayerNodeIdentifier>,
|
previous_sibling: Option<LayerNodeIdentifier>,
|
||||||
next_sibling: Option<LayerNodeIdentifier>,
|
next_sibling: Option<LayerNodeIdentifier>,
|
||||||
@@ -629,6 +645,22 @@ pub struct NodeRelations {
|
|||||||
last_child: Option<LayerNodeIdentifier>,
|
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]
|
#[test]
|
||||||
fn test_tree() {
|
fn test_tree() {
|
||||||
let mut document_metadata = DocumentMetadata::default();
|
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::ser::SerializeStruct;
|
||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
|
||||||
pub enum LayerClassification {
|
pub enum LayerClassification {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -55,8 +43,8 @@ pub struct LayerPanelEntry {
|
|||||||
pub tooltip: String,
|
pub tooltip: String,
|
||||||
#[serde(rename = "layerClassification")]
|
#[serde(rename = "layerClassification")]
|
||||||
pub layer_classification: LayerClassification,
|
pub layer_classification: LayerClassification,
|
||||||
#[serde(rename = "layerMetadata")]
|
pub selected: bool,
|
||||||
pub layer_metadata: LayerMetadata,
|
pub expanded: bool,
|
||||||
pub path: Vec<LayerId>,
|
pub path: Vec<LayerId>,
|
||||||
pub thumbnail: String,
|
pub thumbnail: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
pub use super::layer_panel::{LayerMetadata, LayerPanelEntry};
|
pub use super::layer_panel::LayerPanelEntry;
|
||||||
use document_legacy::document::Document as DocumentLegacy;
|
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||||
use document_legacy::document::LayerId;
|
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
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)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash)]
|
||||||
pub enum FlipAxis {
|
pub enum FlipAxis {
|
||||||
X,
|
X,
|
||||||
@@ -32,8 +25,9 @@ pub enum AlignAggregate {
|
|||||||
Center,
|
Center,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum DocumentMode {
|
pub enum DocumentMode {
|
||||||
|
#[default]
|
||||||
DesignMode,
|
DesignMode,
|
||||||
SelectMode,
|
SelectMode,
|
||||||
GuideMode,
|
GuideMode,
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
pub mod clipboards;
|
pub mod clipboards;
|
||||||
|
pub mod document_metadata;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod layer_panel;
|
pub mod layer_panel;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod transformation;
|
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::consts::{ROTATE_SNAP_ANGLE, SCALE_SNAP_INTERVAL};
|
||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
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::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||||
use crate::messages::tool::utility_types::ToolType;
|
use crate::messages::tool::utility_types::ToolType;
|
||||||
|
|
||||||
use document_legacy::document::Document;
|
use graph_craft::document::NodeNetwork;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::renderer::Quad;
|
use graphene_core::renderer::Quad;
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
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 {
|
match self {
|
||||||
OriginalTransforms::Layer(layer_map) => {
|
OriginalTransforms::Layer(layer_map) => {
|
||||||
layer_map.retain(|layer, _| selected.contains(layer));
|
layer_map.retain(|layer, _| selected.contains(layer));
|
||||||
for &layer in selected {
|
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) => {
|
OriginalTransforms::Path(path_map) => {
|
||||||
@@ -61,7 +61,7 @@ impl OriginalTransforms {
|
|||||||
if path_map.contains_key(&layer) {
|
if path_map.contains_key(&layer) {
|
||||||
continue;
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
let get_manipulator_point_position = |point_id: ManipulatorPointId| {
|
let get_manipulator_point_position = |point_id: ManipulatorPointId| {
|
||||||
@@ -312,7 +312,8 @@ impl TransformOperation {
|
|||||||
pub struct Selected<'a> {
|
pub struct Selected<'a> {
|
||||||
pub selected: &'a [LayerNodeIdentifier],
|
pub selected: &'a [LayerNodeIdentifier],
|
||||||
pub responses: &'a mut VecDeque<Message>,
|
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 original_transforms: &'a mut OriginalTransforms,
|
||||||
pub pivot: &'a mut DVec2,
|
pub pivot: &'a mut DVec2,
|
||||||
pub shape_editor: Option<&'a ShapeState>,
|
pub shape_editor: Option<&'a ShapeState>,
|
||||||
@@ -325,7 +326,8 @@ impl<'a> Selected<'a> {
|
|||||||
pivot: &'a mut DVec2,
|
pivot: &'a mut DVec2,
|
||||||
selected: &'a [LayerNodeIdentifier],
|
selected: &'a [LayerNodeIdentifier],
|
||||||
responses: &'a mut VecDeque<Message>,
|
responses: &'a mut VecDeque<Message>,
|
||||||
document: &'a Document,
|
document_network: &'a NodeNetwork,
|
||||||
|
document_metadata: &'a DocumentMetadata,
|
||||||
shape_editor: Option<&'a ShapeState>,
|
shape_editor: Option<&'a ShapeState>,
|
||||||
tool_type: &'a ToolType,
|
tool_type: &'a ToolType,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -334,12 +336,13 @@ impl<'a> Selected<'a> {
|
|||||||
*original_transforms = OriginalTransforms::Layer(HashMap::new());
|
*original_transforms = OriginalTransforms::Layer(HashMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
original_transforms.update(selected, document, shape_editor);
|
original_transforms.update(selected, document_network, document_metadata, shape_editor);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
selected,
|
selected,
|
||||||
responses,
|
responses,
|
||||||
document,
|
document_network,
|
||||||
|
document_metadata,
|
||||||
original_transforms,
|
original_transforms,
|
||||||
pivot,
|
pivot,
|
||||||
shape_editor,
|
shape_editor,
|
||||||
@@ -351,7 +354,7 @@ impl<'a> Selected<'a> {
|
|||||||
let xy_summation = self
|
let xy_summation = self
|
||||||
.selected
|
.selected
|
||||||
.iter()
|
.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)
|
.reduce(|a, b| a + b)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
@@ -362,15 +365,15 @@ impl<'a> Selected<'a> {
|
|||||||
let [min, max] = self
|
let [min, max] = self
|
||||||
.selected
|
.selected
|
||||||
.iter()
|
.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)
|
.reduce(Quad::combine_bounds)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
(min + max) / 2.
|
(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 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;
|
let new = to.inverse() * transformation * to * original_transform;
|
||||||
responses.add(GraphOperationMessage::TransformSet {
|
responses.add(GraphOperationMessage::TransformSet {
|
||||||
layer: layer.to_path(),
|
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>) {
|
fn transform_path(
|
||||||
let viewspace = document.metadata.transform_to_viewport(layer);
|
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 layerspace_rotation = viewspace.inverse() * transformation;
|
||||||
|
|
||||||
let Some(initial_points) = initial_points else {
|
let Some(initial_points) = initial_points else {
|
||||||
@@ -404,12 +413,12 @@ impl<'a> Selected<'a> {
|
|||||||
pub fn apply_transformation(&mut self, transformation: DAffine2) {
|
pub fn apply_transformation(&mut self, transformation: DAffine2) {
|
||||||
if !self.selected.is_empty() {
|
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
|
// 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();
|
let layer = *layer_ancestors.last().unwrap();
|
||||||
|
|
||||||
match &self.original_transforms {
|
match &self.original_transforms {
|
||||||
OriginalTransforms::Layer(layer_transforms) => Self::transform_layer(self.document, layer, layer_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, layer, path_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);
|
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::frontend::utility_types::{ExportBounds, FileType};
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
|
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use document_legacy::document::LayerId;
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::text::Font;
|
use graphene_core::text::Font;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|||||||
@@ -676,10 +676,8 @@ impl PortfolioMessageHandler {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.executor
|
self.executor.poll_node_graph_evaluation(active_document, responses).unwrap_or_else(|e| {
|
||||||
.poll_node_graph_evaluation(&mut active_document.document_legacy, &mut active_document.collapsed_folders, responses)
|
log::error!("Error while evaluating node graph: {e}");
|
||||||
.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::node_graph::VectorDataModification;
|
||||||
|
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use bezier_rs::{ManipulatorGroup, Subpath};
|
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||||
use document_legacy::{document::Document, document_metadata::LayerNodeIdentifier};
|
|
||||||
use graph_craft::document::{value::TaggedValue, DocumentNode, NodeId, NodeInput, NodeNetwork};
|
use graph_craft::document::{value::TaggedValue, DocumentNode, NodeId, NodeInput, NodeNetwork};
|
||||||
use graphene_core::raster::{BlendMode, ImageFrame};
|
use graphene_core::raster::{BlendMode, ImageFrame};
|
||||||
use graphene_core::text::Font;
|
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
|
/// Locate the subpaths from the shape nodes of a particular layer
|
||||||
pub fn get_subpaths(layer: LayerNodeIdentifier, document: &Document) -> Option<&Vec<Subpath<ManipulatorGroupId>>> {
|
pub fn get_subpaths(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<&Vec<Subpath<ManipulatorGroupId>>> {
|
||||||
if let TaggedValue::Subpaths(subpaths) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 0)? {
|
if let TaggedValue::Subpaths(subpaths) = NodeGraphLayer::new(layer, document_network)?.find_input("Shape", 0)? {
|
||||||
Some(subpaths)
|
Some(subpaths)
|
||||||
} else {
|
} else {
|
||||||
None
|
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)
|
/// 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> {
|
pub fn get_pivot(layer: LayerNodeIdentifier, network: &NodeNetwork) -> Option<DVec2> {
|
||||||
if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, document)?.find_input("Transform", 5)? {
|
if let TaggedValue::DVec2(pivot) = NodeGraphLayer::new(layer, network)?.find_input("Transform", 5)? {
|
||||||
Some(*pivot)
|
Some(*pivot)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_viewport_pivot(layer: LayerNodeIdentifier, document: &Document) -> DVec2 {
|
pub fn get_viewport_pivot(layer: LayerNodeIdentifier, document_network: &NodeNetwork, document_metadata: &DocumentMetadata) -> DVec2 {
|
||||||
let [min, max] = document.metadata.nonzero_bounding_box(layer);
|
let [min, max] = document_metadata.nonzero_bounding_box(layer);
|
||||||
let pivot = get_pivot(layer, document).unwrap_or(DVec2::splat(0.5));
|
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)
|
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
|
/// 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>> {
|
pub fn get_mirror_handles(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<&Vec<ManipulatorGroupId>> {
|
||||||
if let TaggedValue::ManipulatorGroupIds(mirror_handles) = NodeGraphLayer::new(layer, document)?.find_input("Shape", 1)? {
|
if let TaggedValue::ManipulatorGroupIds(mirror_handles) = NodeGraphLayer::new(layer, document_network)?.find_input("Shape", 1)? {
|
||||||
Some(mirror_handles)
|
Some(mirror_handles)
|
||||||
} else {
|
} else {
|
||||||
None
|
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
|
/// Get the current gradient of a layer from the closest Fill node
|
||||||
pub fn get_gradient(layer: LayerNodeIdentifier, document: &Document) -> Option<Gradient> {
|
pub fn get_gradient(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<Gradient> {
|
||||||
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Fill")?;
|
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Fill")?;
|
||||||
let TaggedValue::FillType(FillType::Gradient) = inputs.get(1)?.as_value()? else {
|
let TaggedValue::FillType(FillType::Gradient) = inputs.get(1)?.as_value()? else {
|
||||||
return None;
|
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
|
/// Get the current fill of a layer from the closest Fill node
|
||||||
pub fn get_fill_color(layer: LayerNodeIdentifier, document: &Document) -> Option<Color> {
|
pub fn get_fill_color(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<Color> {
|
||||||
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Fill")?;
|
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Fill")?;
|
||||||
let TaggedValue::Color(color) = inputs.get(2)?.as_value()? else {
|
let TaggedValue::Color(color) = inputs.get(2)?.as_value()? else {
|
||||||
return None;
|
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
|
/// 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> {
|
pub fn get_blend_mode(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<BlendMode> {
|
||||||
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Blend Mode")?;
|
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Blend Mode")?;
|
||||||
let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else {
|
let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else {
|
||||||
return None;
|
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
|
/// - 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
|
/// - 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.
|
/// 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> {
|
pub fn get_opacity(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<f32> {
|
||||||
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Opacity")?;
|
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Opacity")?;
|
||||||
let TaggedValue::F32(opacity) = inputs.get(1)?.as_value()? else {
|
let TaggedValue::F32(opacity) = inputs.get(1)?.as_value()? else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
Some(*opacity)
|
Some(*opacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fill_id(layer: LayerNodeIdentifier, document: &Document) -> Option<NodeId> {
|
pub fn get_fill_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<NodeId> {
|
||||||
NodeGraphLayer::new(layer, document)?.node_id("Fill")
|
NodeGraphLayer::new(layer, document_network)?.node_id("Fill")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_text_id(layer: LayerNodeIdentifier, document: &Document) -> Option<NodeId> {
|
pub fn get_text_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<NodeId> {
|
||||||
NodeGraphLayer::new(layer, document)?.node_id("Text")
|
NodeGraphLayer::new(layer, document_network)?.node_id("Text")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets properties from the Text node
|
/// Gets properties from the Text node
|
||||||
pub fn get_text(layer: LayerNodeIdentifier, document: &Document) -> Option<(&String, &Font, f64)> {
|
pub fn get_text(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<(&String, &Font, f64)> {
|
||||||
let inputs = NodeGraphLayer::new(layer, document)?.find_node_inputs("Text")?;
|
let inputs = NodeGraphLayer::new(layer, document_network)?.find_node_inputs("Text")?;
|
||||||
let NodeInput::Value {
|
let NodeInput::Value {
|
||||||
tagged_value: TaggedValue::String(text),
|
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.
|
/// 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 {
|
pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, document_network: &NodeNetwork, node_name: &str) -> bool {
|
||||||
NodeGraphLayer::new(layer, document).is_some_and(|layer| layer.find_node_inputs(node_name).is_some())
|
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
|
/// Convert subpaths to an iterator of manipulator groups
|
||||||
@@ -205,12 +205,11 @@ pub struct NodeGraphLayer<'a> {
|
|||||||
|
|
||||||
impl<'a> NodeGraphLayer<'a> {
|
impl<'a> NodeGraphLayer<'a> {
|
||||||
/// Get the layer node from the document
|
/// Get the layer node from the document
|
||||||
pub fn new(layer: LayerNodeIdentifier, document: &'a document_legacy::document::Document) -> Option<Self> {
|
pub fn new(layer: LayerNodeIdentifier, network: &'a NodeNetwork) -> Option<Self> {
|
||||||
let node_graph = &document.document_network;
|
let outwards_links = network.collect_outwards_links();
|
||||||
let outwards_links = document.document_network.collect_outwards_links();
|
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
node_graph,
|
node_graph: network,
|
||||||
_outwards_links: outwards_links,
|
_outwards_links: outwards_links,
|
||||||
layer_node: layer.to_node(),
|
layer_node: layer.to_node(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ use super::graph_modification_utils;
|
|||||||
use crate::consts::PIVOT_OUTER;
|
use crate::consts::PIVOT_OUTER;
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||||
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@ impl Pivot {
|
|||||||
|
|
||||||
/// Recomputes the pivot position and transform.
|
/// Recomputes the pivot position and transform.
|
||||||
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
|
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 {
|
let Some(first) = layers.next() else {
|
||||||
// If no layers are selected then we revert things back to default
|
// If no layers are selected then we revert things back to default
|
||||||
self.normalized_pivot = DVec2::splat(0.5);
|
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 just one layer is selected we can use its inner transform (as it accounts for rotation)
|
||||||
if selected_layers_count == 1 {
|
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.normalized_pivot = normalized_pivot;
|
||||||
self.transform_from_normalized = Self::get_layer_pivot_transform(first, document);
|
self.transform_from_normalized = Self::get_layer_pivot_transform(first, document);
|
||||||
self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot));
|
self.pivot = Some(self.transform_from_normalized.transform_point2(normalized_pivot));
|
||||||
} else {
|
} else {
|
||||||
// If more than one layer is selected we use the AABB with the mean of the pivots
|
// If more than one layer is selected we use the AABB with the mean of the pivots
|
||||||
let xy_summation = document
|
let xy_summation = document
|
||||||
.document_legacy
|
|
||||||
.selected_visible_layers()
|
.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)
|
.reduce(|a, b| a + b)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let pivot = xy_summation / selected_layers_count as f64;
|
let pivot = xy_summation / selected_layers_count as f64;
|
||||||
self.pivot = Some(pivot);
|
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.normalized_pivot = (pivot - min) / (max - min);
|
||||||
|
|
||||||
self.transform_from_normalized = DAffine2::from_translation(min) * DAffine2::from_scale(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.
|
/// 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>) {
|
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 transform = Self::get_layer_pivot_transform(layer, document);
|
||||||
let pivot = transform.inverse().transform_point2(position);
|
let pivot = transform.inverse().transform_point2(position);
|
||||||
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
// 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_keyboard::Key;
|
||||||
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
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::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
|
|
||||||
use glam::{DAffine2, DVec2, Vec2Swizzles};
|
use glam::{DAffine2, DVec2, Vec2Swizzles};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use super::graph_modification_utils;
|
use super::graph_modification_utils;
|
||||||
use crate::consts::DRAG_THRESHOLD;
|
use crate::consts::DRAG_THRESHOLD;
|
||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
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::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::{get_manipulator_from_id, get_manipulator_groups, get_mirror_handles, get_subpaths};
|
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 bezier_rs::{Bezier, ManipulatorGroup, TValue};
|
||||||
use document_legacy::document::Document;
|
use graph_craft::document::NodeNetwork;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::uuid::ManipulatorGroupId;
|
use graphene_core::uuid::ManipulatorGroupId;
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
|
|
||||||
@@ -66,15 +66,22 @@ pub type OpposingHandleLengths = HashMap<LayerNodeIdentifier, HashMap<Manipulato
|
|||||||
impl ShapeState {
|
impl ShapeState {
|
||||||
/// Select the first point within the selection threshold.
|
/// Select the first point within the selection threshold.
|
||||||
/// Returns a tuple of the points if found and the offset, or `None` otherwise.
|
/// 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() {
|
if self.selected_shape_state.is_empty() {
|
||||||
return None;
|
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:?}");
|
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 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)?;
|
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);
|
selected_shape_state.select_point(manipulator_point_id);
|
||||||
|
|
||||||
// Offset to snap the selected point to the cursor
|
// 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
|
let points = self
|
||||||
.selected_shape_state
|
.selected_shape_state
|
||||||
@@ -115,9 +122,9 @@ impl ShapeState {
|
|||||||
None
|
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() {
|
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) {
|
for manipulator in get_manipulator_groups(subpaths) {
|
||||||
state.select_point(ManipulatorPointId::new(manipulator.id, SelectedType::Anchor));
|
state.select_point(ManipulatorPointId::new(manipulator.id, SelectedType::Anchor));
|
||||||
for selected_type in &[SelectedType::InHandle, SelectedType::OutHandle] {
|
for selected_type in &[SelectedType::InHandle, SelectedType::OutHandle] {
|
||||||
@@ -148,13 +155,13 @@ impl ShapeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A mutable iterator of all the manipulators, regardless of selection.
|
/// 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>> {
|
pub fn manipulator_groups<'a>(&'a self, document_network: &'a NodeNetwork) -> impl Iterator<Item = &'a ManipulatorGroup<ManipulatorGroupId>> {
|
||||||
self.iter(document).flat_map(|subpaths| get_manipulator_groups(subpaths))
|
self.iter(document_network).flat_map(|subpaths| get_manipulator_groups(subpaths))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the selected points to all points for the corresponding intersection
|
// Sets the selected points to all points for the corresponding intersection
|
||||||
pub fn select_all_anchors(&mut self, document: &Document, layer: LayerNodeIdentifier) {
|
pub fn select_all_anchors(&mut self, document_network: &NodeNetwork, layer: LayerNodeIdentifier) {
|
||||||
let Some(subpaths) = get_subpaths(layer, document) else { return };
|
let Some(subpaths) = get_subpaths(layer, document_network) else { return };
|
||||||
let Some(state) = self.selected_shape_state.get_mut(&layer) else { return };
|
let Some(state) = self.selected_shape_state.get_mut(&layer) else { return };
|
||||||
for manipulator in get_manipulator_groups(subpaths) {
|
for manipulator in get_manipulator_groups(subpaths) {
|
||||||
state.select_point(ManipulatorPointId::new(manipulator.id, SelectedType::Anchor))
|
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.
|
/// Moves a control point to a `new_position` in document space.
|
||||||
/// Returns `Some(())` if successful and `None` otherwise.
|
/// 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<()> {
|
pub fn reposition_control_point(
|
||||||
let subpaths = get_subpaths(layer, document)?;
|
&self,
|
||||||
let transform = document.metadata.transform_to_viewport(layer).inverse();
|
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 position = transform.transform_point2(new_position);
|
||||||
let group = graph_modification_utils::get_manipulator_from_id(subpaths, point.group)?;
|
let group = graph_modification_utils::get_manipulator_from_id(subpaths, point.group)?;
|
||||||
let delta = position - point.manipulator_type.get_position(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.
|
// 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.
|
// 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.
|
// This iterator contains a bool indicating whether or not every selected point has a smooth manipulator angle.
|
||||||
let mut point_smoothness_status = self
|
let mut point_smoothness_status = self
|
||||||
.selected_shape_state
|
.selected_shape_state
|
||||||
.iter()
|
.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)));
|
.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 };
|
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.
|
/// 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();
|
let mut skip_set = HashSet::new();
|
||||||
|
|
||||||
for (&layer, layer_state) in self.selected_shape_state.iter() {
|
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() {
|
for point in layer_state.selected_points.iter() {
|
||||||
if skip_set.contains(&point.group) {
|
if skip_set.contains(&point.group) {
|
||||||
@@ -357,12 +372,12 @@ impl ShapeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Move the selected points by dragging the mouse.
|
/// 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 {
|
for (&layer, state) in &self.selected_shape_state {
|
||||||
let Some(subpaths) = get_subpaths(layer, document) else { continue };
|
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
|
||||||
let Some(mirror_angle) = get_mirror_handles(layer, document) 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);
|
let delta = transform.inverse().transform_vector2(delta);
|
||||||
|
|
||||||
for &point in state.selected_points.iter() {
|
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.
|
/// 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 {
|
for (&layer, state) in &self.selected_shape_state {
|
||||||
let Some(subpaths) = get_subpaths(layer, document) else { continue };
|
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
|
||||||
let Some(mirror_angle) = get_mirror_handles(layer, document) 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 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() {
|
for &point in state.selected_points.iter() {
|
||||||
let anchor = ManipulatorPointId::new(point.group, SelectedType::Anchor);
|
let anchor = ManipulatorPointId::new(point.group, SelectedType::Anchor);
|
||||||
@@ -472,11 +493,11 @@ impl ShapeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The opposing handle lengths.
|
/// 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
|
self.selected_shape_state
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(&layer, state)| {
|
.filter_map(|(&layer, state)| {
|
||||||
let subpaths = get_subpaths(layer, document)?;
|
let subpaths = get_subpaths(layer, document_network)?;
|
||||||
let opposing_handle_lengths = subpaths
|
let opposing_handle_lengths = subpaths
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|subpath| {
|
.flat_map(|subpath| {
|
||||||
@@ -514,10 +535,10 @@ impl ShapeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the opposing handle lengths.
|
/// 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 {
|
for (&layer, state) in &self.selected_shape_state {
|
||||||
let Some(subpaths) = get_subpaths(layer, document) else { continue };
|
let Some(subpaths) = get_subpaths(layer, document_network) else { continue };
|
||||||
let Some(mirror_angle) = get_mirror_handles(layer, document) 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 };
|
let Some(opposing_handle_lengths) = opposing_handle_lengths.get(&layer) else { continue };
|
||||||
|
|
||||||
for subpath in subpaths {
|
for subpath in subpaths {
|
||||||
@@ -610,12 +631,18 @@ impl ShapeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over the shapes.
|
/// Iterate over the shapes.
|
||||||
pub fn iter<'a>(&'a self, document: &'a Document) -> impl Iterator<Item = &'a Vec<bezier_rs::Subpath<ManipulatorGroupId>>> + 'a {
|
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))
|
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].
|
/// 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() {
|
if self.selected_shape_state.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -623,7 +650,7 @@ impl ShapeState {
|
|||||||
let select_threshold_squared = select_threshold * select_threshold;
|
let select_threshold_squared = select_threshold * select_threshold;
|
||||||
// Find the closest control point among all elements of shapes_to_modify
|
// Find the closest control point among all elements of shapes_to_modify
|
||||||
for &layer in self.selected_shape_state.keys() {
|
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
|
// Choose the first point under the threshold
|
||||||
if distance_squared < select_threshold_squared {
|
if distance_squared < select_threshold_squared {
|
||||||
trace!("Selecting... manipulator point: {manipulator_point_id:?}");
|
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.
|
/// 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.
|
/// 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)`.
|
/// 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 closest_distance_squared: f64 = f64::MAX;
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
|
|
||||||
let subpaths = get_subpaths(layer, document)?;
|
let subpaths = get_subpaths(layer, document_network)?;
|
||||||
let viewspace = document.metadata.transform_to_viewport(layer);
|
let viewspace = document_metadata.transform_to_viewport(layer);
|
||||||
for manipulator in get_manipulator_groups(subpaths) {
|
for manipulator in get_manipulator_groups(subpaths) {
|
||||||
let (selected, distance_squared) = SelectedType::closest_widget(manipulator, viewspace, pos, crate::consts::HIDE_HANDLE_DISTANCE);
|
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.
|
/// 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)> {
|
fn closest_segment(
|
||||||
let transform = document.metadata.transform_to_viewport(layer);
|
&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 layer_pos = transform.inverse().transform_point2(position);
|
||||||
let projection_options = bezier_rs::ProjectionOptions { lut_size: 5, ..Default::default() };
|
let projection_options = bezier_rs::ProjectionOptions { lut_size: 5, ..Default::default() };
|
||||||
|
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
let mut closest_distance_squared: f64 = tolerance * tolerance;
|
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 subpath in subpaths {
|
||||||
for (manipulator_index, bezier) in subpath.iter().enumerate() {
|
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).
|
/// 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() {
|
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));
|
let [first, second] = bezier.split(TValue::Parametric(t));
|
||||||
|
|
||||||
// Adjust the first manipulator group's out handle
|
// 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).
|
/// 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 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 result = None;
|
||||||
let mut closest_distance_squared = tolerance * tolerance;
|
let mut closest_distance_squared = tolerance * tolerance;
|
||||||
|
|
||||||
@@ -751,7 +785,7 @@ impl ShapeState {
|
|||||||
|
|
||||||
let subpath = &subpaths[subpath_index];
|
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) {
|
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(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),
|
(Some(handle), None) | (None, Some(handle)) => anchor_position.abs_diff_eq(handle, 1e-10),
|
||||||
@@ -790,15 +824,15 @@ impl ShapeState {
|
|||||||
false
|
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 {
|
for (&layer, state) in &mut self.selected_shape_state {
|
||||||
if clear_selection {
|
if clear_selection {
|
||||||
state.clear_points()
|
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 manipulator_group in get_manipulator_groups(subpaths) {
|
||||||
for selected_type in [SelectedType::Anchor, SelectedType::InHandle, SelectedType::OutHandle] {
|
for selected_type in [SelectedType::Anchor, SelectedType::InHandle, SelectedType::OutHandle] {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use super::shape_editor::ManipulatorPointInfo;
|
use super::shape_editor::ManipulatorPointInfo;
|
||||||
use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE};
|
use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE};
|
||||||
|
use crate::messages::portfolio::document::utility_types::LayerId;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use document_legacy::document::LayerId;
|
|
||||||
|
|
||||||
use glam::DVec2;
|
use glam::DVec2;
|
||||||
|
|
||||||
/// Handles snapping and snap overlays
|
/// Handles snapping and snap overlays
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::application::generate_uuid;
|
use crate::application::generate_uuid;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
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::graph_modification_utils::is_layer_fed_by_node_of_name;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
|
|
||||||
use glam::{IVec2, Vec2Swizzles};
|
use glam::{IVec2, Vec2Swizzles};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -132,9 +131,8 @@ impl ArtboardToolData {
|
|||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
let mut intersections = document
|
let mut intersections = document
|
||||||
.document_legacy
|
|
||||||
.click_xray(input.mouse.position)
|
.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);
|
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||||
if let Some(intersection) = intersections.next() {
|
if let Some(intersection) = intersections.next() {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::resolve_document_node_type;
|
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::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 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::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNodeMetadata, NodeInput};
|
use graph_craft::document::{DocumentNodeMetadata, NodeInput};
|
||||||
use graphene_core::raster::BlendMode;
|
use graphene_core::raster::BlendMode;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ impl Fsm for FillToolFsmState {
|
|||||||
let ToolMessage::Fill(event) = event else {
|
let ToolMessage::Fill(event) = event else {
|
||||||
return self;
|
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;
|
return self;
|
||||||
};
|
};
|
||||||
let layer = layer_identifier.to_path();
|
let layer = layer_identifier.to_path();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
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::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::uuid::generate_uuid;
|
use graphene_core::uuid::generate_uuid;
|
||||||
use graphene_core::vector::style::{Fill, Stroke};
|
use graphene_core::vector::style::{Fill, Stroke};
|
||||||
use graphene_core::Color;
|
use graphene_core::Color;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ use super::tool_prelude::*;
|
|||||||
use crate::application::generate_uuid;
|
use crate::application::generate_uuid;
|
||||||
use crate::consts::{LINE_ROTATE_SNAP_ANGLE, MANIPULATOR_GROUP_MARKER_SIZE, SELECTION_THRESHOLD};
|
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::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::graph_modification_utils::get_gradient;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::raster::color::Color;
|
use graphene_core::raster::color::Color;
|
||||||
use graphene_core::vector::style::{Fill, Gradient, GradientType};
|
use graphene_core::vector::style::{Fill, Gradient, GradientType};
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ impl SelectedGradient {
|
|||||||
inner_gradient.transform = gradient_space_transform(inner_gradient.layer, document);
|
inner_gradient.transform = gradient_space_transform(inner_gradient.layer, document);
|
||||||
|
|
||||||
// Clear if no longer a gradient
|
// 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);
|
responses.add(ToolMessage::RefreshToolOptions);
|
||||||
*gradient = None;
|
*gradient = None;
|
||||||
return;
|
return;
|
||||||
@@ -296,8 +296,8 @@ impl Fsm for GradientToolFsmState {
|
|||||||
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
||||||
let selected = tool_data.selected_gradient.as_ref();
|
let selected = tool_data.selected_gradient.as_ref();
|
||||||
|
|
||||||
for layer in document.document_legacy.selected_visible_layers() {
|
for layer in document.selected_visible_layers() {
|
||||||
let Some(gradient) = get_gradient(layer, &document.document_legacy) else { continue };
|
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
|
||||||
let transform = gradient_space_transform(layer, document);
|
let transform = gradient_space_transform(layer, document);
|
||||||
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
|
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
|
||||||
|
|
||||||
@@ -366,8 +366,8 @@ impl Fsm for GradientToolFsmState {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, GradientToolMessage::InsertStop) => {
|
(_, GradientToolMessage::InsertStop) => {
|
||||||
for layer in document.document_legacy.selected_visible_layers() {
|
for layer in document.selected_visible_layers() {
|
||||||
let Some(mut gradient) = get_gradient(layer, &document.document_legacy) else { continue };
|
let Some(mut gradient) = get_gradient(layer, &document.network) else { continue };
|
||||||
let transform = gradient_space_transform(layer, document);
|
let transform = gradient_space_transform(layer, document);
|
||||||
|
|
||||||
let mouse = input.mouse.position;
|
let mouse = input.mouse.position;
|
||||||
@@ -407,8 +407,8 @@ impl Fsm for GradientToolFsmState {
|
|||||||
let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
|
let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
|
||||||
|
|
||||||
let mut dragging = false;
|
let mut dragging = false;
|
||||||
for layer in document.document_legacy.selected_visible_layers() {
|
for layer in document.selected_visible_layers() {
|
||||||
let Some(gradient) = get_gradient(layer, &document.document_legacy) else { continue };
|
let Some(gradient) = get_gradient(layer, &document.network) else { continue };
|
||||||
let transform = gradient_space_transform(layer, document);
|
let transform = gradient_space_transform(layer, document);
|
||||||
|
|
||||||
// Check for dragging step
|
// Check for dragging step
|
||||||
@@ -444,7 +444,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
document.backup_nonmut(responses);
|
document.backup_nonmut(responses);
|
||||||
GradientToolFsmState::Drawing
|
GradientToolFsmState::Drawing
|
||||||
} else {
|
} 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
|
// Apply the gradient to the selected layer
|
||||||
if let Some(layer) = selected_layer {
|
if let Some(layer) = selected_layer {
|
||||||
@@ -457,7 +457,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
// Use the already existing gradient if it exists
|
// 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()
|
gradient.clone()
|
||||||
} else {
|
} else {
|
||||||
// Generate a new gradient
|
// Generate a new gradient
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::messages::portfolio::document::node_graph::{self, IMAGINATE_NODE};
|
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 crate::messages::tool::common_functionality::resize::Resize;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::consts::LINE_ROTATE_SNAP_ANGLE;
|
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::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::uuid::generate_uuid;
|
use graphene_core::uuid::generate_uuid;
|
||||||
use graphene_core::vector::style::Stroke;
|
use graphene_core::vector::style::Stroke;
|
||||||
use graphene_core::Color;
|
use graphene_core::Color;
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ use super::tool_prelude::*;
|
|||||||
use crate::consts::{DRAG_THRESHOLD, SELECTION_THRESHOLD, SELECTION_TOLERANCE};
|
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_functions::path_overlays;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
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::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::shape_editor::{ManipulatorAngle, ManipulatorPointInfo, OpposingHandleLengths, SelectedPointsInfo, ShapeState};
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::document::Document;
|
use graph_craft::document::NodeNetwork;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::renderer::Quad;
|
use graphene_core::renderer::Quad;
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
|
|
||||||
@@ -223,14 +223,14 @@ impl PathToolData {
|
|||||||
let _selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
let _selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
// Select the first point within the threshold (in pixels)
|
// 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);
|
self.start_dragging_point(selected_points, input, document, responses);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|
||||||
PathToolFsmState::Dragging
|
PathToolFsmState::Dragging
|
||||||
}
|
}
|
||||||
// We didn't find a point nearby, so consider selecting the nearest shape instead
|
// 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 {
|
if shift {
|
||||||
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] });
|
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] });
|
||||||
} else {
|
} else {
|
||||||
@@ -238,7 +238,7 @@ impl PathToolData {
|
|||||||
}
|
}
|
||||||
self.drag_start_pos = input.mouse.position;
|
self.drag_start_pos = input.mouse.position;
|
||||||
self.previous_mouse_position = 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
|
PathToolFsmState::Dragging
|
||||||
} else {
|
} else {
|
||||||
@@ -292,16 +292,16 @@ impl PathToolData {
|
|||||||
|
|
||||||
if shift {
|
if shift {
|
||||||
if self.opposing_handle_lengths.is_none() {
|
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 {
|
} 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;
|
self.opposing_handle_lengths = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the selected points with the mouse
|
// Move the selected points with the mouse
|
||||||
let snapped_position = self.snap_manager.snap_position(responses, document, input.mouse.position);
|
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;
|
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 {
|
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
|
||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
|
||||||
} else {
|
} 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(OverlaysMessage::Draw);
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ impl Fsm for PathToolFsmState {
|
|||||||
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
|
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
|
||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
|
||||||
} else {
|
} 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(OverlaysMessage::Draw);
|
||||||
responses.add(PathToolMessage::SelectedPointUpdated);
|
responses.add(PathToolMessage::SelectedPointUpdated);
|
||||||
@@ -391,16 +391,16 @@ impl Fsm for PathToolFsmState {
|
|||||||
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
|
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
|
||||||
|
|
||||||
let nearest_point = shape_editor
|
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);
|
.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 {
|
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));
|
let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == Some(point));
|
||||||
if clicked_selected {
|
if clicked_selected {
|
||||||
shape_editor.deselect_all();
|
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);
|
responses.add(OverlaysMessage::Draw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,9 +421,9 @@ impl Fsm for PathToolFsmState {
|
|||||||
}
|
}
|
||||||
(_, PathToolMessage::InsertPoint) => {
|
(_, PathToolMessage::InsertPoint) => {
|
||||||
// First we try and flip the sharpness (if they have clicked on an anchor)
|
// 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
|
// 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);
|
responses.add(PathToolMessage::SelectedPointUpdated);
|
||||||
@@ -436,35 +436,35 @@ impl Fsm for PathToolFsmState {
|
|||||||
}
|
}
|
||||||
(_, PathToolMessage::PointerMove { .. }) => self,
|
(_, PathToolMessage::PointerMove { .. }) => self,
|
||||||
(_, PathToolMessage::NudgeSelectedPoints { delta_x, delta_y }) => {
|
(_, 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
|
PathToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::SelectAllPoints) => {
|
(_, PathToolMessage::SelectAllPoints) => {
|
||||||
shape_editor.select_all_points(&document.document_legacy);
|
shape_editor.select_all_points(&document.network);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
PathToolFsmState::Ready
|
PathToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::SelectedPointXChanged { new_x }) => {
|
(_, PathToolMessage::SelectedPointXChanged { new_x }) => {
|
||||||
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
|
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
|
PathToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::SelectedPointYChanged { new_y }) => {
|
(_, PathToolMessage::SelectedPointYChanged { new_y }) => {
|
||||||
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
|
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
|
PathToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::SelectedPointUpdated) => {
|
(_, 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
|
self
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::ManipulatorAngleMakeSmooth) => {
|
(_, PathToolMessage::ManipulatorAngleMakeSmooth) => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
shape_editor.set_handle_mirroring_on_selected(true, responses);
|
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);
|
responses.add(DocumentMessage::CommitTransaction);
|
||||||
PathToolFsmState::Ready
|
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.
|
/// 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.
|
/// 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 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>();
|
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;
|
return SelectionStatus::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(subpaths) = get_subpaths(layer, document) else {
|
let Some(subpaths) = get_subpaths(layer, document_network) else {
|
||||||
return SelectionStatus::None;
|
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;
|
return SelectionStatus::None;
|
||||||
};
|
};
|
||||||
let Some(point) = shape_state.selected_points().next() else {
|
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 };
|
let manipulator_angle = if mirror.contains(&point.group) { ManipulatorAngle::Smooth } else { ManipulatorAngle::Sharp };
|
||||||
|
|
||||||
return SelectionStatus::One(SingleSelectedPoint {
|
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,
|
layer,
|
||||||
id: *point,
|
id: *point,
|
||||||
manipulator_angle,
|
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
|
// Check to see if multiple manipulator groups are selected
|
||||||
if total_selected_points > 1 {
|
if total_selected_points > 1 {
|
||||||
return SelectionStatus::Multiple(MultipleSelectedPoints {
|
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::node_graph::VectorDataModification;
|
||||||
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
|
use crate::messages::portfolio::document::overlays::utility_functions::path_overlays;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
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::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
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::graph_modification_utils::get_subpaths;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::uuid::{generate_uuid, ManipulatorGroupId};
|
use graphene_core::uuid::{generate_uuid, ManipulatorGroupId};
|
||||||
use graphene_core::vector::style::{Fill, Stroke};
|
use graphene_core::vector::style::{Fill, Stroke};
|
||||||
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
use graphene_core::vector::{ManipulatorPointId, SelectedType};
|
||||||
@@ -217,7 +217,7 @@ impl PenToolData {
|
|||||||
self.subpath_index = subpath_index;
|
self.subpath_index = subpath_index;
|
||||||
|
|
||||||
// Stop the handles on the first point from mirroring
|
// 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;
|
return;
|
||||||
};
|
};
|
||||||
let manipulator_groups = subpaths[subpath_index].manipulator_groups();
|
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<()> {
|
fn check_break(&mut self, document: &DocumentMessageHandler, transform: DAffine2, responses: &mut VecDeque<Message>) -> Option<()> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer = self.layer?;
|
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
|
// Get the last manipulator group and the one previous to that
|
||||||
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
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> {
|
fn finish_placing_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer = self.layer?;
|
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
|
// Get the last manipulator group and the one previous to that
|
||||||
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
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> {
|
fn drag_handle(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
||||||
// Get subpath
|
// 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
|
// Get the last manipulator group
|
||||||
let manipulator_groups = subpath.manipulator_groups();
|
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> {
|
fn place_anchor(&mut self, document: &DocumentMessageHandler, transform: DAffine2, mouse: DVec2, modifiers: ModifierState, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer = self.layer?;
|
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
|
// Get the last manipulator group and the one previous to that
|
||||||
let mut manipulator_groups = subpath.manipulator_groups().iter();
|
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> {
|
fn finish_transaction(&mut self, fsm: PenToolFsmState, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) -> Option<DocumentMessage> {
|
||||||
// Get subpath
|
// 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
|
// Abort if only one manipulator group has been placed
|
||||||
if fsm == PenToolFsmState::PlacingAnchor && subpath.len() < 3 {
|
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() {
|
for layer in document.metadata().selected_layers() {
|
||||||
let viewspace = document.metadata().transform_to_viewport(layer);
|
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() {
|
for (subpath_index, subpath) in subpaths.iter().enumerate() {
|
||||||
if subpath.closed() {
|
if subpath.closed() {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use super::tool_prelude::*;
|
|||||||
use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE};
|
use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE};
|
||||||
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
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::misc::{AlignAggregate, AlignAxis, FlipAxis};
|
||||||
use crate::messages::portfolio::document::utility_types::transformation::Selected;
|
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;
|
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::snapping::{self, SnapManager};
|
||||||
use crate::messages::tool::common_functionality::transformation_cage::*;
|
use crate::messages::tool::common_functionality::transformation_cage::*;
|
||||||
|
|
||||||
use document_legacy::document::Document;
|
use graph_craft::document::NodeNetwork;
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::renderer::Quad;
|
use graphene_core::renderer::Quad;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -394,22 +394,21 @@ impl Fsm for SelectToolFsmState {
|
|||||||
tool_data.selected_layers_count = selected_layers_count;
|
tool_data.selected_layers_count = selected_layers_count;
|
||||||
|
|
||||||
// Outline selected layers
|
// 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));
|
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the layer the user is hovering over
|
// 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));
|
let not_selected_click = click.filter(|&hovered_layer| !document.metadata().selected_layers_contains(hovered_layer));
|
||||||
if let Some(layer) = not_selected_click {
|
if let Some(layer) = not_selected_click {
|
||||||
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update bounds
|
// 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 transform = transform.unwrap_or(DAffine2::IDENTITY);
|
||||||
let bounds = document
|
let bounds = document
|
||||||
.document_legacy
|
|
||||||
.selected_visible_layers()
|
.selected_visible_layers()
|
||||||
.filter_map(|layer| {
|
.filter_map(|layer| {
|
||||||
document
|
document
|
||||||
@@ -440,10 +439,10 @@ impl Fsm for SelectToolFsmState {
|
|||||||
}
|
}
|
||||||
(_, SelectToolMessage::EditLayer) => {
|
(_, SelectToolMessage::EditLayer) => {
|
||||||
// Edit the clicked layer
|
// 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 {
|
match tool_data.nested_selection_behavior {
|
||||||
NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect, responses),
|
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))
|
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut selected: Vec<_> = document.document_legacy.selected_visible_layers().collect();
|
let mut selected: Vec<_> = document.selected_visible_layers().collect();
|
||||||
let intersection = document.document_legacy.click(input.mouse.position, &document.document_legacy.document_network);
|
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 bounding box bounds, go into ResizingBounds mode.
|
||||||
// If the user is dragging the rotate trigger, go into RotatingBounds 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;
|
tool_data.layers_dragging = selected;
|
||||||
|
|
||||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||||
let document = &document.document_legacy;
|
|
||||||
bounds.original_bound_transform = bounds.transform;
|
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(
|
let mut selected = Selected::new(
|
||||||
&mut bounds.original_transforms,
|
&mut bounds.original_transforms,
|
||||||
&mut bounds.center_of_transformation,
|
&mut bounds.center_of_transformation,
|
||||||
&tool_data.layers_dragging,
|
&tool_data.layers_dragging,
|
||||||
responses,
|
responses,
|
||||||
document,
|
&document.network,
|
||||||
|
&document.metadata,
|
||||||
None,
|
None,
|
||||||
&ToolType::Select,
|
&ToolType::Select,
|
||||||
);
|
);
|
||||||
@@ -529,7 +528,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
&mut bounds.center_of_transformation,
|
&mut bounds.center_of_transformation,
|
||||||
&selected,
|
&selected,
|
||||||
responses,
|
responses,
|
||||||
&document.document_legacy,
|
&document.network,
|
||||||
|
&document.metadata,
|
||||||
None,
|
None,
|
||||||
&ToolType::Select,
|
&ToolType::Select,
|
||||||
);
|
);
|
||||||
@@ -639,7 +639,16 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
|
tool_data.layers_dragging.retain(|layer| document.network().nodes.contains_key(&layer.to_node()));
|
||||||
let selected = &tool_data.layers_dragging;
|
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());
|
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,
|
&mut bounds.center_of_transformation,
|
||||||
&tool_data.layers_dragging,
|
&tool_data.layers_dragging,
|
||||||
responses,
|
responses,
|
||||||
&document.document_legacy,
|
&document.network,
|
||||||
|
&document.metadata,
|
||||||
None,
|
None,
|
||||||
&ToolType::Select,
|
&ToolType::Select,
|
||||||
);
|
);
|
||||||
@@ -725,7 +735,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
// Deselect layer if not snap dragging
|
// 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() {
|
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 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() {
|
if let Some(path) = intersection.last() {
|
||||||
let replacement_selected_layers: Vec<_> = document.metadata().selected_layers().filter(|&layer| !path.starts_with(layer, document.metadata())).collect();
|
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) => {
|
(SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||||
let quad = tool_data.selection_quad();
|
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();
|
let current_selected: HashSet<_> = document.metadata().selected_layers().collect();
|
||||||
if new_selected != current_selected {
|
if new_selected != current_selected {
|
||||||
tool_data.layers_dragging = new_selected.into_iter().collect();
|
tool_data.layers_dragging = new_selected.into_iter().collect();
|
||||||
@@ -813,7 +823,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
|
|
||||||
if let Some(layer) = selected_layers.next() {
|
if let Some(layer) = selected_layers.next() {
|
||||||
// Check that only one layer is selected
|
// 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_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
||||||
responses.add(TextToolMessage::EditSelected);
|
responses.add(TextToolMessage::EditSelected);
|
||||||
}
|
}
|
||||||
@@ -836,7 +846,8 @@ impl Fsm for SelectToolFsmState {
|
|||||||
&mut bounding_box_overlays.opposite_pivot,
|
&mut bounding_box_overlays.opposite_pivot,
|
||||||
&tool_data.layers_dragging,
|
&tool_data.layers_dragging,
|
||||||
responses,
|
responses,
|
||||||
&document.document_legacy,
|
&document.network,
|
||||||
|
&document.metadata,
|
||||||
None,
|
None,
|
||||||
&ToolType::Select,
|
&ToolType::Select,
|
||||||
);
|
);
|
||||||
@@ -951,11 +962,11 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer:
|
|||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_selected.to_node()] });
|
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_selected.to_node()] });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, document: &Document, responses: &mut VecDeque<Message>) {
|
fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, document_network: &NodeNetwork, responses: &mut VecDeque<Message>) {
|
||||||
if is_layer_fed_by_node_of_name(layer, document, "Text") {
|
if is_layer_fed_by_node_of_name(layer, document_network, "Text") {
|
||||||
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text });
|
||||||
responses.add(TextToolMessage::EditSelected);
|
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 });
|
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::consts::DRAG_THRESHOLD;
|
use crate::consts::DRAG_THRESHOLD;
|
||||||
use crate::messages::portfolio::document::node_graph::VectorDataModification;
|
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::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||||
|
|
||||||
use document_legacy::document_metadata::LayerNodeIdentifier;
|
|
||||||
use graphene_core::uuid::generate_uuid;
|
use graphene_core::uuid::generate_uuid;
|
||||||
use graphene_core::vector::style::{Fill, Stroke};
|
use graphene_core::vector::style::{Fill, Stroke};
|
||||||
use graphene_core::Color;
|
use graphene_core::Color;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
use super::tool_prelude::*;
|
use super::tool_prelude::*;
|
||||||
use crate::application::generate_uuid;
|
use crate::application::generate_uuid;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
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::color_selector::{ToolColorOptions, ToolColorType};
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, is_layer_fed_by_node_of_name};
|
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 graph_craft::document::value::TaggedValue;
|
||||||
use graphene_core::renderer::Quad;
|
use graphene_core::renderer::Quad;
|
||||||
use graphene_core::text::{load_face, Font, FontCache};
|
use graphene_core::text::{load_face, Font, FontCache};
|
||||||
@@ -225,7 +225,7 @@ struct TextToolData {
|
|||||||
impl TextToolData {
|
impl TextToolData {
|
||||||
/// Set the editing state of the currently modifying layer
|
/// Set the editing state of the currently modifying layer
|
||||||
fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
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 });
|
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: editable });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,8 +245,8 @@ impl TextToolData {
|
|||||||
|
|
||||||
fn load_layer_text_node(&mut self, document: &DocumentMessageHandler) -> Option<()> {
|
fn load_layer_text_node(&mut self, document: &DocumentMessageHandler) -> Option<()> {
|
||||||
let transform = document.metadata().transform_to_viewport(self.layer);
|
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 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.document_legacy)?;
|
let (text, font, font_size) = graph_modification_utils::get_text(self.layer, &document.network)?;
|
||||||
self.editing_text = Some(EditingText {
|
self.editing_text = Some(EditingText {
|
||||||
text: text.clone(),
|
text: text.clone(),
|
||||||
font: font.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 {
|
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
|
// Check if the user has selected an existing text layer
|
||||||
if let Some(clicked_text_layer_path) = document
|
if let Some(clicked_text_layer_path) = document
|
||||||
.document_legacy
|
|
||||||
.click(mouse, document.network())
|
.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);
|
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;
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +390,7 @@ impl Fsm for TextToolFsmState {
|
|||||||
}
|
}
|
||||||
(_, TextToolMessage::Overlays(mut overlay_context)) => {
|
(_, TextToolMessage::Overlays(mut overlay_context)) => {
|
||||||
for layer in document.metadata().selected_layers() {
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
let buzz_face = font_cache.get(font).map(|data| load_face(data));
|
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);
|
tool_data.fix_text_bounds(&new_text, document, font_cache, responses);
|
||||||
responses.add(NodeGraphMessage::SetQualifiedInputValue {
|
responses.add(NodeGraphMessage::SetQualifiedInputValue {
|
||||||
layer_path: Vec::new(),
|
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,
|
input_index: 1,
|
||||||
value: TaggedValue::String(new_text),
|
value: TaggedValue::String(new_text),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
|||||||
&mut self.pivot,
|
&mut self.pivot,
|
||||||
&selected_layers,
|
&selected_layers,
|
||||||
responses,
|
responses,
|
||||||
&document.document_legacy,
|
&document.network,
|
||||||
|
&document.metadata,
|
||||||
Some(shape_editor),
|
Some(shape_editor),
|
||||||
&tool_data.active_tool_type,
|
&tool_data.active_tool_type,
|
||||||
);
|
);
|
||||||
@@ -67,7 +68,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
|
|||||||
}
|
}
|
||||||
|
|
||||||
if using_path_tool {
|
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();
|
*selected.original_transforms = OriginalTransforms::default();
|
||||||
let viewspace = document.metadata().transform_to_viewport(selected_layers[0]);
|
let viewspace = document.metadata().transform_to_viewport(selected_layers[0]);
|
||||||
|
|
||||||
|
|||||||
@@ -599,32 +599,3 @@ impl HintInfo {
|
|||||||
self
|
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::FrontendImageData;
|
||||||
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
use crate::messages::frontend::utility_types::{ExportBounds, FileType};
|
||||||
use crate::messages::portfolio::document::node_graph::wrap_network_in_scope;
|
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::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 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::value::TaggedValue;
|
||||||
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
||||||
use graph_craft::graphene_compiler::Compiler;
|
use graph_craft::graphene_compiler::Compiler;
|
||||||
@@ -493,7 +492,7 @@ impl NodeGraphExecutor {
|
|||||||
|
|
||||||
let render_config = RenderConfig {
|
let render_config = RenderConfig {
|
||||||
viewport: Footprint {
|
viewport: Footprint {
|
||||||
transform: document.document_legacy.metadata.document_to_viewport,
|
transform: document.metadata.document_to_viewport,
|
||||||
resolution: viewport_resolution,
|
resolution: viewport_resolution,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -581,7 +580,14 @@ impl NodeGraphExecutor {
|
|||||||
Ok(())
|
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<_>>();
|
let results = self.receiver.try_iter().collect::<Vec<_>>();
|
||||||
for response in results {
|
for response in results {
|
||||||
match response {
|
match response {
|
||||||
@@ -602,34 +608,32 @@ impl NodeGraphExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (&node_id, svg) in &new_thumbnails {
|
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");
|
warn!("Missing node");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let layer = LayerNodeIdentifier::new(node_id, &document.document_network);
|
let layer = LayerNodeIdentifier::new(node_id, document_network);
|
||||||
responses.add(FrontendMessage::UpdateDocumentLayerDetails {
|
responses.add(FrontendMessage::UpdateDocumentLayerDetails {
|
||||||
data: LayerPanelEntry {
|
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() },
|
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
|
LayerClassification::Artboard
|
||||||
} else if document.metadata.is_folder(layer) {
|
} else if document_metadata.is_folder(layer) {
|
||||||
LayerClassification::Folder
|
LayerClassification::Folder
|
||||||
} else {
|
} else {
|
||||||
LayerClassification::Layer
|
LayerClassification::Layer
|
||||||
},
|
},
|
||||||
layer_metadata: LayerMetadata {
|
expanded: layer.has_children(document_metadata) && !collapsed.contains(&layer),
|
||||||
expanded: layer.has_children(&document.metadata) && !collapsed_folders.contains(&layer),
|
selected: document_metadata.selected_layers_contains(layer),
|
||||||
selected: document.metadata.selected_layers_contains(layer),
|
|
||||||
},
|
|
||||||
path: vec![node_id],
|
path: vec![node_id],
|
||||||
thumbnail: svg.to_string(),
|
thumbnail: svg.to_string(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.thumbnails = new_thumbnails;
|
self.thumbnails = new_thumbnails;
|
||||||
document.metadata.update_transforms(new_upstream_transforms);
|
document_metadata.update_transforms(new_upstream_transforms);
|
||||||
document.metadata.update_click_targets(new_click_targets);
|
document_metadata.update_click_targets(new_click_targets);
|
||||||
responses.extend(updates);
|
responses.extend(updates);
|
||||||
self.process_node_graph_output(node_graph_output, execution_context.layer_path.clone(), transform, responses)?;
|
self.process_node_graph_output(node_graph_output, execution_context.layer_path.clone(), transform, responses)?;
|
||||||
responses.add(DocumentMessage::RenderDocument);
|
responses.add(DocumentMessage::RenderDocument);
|
||||||
|
|||||||
@@ -209,11 +209,11 @@
|
|||||||
async function dragStart(event: DragEvent, listing: LayerListingInfo) {
|
async function dragStart(event: DragEvent, listing: LayerListingInfo) {
|
||||||
const layer = listing.entry;
|
const layer = listing.entry;
|
||||||
dragInPanel = true;
|
dragInPanel = true;
|
||||||
if (!layer.layerMetadata.selected) {
|
if (!layer.selected) {
|
||||||
fakeHighlight = [layer.path];
|
fakeHighlight = [layer.path];
|
||||||
}
|
}
|
||||||
const select = () => {
|
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;
|
const target = (event.target instanceof HTMLElement && event.target) || undefined;
|
||||||
@@ -309,7 +309,7 @@
|
|||||||
<LayoutRow
|
<LayoutRow
|
||||||
class="layer"
|
class="layer"
|
||||||
classes={{
|
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,
|
"insert-folder": (draggingData?.highlightFolder || false) && draggingData?.insertFolder === listing.entry.path,
|
||||||
}}
|
}}
|
||||||
styles={{ "--layer-indent-levels": `${listing.entry.path.length - 1}` }}
|
styles={{ "--layer-indent-levels": `${listing.entry.path.length - 1}` }}
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
on:click={(e) => selectLayerWithModifiers(e, listing)}
|
||||||
>
|
>
|
||||||
{#if isNestingLayer(listing.entry.layerClassification)}
|
{#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"}
|
{#if listing.entry.layerClassification === "Artboard"}
|
||||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||||
{:else if listing.entry.layerClassification === "Folder"}
|
{:else if listing.entry.layerClassification === "Folder"}
|
||||||
|
|||||||
@@ -672,16 +672,11 @@ export class LayerPanelEntry {
|
|||||||
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
|
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
|
||||||
path!: BigUint64Array;
|
path!: BigUint64Array;
|
||||||
|
|
||||||
@Type(() => LayerMetadata)
|
|
||||||
layerMetadata!: LayerMetadata;
|
|
||||||
|
|
||||||
thumbnail!: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LayerMetadata {
|
|
||||||
expanded!: boolean;
|
expanded!: boolean;
|
||||||
|
|
||||||
selected!: boolean;
|
selected!: boolean;
|
||||||
|
|
||||||
|
thumbnail!: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LayerClassification = "Folder" | "Artboard" | "Layer";
|
export type LayerClassification = "Folder" | "Artboard" | "Layer";
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
editor = { path = "../../editor", package = "graphite-editor" }
|
editor = { path = "../../editor", package = "graphite-editor" }
|
||||||
document-legacy = { workspace = true }
|
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
graphene-core = { workspace = true, features = ["std", "alloc"] }
|
graphene-core = { workspace = true, features = ["std", "alloc"] }
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
use crate::helpers::translate_key;
|
use crate::helpers::translate_key;
|
||||||
use crate::{Error, EDITOR_HAS_CRASHED, EDITOR_INSTANCES, JS_EDITOR_HANDLES};
|
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::generate_uuid;
|
||||||
use editor::application::Editor;
|
use editor::application::Editor;
|
||||||
use editor::consts::{FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION};
|
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_keyboard::ModifierKeys;
|
||||||
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
|
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::portfolio::utility_types::Platform;
|
||||||
use editor::messages::prelude::*;
|
use editor::messages::prelude::*;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ serde = { workspace = true }
|
|||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
bezier-rs = { workspace = true }
|
bezier-rs = { workspace = true }
|
||||||
glam = { workspace = true }
|
glam = { workspace = true }
|
||||||
graphene-std = { path = "../gstd" }
|
graphene-std = { path = "../gstd", features = ["serde"] }
|
||||||
image = { workspace = true, default-features = false, features = [
|
image = { workspace = true, default-features = false, features = [
|
||||||
"bmp",
|
"bmp",
|
||||||
"png",
|
"png",
|
||||||
@@ -49,8 +49,4 @@ chrono = { workspace = true }
|
|||||||
tokio = { workspace = true, features = ["macros", "rt"] }
|
tokio = { workspace = true, features = ["macros", "rt"] }
|
||||||
wgpu = { workspace = true }
|
wgpu = { workspace = true }
|
||||||
|
|
||||||
[dependencies.document-legacy]
|
|
||||||
path = "../../document-legacy"
|
|
||||||
package = "graphite-document-legacy"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -74,16 +74,8 @@ image-compare = { version = "0.3.0", optional = true }
|
|||||||
vello = { workspace = true, optional = true }
|
vello = { workspace = true, optional = true }
|
||||||
vello_svg = { workspace = true, optional = true }
|
vello_svg = { workspace = true, optional = true }
|
||||||
resvg = { workspace = true, optional = true }
|
resvg = { workspace = true, optional = true }
|
||||||
|
serde = { workspace = true, optional = true, features = ["derive"] }
|
||||||
[dependencies.serde]
|
web-sys = { workspace = true, optional = true, features = [
|
||||||
workspace = true
|
|
||||||
optional = true
|
|
||||||
features = ["derive"]
|
|
||||||
|
|
||||||
[dependencies.web-sys]
|
|
||||||
workspace = true
|
|
||||||
optional = true
|
|
||||||
features = [
|
|
||||||
"Window",
|
"Window",
|
||||||
"CanvasRenderingContext2d",
|
"CanvasRenderingContext2d",
|
||||||
"ImageData",
|
"ImageData",
|
||||||
@@ -93,4 +85,4 @@ features = [
|
|||||||
"HtmlCanvasElement",
|
"HtmlCanvasElement",
|
||||||
"HtmlImageElement",
|
"HtmlImageElement",
|
||||||
"ImageBitmapRenderingContext",
|
"ImageBitmapRenderingContext",
|
||||||
]
|
] }
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ quantization = ["graphene-std/quantization"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
graphene-core = { workspace = true, features = ["std"] }
|
graphene-core = { workspace = true, features = ["std"] }
|
||||||
graphene-std = { path = "../gstd" }
|
graphene-std = { path = "../gstd", features = ["serde"] }
|
||||||
graph-craft = { path = "../graph-craft" }
|
graph-craft = { path = "../graph-craft" }
|
||||||
gpu-executor = { path = "../gpu-executor" }
|
gpu-executor = { path = "../gpu-executor" }
|
||||||
wgpu-executor = { path = "../wgpu-executor" }
|
wgpu-executor = { path = "../wgpu-executor" }
|
||||||
@@ -23,5 +23,6 @@ num-traits = { workspace = true }
|
|||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
glam = { workspace = 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 }
|
futures = { workspace = true }
|
||||||
|
|||||||
Reference in New Issue
Block a user