mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 20:28:11 +08:00
Remove the whole document-legacy crate (#1524)
Remove the whole document-legacy crate Closes #1520
This commit is contained in:
@@ -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)]
|
||||
|
||||
+104
-91
@@ -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));
|
||||
}
|
||||
|
||||
+6
-6
@@ -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 {
|
||||
|
||||
+13
-9
@@ -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));
|
||||
|
||||
+5
-4
@@ -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(¤t_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 = ¤t_node.inputs[1];
|
||||
current = construct_layer_node.as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.is_layer()).map(|node| (node, id)));
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
Reference in New Issue
Block a user