Remove the whole document-legacy crate (#1524)

Remove the whole document-legacy crate

Closes #1520
This commit is contained in:
Keavon Chambers
2023-12-20 05:45:54 -08:00
committed by GitHub
parent dcd38f2e4c
commit 92203f3576
62 changed files with 1287 additions and 1214 deletions
@@ -1,16 +1,15 @@
use crate::messages::input_mapper::utility_types::input_keyboard::Key;
use crate::messages::portfolio::document::utility_types::layer_panel::LayerMetadata;
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeId;
use graphene_core::raster::BlendMode;
use graphene_core::raster::Image;
use graphene_core::vector::style::ViewMode;
use graphene_core::Color;
use serde::{Deserialize, Serialize};
#[remain::sorted]
@@ -41,8 +40,7 @@ pub enum DocumentMessage {
aggregate: AlignAggregate,
},
BackupDocument {
document: DocumentLegacy,
layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
document: DocumentMessageHandler,
},
ClearLayerTree,
CommitTransaction,
@@ -7,26 +7,31 @@ use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData;
use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData;
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::portfolio::document::utility_types::layer_panel::{LayerMetadata, RawBuffer};
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, DocumentSave, FlipAxis};
use crate::messages::portfolio::document::utility_types::vectorize_layer_metadata;
use crate::messages::portfolio::document::utility_types::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::layer_panel::RawBuffer;
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
use crate::messages::tool::utility_types::ToolType;
use crate::node_graph_executor::NodeGraphExecutor;
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeInput, NodeNetwork};
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, DocumentNodeMetadata, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::raster::BlendMode;
use graphene_core::raster::ImageFrame;
use graphene_core::renderer::ClickTarget;
use graphene_core::transform::Footprint;
use graphene_core::vector::style::ViewMode;
use graphene_core::{concrete, generic, ProtoNodeIdentifier};
use graphene_std::wasm_application_io::WasmEditorApi;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::vec;
/// Utility function for providing a default boolean value to serde.
#[inline(always)]
@@ -36,52 +41,71 @@ fn return_true() -> bool {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DocumentMessageHandler {
pub document_legacy: DocumentLegacy,
pub saved_document_identifier: u64,
pub auto_saved_document_identifier: u64,
pub name: String,
pub version: String,
#[serde(default)]
pub commit_hash: String,
#[serde(default)]
pub collapsed_folders: Vec<LayerNodeIdentifier>,
pub document_mode: DocumentMode,
pub view_mode: ViewMode,
#[serde(skip)]
pub snapping_state: SnappingState,
pub overlays_visible: bool,
#[serde(default = "return_true")]
pub rulers_visible: bool,
#[serde(skip)]
pub document_undo_history: VecDeque<DocumentSave>,
#[serde(skip)]
pub document_redo_history: VecDeque<DocumentSave>,
/// Don't allow aborting transactions whilst undoing to avoid #559
#[serde(skip)]
undo_in_progress: bool,
#[serde(with = "vectorize_layer_metadata")]
pub layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
#[serde(skip)]
layer_range_selection_reference: Option<LayerNodeIdentifier>,
// Child message handlers
navigation_handler: NavigationMessageHandler,
#[serde(skip)]
node_graph_handler: NodeGraphMessageHandler,
#[serde(skip)]
overlays_message_handler: OverlaysMessageHandler,
#[serde(skip)]
properties_panel_message_handler: PropertiesPanelMessageHandler,
// Fields that are saved in the document format
//
pub name: String,
pub version: String,
pub network: NodeNetwork,
pub saved_document_identifier: u64,
pub auto_saved_document_identifier: u64,
// Fields that can be non-fatally missing from the saved document format
//
#[serde(default)]
pub document_mode: DocumentMode,
#[serde(default)]
pub view_mode: ViewMode,
#[serde(default = "return_true")]
pub overlays_visible: bool,
#[serde(default = "return_true")]
pub rulers_visible: bool,
#[serde(default)]
pub commit_hash: String,
#[serde(default)]
pub collapsed: Vec<LayerNodeIdentifier>,
#[serde(default)]
pub selected: HashMap<Vec<LayerId>, bool>,
// Fields omitted from the saved document format
//
#[serde(skip)]
node_graph_handler: NodeGraphMessageHandler,
pub document_undo_history: VecDeque<DocumentMessageHandler>,
#[serde(skip)]
pub document_redo_history: VecDeque<DocumentMessageHandler>,
/// Don't allow aborting transactions whilst undoing to avoid #559
#[serde(skip)]
undo_in_progress: bool,
#[serde(skip)]
pub snapping_state: SnappingState,
#[serde(skip)]
layer_range_selection_reference: Option<LayerNodeIdentifier>,
#[serde(skip)]
pub metadata: DocumentMetadata,
/// The state_identifier serves to provide a way to uniquely identify a particular state that the document is in.
/// This identifier is not a hash and is not guaranteed to be equal for equivalent documents.
#[serde(skip)]
pub state_identifier: DefaultHasher,
}
impl Default for DocumentMessageHandler {
fn default() -> Self {
Self {
document_legacy: DocumentLegacy::default(),
network: root_network(),
saved_document_identifier: 0,
auto_saved_document_identifier: 0,
name: DEFAULT_DOCUMENT_NAME.to_string(),
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
commit_hash: crate::application::GRAPHITE_GIT_COMMIT_HASH.to_string(),
collapsed_folders: Vec::new(),
collapsed: Vec::new(),
document_mode: DocumentMode::DesignMode,
view_mode: ViewMode::default(),
snapping_state: SnappingState::default(),
@@ -90,16 +114,79 @@ impl Default for DocumentMessageHandler {
document_undo_history: VecDeque::new(),
document_redo_history: VecDeque::new(),
undo_in_progress: false,
layer_metadata: vec![(vec![], LayerMetadata::new(true))].into_iter().collect(),
selected: vec![(vec![], true)].into_iter().collect(),
layer_range_selection_reference: None,
navigation_handler: NavigationMessageHandler::default(),
overlays_message_handler: OverlaysMessageHandler::default(),
properties_panel_message_handler: PropertiesPanelMessageHandler::default(),
node_graph_handler: Default::default(),
state_identifier: DefaultHasher::new(),
metadata: Default::default(),
}
}
}
fn root_network() -> NodeNetwork {
{
let mut network = NodeNetwork::default();
let node = graph_craft::document::DocumentNode {
name: "Output".into(),
inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true), NodeInput::Network(concrete!(WasmEditorApi))],
implementation: graph_craft::document::DocumentNodeImplementation::Network(NodeNetwork {
inputs: vec![3, 0],
outputs: vec![NodeOutput::new(3, 0)],
nodes: [
DocumentNode {
name: "EditorApi".to_string(),
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")),
..Default::default()
},
DocumentNode {
name: "Create Canvas".to_string(),
inputs: vec![NodeInput::node(0, 0)],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
skip_deduplication: true,
..Default::default()
},
DocumentNode {
name: "Cache".to_string(),
manual_composition: Some(concrete!(())),
inputs: vec![NodeInput::node(1, 0)],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
..Default::default()
},
DocumentNode {
name: "RenderNode".to_string(),
inputs: vec![
NodeInput::node(0, 0),
NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(generic!(T)))),
NodeInput::node(2, 0),
],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RenderNode<_, _, _>")),
..Default::default()
},
]
.into_iter()
.enumerate()
.map(|(id, node)| (id as NodeId, node))
.collect(),
..Default::default()
}),
metadata: DocumentNodeMetadata::position((8, 4)),
..Default::default()
};
network.push_node(node);
network
}
}
impl PartialEq for DocumentMessageHandler {
fn eq(&self, other: &Self) -> bool {
self.state_identifier.finish() == other.state_identifier.finish()
}
}
pub struct DocumentInputs<'a> {
pub document_id: u64,
pub ipp: &'a InputPreprocessorMessageHandler,
@@ -126,11 +213,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
#[remain::unsorted]
Navigation(message) => {
let document_bounds = self.metadata().document_bounds_viewport_space();
self.navigation_handler.process_message(
message,
responses,
(&self.document_legacy, document_bounds, ipp, self.document_legacy.selected_visible_layers_bounding_box_viewport()),
);
self.navigation_handler
.process_message(message, responses, (&self.metadata, document_bounds, ipp, self.selected_visible_layers_bounding_box_viewport()));
}
#[remain::unsorted]
Overlays(message) => {
@@ -139,11 +223,12 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
#[remain::unsorted]
PropertiesPanel(message) => {
let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData {
document_name: self.name.as_str(),
artwork_document: &self.document_legacy,
selected_layers: &mut self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice())),
selected_layers: &mut self.selected.iter().filter_map(|(path, selected)| selected.then_some(path.as_slice())),
node_graph_message_handler: &self.node_graph_handler,
executor,
document_name: self.name.as_str(),
document_network: &mut self.network,
document_metadata: &mut self.metadata,
};
self.properties_panel_message_handler
.process_message(message, responses, (persistent_data, properties_panel_message_handler_data));
@@ -154,17 +239,18 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
message,
responses,
NodeGraphHandlerData {
document: &mut self.document_legacy,
document_network: &mut self.network,
document_metadata: &mut self.metadata,
document_id,
document_name: self.name.as_str(),
collapsed_folders: &mut self.collapsed_folders,
collapsed: &mut self.collapsed,
input: ipp,
graph_view_overlay_open,
},
);
}
#[remain::unsorted]
GraphOperation(message) => GraphOperationMessageHandler.process_message(message, responses, (&mut self.document_legacy, &mut self.collapsed_folders, &mut self.node_graph_handler)),
GraphOperation(message) => GraphOperationMessageHandler.process_message(message, responses, (&mut self.network, &mut self.metadata, &mut self.collapsed, &mut self.node_graph_handler)),
// Messages
AbortTransaction => {
@@ -180,7 +266,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
AlignAxis::X => DVec2::X,
AlignAxis::Y => DVec2::Y,
};
let Some(combined_box) = self.document_legacy.selected_visible_layers_bounding_box_viewport() else {
let Some(combined_box) = self.selected_visible_layers_bounding_box_viewport() else {
return;
};
@@ -208,7 +294,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
responses.add(BroadcastEvent::DocumentIsDirty);
}
BackupDocument { document, layer_metadata } => self.backup_with_document(document, layer_metadata, responses),
BackupDocument { document } => self.backup_with_document(document, responses),
ClearLayerTree => {
// Send an empty layer tree
let data_buffer: RawBuffer = Self::default().serialize_root().as_slice().into();
@@ -233,7 +319,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });
}
DebugPrintDocument => {
info!("{:#?}\n{:#?}", self.document_legacy, self.layer_metadata);
info!("{:#?}\n{:#?}", self.network, self.selected);
}
DeleteLayer { layer_path } => {
responses.add(GraphOperationMessage::DeleteLayer { id: layer_path[0] });
@@ -277,7 +363,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
FlipAxis::X => DVec2::new(-1., 1.),
FlipAxis::Y => DVec2::new(1., -1.),
};
if let Some([min, max]) = self.document_legacy.selected_visible_layers_bounding_box_viewport() {
if let Some([min, max]) = self.selected_visible_layers_bounding_box_viewport() {
let center = (max + min) / 2.;
let bbox_trans = DAffine2::from_translation(-center);
for layer in self.metadata().selected_layers() {
@@ -379,7 +465,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
});
}
// Nudge resize
else if let Some([existing_top_left, existing_bottom_right]) = self.document_legacy.metadata.bounding_box_document(layer) {
else if let Some([existing_top_left, existing_bottom_right]) = self.metadata.bounding_box_document(layer) {
let size = existing_bottom_right - existing_top_left;
let new_size = size + if opposite_corner { -delta } else { delta };
let enlargement_factor = new_size / size;
@@ -620,10 +706,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
StartTransaction => self.backup(responses),
ToggleLayerExpansion { layer } => {
let layer = LayerNodeIdentifier::new(layer, self.network());
if self.collapsed_folders.contains(&layer) {
self.collapsed_folders.retain(|&collapsed_layer| collapsed_layer != layer);
if self.collapsed.contains(&layer) {
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
} else {
self.collapsed_folders.push(layer);
self.collapsed.push(layer);
}
responses.add(NodeGraphMessage::RunDocumentGraph);
}
@@ -663,7 +749,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(DocumentMessage::CommitTransaction);
}
UpdateDocumentTransform { transform } => {
self.document_legacy.metadata.document_to_viewport = transform;
self.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::RenderRulers);
responses.add(DocumentMessage::RenderScrollbars);
responses.add(NodeGraphMessage::RunDocumentGraph);
@@ -692,49 +778,61 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
impl DocumentMessageHandler {
pub fn actions_with_graph_open(&self, graph_open: bool) -> ActionList {
let mut common = actions!(DocumentMessageDiscriminant;
Undo,
Redo,
SelectAllLayers,
DeselectAllLayers,
RenderDocument,
SaveDocument,
SetSnapping,
DebugPrintDocument,
ZoomCanvasToFitAll,
ZoomCanvasTo100Percent,
ZoomCanvasTo200Percent,
CreateEmptyFolder,
);
pub fn layer_visible(&self, layer: LayerNodeIdentifier) -> bool {
!layer.ancestors(&self.metadata).any(|layer| self.network.disabled.contains(&layer.to_node()))
}
if self.metadata().selected_layers().next().is_some() {
let select = actions!(DocumentMessageDiscriminant;
DeleteSelectedLayers,
DuplicateSelectedLayers,
NudgeSelectedLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
GroupSelectedLayers,
UngroupSelectedLayers,
);
common.extend(select);
}
common.extend(self.navigation_handler.actions());
common.extend(self.node_graph_handler.actions_with_node_graph_open(graph_open));
common
pub fn selected_visible_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.metadata.selected_layers().filter(|&layer| self.layer_visible(layer))
}
/// Runs an intersection test with all layers and a viewport space quad
pub fn intersect_quad<'a>(&'a self, viewport_quad: graphene_core::renderer::Quad, network: &'a NodeNetwork) -> impl Iterator<Item = LayerNodeIdentifier> + 'a {
let document_quad = self.metadata.document_to_viewport.inverse() * viewport_quad;
self.metadata
.root()
.decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer))
.filter(|&layer| !is_artboard(layer, network))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(move |target| target.intersect_rectangle(document_quad, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find all of the layers that were clicked on from a viewport space location
pub fn click_xray(&self, viewport_location: DVec2) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
let point = self.metadata.document_to_viewport.inverse().transform_point2(viewport_location);
self.metadata
.root()
.decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find the layer that has been clicked on from a viewport space location
pub fn click(&self, viewport_location: DVec2, network: &NodeNetwork) -> Option<LayerNodeIdentifier> {
self.click_xray(viewport_location).find(|&layer| !is_artboard(layer, network))
}
/// Get the combined bounding box of the click targets of the selected visible layers in viewport space
pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_visible_layers()
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
.reduce(graphene_core::renderer::Quad::combine_bounds)
}
pub fn current_state_identifier(&self) -> u64 {
self.state_identifier.finish()
}
}
impl DocumentMessageHandler {
pub fn network(&self) -> &NodeNetwork {
&self.document_legacy.document_network
&self.network
}
pub fn metadata(&self) -> &document_legacy::document_metadata::DocumentMetadata {
&self.document_legacy.metadata
pub fn metadata(&self) -> &DocumentMetadata {
&self.metadata
}
pub fn serialize_document(&self) -> String {
@@ -760,7 +858,7 @@ impl DocumentMessageHandler {
pub fn with_name(name: String, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Self {
let mut document = Self { name, ..Self::default() };
let transform = document.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2.);
document.document_legacy.metadata.document_to_viewport = transform;
document.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::UpdateDocumentTransform { transform });
document
@@ -773,7 +871,7 @@ impl DocumentMessageHandler {
}
pub fn selected_layers(&self) -> impl Iterator<Item = &[LayerId]> {
self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice()))
self.selected.iter().filter_map(|(path, selected)| selected.then_some(path.as_slice()))
}
/// Returns the bounding boxes for all visible layers.
@@ -788,7 +886,7 @@ impl DocumentMessageHandler {
for layer_node in folder.children(self.metadata()) {
data.push(layer_node.to_node());
space += 1;
if layer_node.has_children(self.metadata()) && !self.collapsed_folders.contains(&layer_node) {
if layer_node.has_children(self.metadata()) && !self.collapsed.contains(&layer_node) {
path.push(layer_node.to_node());
// TODO: Skip if folder is not expanded.
@@ -843,14 +941,10 @@ impl DocumentMessageHandler {
structure
}
pub fn layer_metadata(&self, path: &[LayerId]) -> &LayerMetadata {
self.layer_metadata.get(path).unwrap_or_else(|| panic!("Editor's layer metadata for {path:?} does not exist"))
}
/// Places a document into the history system
fn backup_with_document(&mut self, document: DocumentLegacy, layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>, responses: &mut VecDeque<Message>) {
fn backup_with_document(&mut self, document: DocumentMessageHandler, responses: &mut VecDeque<Message>) {
self.document_redo_history.clear();
self.document_undo_history.push_back(DocumentSave { document, layer_metadata });
self.document_undo_history.push_back(document);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
@@ -861,27 +955,23 @@ impl DocumentMessageHandler {
/// Copies the entire document into the history system
pub fn backup(&mut self, responses: &mut VecDeque<Message>) {
self.backup_with_document(self.document_legacy.clone(), self.layer_metadata.clone(), responses);
self.backup_with_document(self.clone(), responses);
}
// TODO: Is this now redundant?
/// Push a message backing up the document in its current state
pub fn backup_nonmut(&self, responses: &mut VecDeque<Message>) {
responses.add(DocumentMessage::BackupDocument {
document: self.document_legacy.clone(),
layer_metadata: self.layer_metadata.clone(),
});
responses.add(DocumentMessage::BackupDocument { document: self.clone() });
}
/// Replace the document with a new document save, returning the document save.
pub fn replace_document(&mut self, DocumentSave { document, layer_metadata }: DocumentSave) -> DocumentSave {
// Keeping the root is required if the bounds of the viewport have changed during the operation
pub fn replace_document(&mut self, document: DocumentMessageHandler) -> DocumentMessageHandler {
// Replace the network. (Keeping the root is required if the bounds of the viewport have changed during the operation.)
let old_root = self.metadata().document_to_viewport;
let document = std::mem::replace(&mut self.document_legacy, document);
self.document_legacy.metadata.document_to_viewport = old_root;
let document = std::mem::replace(self, document);
self.metadata.document_to_viewport = old_root;
let layer_metadata = std::mem::replace(&mut self.layer_metadata, layer_metadata);
DocumentSave { document, layer_metadata }
document
}
pub fn undo(&mut self, responses: &mut VecDeque<Message>) {
@@ -890,25 +980,27 @@ impl DocumentMessageHandler {
let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();
if let Some(DocumentSave { document, layer_metadata }) = self.document_undo_history.pop_back() {
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();
let Some(document) = self.document_undo_history.pop_back() else {
return;
};
if prev_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
// Update the currently displayed layer on the Properties panel if the selection changes after an undo action
// Also appropriately update the Properties panel if an undo action results in a layer being deleted
let prev_selected_paths: Vec<Vec<LayerId>> = self.selected.iter().filter_map(|(layer_id, selected)| selected.then_some(layer_id.clone())).collect();
let document_save = self.replace_document(DocumentSave { document, layer_metadata });
self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
if prev_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
let document_save = self.replace_document(document);
self.document_redo_history.push_back(document_save);
if self.document_redo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_redo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
pub fn redo(&mut self, responses: &mut VecDeque<Message>) {
@@ -917,34 +1009,30 @@ impl DocumentMessageHandler {
let selected_paths: Vec<Vec<LayerId>> = self.selected_layers().map(|path| path.to_vec()).collect();
if let Some(DocumentSave { document, layer_metadata }) = self.document_redo_history.pop_back() {
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = layer_metadata.iter().filter_map(|(layer_id, metadata)| metadata.selected.then_some(layer_id.clone())).collect();
let Some(document) = self.document_redo_history.pop_back() else { return };
if next_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
// Update currently displayed layer on property panel if selection changes after redo action
// Also appropriately update property panel if redo action results in a layer being added
let next_selected_paths: Vec<Vec<LayerId>> = self.selected.iter().filter_map(|(layer_id, selected)| selected.then_some(layer_id.clone())).collect();
let document_save = self.replace_document(DocumentSave { document, layer_metadata });
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
if next_selected_paths != selected_paths {
responses.add(BroadcastEvent::SelectionChanged);
}
let document_save = self.replace_document(document);
self.document_undo_history.push_back(document_save);
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
self.document_undo_history.pop_front();
}
responses.add(DocumentMessage::DocumentStructureChanged);
responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
pub fn current_identifier(&self) -> u64 {
// We can use the last state of the document to serve as the identifier to compare against
// This is useful since when the document is empty the identifier will be 0
self.document_undo_history
.iter()
.last()
.map(|DocumentSave { document, .. }| document.current_state_identifier())
.unwrap_or(0)
self.document_undo_history.iter().last().map(|document| document.state_identifier.finish()).unwrap_or(0)
}
pub fn is_auto_saved(&self) -> bool {
@@ -990,7 +1078,7 @@ impl DocumentMessageHandler {
/// Loads layer resources such as creating the blob URLs for the images and loading all of the fonts in the document
pub fn load_layer_resources(&self, responses: &mut VecDeque<Message>) {
let mut fonts = HashSet::new();
for (_node_id, node) in self.document_legacy.document_network.recursive_nodes() {
for (_node_id, node) in self.network.recursive_nodes() {
for input in &node.inputs {
if let NodeInput::Value {
tagged_value: TaggedValue::Font(font),
@@ -1191,12 +1279,7 @@ impl DocumentMessageHandler {
let selected_layers_except_artboards = self.metadata().selected_layers_except_artboards();
// Look up the current opacity and blend mode of the selected layers (if any), and split the iterator into the first tuple and the rest.
let mut opacity_and_blend_mode = selected_layers_except_artboards.map(|layer| {
(
get_opacity(layer, &self.document_legacy).unwrap_or(100.),
get_blend_mode(layer, &self.document_legacy).unwrap_or_default(),
)
});
let mut opacity_and_blend_mode = selected_layers_except_artboards.map(|layer| (get_opacity(layer, &self.network).unwrap_or(100.), get_blend_mode(layer, &self.network).unwrap_or_default()));
let first_opacity_and_blend_mode = opacity_and_blend_mode.next();
let result_opacity_and_blend_mode = opacity_and_blend_mode;
@@ -1322,4 +1405,39 @@ impl DocumentMessageHandler {
responses.add(DocumentMessage::MoveSelectedLayersTo { parent, insert_index });
}
pub fn actions_with_graph_open(&self, graph_open: bool) -> ActionList {
let mut common = actions!(DocumentMessageDiscriminant;
Undo,
Redo,
SelectAllLayers,
DeselectAllLayers,
RenderDocument,
SaveDocument,
SetSnapping,
DebugPrintDocument,
ZoomCanvasToFitAll,
ZoomCanvasTo100Percent,
ZoomCanvasTo200Percent,
CreateEmptyFolder,
);
if self.metadata().selected_layers().next().is_some() {
let select = actions!(DocumentMessageDiscriminant;
DeleteSelectedLayers,
DuplicateSelectedLayers,
NudgeSelectedLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
GroupSelectedLayers,
UngroupSelectedLayers,
);
common.extend(select);
}
common.extend(self.navigation_handler.actions());
common.extend(self.node_graph_handler.actions_with_node_graph_open(graph_open));
common
}
}
@@ -5,11 +5,10 @@ use crate::consts::{
use crate::messages::frontend::utility_types::MouseCursorIcon;
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion};
use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::prelude::*;
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
use document_legacy::document::Document;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
@@ -59,13 +58,13 @@ impl Default for NavigationMessageHandler {
}
}
impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>)> for NavigationMessageHandler {
impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>)> for NavigationMessageHandler {
#[remain::check]
fn process_message(
&mut self,
message: NavigationMessage,
responses: &mut VecDeque<Message>,
(document, document_bounds, ipp, selection_bounds): (&Document, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>),
(document_metadata, document_bounds, ipp, selection_bounds): (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>),
) {
use NavigationMessage::*;
@@ -85,8 +84,8 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
padding_scale_factor,
prevent_zoom_past_100,
} => {
let v1 = document.metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
let v2 = document.metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size());
let v1 = document_metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
let v2 = document_metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size());
let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5);
let size = (pos2 - pos1) / (v2 - v1);
@@ -108,7 +107,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
}
FitViewportToSelection => {
if let Some(bounds) = selection_bounds {
let transform = document.metadata.document_to_viewport.inverse();
let transform = document_metadata.document_to_viewport.inverse();
responses.add(FitViewportToBounds {
bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])],
padding_scale_factor: Some(VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR),
@@ -270,7 +269,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
responses.add(TransformCanvasEnd { abort_transform });
}
TranslateCanvas { delta } => {
let transformed_delta = document.metadata.document_to_viewport.inverse().transform_vector2(delta);
let transformed_delta = document_metadata.document_to_viewport.inverse().transform_vector2(delta);
self.pan += transformed_delta;
responses.add(BroadcastEvent::CanvasTransformed);
@@ -288,7 +287,7 @@ impl MessageHandler<NavigationMessage, (&Document, Option<[DVec2; 2]>, &InputPre
self.transform_operation = TransformOperation::Pan { pre_commit_pan: self.pan };
}
TranslateCanvasByViewportFraction { delta } => {
let transformed_delta = document.metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
let transformed_delta = document_metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
self.pan += transformed_delta;
responses.add(BroadcastEvent::DocumentIsDirty);
@@ -1,7 +1,8 @@
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use bezier_rs::Subpath;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::DocumentNode;
use graph_craft::document::NodeId;
use graphene_core::raster::BlendMode;
@@ -15,7 +16,7 @@ use graphene_core::{Artboard, Color};
use glam::{DAffine2, DVec2, IVec2};
pub type LayerIdentifier = Vec<document_legacy::document::LayerId>;
pub type LayerIdentifier = Vec<LayerId>;
#[impl_message(Message, DocumentMessage, GraphOperation)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -1,10 +1,9 @@
use super::{resolve_document_node_type, VectorDataModification};
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use bezier_rs::Subpath;
use document_legacy::document::Document;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{generate_uuid, DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::raster::{BlendMode, ImageFrame};
@@ -23,35 +22,41 @@ pub mod transform_utils;
pub struct GraphOperationMessageHandler;
struct ModifyInputsContext<'a> {
network: &'a mut NodeNetwork,
document_metadata: &'a mut DocumentMetadata,
document_network: &'a mut NodeNetwork,
node_graph: &'a mut NodeGraphMessageHandler,
responses: &'a mut VecDeque<Message>,
layer: &'a [LayerId],
outwards_links: HashMap<NodeId, Vec<NodeId>>,
layer_node: Option<NodeId>,
document_metadata: &'a mut DocumentMetadata,
}
impl<'a> ModifyInputsContext<'a> {
/// Get the node network from the document
fn new(document: &'a mut Document, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque<Message>) -> Self {
fn new(document_network: &'a mut NodeNetwork, document_metadata: &'a mut DocumentMetadata, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque<Message>) -> Self {
Self {
outwards_links: document.document_network.collect_outwards_links(),
network: &mut document.document_network,
outwards_links: document_network.collect_outwards_links(),
document_network,
node_graph,
responses,
layer: &[],
layer_node: None,
document_metadata: &mut document.metadata,
document_metadata,
}
}
fn new_with_layer(layer: &'a [LayerId], document: &'a mut Document, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque<Message>) -> Option<Self> {
let mut document = Self::new(document, node_graph, responses);
fn new_with_layer(
layer: &'a [LayerId],
document_network: &'a mut NodeNetwork,
document_metadata: &'a mut DocumentMetadata,
node_graph: &'a mut NodeGraphMessageHandler,
responses: &'a mut VecDeque<Message>,
) -> Option<Self> {
let mut document = Self::new(document_network, document_metadata, node_graph, responses);
let Some(mut id) = layer.last().copied() else {
error!("Tried to modify root layer");
return None;
};
while !document.network.nodes.get(&id)?.is_layer() {
while !document.document_network.nodes.get(&id)?.is_layer() {
id = document.outwards_links.get(&id)?.first().copied()?;
}
document.layer_node = Some(id);
@@ -60,20 +65,20 @@ impl<'a> ModifyInputsContext<'a> {
/// Updates the input of an existing node
fn modify_existing_node_inputs(&mut self, node_id: NodeId, update_input: impl FnOnce(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let document_node = self.network.nodes.get_mut(&node_id).unwrap();
let document_node = self.document_network.nodes.get_mut(&node_id).unwrap();
update_input(&mut document_node.inputs, node_id, self.document_metadata);
}
pub fn insert_between(&mut self, id: NodeId, pre: NodeOutput, post: NodeOutput, mut node: DocumentNode, input: usize, output: usize, shift_upstream: IVec2) -> Option<NodeId> {
assert!(!self.network.nodes.contains_key(&id), "Creating already existing node");
let pre_node = self.network.nodes.get_mut(&pre.node_id)?;
assert!(!self.document_network.nodes.contains_key(&id), "Creating already existing node");
let pre_node = self.document_network.nodes.get_mut(&pre.node_id)?;
node.metadata.position = pre_node.metadata.position;
let post_node = self.network.nodes.get_mut(&post.node_id)?;
let post_node = self.document_network.nodes.get_mut(&post.node_id)?;
node.inputs[input] = NodeInput::node(pre.node_id, pre.node_output_index);
post_node.inputs[post.node_output_index] = NodeInput::node(id, output);
self.network.nodes.insert(id, node);
self.document_network.nodes.insert(id, node);
self.shift_upstream(id, shift_upstream);
@@ -81,19 +86,19 @@ impl<'a> ModifyInputsContext<'a> {
}
pub fn insert_node_before(&mut self, new_id: NodeId, node_id: NodeId, input_index: usize, mut document_node: DocumentNode, offset: IVec2) -> Option<NodeId> {
assert!(!self.network.nodes.contains_key(&new_id), "Creating already existing node");
let post_node = self.network.nodes.get_mut(&node_id)?;
assert!(!self.document_network.nodes.contains_key(&new_id), "Creating already existing node");
let post_node = self.document_network.nodes.get_mut(&node_id)?;
post_node.inputs[input_index] = NodeInput::node(new_id, 0);
document_node.metadata.position = post_node.metadata.position + offset;
self.network.nodes.insert(new_id, document_node);
self.document_network.nodes.insert(new_id, document_node);
Some(new_id)
}
pub fn skip_artboards(&self, output: &mut NodeOutput) -> Option<(NodeId, usize)> {
while let NodeInput::Node { node_id, output_index, .. } = &self.network.nodes.get(&output.node_id)?.inputs[output.node_output_index] {
let sibling_node = self.network.nodes.get(node_id)?;
while let NodeInput::Node { node_id, output_index, .. } = &self.document_network.nodes.get(&output.node_id)?.inputs[output.node_output_index] {
let sibling_node = self.document_network.nodes.get(node_id)?;
if sibling_node.name != "Artboard" {
return Some((*node_id, *output_index));
}
@@ -103,14 +108,14 @@ impl<'a> ModifyInputsContext<'a> {
}
pub fn create_layer(&mut self, new_id: NodeId, output_node_id: NodeId, input_index: usize, skip_layer_nodes: usize) -> Option<NodeId> {
assert!(!self.network.nodes.contains_key(&new_id), "Creating already existing layer");
assert!(!self.document_network.nodes.contains_key(&new_id), "Creating already existing layer");
let mut output = NodeOutput::new(output_node_id, input_index);
let mut sibling_layer = None;
let mut shift = IVec2::new(0, 3);
// Locate the node output of the first sibling layer to the new layer
if let Some((node_id, output_index)) = self.skip_artboards(&mut output) {
let sibling_node = self.network.nodes.get(&node_id)?;
let sibling_node = self.document_network.nodes.get(&node_id)?;
if sibling_node.is_layer() {
// There is already a layer node
sibling_layer = Some(NodeOutput::new(node_id, 0));
@@ -125,7 +130,7 @@ impl<'a> ModifyInputsContext<'a> {
for _ in 0..skip_layer_nodes {
if let Some(old_sibling) = &sibling_layer {
output = NodeOutput::new(old_sibling.node_id, 1);
sibling_layer = self.network.nodes.get(&old_sibling.node_id)?.inputs[1].as_node().map(|node| NodeOutput::new(node, 0));
sibling_layer = self.document_network.nodes.get(&old_sibling.node_id)?.inputs[1].as_node().map(|node| NodeOutput::new(node, 0));
shift = IVec2::new(0, 3);
}
}
@@ -145,12 +150,12 @@ impl<'a> ModifyInputsContext<'a> {
// Update the document metadata structure
if let Some(new_id) = new_id {
let parent = if self.network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
LayerNodeIdentifier::new(output_node_id, self.network)
let parent = if self.document_network.nodes.get(&output_node_id).is_some_and(|node| node.is_layer()) {
LayerNodeIdentifier::new(output_node_id, self.document_network)
} else {
LayerNodeIdentifier::ROOT
};
let new_child = LayerNodeIdentifier::new(new_id, self.network);
let new_child = LayerNodeIdentifier::new(new_id, self.document_network);
parent.push_front_child(self.document_metadata, new_child);
self.responses.add(DocumentMessage::DocumentStructureChanged);
}
@@ -162,7 +167,7 @@ impl<'a> ModifyInputsContext<'a> {
let skip_layer_nodes = if insert_index < 0 { (-1 - insert_index) as usize } else { insert_index as usize };
let output_node_id = if parent == LayerNodeIdentifier::ROOT {
self.network.original_outputs()[0].node_id
self.document_network.original_outputs()[0].node_id
} else {
parent.to_node()
};
@@ -256,7 +261,7 @@ impl<'a> ModifyInputsContext<'a> {
let mut shift_nodes = HashSet::new();
let mut stack = vec![node_id];
while let Some(node_id) = stack.pop() {
let Some(node) = self.network.nodes.get(&node_id) else { continue };
let Some(node) = self.document_network.nodes.get(&node_id) else { continue };
for input in &node.inputs {
let NodeInput::Node { node_id, .. } = input else { continue };
if shift_nodes.insert(*node_id) {
@@ -266,7 +271,7 @@ impl<'a> ModifyInputsContext<'a> {
}
for node_id in shift_nodes {
if let Some(node) = self.network.nodes.get_mut(&node_id) {
if let Some(node) = self.document_network.nodes.get_mut(&node_id) {
node.metadata.position += shift;
}
}
@@ -274,8 +279,8 @@ impl<'a> ModifyInputsContext<'a> {
/// Inserts a new node and modifies the inputs
fn modify_new_node(&mut self, name: &'static str, update_input: impl FnOnce(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let output_node_id = self.layer_node.unwrap_or(self.network.outputs[0].node_id);
let Some(output_node) = self.network.nodes.get_mut(&output_node_id) else {
let output_node_id = self.layer_node.unwrap_or(self.document_network.outputs[0].node_id);
let Some(output_node) = self.document_network.nodes.get_mut(&output_node_id) else {
warn!("Output node doesn't exist");
return;
};
@@ -292,11 +297,11 @@ impl<'a> ModifyInputsContext<'a> {
};
let mut new_document_node = node_type.to_document_node_default_inputs([new_input], metadata);
update_input(&mut new_document_node.inputs, node_id, self.document_metadata);
self.network.nodes.insert(node_id, new_document_node);
self.document_network.nodes.insert(node_id, new_document_node);
let upstream_nodes = self.network.upstream_flow_back_from_nodes(vec![node_id], true).map(|(_, id)| id).collect::<Vec<_>>();
let upstream_nodes = self.document_network.upstream_flow_back_from_nodes(vec![node_id], true).map(|(_, id)| id).collect::<Vec<_>>();
for node_id in upstream_nodes {
let Some(node) = self.network.nodes.get_mut(&node_id) else { continue };
let Some(node) = self.document_network.nodes.get_mut(&node_id) else { continue };
node.metadata.position.x -= 8;
}
}
@@ -304,8 +309,12 @@ impl<'a> ModifyInputsContext<'a> {
/// Changes the inputs of a specific node
fn modify_inputs(&mut self, name: &'static str, skip_rerender: bool, update_input: impl FnOnce(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let existing_node_id = self
.network
.upstream_flow_back_from_nodes(self.layer_node.map_or_else(|| self.network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]), true)
.document_network
.upstream_flow_back_from_nodes(
self.layer_node
.map_or_else(|| self.document_network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]),
true,
)
.find(|(node, _)| node.name == name)
.map(|(_, id)| id);
if let Some(node_id) = existing_node_id {
@@ -331,8 +340,12 @@ impl<'a> ModifyInputsContext<'a> {
/// Changes the inputs of a all of the existing instances of a node name
fn modify_all_node_inputs(&mut self, name: &'static str, skip_rerender: bool, mut update_input: impl FnMut(&mut Vec<NodeInput>, NodeId, &DocumentMetadata)) {
let existing_nodes: Vec<_> = self
.network
.upstream_flow_back_from_nodes(self.layer_node.map_or_else(|| self.network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]), true)
.document_network
.upstream_flow_back_from_nodes(
self.layer_node
.map_or_else(|| self.document_network.outputs.iter().map(|output| output.node_id).collect(), |id| vec![id]),
true,
)
.filter(|(node, _)| node.name == name)
.map(|(_, id)| id)
.collect();
@@ -516,18 +529,18 @@ impl<'a> ModifyInputsContext<'a> {
}
fn delete_layer(&mut self, id: NodeId) {
let Some(node) = self.network.nodes.get(&id) else {
let Some(node) = self.document_network.nodes.get(&id) else {
warn!("Deleting layer node that does not exist");
return;
};
LayerNodeIdentifier::new(id, self.network).delete(self.document_metadata);
LayerNodeIdentifier::new(id, self.document_network).delete(self.document_metadata);
let new_input = node.inputs[1].clone();
let deleted_position = node.metadata.position;
for post_node in self.outwards_links.get(&id).unwrap_or(&Vec::new()) {
let Some(node) = self.network.nodes.get_mut(post_node) else {
let Some(node) = self.document_network.nodes.get_mut(post_node) else {
continue;
};
@@ -541,7 +554,7 @@ impl<'a> ModifyInputsContext<'a> {
}
let mut delete_nodes = vec![id];
for (_node, id) in self.network.upstream_flow_back_from_nodes(vec![id], true) {
for (_node, id) in self.document_network.upstream_flow_back_from_nodes(vec![id], true) {
// Don't delete the node if other layers depend on it.
if self.outwards_links.get(&id).is_some_and(|nodes| nodes.len() > 1) {
break;
@@ -552,13 +565,13 @@ impl<'a> ModifyInputsContext<'a> {
}
for node_id in &delete_nodes {
self.network.nodes.remove(node_id);
self.document_network.nodes.remove(node_id);
}
if let Some(node_id) = new_input.as_node() {
if let Some(shift) = self.network.nodes.get(&node_id).map(|node| deleted_position - node.metadata.position) {
for node_id in self.network.upstream_flow_back_from_nodes(vec![node_id], false).map(|(_, id)| id).collect::<Vec<_>>() {
let Some(node) = self.network.nodes.get_mut(&node_id) else { continue };
if let Some(shift) = self.document_network.nodes.get(&node_id).map(|node| deleted_position - node.metadata.position) {
for node_id in self.document_network.upstream_flow_back_from_nodes(vec![node_id], false).map(|(_, id)| id).collect::<Vec<_>>() {
let Some(node) = self.document_network.nodes.get_mut(&node_id) else { continue };
node.metadata.position += shift;
}
}
@@ -572,36 +585,36 @@ impl<'a> ModifyInputsContext<'a> {
}
}
impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler)> for GraphOperationMessageHandler {
impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler)> for GraphOperationMessageHandler {
fn process_message(
&mut self,
message: GraphOperationMessage,
responses: &mut VecDeque<Message>,
(document, collapsed_folders, node_graph): (&mut Document, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler),
(document_network, document_metadata, collapsed, node_graph): (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler),
) {
match message {
GraphOperationMessage::FillSet { layer, fill } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.fill_set(fill);
}
}
GraphOperationMessage::OpacitySet { layer, opacity } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.opacity_set(opacity);
}
}
GraphOperationMessage::BlendModeSet { layer, blend_mode } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.blend_mode_set(blend_mode);
}
}
GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.update_bounds(old_bounds, new_bounds);
}
}
GraphOperationMessage::StrokeSet { layer, stroke } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.stroke_set(stroke);
}
}
@@ -611,10 +624,10 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
transform_in,
skip_rerender,
} => {
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
let parent_transform = document.metadata.downstream_transform_to_viewport(layer_identifier);
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender);
}
}
@@ -624,37 +637,37 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
transform_in,
skip_rerender,
} => {
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
let parent_transform = document.metadata.downstream_transform_to_viewport(layer_identifier);
let layer_identifier = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
let parent_transform = document_metadata.downstream_transform_to_viewport(layer_identifier);
let current_transform = Some(document.metadata.transform_to_viewport(layer_identifier));
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
let current_transform = Some(document_metadata.transform_to_viewport(layer_identifier));
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender);
}
}
GraphOperationMessage::TransformSetPivot { layer, pivot } => {
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
let bounds = LayerBounds::new(document_network, document_metadata, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.pivot_set(pivot, bounds);
}
}
GraphOperationMessage::Vector { layer, modification } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.vector_modify(modification);
}
}
GraphOperationMessage::Brush { layer, strokes } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&layer, document_network, document_metadata, node_graph, responses) {
modify_inputs.brush_modify(strokes);
}
}
GraphOperationMessage::NewArtboard { id, artboard } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.network.original_outputs()[0].node_id, 0, 0) {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.document_network.original_outputs()[0].node_id, 0, 0) {
modify_inputs.insert_artboard(artboard, layer);
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::NewBitmapLayer {
id,
@@ -662,7 +675,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
parent,
insert_index,
} => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_image_data(image_frame, layer);
}
@@ -670,7 +683,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index } => {
trace!("Inserting new layer {id} as a child of {parent:?} at index {insert_index}");
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
let new_ids: HashMap<_, _> = nodes.iter().map(|(&id, _)| (id, crate::application::generate_uuid())).collect();
@@ -679,7 +692,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
.get(&0)
.and_then(|node| {
modify_inputs
.network
.document_network
.nodes
.get(&layer)
.map(|layer| layer.metadata.position - node.metadata.position + IVec2::new(-8, 0))
@@ -695,10 +708,10 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
document_node = document_node.map_ids(NodeGraphMessageHandler::default_node_input, &new_ids);
// Insert node into network
modify_inputs.network.nodes.insert(node_id, document_node);
modify_inputs.document_network.nodes.insert(node_id, document_node);
}
if let Some(layer_node) = modify_inputs.network.nodes.get_mut(&layer) {
if let Some(layer_node) = modify_inputs.document_network.nodes.get_mut(&layer) {
if let Some(&input) = new_ids.get(&0) {
layer_node.inputs[0] = NodeInput::node(input, 0)
}
@@ -707,14 +720,14 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
modify_inputs.responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_vector_data(subpaths, layer);
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::NewTextLayer {
id,
@@ -724,31 +737,31 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
parent,
insert_index,
} => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_text(text, font, size, layer);
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::ResizeArtboard { id, location, dimensions } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&[id], document, node_graph, responses) {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(&[id], document_network, document_metadata, node_graph, responses) {
modify_inputs.resize_artboard(location, dimensions);
}
}
GraphOperationMessage::DeleteLayer { id } => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
modify_inputs.delete_layer(id);
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
GraphOperationMessage::ClearArtboards => {
let mut modify_inputs = ModifyInputsContext::new(document, node_graph, responses);
let layer_nodes = modify_inputs.network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
for layer in layer_nodes {
if modify_inputs.network.upstream_flow_back_from_nodes(vec![layer], true).any(|(node, _id)| node.is_artboard()) {
if modify_inputs.document_network.upstream_flow_back_from_nodes(vec![layer], true).any(|(node, _id)| node.is_artboard()) {
modify_inputs.delete_layer(layer);
}
}
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, document_metadata, collapsed);
}
}
}
@@ -758,7 +771,7 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut Vec<LayerNodeIde
}
}
pub fn load_network_structure(document: &mut Document, collapsed_folders: &mut Vec<LayerNodeIdentifier>) {
document.metadata.load_structure(&document.document_network);
collapsed_folders.retain(|&layer| document.metadata.layer_exists(layer));
pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, collapsed: &mut Vec<LayerNodeIdentifier>) {
document_metadata.load_structure(document_network);
collapsed.retain(|&layer| document_metadata.layer_exists(layer));
}
@@ -1,8 +1,8 @@
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use bezier_rs::{ManipulatorGroup, Subpath};
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graph_craft::document::{value::TaggedValue, NodeInput};
use graphene_core::uuid::ManipulatorGroupId;
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -53,12 +53,12 @@ pub struct LayerBounds {
impl LayerBounds {
/// Extract the layer bounds and their transform for a layer.
pub fn new(document: &Document, layer: &[u64]) -> Self {
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), &document.document_network);
pub fn new(document_network: &NodeNetwork, document_metadata: &DocumentMetadata, layer: &[u64]) -> Self {
let layer = LayerNodeIdentifier::new(*layer.last().unwrap(), document_network);
Self {
bounds: document.metadata.nonzero_bounding_box(layer),
bounds: document_metadata.nonzero_bounding_box(layer),
bounds_transform: DAffine2::IDENTITY,
layer_transform: document.metadata.transform_to_document(layer),
layer_transform: document_metadata.transform_to_document(layer),
}
}
@@ -1,6 +1,6 @@
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use document_legacy::document::LayerId;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
@@ -2,12 +2,11 @@ pub use self::document_node_types::*;
use super::load_network_structure;
use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::*;
use crate::node_graph_executor::GraphIdentifier;
use document_legacy::document::Document;
use document_legacy::document::LayerId;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput};
use graphene_core::*;
@@ -157,19 +156,19 @@ impl NodeGraphMessageHandler {
}
/// Updates the buttons for disable and preview
fn update_selection_action_buttons(&mut self, document: &Document, responses: &mut VecDeque<Message>) {
if let Some(network) = document.document_network.nested_network(&self.network) {
fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) {
if let Some(network) = document_network.nested_network(&self.network) {
let mut widgets = Vec::new();
// Don't allow disabling input or output nodes
let mut selected_nodes = document.metadata.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id));
let mut selected_nodes = document_metadata.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id));
// If there is at least one other selected node then show the hide or show button
if selected_nodes.next().is_some() {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
// Check if any of the selected nodes are disabled
let is_hidden = document.metadata.selected_nodes().any(|id| network.disabled.contains(id));
let is_hidden = document_metadata.selected_nodes().any(|id| network.disabled.contains(id));
// Check if multiple nodes are selected
let multiple_nodes = selected_nodes.next().is_some();
@@ -186,7 +185,7 @@ impl NodeGraphMessageHandler {
}
// If only one node is selected then show the preview or stop previewing button
let mut selected_nodes = document.metadata.selected_nodes();
let mut selected_nodes = document_metadata.selected_nodes();
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) {
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
@@ -212,7 +211,6 @@ impl NodeGraphMessageHandler {
/// Collate the properties panel sections for a node graph
pub fn collate_properties(&self, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let mut network = context.network;
let document = context.document;
for segment in &self.network {
network = network.nodes.get(segment).and_then(|node| node.implementation.get_network()).unwrap();
@@ -225,7 +223,7 @@ impl NodeGraphMessageHandler {
// First, we filter all the selections into layers and nodes
let (mut layers, mut nodes) = (Vec::new(), Vec::new());
for node_id in document.metadata.selected_nodes() {
for node_id in context.metadata.selected_nodes() {
if let Some(layer_or_node) = network.nodes.get(node_id) {
if layer_or_node.is_layer() {
layers.push(*node_id);
@@ -341,10 +339,10 @@ impl NodeGraphMessageHandler {
}
/// Updates the frontend's selection state in line with the backend
fn update_selected(&mut self, document: &mut Document, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document, responses);
fn update_selected(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document_network, document_metadata, responses);
responses.add(FrontendMessage::UpdateNodeGraphSelection {
selected: document.metadata.selected_nodes_ref().clone(),
selected: document_metadata.selected_nodes_ref().clone(),
});
}
@@ -415,15 +413,15 @@ impl NodeGraphMessageHandler {
}
/// Tries to remove a node from the network, returning true on success.
fn remove_node(&mut self, document: &mut Document, node_id: NodeId, responses: &mut VecDeque<Message>, reconnect: bool) -> bool {
let Some(network) = document.document_network.nested_network_mut(&self.network) else {
fn remove_node(&mut self, document_network: &mut NodeNetwork, document_metadata: &mut DocumentMetadata, node_id: NodeId, responses: &mut VecDeque<Message>, reconnect: bool) -> bool {
let Some(network) = document_network.nested_network_mut(&self.network) else {
return false;
};
if !Self::remove_references_from_network(network, node_id, reconnect) {
return false;
}
network.nodes.remove(&node_id);
document.metadata.retain_selected_nodes(|&id| id != node_id);
document_metadata.retain_selected_nodes(|&id| id != node_id);
responses.add(BroadcastEvent::SelectionChanged);
true
}
@@ -447,10 +445,11 @@ impl NodeGraphMessageHandler {
#[derive(Debug)]
pub struct NodeGraphHandlerData<'a> {
pub document: &'a mut Document,
pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub document_id: u64,
pub document_name: &'a str,
pub collapsed_folders: &'a mut Vec<LayerNodeIdentifier>,
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
pub input: &'a InputPreprocessorMessageHandler,
pub graph_view_overlay_open: bool,
}
@@ -458,9 +457,10 @@ pub struct NodeGraphHandlerData<'a> {
impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGraphMessageHandler {
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, data: NodeGraphHandlerData<'a>) {
let NodeGraphHandlerData {
document,
document_network,
document_metadata: metadata,
document_id,
collapsed_folders,
collapsed,
graph_view_overlay_open,
..
} = data;
@@ -471,15 +471,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
on: BroadcastEvent::SelectionChanged,
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
});
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, metadata, collapsed);
responses.add(DocumentMessage::DocumentStructureChanged);
}
NodeGraphMessage::SelectedNodesUpdated => {
self.update_selection_action_buttons(document, responses);
self.update_selected(document, responses);
if document.metadata.selected_layers().count() <= 1 {
self.update_selection_action_buttons(document_network, metadata, responses);
self.update_selected(document_network, metadata, responses);
if metadata.selected_layers().count() <= 1 {
responses.add(DocumentMessage::SetRangeSelectionLayer {
new_layer: document.metadata.selected_layers().next(),
new_layer: metadata.selected_layers().next(),
});
}
responses.add(NodeGraphMessage::RunDocumentGraph);
@@ -492,7 +492,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
} => {
let node_id = input_node;
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
error!("No network");
return;
};
@@ -515,13 +515,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender });
}
NodeGraphMessage::Copy => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
error!("No network");
return;
};
// Collect the selected nodes
let new_ids = &document.metadata.selected_nodes().copied().enumerate().map(|(new, old)| (old, new as NodeId)).collect();
let new_ids = &metadata.selected_nodes().copied().enumerate().map(|(new, old)| (old, new as NodeId)).collect();
let copied_nodes: Vec<_> = Self::copy_nodes(network, new_ids).collect();
// Prefix to show that this is nodes
@@ -556,20 +556,20 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
}
NodeGraphMessage::DeleteNode { node_id, reconnect } => {
self.remove_node(document, node_id, responses, reconnect);
self.remove_node(document_network, metadata, node_id, responses, reconnect);
}
NodeGraphMessage::DeleteSelectedNodes { reconnect } => {
responses.add(DocumentMessage::StartTransaction);
for node_id in document.metadata.selected_nodes().copied() {
for node_id in metadata.selected_nodes().copied() {
responses.add(NodeGraphMessage::DeleteNode { node_id, reconnect });
}
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
// Only generate node graph if one of the selected nodes is connected to the output
if document.metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
if metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
if let Some(layer_path) = self.layer_path.clone() {
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
} else {
@@ -579,7 +579,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::DisconnectNodes { node_id, input_index } => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
warn!("No network");
return;
};
@@ -607,30 +607,30 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender });
}
NodeGraphMessage::DoubleClickNode { node } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
if network.nodes.get(&node).and_then(|node| node.implementation.get_network()).is_some() {
self.network.push(node);
}
}
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
}
NodeGraphMessage::DuplicateSelectedNodes => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction);
let new_ids = &document.metadata.selected_nodes().map(|&id| (id, crate::application::generate_uuid())).collect();
let new_ids = &metadata.selected_nodes().map(|&id| (id, crate::application::generate_uuid())).collect();
document.metadata.clear_selected_nodes();
metadata.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
// Copy the selected nodes
let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>();
// Select the new nodes
document.metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
responses.add(BroadcastEvent::SelectionChanged);
for (node_id, mut document_node) in copied_nodes {
@@ -642,24 +642,24 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
}
}
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
document.metadata.clear_selected_nodes();
metadata.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
for _ in 0..depth_of_nesting {
self.network.pop();
}
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
}
NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
warn!("No network");
return;
};
@@ -689,17 +689,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(PropertiesPanelMessage::Refresh);
}
NodeGraphMessage::InsertNode { node_id, document_node } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
network.nodes.insert(node_id, document_node);
}
}
NodeGraphMessage::MoveSelectedNodes { displacement_x, displacement_y } => {
let Some(network) = document.document_network.nested_network_mut(&self.network) else {
let Some(network) = document_network.nested_network_mut(&self.network) else {
warn!("No network");
return;
};
for node_id in document.metadata.selected_nodes() {
for node_id in metadata.selected_nodes() {
if let Some(node) = network.nodes.get_mut(node_id) {
node.metadata.position += IVec2::new(displacement_x, displacement_y)
}
@@ -707,7 +707,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
NodeGraphMessage::PasteNodes { serialized_nodes } => {
let Some(network) = document.document_network.nested_network(&self.network) else {
let Some(network) = document_network.nested_network(&self.network) else {
warn!("No network");
return;
};
@@ -755,20 +755,20 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path: Vec::new() }),
NodeGraphMessage::SelectedNodesAdd { nodes } => {
document.metadata.add_selected_nodes(nodes);
metadata.add_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged);
}
NodeGraphMessage::SelectedNodesRemove { nodes } => {
document.metadata.retain_selected_nodes(|node| !nodes.contains(node));
metadata.retain_selected_nodes(|node| !nodes.contains(node));
responses.add(BroadcastEvent::SelectionChanged);
}
NodeGraphMessage::SelectedNodesSet { nodes } => {
document.metadata.set_selected_nodes(nodes);
metadata.set_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged);
responses.add(PropertiesPanelMessage::Refresh);
}
NodeGraphMessage::SendGraph { should_rerender } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
if should_rerender {
if let Some(layer_path) = self.layer_path.clone() {
@@ -780,7 +780,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::SetInputValue { node_id, input_index, value } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
if let Some(node) = network.nodes.get(&node_id) {
responses.add(DocumentMessage::StartTransaction);
@@ -798,7 +798,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::SetNodeInput { node_id, input_index, input } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
if let Some(node) = network.nodes.get_mut(&node_id) {
let Some(node_input) = node.inputs.get_mut(input_index) else {
error!("Tried to set input {input_index} to {input:?}, but the index was invalid. Node {node_id}:\n{node:#?}");
@@ -807,7 +807,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let structure_changed = node_input.as_node().is_some() || input.as_node().is_some();
*node_input = input;
if structure_changed {
load_network_structure(document, collapsed_folders);
load_network_structure(document_network, metadata, collapsed);
}
}
}
@@ -823,7 +823,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
return;
};
let network = document.document_network.nested_network_mut(node_path);
let network = document_network.nested_network_mut(node_path);
if let Some(network) = network {
if let Some(node) = network.nodes.get_mut(node_id) {
@@ -839,7 +839,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::ShiftNode { node_id } => {
let Some(network) = document.document_network.nested_network_mut(&self.network) else {
let Some(network) = document_network.nested_network_mut(&self.network) else {
warn!("No network");
return;
};
@@ -887,23 +887,23 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
}
NodeGraphMessage::ToggleSelectedHidden => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction);
let new_hidden = !document.metadata.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in document.metadata.selected_nodes() {
let new_hidden = !metadata.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in metadata.selected_nodes() {
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
}
}
}
NodeGraphMessage::ToggleHidden { node_id } => {
if let Some(network) = document.document_network.nested_network(&self.network) {
if let Some(network) = document_network.nested_network(&self.network) {
let new_hidden = !network.disabled.contains(&node_id);
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
}
}
NodeGraphMessage::SetHidden { node_id, hidden } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
if !hidden {
network.disabled.retain(|&id| node_id != id);
} else if !network.inputs.contains(&node_id) && !network.original_outputs().iter().any(|output| output.node_id == node_id) {
@@ -916,14 +916,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::RunDocumentGraph);
}
}
self.update_selection_action_buttons(document, responses);
self.update_selection_action_buttons(document_network, metadata, responses);
}
NodeGraphMessage::SetName { node_id, name } => {
responses.add(DocumentMessage::StartTransaction);
responses.add(NodeGraphMessage::SetNameImpl { node_id, name });
}
NodeGraphMessage::SetNameImpl { node_id, name } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
if let Some(node) = network.nodes.get_mut(&node_id) {
node.alias = name;
responses.add(NodeGraphMessage::SendGraph { should_rerender: false });
@@ -935,7 +935,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::TogglePreviewImpl { node_id });
}
NodeGraphMessage::TogglePreviewImpl { node_id } => {
if let Some(network) = document.document_network.nested_network_mut(&self.network) {
if let Some(network) = document_network.nested_network_mut(&self.network) {
// Check if the node is not already being previewed
if !network.outputs_contain(node_id) {
network.previous_outputs = Some(network.previous_outputs.to_owned().unwrap_or_else(|| network.outputs.clone()));
@@ -947,7 +947,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
}
self.update_selection_action_buttons(document, responses);
self.update_selection_action_buttons(document_network, metadata, responses);
if let Some(layer_path) = self.layer_path.clone() {
responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path });
} else {
@@ -955,8 +955,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}
}
NodeGraphMessage::UpdateNewNodeGraph => {
if let Some(network) = document.document_network.nested_network(&self.network) {
document.metadata.clear_selected_nodes();
if let Some(network) = document_network.nested_network(&self.network) {
metadata.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses);
@@ -964,10 +964,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let node_types = document_node_types::collect_node_types();
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
}
self.update_selected(document, responses);
self.update_selected(document_network, metadata, responses);
}
}
self.has_selection = document.metadata.has_selected_nodes();
self.has_selection = metadata.has_selected_nodes();
}
fn actions(&self) -> ActionList {
@@ -1,11 +1,15 @@
use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE};
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::Message;
use crate::node_graph_executor::NodeGraphExecutor;
use graph_craft::concrete;
use graph_craft::document::value::*;
use graph_craft::document::*;
use graph_craft::document::{value::*, DocumentNodeMetadata};
use graph_craft::imaginate_input::ImaginateSamplingMethod;
use graph_craft::ProtoNodeIdentifier;
#[cfg(feature = "gpu")]
@@ -68,13 +72,13 @@ impl DocumentOutputType {
}
pub struct NodePropertiesContext<'a> {
pub persistent_data: &'a crate::messages::portfolio::utility_types::PersistentData,
pub document: &'a document_legacy::document::Document,
pub responses: &'a mut VecDeque<crate::messages::prelude::Message>,
pub layer_path: &'a [document_legacy::document::LayerId],
pub persistent_data: &'a PersistentData,
pub responses: &'a mut VecDeque<Message>,
pub layer_path: &'a [LayerId],
pub nested_path: &'a [NodeId],
pub executor: &'a mut NodeGraphExecutor,
pub network: &'a NodeNetwork,
pub metadata: &'a mut DocumentMetadata,
}
#[derive(Clone)]
@@ -2493,7 +2497,7 @@ impl DocumentNodeDefinition {
}
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], based on the inputs from the graph (which must be the correct length) and the metadata
pub fn to_document_node(&self, inputs: impl IntoIterator<Item = NodeInput>, metadata: graph_craft::document::DocumentNodeMetadata) -> DocumentNode {
pub fn to_document_node(&self, inputs: impl IntoIterator<Item = NodeInput>, document_metadata: DocumentNodeMetadata) -> DocumentNode {
let inputs: Vec<_> = inputs.into_iter().collect();
assert_eq!(inputs.len(), self.inputs.len(), "Inputs passed from the graph must be equal to the number required");
DocumentNode {
@@ -2501,7 +2505,7 @@ impl DocumentNodeDefinition {
inputs,
has_primary_output: self.has_primary_output,
implementation: self.generate_implementation(),
metadata,
metadata: document_metadata,
manual_composition: self.manual_composition.clone(),
..Default::default()
}
@@ -2509,10 +2513,10 @@ impl DocumentNodeDefinition {
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], using the provided `input_override` and falling back to the default inputs.
/// `input_override` does not have to be the correct length.
pub fn to_document_node_default_inputs(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>, metadata: graph_craft::document::DocumentNodeMetadata) -> DocumentNode {
pub fn to_document_node_default_inputs(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>, document_metadata: DocumentNodeMetadata) -> DocumentNode {
let mut input_override = input_override.into_iter();
let inputs = self.inputs.iter().map(|default| input_override.next().unwrap_or_default().unwrap_or_else(|| default.default.clone()));
self.to_document_node(inputs, metadata)
self.to_document_node(inputs, document_metadata)
}
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], completely default
@@ -26,7 +26,7 @@ pub fn overlay_canvas_context() -> web_sys::CanvasRenderingContext2d {
pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext) {
for layer in document.metadata().selected_layers() {
let Some(subpaths) = get_subpaths(layer, &document.document_legacy) else { continue };
let Some(subpaths) = get_subpaths(layer, &document.network) else { continue };
let transform = document.metadata().transform_to_viewport(layer);
let selected = shape_editor.selected_shape_state.get(&layer);
let is_selected = |selected: Option<&SelectedLayerState>, point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
@@ -15,10 +15,11 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
use PropertiesPanelMessage::*;
let PropertiesPanelMessageHandlerData {
document_name,
artwork_document,
node_graph_message_handler,
executor,
document_network,
document_metadata,
document_name,
..
} = data;
@@ -36,12 +37,12 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
Refresh => {
let mut context = NodePropertiesContext {
persistent_data,
document: artwork_document,
responses,
nested_path: &node_graph_message_handler.network,
layer_path: &[],
executor,
network: &artwork_document.document_network,
network: document_network,
metadata: document_metadata,
};
let properties_sections = node_graph_message_handler.collate_properties(&mut context);
@@ -1,11 +1,14 @@
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::portfolio::document::utility_types::LayerId;
use crate::messages::prelude::NodeGraphMessageHandler;
use crate::node_graph_executor::NodeGraphExecutor;
use crate::{messages::prelude::NodeGraphMessageHandler, node_graph_executor::NodeGraphExecutor};
use graph_craft::document::NodeNetwork;
pub struct PropertiesPanelMessageHandlerData<'a> {
pub document_name: &'a str,
pub artwork_document: &'a DocumentLegacy,
pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub selected_layers: &'a mut dyn Iterator<Item = &'a [LayerId]>,
pub node_graph_message_handler: &'a NodeGraphMessageHandler,
pub executor: &'a mut NodeGraphExecutor,
@@ -0,0 +1,697 @@
use graph_craft::document::{DocumentNode, NodeId, NodeNetwork};
use graphene_core::renderer::ClickTarget;
use graphene_core::renderer::Quad;
use graphene_core::transform::Footprint;
use graphene_core::uuid::ManipulatorGroupId;
use glam::{DAffine2, DVec2};
use std::collections::{HashMap, HashSet};
use std::num::NonZeroU64;
// ================
// DocumentMetadata
// ================
#[derive(Debug, Clone)]
pub struct DocumentMetadata {
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
structure: HashMap<LayerNodeIdentifier, NodeRelations>,
artboards: HashSet<LayerNodeIdentifier>,
folders: HashSet<LayerNodeIdentifier>,
click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
selected_nodes: Vec<NodeId>,
/// Transform from document space to viewport space.
pub document_to_viewport: DAffine2,
}
impl Default for DocumentMetadata {
fn default() -> Self {
Self {
upstream_transforms: HashMap::new(),
click_targets: HashMap::new(),
structure: HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]),
artboards: HashSet::new(),
folders: HashSet::new(),
selected_nodes: Vec::new(),
document_to_viewport: DAffine2::IDENTITY,
}
}
}
// =================================
// DocumentMetadata: Layer iterators
// =================================
impl DocumentMetadata {
/// Get the root layer from the document
pub const fn root(&self) -> LayerNodeIdentifier {
LayerNodeIdentifier::ROOT
}
pub fn all_layers(&self) -> DecendantsIter<'_> {
self.root().decendants(self)
}
pub fn all_layers_except_artboards(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.all_layers().filter(move |layer| !self.artboards.contains(layer))
}
pub fn selected_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.all_layers().filter(|layer| self.selected_nodes.contains(&layer.to_node()))
}
pub fn selected_layers_except_artboards(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.selected_layers().filter(move |layer| !self.artboards.contains(layer))
}
pub fn selected_layers_contains(&self, layer: LayerNodeIdentifier) -> bool {
self.selected_layers().any(|selected| selected == layer)
}
pub fn selected_nodes(&self) -> core::slice::Iter<'_, NodeId> {
self.selected_nodes.iter()
}
pub fn selected_nodes_ref(&self) -> &Vec<NodeId> {
&self.selected_nodes
}
pub fn has_selected_nodes(&self) -> bool {
!self.selected_nodes.is_empty()
}
pub fn layer_exists(&self, layer: LayerNodeIdentifier) -> bool {
self.structure.contains_key(&layer)
}
pub fn click_target(&self, layer: LayerNodeIdentifier) -> Option<&Vec<ClickTarget>> {
self.click_targets.get(&layer)
}
/// Access the [`NodeRelations`] of a layer.
fn get_relations(&self, node_identifier: LayerNodeIdentifier) -> Option<&NodeRelations> {
self.structure.get(&node_identifier)
}
/// Mutably access the [`NodeRelations`] of a layer.
fn get_structure_mut(&mut self, node_identifier: LayerNodeIdentifier) -> &mut NodeRelations {
self.structure.entry(node_identifier).or_default()
}
/// Layers excluding ones that are children of other layers in the list.
pub fn shallowest_unique_layers(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<Vec<LayerNodeIdentifier>> {
let mut sorted_layers = layers
.map(|layer| {
let mut layer_path = layer.ancestors(self).collect::<Vec<_>>();
layer_path.reverse();
layer_path
})
.collect::<Vec<_>>();
sorted_layers.sort();
// Sorting here creates groups of similar UUID paths
sorted_layers.dedup_by(|a, b| a.starts_with(b));
sorted_layers
}
/// Ancestor that is shared by all layers and that is deepest (more nested). Default may be the root.
pub fn deepest_common_ancestor(&self, layers: impl Iterator<Item = LayerNodeIdentifier>, include_self: bool) -> Option<LayerNodeIdentifier> {
layers
.map(|layer| {
let mut layer_path = layer.ancestors(self).collect::<Vec<_>>();
layer_path.reverse();
if include_self || !self.folders.contains(&layer) {
layer_path.pop();
}
layer_path
})
.reduce(|mut a, b| {
a.truncate(a.iter().zip(b.iter()).position(|(&a, &b)| a != b).unwrap_or_else(|| a.len().min(b.len())));
a
})
.and_then(|layer| layer.last().copied())
}
pub fn active_artboard(&self) -> LayerNodeIdentifier {
self.artboards.iter().next().copied().unwrap_or(LayerNodeIdentifier::ROOT)
}
pub fn is_folder(&self, layer: LayerNodeIdentifier) -> bool {
self.folders.contains(&layer)
}
pub fn is_artboard(&self, layer: LayerNodeIdentifier) -> bool {
self.artboards.contains(&layer)
}
/// Filter out non folder layers
pub fn folders<'a>(&'a self, layers: impl Iterator<Item = LayerNodeIdentifier> + 'a) -> impl Iterator<Item = LayerNodeIdentifier> + 'a {
layers.filter(|layer| self.folders.contains(layer))
}
/// Folders sorted from most nested to least nested
pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<LayerNodeIdentifier> {
let mut folders: Vec<_> = self.folders(layers).collect();
folders.sort_by_cached_key(|a| std::cmp::Reverse(a.ancestors(self).count()));
folders
}
}
// ==============================================
// DocumentMetadata: Selected layer modifications
// ==============================================
impl DocumentMetadata {
pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
self.selected_nodes.retain(f);
}
pub fn set_selected_nodes(&mut self, new: Vec<NodeId>) {
self.selected_nodes = new;
}
pub fn add_selected_nodes(&mut self, iter: impl IntoIterator<Item = NodeId>) {
self.selected_nodes.extend(iter);
}
pub fn clear_selected_nodes(&mut self) {
self.set_selected_nodes(Vec::new());
}
/// Loads the structure of layer nodes from a node graph.
pub fn load_structure(&mut self, graph: &NodeNetwork) {
fn first_child_layer<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
graph.upstream_flow_back_from_nodes(vec![node.inputs[0].as_node()?], true).find(|(node, _)| node.is_layer())
}
self.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]);
self.folders = HashSet::new();
self.artboards = HashSet::new();
let id = graph.outputs[0].node_id;
let Some(output_node) = graph.nodes.get(&id) else {
return;
};
let Some((layer_node, node_id)) = first_child_layer(graph, output_node) else {
return;
};
let parent = LayerNodeIdentifier::ROOT;
let mut stack = vec![(layer_node, node_id, parent)];
while let Some((node, id, parent)) = stack.pop() {
let mut current = Some((node, id));
while let Some(&(current_node, current_id)) = current.as_ref() {
let current_identifier = LayerNodeIdentifier::new_unchecked(current_id);
if !self.structure.contains_key(&current_identifier) {
parent.push_child(self, current_identifier);
if let Some((child_node, child_id)) = first_child_layer(graph, current_node) {
stack.push((child_node, child_id, current_identifier));
}
if is_artboard(current_identifier, graph) {
self.artboards.insert(current_identifier);
}
if is_folder(current_identifier, graph) {
self.folders.insert(current_identifier);
}
}
// Get the sibling below
let construct_layer_node = &current_node.inputs[1];
current = construct_layer_node.as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.is_layer()).map(|node| (node, id)));
}
}
self.selected_nodes.retain(|node| graph.nodes.contains_key(node));
self.upstream_transforms.retain(|node, _| graph.nodes.contains_key(node));
self.click_targets.retain(|layer, _| self.structure.contains_key(layer));
}
}
// ============================
// DocumentMetadata: Transforms
// ============================
impl DocumentMetadata {
/// Update the cached transforms of the layers
pub fn update_transforms(&mut self, new_upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>) {
self.upstream_transforms = new_upstream_transforms;
}
/// Access the cached transformation to document space from layer space
pub fn transform_to_document(&self, layer: LayerNodeIdentifier) -> DAffine2 {
self.document_to_viewport.inverse() * self.transform_to_viewport(layer)
}
pub fn transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 {
layer
.ancestors(self)
.filter_map(|layer| self.upstream_transforms.get(&layer.to_node()))
.copied()
.map(|(footprint, transform)| footprint.transform * transform)
.next()
.unwrap_or(self.document_to_viewport)
}
pub fn upstream_transform(&self, node_id: NodeId) -> DAffine2 {
self.upstream_transforms.get(&node_id).copied().map(|(_, transform)| transform).unwrap_or(DAffine2::IDENTITY)
}
pub fn downstream_transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 {
self.upstream_transforms
.get(&layer.to_node())
.copied()
.map(|(footprint, _)| footprint.transform)
.unwrap_or_else(|| self.transform_to_viewport(layer))
}
}
// ===============================
// DocumentMetadata: Click targets
// ===============================
impl DocumentMetadata {
/// Update the cached click targets of the layers
pub fn update_click_targets(&mut self, new_click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>) {
self.click_targets = new_click_targets;
}
/// Get the bounding box of the click target of the specified layer in the specified transform space
pub fn bounding_box_with_transform(&self, layer: LayerNodeIdentifier, transform: DAffine2) -> Option<[DVec2; 2]> {
self.click_targets
.get(&layer)?
.iter()
.filter_map(|click_target| click_target.subpath.bounding_box_with_transform(transform))
.reduce(Quad::combine_bounds)
}
/// Calculate the corners of the bounding box but with a nonzero size.
///
/// If the layer bounds are `0` in either axis then they are changed to be `1`.
pub fn nonzero_bounding_box(&self, layer: LayerNodeIdentifier) -> [DVec2; 2] {
let [bounds_min, mut bounds_max] = self.bounding_box_with_transform(layer, DAffine2::IDENTITY).unwrap_or_default();
let bounds_size = bounds_max - bounds_min;
if bounds_size.x < 1e-10 {
bounds_max.x = bounds_min.x + 1.;
}
if bounds_size.y < 1e-10 {
bounds_max.y = bounds_min.y + 1.;
}
[bounds_min, bounds_max]
}
/// Get the bounding box of the click target of the specified layer in document space
pub fn bounding_box_document(&self, layer: LayerNodeIdentifier) -> Option<[DVec2; 2]> {
self.bounding_box_with_transform(layer, self.transform_to_document(layer))
}
/// Get the bounding box of the click target of the specified layer in viewport space
pub fn bounding_box_viewport(&self, layer: LayerNodeIdentifier) -> Option<[DVec2; 2]> {
self.bounding_box_with_transform(layer, self.transform_to_viewport(layer))
}
/// Calculates the document bounds in viewport space
pub fn document_bounds_viewport_space(&self) -> Option<[DVec2; 2]> {
self.all_layers().filter_map(|layer| self.bounding_box_viewport(layer)).reduce(Quad::combine_bounds)
}
/// Calculates the document bounds in document space
pub fn document_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> {
self.all_layers()
.filter(|&layer| include_artboards || !self.is_artboard(layer))
.filter_map(|layer| self.bounding_box_document(layer))
.reduce(Quad::combine_bounds)
}
/// Calculates the selected layer bounds in document space
pub fn selected_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> {
self.selected_layers()
.filter(|&layer| include_artboards || !self.is_artboard(layer))
.filter_map(|layer| self.bounding_box_document(layer))
.reduce(Quad::combine_bounds)
}
pub fn layer_outline(&self, layer: LayerNodeIdentifier) -> impl Iterator<Item = &bezier_rs::Subpath<ManipulatorGroupId>> {
static EMPTY: Vec<ClickTarget> = Vec::new();
let click_targets = self.click_targets.get(&layer).unwrap_or(&EMPTY);
click_targets.iter().map(|click_target| &click_target.subpath)
}
}
// ===================
// LayerNodeIdentifier
// ===================
/// ID of a layer node
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct LayerNodeIdentifier(NonZeroU64);
impl Default for LayerNodeIdentifier {
fn default() -> Self {
Self::ROOT
}
}
impl core::fmt::Debug for LayerNodeIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("LayerNodeIdentifier").field(&self.to_node()).finish()
}
}
impl LayerNodeIdentifier {
pub const ROOT: Self = LayerNodeIdentifier::new_unchecked(0);
/// Construct a [`LayerNodeIdentifier`] without checking if it is a layer node
pub const fn new_unchecked(node_id: NodeId) -> Self {
// Safety: will always be >=1
Self(unsafe { NonZeroU64::new_unchecked(node_id + 1) })
}
/// Construct a [`LayerNodeIdentifier`], debug asserting that it is a layer node
#[track_caller]
pub fn new(node_id: NodeId, network: &NodeNetwork) -> Self {
debug_assert!(
node_id == LayerNodeIdentifier::ROOT.to_node() || network.nodes.get(&node_id).is_some_and(|node| node.is_layer()),
"Layer identifier constructed from non-layer node {node_id}: {:#?}",
network.nodes.get(&node_id)
);
Self::new_unchecked(node_id)
}
/// Access the node id of this layer
pub fn to_node(self) -> NodeId {
u64::from(self.0) - 1
}
/// Convert layer to layer path
pub fn to_path(self) -> Vec<NodeId> {
vec![self.to_node()]
}
/// Access the parent layer if possible
pub fn parent(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.parent)
}
/// Access the previous sibling of this layer (up the layer tree)
pub fn previous_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.previous_sibling)
}
/// Access the next sibling of this layer (down the layer tree)
pub fn next_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.next_sibling)
}
/// Access the first child of this layer (top most in layer tree)
pub fn first_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.first_child)
}
/// Access the last child of this layer (bottom most in layer tree)
pub fn last_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.last_child)
}
/// Does the layer have children?
pub fn has_children(self, document_metadata: &DocumentMetadata) -> bool {
self.first_child(document_metadata).is_some()
}
/// Iterator over all direct children (excluding self and recursive children)
pub fn children(self, document_metadata: &DocumentMetadata) -> AxisIter {
AxisIter {
layer_node: self.first_child(document_metadata),
next_node: Self::next_sibling,
document_metadata,
}
}
/// All ancestors of this layer, including self, going to the document root
pub fn ancestors(self, document_metadata: &DocumentMetadata) -> AxisIter {
AxisIter {
layer_node: Some(self),
next_node: Self::parent,
document_metadata,
}
}
/// Iterator through all the last children, starting from self
pub fn last_children(self, document_metadata: &DocumentMetadata) -> AxisIter {
AxisIter {
layer_node: Some(self),
next_node: Self::last_child,
document_metadata,
}
}
/// Iterator through all decendants, including recursive children (not including self)
pub fn decendants(self, document_metadata: &DocumentMetadata) -> DecendantsIter {
DecendantsIter {
front: self.first_child(document_metadata),
back: self.last_child(document_metadata).and_then(|child| child.last_children(document_metadata).last()),
document_metadata,
}
}
/// Add a child towards the top of the layer tree
pub fn push_front_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
let parent = document_metadata.get_structure_mut(self);
let old_first_child = parent.first_child.replace(new);
parent.last_child.get_or_insert(new);
if let Some(old_first_child) = old_first_child {
document_metadata.get_structure_mut(old_first_child).previous_sibling = Some(new);
}
document_metadata.get_structure_mut(new).next_sibling = old_first_child;
document_metadata.get_structure_mut(new).parent = Some(self);
}
/// Add a child towards the bottom of the layer tree
pub fn push_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
let parent = document_metadata.get_structure_mut(self);
let old_last_child = parent.last_child.replace(new);
parent.first_child.get_or_insert(new);
if let Some(old_last_child) = old_last_child {
document_metadata.get_structure_mut(old_last_child).next_sibling = Some(new);
}
document_metadata.get_structure_mut(new).previous_sibling = old_last_child;
document_metadata.get_structure_mut(new).parent = Some(self);
}
/// Add sibling above in the layer tree
pub fn add_before(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
document_metadata.get_structure_mut(new).next_sibling = Some(self);
document_metadata.get_structure_mut(new).parent = self.parent(document_metadata);
let old_previous_sibling = document_metadata.get_structure_mut(self).previous_sibling.replace(new);
if let Some(old_previous_sibling) = old_previous_sibling {
document_metadata.get_structure_mut(old_previous_sibling).next_sibling = Some(new);
document_metadata.get_structure_mut(new).previous_sibling = Some(old_previous_sibling);
} else if let Some(structure) = self
.parent(document_metadata)
.map(|parent| document_metadata.get_structure_mut(parent))
.filter(|structure| structure.first_child == Some(self))
{
structure.first_child = Some(new);
}
}
/// Add sibling below in the layer tree
pub fn add_after(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer");
document_metadata.get_structure_mut(new).previous_sibling = Some(self);
document_metadata.get_structure_mut(new).parent = self.parent(document_metadata);
let old_next_sibling = document_metadata.get_structure_mut(self).next_sibling.replace(new);
if let Some(old_next_sibling) = old_next_sibling {
document_metadata.get_structure_mut(old_next_sibling).previous_sibling = Some(new);
document_metadata.get_structure_mut(new).next_sibling = Some(old_next_sibling);
} else if let Some(structure) = self
.parent(document_metadata)
.map(|parent| document_metadata.get_structure_mut(parent))
.filter(|structure| structure.last_child == Some(self))
{
structure.last_child = Some(new);
}
}
/// Delete layer and all children
pub fn delete(self, document_metadata: &mut DocumentMetadata) {
let previous_sibling = self.previous_sibling(document_metadata);
let next_sibling = self.next_sibling(document_metadata);
if let Some(previous_sibling) = previous_sibling.map(|node| document_metadata.get_structure_mut(node)) {
previous_sibling.next_sibling = next_sibling;
}
if let Some(next_sibling) = next_sibling.map(|node| document_metadata.get_structure_mut(node)) {
next_sibling.previous_sibling = previous_sibling;
}
let mut parent = self.parent(document_metadata).map(|parent| document_metadata.get_structure_mut(parent));
if let Some(structure) = parent.as_mut().filter(|structure| structure.first_child == Some(self)) {
structure.first_child = next_sibling;
}
if let Some(structure) = parent.as_mut().filter(|structure| structure.last_child == Some(self)) {
structure.last_child = previous_sibling;
}
let mut delete = vec![self];
delete.extend(self.decendants(document_metadata));
for node in delete {
document_metadata.structure.remove(&node);
}
}
pub fn exists(&self, document_metadata: &DocumentMetadata) -> bool {
document_metadata.get_relations(*self).is_some()
}
pub fn starts_with(&self, other: Self, document_metadata: &DocumentMetadata) -> bool {
self.ancestors(document_metadata).any(|parent| parent == other)
}
pub fn child_of_root(&self, document_metadata: &DocumentMetadata) -> Self {
self.ancestors(document_metadata)
.filter(|&layer| layer != LayerNodeIdentifier::ROOT)
.last()
.expect("There should be a layer before the root")
}
}
// ========
// AxisIter
// ========
/// Iterator over specified axis.
#[derive(Clone)]
pub struct AxisIter<'a> {
pub layer_node: Option<LayerNodeIdentifier>,
pub next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>,
pub document_metadata: &'a DocumentMetadata,
}
impl<'a> Iterator for AxisIter<'a> {
type Item = LayerNodeIdentifier;
fn next(&mut self) -> Option<Self::Item> {
let layer_node = self.layer_node.take();
self.layer_node = layer_node.and_then(|node| (self.next_node)(node, self.document_metadata));
layer_node
}
}
// ==============
// DecendantsIter
// ==============
#[derive(Clone)]
pub struct DecendantsIter<'a> {
front: Option<LayerNodeIdentifier>,
back: Option<LayerNodeIdentifier>,
document_metadata: &'a DocumentMetadata,
}
impl<'a> Iterator for DecendantsIter<'a> {
type Item = LayerNodeIdentifier;
fn next(&mut self) -> Option<Self::Item> {
if self.front == self.back {
self.back = None;
self.front.take()
} else {
let layer_node = self.front.take();
if let Some(layer_node) = layer_node {
self.front = layer_node
.first_child(self.document_metadata)
.or_else(|| layer_node.ancestors(self.document_metadata).find_map(|ancestor| ancestor.next_sibling(self.document_metadata)));
}
layer_node
}
}
}
impl<'a> DoubleEndedIterator for DecendantsIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.front == self.back {
self.front = None;
self.back.take()
} else {
let layer_node = self.back.take();
if let Some(layer_node) = layer_node {
self.back = layer_node
.previous_sibling(self.document_metadata)
.and_then(|sibling| sibling.last_children(self.document_metadata).last())
.or_else(|| layer_node.parent(self.document_metadata));
}
layer_node
}
}
}
// =============
// NodeRelations
// =============
#[derive(Debug, Clone, Copy, Default)]
struct NodeRelations {
parent: Option<LayerNodeIdentifier>,
previous_sibling: Option<LayerNodeIdentifier>,
next_sibling: Option<LayerNodeIdentifier>,
first_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]
fn test_tree() {
let mut document_metadata = DocumentMetadata::default();
let root = document_metadata.root();
let document_metadata = &mut document_metadata;
root.push_child(document_metadata, LayerNodeIdentifier::new_unchecked(3));
assert_eq!(root.children(document_metadata).collect::<Vec<_>>(), vec![LayerNodeIdentifier::new_unchecked(3)]);
root.push_child(document_metadata, LayerNodeIdentifier::new_unchecked(6));
assert_eq!(root.children(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![3, 6]);
assert_eq!(root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![3, 6]);
LayerNodeIdentifier::new_unchecked(3).add_after(document_metadata, LayerNodeIdentifier::new_unchecked(4));
LayerNodeIdentifier::new_unchecked(3).add_before(document_metadata, LayerNodeIdentifier::new_unchecked(2));
LayerNodeIdentifier::new_unchecked(6).add_before(document_metadata, LayerNodeIdentifier::new_unchecked(5));
LayerNodeIdentifier::new_unchecked(6).add_after(document_metadata, LayerNodeIdentifier::new_unchecked(9));
LayerNodeIdentifier::new_unchecked(6).push_child(document_metadata, LayerNodeIdentifier::new_unchecked(8));
LayerNodeIdentifier::new_unchecked(6).push_front_child(document_metadata, LayerNodeIdentifier::new_unchecked(7));
root.push_front_child(document_metadata, LayerNodeIdentifier::new_unchecked(1));
assert_eq!(root.children(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 9]);
assert_eq!(
root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
vec![1, 2, 3, 4, 5, 6, 7, 8, 9]
);
assert_eq!(
root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(),
vec![9, 8, 7, 6, 5, 4, 3, 2, 1]
);
assert!(root.children(document_metadata).all(|child| child.parent(document_metadata) == Some(root)));
LayerNodeIdentifier::new_unchecked(6).delete(document_metadata);
LayerNodeIdentifier::new_unchecked(1).delete(document_metadata);
LayerNodeIdentifier::new_unchecked(9).push_child(document_metadata, LayerNodeIdentifier::new_unchecked(10));
assert_eq!(root.children(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![2, 3, 4, 5, 9]);
assert_eq!(root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![2, 3, 4, 5, 9, 10]);
assert_eq!(root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(), vec![10, 9, 5, 4, 3, 2]);
}
@@ -1,4 +1,4 @@
use document_legacy::document::LayerId;
use crate::messages::portfolio::document::utility_types::LayerId;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
@@ -29,18 +29,6 @@ impl Serialize for JsRawBuffer {
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Copy, specta::Type)]
pub struct LayerMetadata {
pub selected: bool,
pub expanded: bool,
}
impl LayerMetadata {
pub fn new(expanded: bool) -> Self {
Self { selected: false, expanded }
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub enum LayerClassification {
#[default]
@@ -55,8 +43,8 @@ pub struct LayerPanelEntry {
pub tooltip: String,
#[serde(rename = "layerClassification")]
pub layer_classification: LayerClassification,
#[serde(rename = "layerMetadata")]
pub layer_metadata: LayerMetadata,
pub selected: bool,
pub expanded: bool,
pub path: Vec<LayerId>,
pub thumbnail: String,
}
@@ -1,18 +1,11 @@
pub use super::layer_panel::{LayerMetadata, LayerPanelEntry};
use document_legacy::document::Document as DocumentLegacy;
use document_legacy::document::LayerId;
pub use super::layer_panel::LayerPanelEntry;
use crate::messages::portfolio::document::utility_types::LayerId;
use graphene_core::raster::color::Color;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct DocumentSave {
pub document: DocumentLegacy,
pub layer_metadata: HashMap<Vec<LayerId>, LayerMetadata>,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash)]
pub enum FlipAxis {
X,
@@ -32,8 +25,9 @@ pub enum AlignAggregate {
Center,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
pub enum DocumentMode {
#[default]
DesignMode,
SelectMode,
GuideMode,
@@ -1,6 +1,11 @@
pub mod clipboards;
pub mod document_metadata;
pub mod error;
pub mod layer_panel;
pub mod misc;
pub mod transformation;
pub mod vectorize_layer_metadata;
// TODO: Remove this entirely
/// A number that identifies a layer.
/// This does not technically need to be unique globally, only within a folder.
pub type LayerId = u64;
@@ -1,12 +1,12 @@
use crate::consts::{ROTATE_SNAP_ANGLE, SCALE_SNAP_INTERVAL};
use crate::messages::portfolio::document::node_graph::VectorDataModification;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils;
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
use crate::messages::tool::utility_types::ToolType;
use document_legacy::document::Document;
use document_legacy::document_metadata::LayerNodeIdentifier;
use graph_craft::document::NodeNetwork;
use graphene_core::renderer::Quad;
use graphene_core::vector::{ManipulatorPointId, SelectedType};
@@ -31,12 +31,12 @@ impl OriginalTransforms {
}
}
pub fn update<'a>(&mut self, selected: &'a [LayerNodeIdentifier], document: &'a Document, shape_editor: Option<&'a ShapeState>) {
pub fn update<'a>(&mut self, selected: &'a [LayerNodeIdentifier], document_network: &NodeNetwork, document_metadata: &DocumentMetadata, shape_editor: Option<&'a ShapeState>) {
match self {
OriginalTransforms::Layer(layer_map) => {
layer_map.retain(|layer, _| selected.contains(layer));
for &layer in selected {
layer_map.entry(layer).or_insert_with(|| document.metadata.upstream_transform(layer.to_node()));
layer_map.entry(layer).or_insert_with(|| document_metadata.upstream_transform(layer.to_node()));
}
}
OriginalTransforms::Path(path_map) => {
@@ -61,7 +61,7 @@ impl OriginalTransforms {
if path_map.contains_key(&layer) {
continue;
}
let Some(vector_data) = graph_modification_utils::get_subpaths(layer, document) else {
let Some(vector_data) = graph_modification_utils::get_subpaths(layer, document_network) else {
continue;
};
let get_manipulator_point_position = |point_id: ManipulatorPointId| {
@@ -312,7 +312,8 @@ impl TransformOperation {
pub struct Selected<'a> {
pub selected: &'a [LayerNodeIdentifier],
pub responses: &'a mut VecDeque<Message>,
pub document: &'a Document,
pub document_network: &'a NodeNetwork,
pub document_metadata: &'a DocumentMetadata,
pub original_transforms: &'a mut OriginalTransforms,
pub pivot: &'a mut DVec2,
pub shape_editor: Option<&'a ShapeState>,
@@ -325,7 +326,8 @@ impl<'a> Selected<'a> {
pivot: &'a mut DVec2,
selected: &'a [LayerNodeIdentifier],
responses: &'a mut VecDeque<Message>,
document: &'a Document,
document_network: &'a NodeNetwork,
document_metadata: &'a DocumentMetadata,
shape_editor: Option<&'a ShapeState>,
tool_type: &'a ToolType,
) -> Self {
@@ -334,12 +336,13 @@ impl<'a> Selected<'a> {
*original_transforms = OriginalTransforms::Layer(HashMap::new());
}
original_transforms.update(selected, document, shape_editor);
original_transforms.update(selected, document_network, document_metadata, shape_editor);
Self {
selected,
responses,
document,
document_network,
document_metadata,
original_transforms,
pivot,
shape_editor,
@@ -351,7 +354,7 @@ impl<'a> Selected<'a> {
let xy_summation = self
.selected
.iter()
.map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.document))
.map(|&layer| graph_modification_utils::get_viewport_pivot(layer, self.document_network, self.document_metadata))
.reduce(|a, b| a + b)
.unwrap_or_default();
@@ -362,15 +365,15 @@ impl<'a> Selected<'a> {
let [min, max] = self
.selected
.iter()
.filter_map(|&layer| self.document.metadata.bounding_box_viewport(layer))
.filter_map(|&layer| self.document_metadata.bounding_box_viewport(layer))
.reduce(Quad::combine_bounds)
.unwrap_or_default();
(min + max) / 2.
}
fn transform_layer(document: &Document, layer: LayerNodeIdentifier, original_transform: Option<&DAffine2>, transformation: DAffine2, responses: &mut VecDeque<Message>) {
fn transform_layer(document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier, original_transform: Option<&DAffine2>, transformation: DAffine2, responses: &mut VecDeque<Message>) {
let Some(&original_transform) = original_transform else { return };
let to = document.metadata.downstream_transform_to_viewport(layer);
let to = document_metadata.downstream_transform_to_viewport(layer);
let new = to.inverse() * transformation * to * original_transform;
responses.add(GraphOperationMessage::TransformSet {
layer: layer.to_path(),
@@ -380,8 +383,14 @@ impl<'a> Selected<'a> {
});
}
fn transform_path(document: &Document, layer: LayerNodeIdentifier, initial_points: Option<&Vec<(ManipulatorPointId, DVec2)>>, transformation: DAffine2, responses: &mut VecDeque<Message>) {
let viewspace = document.metadata.transform_to_viewport(layer);
fn transform_path(
document_metadata: &DocumentMetadata,
layer: LayerNodeIdentifier,
initial_points: Option<&Vec<(ManipulatorPointId, DVec2)>>,
transformation: DAffine2,
responses: &mut VecDeque<Message>,
) {
let viewspace = document_metadata.transform_to_viewport(layer);
let layerspace_rotation = viewspace.inverse() * transformation;
let Some(initial_points) = initial_points else {
@@ -404,12 +413,12 @@ impl<'a> Selected<'a> {
pub fn apply_transformation(&mut self, transformation: DAffine2) {
if !self.selected.is_empty() {
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
for layer_ancestors in self.document.metadata.shallowest_unique_layers(self.selected.iter().copied()) {
for layer_ancestors in self.document_metadata.shallowest_unique_layers(self.selected.iter().copied()) {
let layer = *layer_ancestors.last().unwrap();
match &self.original_transforms {
OriginalTransforms::Layer(layer_transforms) => Self::transform_layer(self.document, layer, layer_transforms.get(&layer), transformation, self.responses),
OriginalTransforms::Path(path_transforms) => Self::transform_path(self.document, layer, path_transforms.get(&layer), transformation, self.responses),
OriginalTransforms::Layer(layer_transforms) => Self::transform_layer(self.document_metadata, layer, layer_transforms.get(&layer), transformation, self.responses),
OriginalTransforms::Path(path_transforms) => Self::transform_path(&self.document_metadata, layer, path_transforms.get(&layer), transformation, self.responses),
}
}
self.responses.add(BroadcastEvent::DocumentIsDirty);
@@ -1,25 +0,0 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::iter::FromIterator;
/// Necessary because serde can't serialize hashmaps when the keys don't implement display.
pub fn serialize<'a, T, K, V, S>(target: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: IntoIterator<Item = (&'a K, &'a V)>,
K: Serialize + 'a,
V: Serialize + 'a,
{
let container: Vec<_> = target.into_iter().collect();
serde::Serialize::serialize(&container, serializer)
}
pub fn deserialize<'de, T, K, V, D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromIterator<(K, V)>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
let container: Vec<_> = serde::Deserialize::deserialize(deserializer)?;
Ok(T::from_iter(container))
}