Move selected node list from DocumentMetadata to the document (#1565)

This commit is contained in:
Keavon Chambers 2024-01-13 04:30:16 -08:00
parent aab0fcf84c
commit 78a1bb17cd
27 changed files with 511 additions and 465 deletions

View File

@ -306,8 +306,8 @@ mod test {
}); });
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone(); let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();
assert_eq!(layers_before_copy.len(), 3); assert_eq!(layers_before_copy.len(), 3);
assert_eq!(layers_after_copy.len(), 4); assert_eq!(layers_after_copy.len(), 4);
@ -329,7 +329,7 @@ mod test {
let mut editor = create_editor_with_three_layers(); let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone(); let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let shape_id = document_before_copy.document_metadata.all_layers().nth(1).unwrap(); let shape_id = document_before_copy.metadata.all_layers().nth(1).unwrap();
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![shape_id.to_node()] }); editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![shape_id.to_node()] });
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal }); editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
@ -341,8 +341,8 @@ mod test {
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone(); let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();
assert_eq!(layers_before_copy.len(), 3); assert_eq!(layers_before_copy.len(), 3);
assert_eq!(layers_after_copy.len(), 4); assert_eq!(layers_after_copy.len(), 4);
@ -384,8 +384,8 @@ mod test {
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone(); let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();
let [original_folder, original_freehand, original_line, original_ellipse, original_polygon, original_rect] = layers_before_copy[..] else { let [original_folder, original_freehand, original_line, original_ellipse, original_polygon, original_rect] = layers_before_copy[..] else {
panic!("Layers before incorrect"); panic!("Layers before incorrect");
}; };
@ -413,7 +413,7 @@ mod test {
let mut editor = create_editor_with_three_layers(); let mut editor = create_editor_with_three_layers();
let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone(); let document_before_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let mut layers = document_before_copy.document_metadata.all_layers(); let mut layers = document_before_copy.metadata.all_layers();
let rect_id = layers.next().expect("rectangle"); let rect_id = layers.next().expect("rectangle");
let shape_id = layers.next().expect("shape"); let shape_id = layers.next().expect("shape");
let ellipse_id = layers.next().expect("ellipse"); let ellipse_id = layers.next().expect("ellipse");
@ -437,8 +437,8 @@ mod test {
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone(); let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().clone();
let layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_before_copy = document_before_copy.metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_copy.document_metadata.all_layers().collect::<Vec<_>>(); let layers_after_copy = document_after_copy.metadata.all_layers().collect::<Vec<_>>();
assert_eq!(layers_before_copy.len(), 3); assert_eq!(layers_before_copy.len(), 3);
assert_eq!(layers_after_copy.len(), 6); assert_eq!(layers_after_copy.len(), 6);

View File

@ -75,7 +75,7 @@ impl MessageHandler<DialogMessage, DialogData<'_>> for DialogMessageHandler {
if let Some(document) = portfolio.active_document() { if let Some(document) = portfolio.active_document() {
let mut index = 0; let mut index = 0;
let artboards = document let artboards = document
.document_metadata .metadata
.all_layers() .all_layers()
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Artboard")) .filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Artboard"))
.map(|layer| { .map(|layer| {
@ -92,7 +92,7 @@ impl MessageHandler<DialogMessage, DialogData<'_>> for DialogMessageHandler {
self.export_dialog = ExportDialogMessageHandler { self.export_dialog = ExportDialogMessageHandler {
scale_factor: 1., scale_factor: 1.,
artboards, artboards,
has_selection: document.metadata().selected_layers().next().is_some(), has_selection: document.selected_nodes.selected_layers(document.metadata()).next().is_some(),
..Default::default() ..Default::default()
}; };
self.export_dialog.send_dialog_to_frontend(responses); self.export_dialog.send_dialog_to_frontend(responses);

View File

@ -1,7 +1,7 @@
use super::utility_types::{FrontendDocumentDetails, MouseCursorIcon}; use super::utility_types::{FrontendDocumentDetails, MouseCursorIcon};
use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::{FrontendNode, FrontendNodeLink, FrontendNodeType}; use crate::messages::portfolio::document::node_graph::{FrontendNode, FrontendNodeLink, FrontendNodeType};
use crate::messages::portfolio::document::utility_types::layer_panel::{JsRawBuffer, LayerPanelEntry, RawBuffer}; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer};
use crate::messages::prelude::*; use crate::messages::prelude::*;
use crate::messages::tool::utility_types::HintData; use crate::messages::tool::utility_types::HintData;

View File

@ -1,15 +1,16 @@
use super::utility_types::error::EditorError; use super::utility_types::error::EditorError;
use super::utility_types::misc::{SnappingOptions, SnappingState}; use super::utility_types::misc::{SnappingOptions, SnappingState};
use super::utility_types::nodes::{CollapsedLayers, SelectedNodes};
use crate::application::{generate_uuid, GRAPHITE_GIT_COMMIT_HASH}; use crate::application::{generate_uuid, GRAPHITE_GIT_COMMIT_HASH};
use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING}; use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING};
use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData; use crate::messages::portfolio::document::node_graph::{GraphOperationHandlerData, NodeGraphHandlerData};
use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData; use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData;
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
use crate::messages::portfolio::document::utility_types::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier}; 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, PTZ}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ};
use crate::messages::portfolio::document::utility_types::nodes::RawBuffer;
use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*; use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity}; use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
@ -48,6 +49,10 @@ pub struct DocumentMessageHandler {
// ============================================ // ============================================
#[serde(default = "default_network")] #[serde(default = "default_network")]
pub network: NodeNetwork, pub network: NodeNetwork,
#[serde(default = "default_selected_nodes")]
pub selected_nodes: SelectedNodes,
#[serde(default = "default_collapsed")]
pub collapsed: CollapsedLayers,
#[serde(default = "default_name")] #[serde(default = "default_name")]
pub name: String, pub name: String,
#[serde(default = "default_commit_hash")] #[serde(default = "default_commit_hash")]
@ -62,8 +67,6 @@ pub struct DocumentMessageHandler {
overlays_visible: bool, overlays_visible: bool,
#[serde(default = "default_rulers_visible")] #[serde(default = "default_rulers_visible")]
pub rulers_visible: bool, pub rulers_visible: bool,
#[serde(default = "default_collapsed")]
pub collapsed: Vec<LayerNodeIdentifier>,
// ============================================= // =============================================
// Fields omitted from the saved document format // Fields omitted from the saved document format
// ============================================= // =============================================
@ -85,7 +88,7 @@ pub struct DocumentMessageHandler {
#[serde(skip)] #[serde(skip)]
layer_range_selection_reference: Option<LayerNodeIdentifier>, layer_range_selection_reference: Option<LayerNodeIdentifier>,
#[serde(skip)] #[serde(skip)]
pub document_metadata: DocumentMetadata, pub metadata: DocumentMetadata,
} }
impl Default for DocumentMessageHandler { impl Default for DocumentMessageHandler {
@ -102,6 +105,8 @@ impl Default for DocumentMessageHandler {
// Fields that are saved in the document format // Fields that are saved in the document format
// ============================================ // ============================================
network: root_network(), network: root_network(),
selected_nodes: SelectedNodes::default(),
collapsed: CollapsedLayers::default(),
name: DEFAULT_DOCUMENT_NAME.to_string(), name: DEFAULT_DOCUMENT_NAME.to_string(),
commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(), commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(),
navigation: PTZ::default(), navigation: PTZ::default(),
@ -109,7 +114,6 @@ impl Default for DocumentMessageHandler {
view_mode: ViewMode::default(), view_mode: ViewMode::default(),
overlays_visible: true, overlays_visible: true,
rulers_visible: true, rulers_visible: true,
collapsed: Vec::new(),
// ============================================= // =============================================
// Fields omitted from the saved document format // Fields omitted from the saved document format
// ============================================= // =============================================
@ -121,7 +125,7 @@ impl Default for DocumentMessageHandler {
graph_view_overlay_open: false, graph_view_overlay_open: false,
snapping_state: SnappingState::default(), snapping_state: SnappingState::default(),
layer_range_selection_reference: None, layer_range_selection_reference: None,
document_metadata: Default::default(), metadata: Default::default(),
} }
} }
} }
@ -131,6 +135,14 @@ fn default_network() -> NodeNetwork {
DocumentMessageHandler::default().network DocumentMessageHandler::default().network
} }
#[inline(always)] #[inline(always)]
fn default_selected_nodes() -> SelectedNodes {
DocumentMessageHandler::default().selected_nodes
}
#[inline(always)]
fn default_collapsed() -> CollapsedLayers {
DocumentMessageHandler::default().collapsed
}
#[inline(always)]
fn default_name() -> String { fn default_name() -> String {
DocumentMessageHandler::default().name DocumentMessageHandler::default().name
} }
@ -158,10 +170,6 @@ fn default_overlays_visible() -> bool {
fn default_rulers_visible() -> bool { fn default_rulers_visible() -> bool {
DocumentMessageHandler::default().rulers_visible DocumentMessageHandler::default().rulers_visible
} }
#[inline(always)]
fn default_collapsed() -> Vec<LayerNodeIdentifier> {
DocumentMessageHandler::default().collapsed
}
fn root_network() -> NodeNetwork { fn root_network() -> NodeNetwork {
{ {
@ -245,13 +253,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
self.navigation_handler.process_message( self.navigation_handler.process_message(
message, message,
responses, responses,
( (&self.metadata, document_bounds, ipp, self.selected_visible_layers_bounding_box_viewport(), &mut self.navigation),
&self.document_metadata,
document_bounds,
ipp,
self.selected_visible_layers_bounding_box_viewport(),
&mut self.navigation,
),
); );
} }
#[remain::unsorted] #[remain::unsorted]
@ -265,7 +267,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
executor, executor,
document_name: self.name.as_str(), document_name: self.name.as_str(),
document_network: &self.network, document_network: &self.network,
document_metadata: &mut self.document_metadata, document_metadata: &mut self.metadata,
selected_nodes: &self.selected_nodes,
}; };
self.properties_panel_message_handler self.properties_panel_message_handler
.process_message(message, responses, (persistent_data, properties_panel_message_handler_data)); .process_message(message, responses, (persistent_data, properties_panel_message_handler_data));
@ -277,7 +280,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses, responses,
NodeGraphHandlerData { NodeGraphHandlerData {
document_network: &mut self.network, document_network: &mut self.network,
document_metadata: &mut self.document_metadata, document_metadata: &mut self.metadata,
selected_nodes: &mut self.selected_nodes,
document_id, document_id,
document_name: self.name.as_str(), document_name: self.name.as_str(),
collapsed: &mut self.collapsed, collapsed: &mut self.collapsed,
@ -287,7 +291,17 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
); );
} }
#[remain::unsorted] #[remain::unsorted]
GraphOperation(message) => GraphOperationMessageHandler.process_message(message, responses, (&mut self.network, &mut self.document_metadata, &mut self.collapsed, &mut self.node_graph_handler)), GraphOperation(message) => GraphOperationMessageHandler.process_message(
message,
responses,
GraphOperationHandlerData {
document_network: &mut self.network,
document_metadata: &mut self.metadata,
selected_nodes: &mut self.selected_nodes,
collapsed: &mut self.collapsed,
node_graph: &mut self.node_graph_handler,
},
),
// Messages // Messages
AbortTransaction => { AbortTransaction => {
@ -312,7 +326,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
AlignAggregate::Max => combined_box[1], AlignAggregate::Max => combined_box[1],
AlignAggregate::Center => (combined_box[0] + combined_box[1]) / 2., AlignAggregate::Center => (combined_box[0] + combined_box[1]) / 2.,
}; };
for layer in self.metadata().selected_layers() { for layer in self.selected_nodes.selected_layers(self.metadata()) {
let Some(bbox) = self.metadata().bounding_box_viewport(layer) else { let Some(bbox) = self.metadata().bounding_box_viewport(layer) else {
continue; continue;
}; };
@ -366,7 +380,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
self.backup(responses); self.backup(responses);
responses.add_front(BroadcastEvent::SelectionChanged); responses.add_front(BroadcastEvent::SelectionChanged);
for path in self.metadata().shallowest_unique_layers(self.metadata().selected_layers()) { for path in self.metadata().shallowest_unique_layers(self.selected_nodes.selected_layers(self.metadata())) {
responses.add_front(DocumentMessage::DeleteLayer { id: path.last().unwrap().to_node() }); responses.add_front(DocumentMessage::DeleteLayer { id: path.last().unwrap().to_node() });
} }
@ -381,7 +395,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
DocumentStructureChanged => { DocumentStructureChanged => {
self.update_layers_panel_options_bar_widgets(responses); self.update_layers_panel_options_bar_widgets(responses);
self.document_metadata.load_structure(&self.network); self.metadata.load_structure(&self.network, &mut self.selected_nodes);
let data_buffer: RawBuffer = self.serialize_root(); let data_buffer: RawBuffer = self.serialize_root();
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer }); responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
} }
@ -402,7 +416,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
if let Some([min, max]) = self.selected_visible_layers_bounding_box_viewport() { if let Some([min, max]) = self.selected_visible_layers_bounding_box_viewport() {
let center = (max + min) / 2.; let center = (max + min) / 2.;
let bbox_trans = DAffine2::from_translation(-center); let bbox_trans = DAffine2::from_translation(-center);
for layer in self.metadata().selected_layers() { for layer in self.selected_nodes.selected_layers(self.metadata()) {
responses.add(GraphOperationMessage::TransformChange { responses.add(GraphOperationMessage::TransformChange {
layer, layer,
transform: DAffine2::from_scale(scale), transform: DAffine2::from_scale(scale),
@ -426,7 +440,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
} }
GroupSelectedLayers => { GroupSelectedLayers => {
// TODO: Add code that changes the insert index of the new folder based on the selected layer // TODO: Add code that changes the insert index of the new folder based on the selected layer
let parent = self.metadata().deepest_common_ancestor(self.metadata().selected_layers(), true).unwrap_or(LayerNodeIdentifier::ROOT); let parent = self
.metadata()
.deepest_common_ancestor(self.selected_nodes.selected_layers(self.metadata()), true)
.unwrap_or(LayerNodeIdentifier::ROOT);
let folder_id = NodeId(generate_uuid()); let folder_id = NodeId(generate_uuid());
@ -467,7 +484,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
} }
} }
MoveSelectedLayersTo { parent, insert_index } => { MoveSelectedLayersTo { parent, insert_index } => {
let selected_layers = self.metadata().selected_layers().collect::<Vec<_>>(); let selected_layers = self.selected_nodes.selected_layers(self.metadata()).collect::<Vec<_>>();
// Disallow trying to insert into self // Disallow trying to insert into self
if selected_layers.iter().any(|&layer| parent.ancestors(self.metadata()).any(|ancestor| ancestor == layer)) { if selected_layers.iter().any(|&layer| parent.ancestors(self.metadata()).any(|ancestor| ancestor == layer)) {
@ -495,7 +512,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
let opposite_corner = ipp.keyboard.key(resize_opposite_corner); let opposite_corner = ipp.keyboard.key(resize_opposite_corner);
let delta = DVec2::new(delta_x, delta_y); let delta = DVec2::new(delta_x, delta_y);
for layer in self.metadata().selected_layers() { for layer in self.selected_nodes.selected_layers(self.metadata()) {
// Nudge translation // Nudge translation
if !ipp.keyboard.key(resize) { if !ipp.keyboard.key(resize) {
responses.add(GraphOperationMessage::TransformChange { responses.add(GraphOperationMessage::TransformChange {
@ -506,7 +523,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}); });
} }
// Nudge resize // Nudge resize
else if let Some([existing_top_left, existing_bottom_right]) = self.document_metadata.bounding_box_document(layer) { else if let Some([existing_top_left, existing_bottom_right]) = self.metadata.bounding_box_document(layer) {
let size = existing_bottom_right - existing_top_left; let size = existing_bottom_right - existing_top_left;
let new_size = size + if opposite_corner { -delta } else { delta }; let new_size = size + if opposite_corner { -delta } else { delta };
let enlargement_factor = new_size / size; let enlargement_factor = new_size / size;
@ -636,8 +653,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}) })
} }
SelectAllLayers => { SelectAllLayers => {
let all = self.metadata().all_layers_except_artboards().map(|layer| layer.to_node()).collect(); let metadata = self.metadata();
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: all }); let all_layers_except_artboards = metadata.all_layers().filter(move |&layer| !metadata.is_artboard(layer));
let nodes = all_layers_except_artboards.map(|layer| layer.to_node()).collect();
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: nodes });
} }
SelectedLayersLower => { SelectedLayersLower => {
responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: 1 }); responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: 1 });
@ -674,7 +693,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
} else { } else {
if ctrl { if ctrl {
// Toggle selection when holding ctrl // Toggle selection when holding ctrl
if self.metadata().selected_layers_contains(layer) { if self.selected_nodes.selected_layers_contains(layer, self.metadata()) {
responses.add_front(NodeGraphMessage::SelectedNodesRemove { nodes: vec![id] }); responses.add_front(NodeGraphMessage::SelectedNodesRemove { nodes: vec![id] });
} else { } else {
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] }); responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
@ -700,7 +719,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
} }
SetBlendModeForSelectedLayers { blend_mode } => { SetBlendModeForSelectedLayers { blend_mode } => {
self.backup(responses); self.backup(responses);
for layer in self.metadata().selected_layers_except_artboards() { for layer in self.selected_nodes.selected_layers_except_artboards(self.metadata()) {
responses.add(GraphOperationMessage::BlendModeSet { layer, blend_mode }); responses.add(GraphOperationMessage::BlendModeSet { layer, blend_mode });
} }
} }
@ -708,7 +727,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
self.backup(responses); self.backup(responses);
let opacity = opacity.clamp(0., 1.) as f32; let opacity = opacity.clamp(0., 1.) as f32;
for layer in self.metadata().selected_layers_except_artboards() { for layer in self.selected_nodes.selected_layers_except_artboards(self.metadata()) {
responses.add(GraphOperationMessage::OpacitySet { layer, opacity }); responses.add(GraphOperationMessage::OpacitySet { layer, opacity });
} }
} }
@ -742,10 +761,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
StartTransaction => self.backup(responses), StartTransaction => self.backup(responses),
ToggleLayerExpansion { id } => { ToggleLayerExpansion { id } => {
let layer = LayerNodeIdentifier::new(id, self.network()); let layer = LayerNodeIdentifier::new(id, self.network());
if self.collapsed.contains(&layer) { if self.collapsed.0.contains(&layer) {
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer); self.collapsed.0.retain(|&collapsed_layer| collapsed_layer != layer);
} else { } else {
self.collapsed.push(layer); self.collapsed.0.push(layer);
} }
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
} }
@ -761,7 +780,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
UngroupSelectedLayers => { UngroupSelectedLayers => {
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
let folder_paths = self.metadata().folders_sorted_by_most_nested(self.metadata().selected_layers()); let folder_paths = self.metadata().folders_sorted_by_most_nested(self.selected_nodes.selected_layers(self.metadata()));
for folder in folder_paths { for folder in folder_paths {
// Select all the children of the folder // Select all the children of the folder
@ -784,7 +803,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(DocumentMessage::CommitTransaction); responses.add(DocumentMessage::CommitTransaction);
} }
UpdateDocumentTransform { transform } => { UpdateDocumentTransform { transform } => {
self.document_metadata.document_to_viewport = transform; self.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::RenderRulers); responses.add(DocumentMessage::RenderRulers);
responses.add(DocumentMessage::RenderScrollbars); responses.add(DocumentMessage::RenderScrollbars);
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
@ -810,44 +829,28 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
} }
impl DocumentMessageHandler { impl DocumentMessageHandler {
pub fn layer_visible(&self, layer: LayerNodeIdentifier) -> bool {
!layer.ancestors(&self.document_metadata).any(|layer| self.network.disabled.contains(&layer.to_node()))
}
pub fn selected_visible_layers(&self) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.document_metadata.selected_layers().filter(|&layer| self.layer_visible(layer))
}
/// Runs an intersection test with all layers and a viewport space quad /// 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 { 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.document_metadata.document_to_viewport.inverse() * viewport_quad; let document_quad = self.metadata.document_to_viewport.inverse() * viewport_quad;
self.document_metadata self.metadata
.root() .root()
.decendants(&self.document_metadata) .decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer)) .filter(|&layer| self.selected_nodes.layer_visible(layer, &self.network(), &self.metadata()))
.filter(|&layer| !is_artboard(layer, network)) .filter(|&layer| !is_artboard(layer, network))
.filter_map(|layer| self.document_metadata.click_target(layer).map(|targets| (layer, targets))) .filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| { .filter(move |(layer, target)| target.iter().any(move |target| target.intersect_rectangle(document_quad, self.metadata.transform_to_document(*layer))))
target
.iter()
.any(move |target| target.intersect_rectangle(document_quad, self.document_metadata.transform_to_document(*layer)))
})
.map(|(layer, _)| layer) .map(|(layer, _)| layer)
} }
/// Find all of the layers that were clicked on from a viewport space location /// 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> + '_ { pub fn click_xray(&self, viewport_location: DVec2) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
let point = self.document_metadata.document_to_viewport.inverse().transform_point2(viewport_location); let point = self.metadata.document_to_viewport.inverse().transform_point2(viewport_location);
self.document_metadata self.metadata
.root() .root()
.decendants(&self.document_metadata) .decendants(&self.metadata)
.filter(|&layer| self.layer_visible(layer)) .filter(|&layer| self.selected_nodes.layer_visible(layer, &self.network(), &self.metadata()))
.filter_map(|layer| self.document_metadata.click_target(layer).map(|targets| (layer, targets))) .filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| { .filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer))))
target
.iter()
.any(|target: &ClickTarget| target.intersect_point(point, self.document_metadata.transform_to_document(*layer)))
})
.map(|(layer, _)| layer) .map(|(layer, _)| layer)
} }
@ -858,8 +861,9 @@ impl DocumentMessageHandler {
/// Get the combined bounding box of the click targets of the selected visible layers in viewport space /// 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]> { pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_visible_layers() self.selected_nodes
.filter_map(|layer| self.document_metadata.bounding_box_viewport(layer)) .selected_visible_layers(&self.network(), &self.metadata())
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
.reduce(graphene_core::renderer::Quad::combine_bounds) .reduce(graphene_core::renderer::Quad::combine_bounds)
} }
@ -868,7 +872,7 @@ impl DocumentMessageHandler {
} }
pub fn metadata(&self) -> &DocumentMetadata { pub fn metadata(&self) -> &DocumentMetadata {
&self.document_metadata &self.metadata
} }
pub fn serialize_document(&self) -> String { pub fn serialize_document(&self) -> String {
@ -884,7 +888,7 @@ impl DocumentMessageHandler {
pub fn with_name(name: String, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Self { pub fn with_name(name: String, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) -> Self {
let mut document = Self { name, ..Self::default() }; let mut document = Self { name, ..Self::default() };
let transform = document.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2., DVec2::ZERO, 0., 1.); let transform = document.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.size() / 2., DVec2::ZERO, 0., 1.);
document.document_metadata.document_to_viewport = transform; document.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::UpdateDocumentTransform { transform }); responses.add(DocumentMessage::UpdateDocumentTransform { transform });
document document
@ -909,7 +913,7 @@ impl DocumentMessageHandler {
for layer_node in folder.children(self.metadata()) { for layer_node in folder.children(self.metadata()) {
data_section.push(layer_node.to_node().0); data_section.push(layer_node.to_node().0);
space += 1; space += 1;
if layer_node.has_children(self.metadata()) && !self.collapsed.contains(&layer_node) { if layer_node.has_children(self.metadata()) && !self.collapsed.0.contains(&layer_node) {
path.push(layer_node); path.push(layer_node);
// TODO: Skip if folder is not expanded. // TODO: Skip if folder is not expanded.
@ -1066,7 +1070,7 @@ impl DocumentMessageHandler {
pub fn new_layer_parent(&self) -> LayerNodeIdentifier { pub fn new_layer_parent(&self) -> LayerNodeIdentifier {
self.metadata() self.metadata()
.deepest_common_ancestor(self.metadata().selected_layers(), false) .deepest_common_ancestor(self.selected_nodes.selected_layers(self.metadata()), false)
.unwrap_or_else(|| self.metadata().active_artboard()) .unwrap_or_else(|| self.metadata().active_artboard())
} }
@ -1278,7 +1282,7 @@ impl DocumentMessageHandler {
pub fn update_layers_panel_options_bar_widgets(&self, responses: &mut VecDeque<Message>) { pub fn update_layers_panel_options_bar_widgets(&self, responses: &mut VecDeque<Message>) {
// Get an iterator over the selected layers (excluding artboards which don't have an opacity or blend mode). // Get an iterator over the selected layers (excluding artboards which don't have an opacity or blend mode).
let selected_layers_except_artboards = self.metadata().selected_layers_except_artboards(); let selected_layers_except_artboards = self.selected_nodes.selected_layers_except_artboards(self.metadata());
// Look up the current opacity and blend mode of the selected layers (if any), and split the iterator into the first tuple and the rest. // Look up the current opacity and blend mode of the selected layers (if any), and split the iterator into the first tuple and the rest.
let mut opacity_and_blend_mode = selected_layers_except_artboards.map(|layer| (get_opacity(layer, &self.network).unwrap_or(100.), get_blend_mode(layer, &self.network).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()));
@ -1372,7 +1376,7 @@ impl DocumentMessageHandler {
pub fn selected_layers_reorder(&mut self, relative_index_offset: isize, responses: &mut VecDeque<Message>) { pub fn selected_layers_reorder(&mut self, relative_index_offset: isize, responses: &mut VecDeque<Message>) {
self.backup(responses); self.backup(responses);
let mut selected_layers = self.metadata().selected_layers(); let mut selected_layers = self.selected_nodes.selected_layers(self.metadata());
let first_or_last_selected_layer = match relative_index_offset.signum() { let first_or_last_selected_layer = match relative_index_offset.signum() {
-1 => selected_layers.next(), -1 => selected_layers.next(),
@ -1429,7 +1433,7 @@ impl DocumentMessageHandler {
common.extend(escape); common.extend(escape);
} }
if self.metadata().selected_layers().next().is_some() { if self.selected_nodes.selected_layers(self.metadata()).next().is_some() {
let select = actions!(DocumentMessageDiscriminant; let select = actions!(DocumentMessageDiscriminant;
DeleteSelectedLayers, DeleteSelectedLayers,
DuplicateSelectedLayers, DuplicateSelectedLayers,

View File

@ -54,7 +54,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
&mut self, &mut self,
message: NavigationMessage, message: NavigationMessage,
responses: &mut VecDeque<Message>, responses: &mut VecDeque<Message>,
(document_metadata, document_bounds, ipp, selection_bounds, ptz): (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>, &mut PTZ), (metadata, document_bounds, ipp, selection_bounds, ptz): (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>, &mut PTZ),
) { ) {
use NavigationMessage::*; use NavigationMessage::*;
@ -73,8 +73,8 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
bounds: [pos1, pos2], bounds: [pos1, pos2],
prevent_zoom_past_100, prevent_zoom_past_100,
} => { } => {
let v1 = document_metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO); let v1 = metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
let v2 = document_metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size()); let v2 = metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size());
let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5); let center = v1.lerp(v2, 0.5) - pos1.lerp(pos2, 0.5);
let size = (pos2 - pos1) / (v2 - v1); let size = (pos2 - pos1) / (v2 - v1);
@ -96,7 +96,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
} }
FitViewportToSelection => { FitViewportToSelection => {
if let Some(bounds) = selection_bounds { if let Some(bounds) = selection_bounds {
let transform = document_metadata.document_to_viewport.inverse(); let transform = metadata.document_to_viewport.inverse();
responses.add(FitViewportToBounds { responses.add(FitViewportToBounds {
bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])], bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])],
prevent_zoom_past_100: false, prevent_zoom_past_100: false,
@ -257,7 +257,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
responses.add(TransformCanvasEnd { abort_transform }); responses.add(TransformCanvasEnd { abort_transform });
} }
TranslateCanvas { delta } => { TranslateCanvas { delta } => {
let transformed_delta = document_metadata.document_to_viewport.inverse().transform_vector2(delta); let transformed_delta = metadata.document_to_viewport.inverse().transform_vector2(delta);
ptz.pan += transformed_delta; ptz.pan += transformed_delta;
responses.add(BroadcastEvent::CanvasTransformed); responses.add(BroadcastEvent::CanvasTransformed);
@ -275,7 +275,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
self.transform_operation = TransformOperation::Pan { pre_commit_pan: ptz.pan }; self.transform_operation = TransformOperation::Pan { pre_commit_pan: ptz.pan };
} }
TranslateCanvasByViewportFraction { delta } => { TranslateCanvasByViewportFraction { delta } => {
let transformed_delta = document_metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size()); let transformed_delta = metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size());
ptz.pan += transformed_delta; ptz.pan += transformed_delta;
responses.add(BroadcastEvent::DocumentIsDirty); responses.add(BroadcastEvent::DocumentIsDirty);

View File

@ -1,5 +1,6 @@
use super::{resolve_document_node_type, VectorDataModification}; use super::{resolve_document_node_type, VectorDataModification};
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, SelectedNodes};
use crate::messages::prelude::*; use crate::messages::prelude::*;
use bezier_rs::Subpath; use bezier_rs::Subpath;
@ -509,7 +510,7 @@ impl<'a> ModifyInputsContext<'a> {
}); });
} }
fn delete_layer(&mut self, id: NodeId) { fn delete_layer(&mut self, id: NodeId, selected_nodes: &mut SelectedNodes) {
let Some(node) = self.document_network.nodes.get(&id) else { let Some(node) = self.document_network.nodes.get(&id) else {
warn!("Deleting layer node that does not exist"); warn!("Deleting layer node that does not exist");
return; return;
@ -558,20 +559,31 @@ impl<'a> ModifyInputsContext<'a> {
} }
} }
self.document_metadata.retain_selected_nodes(|id| !delete_nodes.contains(id)); selected_nodes.retain_selected_nodes(|id| !delete_nodes.contains(id));
self.responses.add(BroadcastEvent::SelectionChanged); self.responses.add(BroadcastEvent::SelectionChanged);
self.responses.add(NodeGraphMessage::RunDocumentGraph); self.responses.add(NodeGraphMessage::RunDocumentGraph);
} }
} }
impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler)> for GraphOperationMessageHandler { pub struct GraphOperationHandlerData<'a> {
fn process_message( pub document_network: &'a mut NodeNetwork,
&mut self, pub document_metadata: &'a mut DocumentMetadata,
message: GraphOperationMessage, pub selected_nodes: &'a mut SelectedNodes,
responses: &mut VecDeque<Message>, pub collapsed: &'a mut CollapsedLayers,
(document_network, document_metadata, collapsed, node_graph): (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler), pub node_graph: &'a mut NodeGraphMessageHandler,
) { }
impl MessageHandler<GraphOperationMessage, GraphOperationHandlerData<'_>> for GraphOperationMessageHandler {
fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque<Message>, data: GraphOperationHandlerData) {
let GraphOperationHandlerData {
document_network,
document_metadata,
selected_nodes,
collapsed,
node_graph,
} = data;
match message { match message {
GraphOperationMessage::FillSet { layer, fill } => { GraphOperationMessage::FillSet { layer, fill } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) {
@ -645,7 +657,7 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.document_network.original_outputs()[0].node_id, 0, 0) { if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.document_network.original_outputs()[0].node_id, 0, 0) {
modify_inputs.insert_artboard(artboard, layer); modify_inputs.insert_artboard(artboard, layer);
} }
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
GraphOperationMessage::NewBitmapLayer { GraphOperationMessage::NewBitmapLayer {
id, id,
@ -698,14 +710,14 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
modify_inputs.responses.add(NodeGraphMessage::RunDocumentGraph); modify_inputs.responses.add(NodeGraphMessage::RunDocumentGraph);
} }
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => { GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_vector_data(subpaths, layer); modify_inputs.insert_vector_data(subpaths, layer);
} }
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
GraphOperationMessage::NewTextLayer { GraphOperationMessage::NewTextLayer {
id, id,
@ -719,7 +731,7 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_text(text, font, size, layer); modify_inputs.insert_text(text, font, size, layer);
} }
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
GraphOperationMessage::ResizeArtboard { id, location, dimensions } => { GraphOperationMessage::ResizeArtboard { id, location, dimensions } => {
if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(id, document_network, document_metadata, node_graph, responses) { if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(id, document_network, document_metadata, node_graph, responses) {
@ -728,18 +740,18 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
} }
GraphOperationMessage::DeleteLayer { id } => { GraphOperationMessage::DeleteLayer { id } => {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
modify_inputs.delete_layer(id); modify_inputs.delete_layer(id, selected_nodes);
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
GraphOperationMessage::ClearArtboards => { GraphOperationMessage::ClearArtboards => {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); 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<_>>(); let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
for layer in layer_nodes { for layer in layer_nodes {
if modify_inputs.document_network.upstream_flow_back_from_nodes(vec![layer], true).any(|(node, _id)| node.is_artboard()) { if modify_inputs.document_network.upstream_flow_back_from_nodes(vec![layer], true).any(|(node, _id)| node.is_artboard()) {
modify_inputs.delete_layer(layer); modify_inputs.delete_layer(layer, selected_nodes);
} }
} }
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
} }
} }
@ -749,7 +761,7 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
} }
} }
pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, collapsed: &mut Vec<LayerNodeIdentifier>) { pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, selected_nodes: &mut SelectedNodes, collapsed: &mut CollapsedLayers) {
document_metadata.load_structure(document_network); document_metadata.load_structure(document_network, selected_nodes);
collapsed.retain(|&layer| document_metadata.layer_exists(layer)); collapsed.0.retain(|&layer| document_metadata.layer_exists(layer));
} }

View File

@ -52,11 +52,11 @@ pub struct LayerBounds {
impl LayerBounds { impl LayerBounds {
/// Extract the layer bounds and their transform for a layer. /// Extract the layer bounds and their transform for a layer.
pub fn new(document_metadata: &DocumentMetadata, layer: LayerNodeIdentifier) -> Self { pub fn new(metadata: &DocumentMetadata, layer: LayerNodeIdentifier) -> Self {
Self { Self {
bounds: document_metadata.nonzero_bounding_box(layer), bounds: metadata.nonzero_bounding_box(layer),
bounds_transform: DAffine2::IDENTITY, bounds_transform: DAffine2::IDENTITY,
layer_transform: document_metadata.transform_to_document(layer), layer_transform: metadata.transform_to_document(layer),
} }
} }

View File

@ -4,7 +4,7 @@ use crate::application::generate_uuid;
use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
use crate::messages::portfolio::document::utility_types::layer_panel::{LayerClassification, LayerPanelEntry}; use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerClassification, LayerPanelEntry, SelectedNodes};
use crate::messages::prelude::*; use crate::messages::prelude::*;
use graph_craft::document::value::TaggedValue; use graph_craft::document::value::TaggedValue;
@ -174,20 +174,20 @@ impl NodeGraphMessageHandler {
} }
/// Updates the buttons for disable and preview /// Updates the buttons for disable and preview
fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) { fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque<Message>) {
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
let mut widgets = Vec::new(); let mut widgets = Vec::new();
// Don't allow disabling input or output nodes // Don't allow disabling input or output nodes
let mut selected_nodes = document_metadata.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id)); let mut selection = selected_nodes.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id));
// If there is at least one other selected node then show the hide or show button // If there is at least one other selected node then show the hide or show button
if selected_nodes.next().is_some() { if selection.next().is_some() {
// Check if any of the selected nodes are disabled // Check if any of the selected nodes are disabled
let is_hidden = document_metadata.selected_nodes().any(|id| network.disabled.contains(id)); let is_hidden = selected_nodes.selected_nodes().any(|id| network.disabled.contains(id));
// Check if multiple nodes are selected // Check if multiple nodes are selected
let multiple_nodes = selected_nodes.next().is_some(); let multiple_nodes = selection.next().is_some();
// Generate the enable or disable button accordingly // Generate the enable or disable button accordingly
let (hide_show_label, hide_show_icon) = if is_hidden { ("Make Visible", "EyeHidden") } else { ("Make Hidden", "EyeVisible") }; let (hide_show_label, hide_show_icon) = if is_hidden { ("Make Visible", "EyeHidden") } else { ("Make Hidden", "EyeVisible") };
@ -203,8 +203,8 @@ impl NodeGraphMessageHandler {
} }
// If only one node is selected then show the preview or stop previewing button // If only one node is selected then show the preview or stop previewing button
let mut selected_nodes = document_metadata.selected_nodes(); let mut selection = selected_nodes.selected_nodes();
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) { if let (Some(&node_id), None) = (selection.next(), selection.next()) {
// Is this node the current output // Is this node the current output
let is_output = network.outputs_contain(node_id); let is_output = network.outputs_contain(node_id);
@ -225,7 +225,7 @@ impl NodeGraphMessageHandler {
} }
/// Collate the properties panel sections for a node graph /// Collate the properties panel sections for a node graph
pub fn collate_properties(&self, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn collate_properties(&self, context: &mut NodePropertiesContext, selected_nodes: &SelectedNodes) -> Vec<LayoutGroup> {
let mut network = context.network; let mut network = context.network;
for segment in &self.network { for segment in &self.network {
@ -239,7 +239,7 @@ impl NodeGraphMessageHandler {
// First, we filter all the selections into layers and nodes // First, we filter all the selections into layers and nodes
let (mut layers, mut nodes) = (Vec::new(), Vec::new()); let (mut layers, mut nodes) = (Vec::new(), Vec::new());
for node_id in context.metadata.selected_nodes() { for node_id in selected_nodes.selected_nodes() {
if let Some(layer_or_node) = network.nodes.get(node_id) { if let Some(layer_or_node) = network.nodes.get(node_id) {
if layer_or_node.is_layer() { if layer_or_node.is_layer() {
layers.push(*node_id); layers.push(*node_id);
@ -278,8 +278,16 @@ impl NodeGraphMessageHandler {
} }
} }
fn send_graph(&self, network: &NodeNetwork, graph_view_overlay_open: bool, document_metadata: &mut DocumentMetadata, collapsed: &Vec<LayerNodeIdentifier>, responses: &mut VecDeque<Message>) { fn send_graph(
document_metadata.load_structure(&network); &self,
network: &NodeNetwork,
graph_view_overlay_open: bool,
metadata: &mut DocumentMetadata,
selected_nodes: &mut SelectedNodes,
collapsed: &CollapsedLayers,
responses: &mut VecDeque<Message>,
) {
metadata.load_structure(network, selected_nodes);
let links = network let links = network
.nodes .nodes
@ -371,9 +379,9 @@ impl NodeGraphMessageHandler {
if node.is_layer() { if node.is_layer() {
let layer = LayerNodeIdentifier::new(node_id, network); let layer = LayerNodeIdentifier::new(node_id, network);
let layer_classification = { let layer_classification = {
if document_metadata.is_artboard(layer) { if metadata.is_artboard(layer) {
LayerClassification::Artboard LayerClassification::Artboard
} else if document_metadata.is_folder(layer) { } else if metadata.is_folder(layer) {
LayerClassification::Folder LayerClassification::Folder
} else { } else {
LayerClassification::Layer LayerClassification::Layer
@ -391,9 +399,9 @@ impl NodeGraphMessageHandler {
let data = LayerPanelEntry { let data = LayerPanelEntry {
id: node_id, id: node_id,
layer_classification, layer_classification,
expanded: layer.has_children(document_metadata) && !collapsed.contains(&layer), expanded: layer.has_children(metadata) && !collapsed.0.contains(&layer),
depth: layer.ancestors(document_metadata).count() - 1, depth: layer.ancestors(metadata).count() - 1,
parent_id: layer.parent(document_metadata).map(|parent| parent.to_node()), parent_id: layer.parent(metadata).map(|parent| parent.to_node()),
// TODO: Remove and take this from the graph data in the frontend similar to thumbnail? // TODO: Remove and take this from the graph data in the frontend similar to thumbnail?
name: network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(), name: network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(),
// TODO: Remove and take this from the graph data in the frontend similar to thumbnail? // TODO: Remove and take this from the graph data in the frontend similar to thumbnail?
@ -413,10 +421,10 @@ impl NodeGraphMessageHandler {
} }
/// Updates the frontend's selection state in line with the backend /// Updates the frontend's selection state in line with the backend
fn update_selected(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, responses: &mut VecDeque<Message>) { fn update_selected(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document_network, document_metadata, responses); self.update_selection_action_buttons(document_network, selected_nodes, responses);
responses.add(FrontendMessage::UpdateNodeGraphSelection { responses.add(FrontendMessage::UpdateNodeGraphSelection {
selected: document_metadata.selected_nodes_ref().clone(), selected: selected_nodes.selected_nodes_ref().clone(),
}); });
} }
@ -487,7 +495,7 @@ impl NodeGraphMessageHandler {
} }
/// Tries to remove a node from the network, returning true on success. /// Tries to remove a node from the network, returning true on success.
fn remove_node(&mut self, document_network: &mut NodeNetwork, document_metadata: &mut DocumentMetadata, node_id: NodeId, responses: &mut VecDeque<Message>, reconnect: bool) -> bool { fn remove_node(&mut self, document_network: &mut NodeNetwork, selected_nodes: &mut SelectedNodes, node_id: NodeId, responses: &mut VecDeque<Message>, reconnect: bool) -> bool {
let Some(network) = document_network.nested_network_mut(&self.network) else { let Some(network) = document_network.nested_network_mut(&self.network) else {
return false; return false;
}; };
@ -495,7 +503,7 @@ impl NodeGraphMessageHandler {
return false; return false;
} }
network.nodes.remove(&node_id); network.nodes.remove(&node_id);
document_metadata.retain_selected_nodes(|&id| id != node_id); selected_nodes.retain_selected_nodes(|&id| id != node_id);
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
true true
} }
@ -521,9 +529,10 @@ impl NodeGraphMessageHandler {
pub struct NodeGraphHandlerData<'a> { pub struct NodeGraphHandlerData<'a> {
pub document_network: &'a mut NodeNetwork, pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata, pub document_metadata: &'a mut DocumentMetadata,
pub selected_nodes: &'a mut SelectedNodes,
pub document_id: DocumentId, pub document_id: DocumentId,
pub document_name: &'a str, pub document_name: &'a str,
pub collapsed: &'a mut Vec<LayerNodeIdentifier>, pub collapsed: &'a mut CollapsedLayers,
pub input: &'a InputPreprocessorMessageHandler, pub input: &'a InputPreprocessorMessageHandler,
pub graph_view_overlay_open: bool, pub graph_view_overlay_open: bool,
} }
@ -533,6 +542,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let NodeGraphHandlerData { let NodeGraphHandlerData {
document_network, document_network,
document_metadata, document_metadata,
selected_nodes,
document_id, document_id,
collapsed, collapsed,
graph_view_overlay_open, graph_view_overlay_open,
@ -545,14 +555,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
on: BroadcastEvent::SelectionChanged, on: BroadcastEvent::SelectionChanged,
send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()), send: Box::new(NodeGraphMessage::SelectedNodesUpdated.into()),
}); });
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
NodeGraphMessage::SelectedNodesUpdated => { NodeGraphMessage::SelectedNodesUpdated => {
self.update_selection_action_buttons(document_network, document_metadata, responses); self.update_selection_action_buttons(document_network, selected_nodes, responses);
self.update_selected(document_network, document_metadata, responses); self.update_selected(document_network, selected_nodes, responses);
if document_metadata.selected_layers().count() <= 1 { if selected_nodes.selected_layers(document_metadata).count() <= 1 {
responses.add(DocumentMessage::SetRangeSelectionLayer { responses.add(DocumentMessage::SetRangeSelectionLayer {
new_layer: document_metadata.selected_layers().next(), new_layer: selected_nodes.selected_layers(document_metadata).next(),
}); });
} }
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
@ -594,7 +604,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
}; };
// Collect the selected nodes // Collect the selected nodes
let new_ids = &document_metadata.selected_nodes().copied().enumerate().map(|(new, old)| (old, NodeId(new as u64))).collect(); let new_ids = &selected_nodes.selected_nodes().copied().enumerate().map(|(new, old)| (old, NodeId(new as u64))).collect();
let copied_nodes: Vec<_> = Self::copy_nodes(network, new_ids).collect(); let copied_nodes: Vec<_> = Self::copy_nodes(network, new_ids).collect();
// Prefix to show that this is nodes // Prefix to show that this is nodes
@ -627,18 +637,18 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true }); responses.add(NodeGraphMessage::DeleteSelectedNodes { reconnect: true });
} }
NodeGraphMessage::DeleteNode { node_id, reconnect } => { NodeGraphMessage::DeleteNode { node_id, reconnect } => {
self.remove_node(document_network, document_metadata, node_id, responses, reconnect); self.remove_node(document_network, selected_nodes, node_id, responses, reconnect);
} }
NodeGraphMessage::DeleteSelectedNodes { reconnect } => { NodeGraphMessage::DeleteSelectedNodes { reconnect } => {
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
for node_id in document_metadata.selected_nodes().copied() { for node_id in selected_nodes.selected_nodes().copied() {
responses.add(NodeGraphMessage::DeleteNode { node_id, reconnect }); responses.add(NodeGraphMessage::DeleteNode { node_id, reconnect });
} }
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
// Only generate node graph if one of the selected nodes is connected to the output // Only generate node graph if one of the selected nodes is connected to the output
if document_metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) { if selected_nodes.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
} }
} }
@ -679,24 +689,24 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
} }
} }
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
} }
self.update_selected(document_network, document_metadata, responses); self.update_selected(document_network, selected_nodes, responses);
} }
NodeGraphMessage::DuplicateSelectedNodes => { NodeGraphMessage::DuplicateSelectedNodes => {
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
let new_ids = &document_metadata.selected_nodes().map(|&id| (id, NodeId(generate_uuid()))).collect(); let new_ids = &selected_nodes.selected_nodes().map(|&id| (id, NodeId(generate_uuid()))).collect();
document_metadata.clear_selected_nodes(); selected_nodes.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
// Copy the selected nodes // Copy the selected nodes
let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>(); let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>();
// Select the new nodes // Select the new nodes
document_metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id)); selected_nodes.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
for (node_id, mut document_node) in copied_nodes { for (node_id, mut document_node) in copied_nodes {
@ -707,20 +717,20 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::InsertNode { node_id, document_node }); responses.add(NodeGraphMessage::InsertNode { node_id, document_node });
} }
self.update_selected(document_network, document_metadata, responses); self.update_selected(document_network, selected_nodes, responses);
} }
} }
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => { NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
document_metadata.clear_selected_nodes(); selected_nodes.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
for _ in 0..depth_of_nesting { for _ in 0..depth_of_nesting {
self.network.pop(); self.network.pop();
} }
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
} }
self.update_selected(document_network, document_metadata, responses); self.update_selected(document_network, selected_nodes, responses);
} }
NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => { NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => {
let Some(network) = document_network.nested_network(&self.network) else { let Some(network) = document_network.nested_network(&self.network) else {
@ -761,12 +771,12 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
return; return;
}; };
for node_id in document_metadata.selected_nodes() { for node_id in selected_nodes.selected_nodes() {
if let Some(node) = network.nodes.get_mut(node_id) { if let Some(node) = network.nodes.get_mut(node_id) {
node.metadata.position += IVec2::new(displacement_x, displacement_y) node.metadata.position += IVec2::new(displacement_x, displacement_y)
} }
} }
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
} }
NodeGraphMessage::PasteNodes { serialized_nodes } => { NodeGraphMessage::PasteNodes { serialized_nodes } => {
let Some(network) = document_network.nested_network(&self.network) else { let Some(network) = document_network.nested_network(&self.network) else {
@ -817,21 +827,21 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(PortfolioMessage::SubmitGraphRender { document_id }); responses.add(PortfolioMessage::SubmitGraphRender { document_id });
} }
NodeGraphMessage::SelectedNodesAdd { nodes } => { NodeGraphMessage::SelectedNodesAdd { nodes } => {
document_metadata.add_selected_nodes(nodes); selected_nodes.add_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
} }
NodeGraphMessage::SelectedNodesRemove { nodes } => { NodeGraphMessage::SelectedNodesRemove { nodes } => {
document_metadata.retain_selected_nodes(|node| !nodes.contains(node)); selected_nodes.retain_selected_nodes(|node| !nodes.contains(node));
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
} }
NodeGraphMessage::SelectedNodesSet { nodes } => { NodeGraphMessage::SelectedNodesSet { nodes } => {
document_metadata.set_selected_nodes(nodes); selected_nodes.set_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
responses.add(PropertiesPanelMessage::Refresh); responses.add(PropertiesPanelMessage::Refresh);
} }
NodeGraphMessage::SendGraph => { NodeGraphMessage::SendGraph => {
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
} }
} }
NodeGraphMessage::SetInputValue { node_id, input_index, value } => { NodeGraphMessage::SetInputValue { node_id, input_index, value } => {
@ -858,7 +868,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let structure_changed = node_input.as_node().is_some() || input.as_node().is_some(); let structure_changed = node_input.as_node().is_some() || input.as_node().is_some();
*node_input = input; *node_input = input;
if structure_changed { if structure_changed {
load_network_structure(document_network, document_metadata, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
} }
} }
@ -932,14 +942,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
} }
} }
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
} }
NodeGraphMessage::ToggleSelectedHidden => { NodeGraphMessage::ToggleSelectedHidden => {
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
let new_hidden = !document_metadata.selected_nodes().any(|id| network.disabled.contains(id)); let new_hidden = !selected_nodes.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in document_metadata.selected_nodes() { for &node_id in selected_nodes.selected_nodes() {
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden }); responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
} }
} }
@ -963,7 +973,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
} }
} }
self.update_selection_action_buttons(document_network, document_metadata, responses); self.update_selection_action_buttons(document_network, selected_nodes, responses);
} }
NodeGraphMessage::SetName { node_id, name } => { NodeGraphMessage::SetName { node_id, name } => {
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
@ -974,7 +984,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
if let Some(node) = network.nodes.get_mut(&node_id) { if let Some(node) = network.nodes.get_mut(&node_id) {
node.alias = name; node.alias = name;
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
} }
} }
} }
@ -995,28 +1005,28 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
} }
} }
self.update_selection_action_buttons(document_network, document_metadata, responses); self.update_selection_action_buttons(document_network, selected_nodes, responses);
responses.add(NodeGraphMessage::RunDocumentGraph); responses.add(NodeGraphMessage::RunDocumentGraph);
} }
NodeGraphMessage::UpdateNewNodeGraph => { NodeGraphMessage::UpdateNewNodeGraph => {
if let Some(network) = document_network.nested_network(&self.network) { if let Some(network) = document_network.nested_network(&self.network) {
document_metadata.clear_selected_nodes(); selected_nodes.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged); responses.add(BroadcastEvent::SelectionChanged);
self.send_graph(network, graph_view_overlay_open, document_metadata, collapsed, responses); self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
let node_types = document_node_types::collect_node_types(); let node_types = document_node_types::collect_node_types();
responses.add(FrontendMessage::UpdateNodeTypes { node_types }); responses.add(FrontendMessage::UpdateNodeTypes { node_types });
} }
self.update_selected(document_network, document_metadata, responses); self.update_selected(document_network, selected_nodes, responses);
} }
NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => { NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => {
self.resolved_types = resolved_types; self.resolved_types = resolved_types;
self.node_graph_errors = node_graph_errors; self.node_graph_errors = node_graph_errors;
} }
} }
self.has_selection = document_metadata.has_selected_nodes(); self.has_selection = selected_nodes.has_selected_nodes();
} }
fn actions(&self) -> ActionList { fn actions(&self) -> ActionList {

View File

@ -2919,7 +2919,7 @@ impl DocumentNodeDefinition {
} }
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], based on the inputs from the graph (which must be the correct length) and the metadata /// Converts the [DocumentNodeDefinition] type to a [DocumentNode], based on the inputs from the graph (which must be the correct length) and the metadata
pub fn to_document_node(&self, inputs: impl IntoIterator<Item = NodeInput>, document_metadata: DocumentNodeMetadata) -> DocumentNode { pub fn to_document_node(&self, inputs: impl IntoIterator<Item = NodeInput>, metadata: DocumentNodeMetadata) -> DocumentNode {
let inputs: Vec<_> = inputs.into_iter().collect(); let inputs: Vec<_> = inputs.into_iter().collect();
assert_eq!(inputs.len(), self.inputs.len(), "Inputs passed from the graph must be equal to the number required"); assert_eq!(inputs.len(), self.inputs.len(), "Inputs passed from the graph must be equal to the number required");
DocumentNode { DocumentNode {
@ -2927,7 +2927,7 @@ impl DocumentNodeDefinition {
inputs, inputs,
has_primary_output: self.has_primary_output, has_primary_output: self.has_primary_output,
implementation: self.generate_implementation(), implementation: self.generate_implementation(),
metadata: document_metadata, metadata,
manual_composition: self.manual_composition.clone(), manual_composition: self.manual_composition.clone(),
..Default::default() ..Default::default()
} }
@ -2935,10 +2935,10 @@ impl DocumentNodeDefinition {
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], using the provided `input_override` and falling back to the default inputs. /// Converts the [DocumentNodeDefinition] type to a [DocumentNode], using the provided `input_override` and falling back to the default inputs.
/// `input_override` does not have to be the correct length. /// `input_override` does not have to be the correct length.
pub fn to_document_node_default_inputs(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>, document_metadata: DocumentNodeMetadata) -> DocumentNode { pub fn to_document_node_default_inputs(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>, metadata: DocumentNodeMetadata) -> DocumentNode {
let mut input_override = input_override.into_iter(); let mut input_override = input_override.into_iter();
let inputs = self.inputs.iter().map(|default| input_override.next().unwrap_or_default().unwrap_or_else(|| default.default.clone())); let inputs = self.inputs.iter().map(|default| input_override.next().unwrap_or_default().unwrap_or_else(|| default.default.clone()));
self.to_document_node(inputs, document_metadata) self.to_document_node(inputs, metadata)
} }
/// Converts the [DocumentNodeDefinition] type to a [DocumentNode], completely default /// Converts the [DocumentNodeDefinition] type to a [DocumentNode], completely default

View File

@ -25,7 +25,7 @@ pub fn overlay_canvas_context() -> web_sys::CanvasRenderingContext2d {
} }
pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext) { pub fn path_overlays(document: &DocumentMessageHandler, shape_editor: &mut ShapeState, overlay_context: &mut OverlayContext) {
for layer in document.metadata().selected_layers() { for layer in document.selected_nodes.selected_layers(document.metadata()) {
let Some(subpaths) = get_subpaths(layer, &document.network) else { continue }; let Some(subpaths) = get_subpaths(layer, &document.network) else { continue };
let transform = document.metadata().transform_to_viewport(layer); let transform = document.metadata().transform_to_viewport(layer);
let selected = shape_editor.selected_shape_state.get(&layer); let selected = shape_editor.selected_shape_state.get(&layer);

View File

@ -15,10 +15,10 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
let PropertiesPanelMessageHandlerData { let PropertiesPanelMessageHandlerData {
node_graph_message_handler, node_graph_message_handler,
executor, executor,
document_network, document_network: network,
document_metadata, document_metadata: metadata,
selected_nodes,
document_name, document_name,
..
} = data; } = data;
match message { match message {
@ -38,11 +38,11 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
responses, responses,
nested_path: &node_graph_message_handler.network, nested_path: &node_graph_message_handler.network,
executor, executor,
network: document_network, network,
metadata: document_metadata, metadata,
}; };
let properties_sections = node_graph_message_handler.collate_properties(&mut context); let properties_sections = node_graph_message_handler.collate_properties(&mut context, selected_nodes);
let options_bar = vec![LayoutGroup::Row { let options_bar = vec![LayoutGroup::Row {
widgets: vec![ widgets: vec![

View File

@ -1,4 +1,5 @@
use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata; use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata;
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
use crate::messages::prelude::NodeGraphMessageHandler; use crate::messages::prelude::NodeGraphMessageHandler;
use crate::node_graph_executor::NodeGraphExecutor; use crate::node_graph_executor::NodeGraphExecutor;
@ -8,6 +9,7 @@ pub struct PropertiesPanelMessageHandlerData<'a> {
pub document_name: &'a str, pub document_name: &'a str,
pub document_network: &'a NodeNetwork, pub document_network: &'a NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata, pub document_metadata: &'a mut DocumentMetadata,
pub selected_nodes: &'a SelectedNodes,
pub node_graph_message_handler: &'a NodeGraphMessageHandler, pub node_graph_message_handler: &'a NodeGraphMessageHandler,
pub executor: &'a mut NodeGraphExecutor, pub executor: &'a mut NodeGraphExecutor,
} }

View File

@ -1,3 +1,5 @@
use super::nodes::SelectedNodes;
use graph_craft::document::{DocumentNode, NodeId, NodeNetwork}; use graph_craft::document::{DocumentNode, NodeId, NodeNetwork};
use graphene_core::renderer::ClickTarget; use graphene_core::renderer::ClickTarget;
use graphene_core::renderer::Quad; use graphene_core::renderer::Quad;
@ -19,7 +21,6 @@ pub struct DocumentMetadata {
artboards: HashSet<LayerNodeIdentifier>, artboards: HashSet<LayerNodeIdentifier>,
folders: HashSet<LayerNodeIdentifier>, folders: HashSet<LayerNodeIdentifier>,
click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>, click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
selected_nodes: Vec<NodeId>,
/// Transform from document space to viewport space. /// Transform from document space to viewport space.
pub document_to_viewport: DAffine2, pub document_to_viewport: DAffine2,
} }
@ -32,7 +33,6 @@ impl Default for DocumentMetadata {
structure: HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]), structure: HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]),
artboards: HashSet::new(), artboards: HashSet::new(),
folders: HashSet::new(), folders: HashSet::new(),
selected_nodes: Vec::new(),
document_to_viewport: DAffine2::IDENTITY, document_to_viewport: DAffine2::IDENTITY,
} }
} }
@ -52,34 +52,6 @@ impl DocumentMetadata {
self.root().decendants(self) 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 { pub fn layer_exists(&self, layer: LayerNodeIdentifier) -> bool {
self.structure.contains_key(&layer) self.structure.contains_key(&layer)
} }
@ -146,14 +118,9 @@ impl DocumentMetadata {
self.artboards.contains(&layer) 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 /// Folders sorted from most nested to least nested
pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<LayerNodeIdentifier> { pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<LayerNodeIdentifier> {
let mut folders: Vec<_> = self.folders(layers).collect(); let mut folders: Vec<_> = layers.filter(|layer| self.folders.contains(layer)).collect();
folders.sort_by_cached_key(|a| std::cmp::Reverse(a.ancestors(self).count())); folders.sort_by_cached_key(|a| std::cmp::Reverse(a.ancestors(self).count()));
folders folders
} }
@ -164,24 +131,8 @@ impl DocumentMetadata {
// ============================================== // ==============================================
impl DocumentMetadata { 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. /// Loads the structure of layer nodes from a node graph.
pub fn load_structure(&mut self, graph: &NodeNetwork) { pub fn load_structure(&mut self, graph: &NodeNetwork, selected_nodes: &mut SelectedNodes) {
fn first_child_layer<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> { 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()) graph.upstream_flow_back_from_nodes(vec![node.inputs[0].as_node()?], true).find(|(node, _)| node.is_layer())
} }
@ -224,7 +175,7 @@ impl DocumentMetadata {
} }
} }
self.selected_nodes.retain(|node| graph.nodes.contains_key(node)); selected_nodes.0.retain(|node| graph.nodes.contains_key(node));
self.upstream_transforms.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)); self.click_targets.retain(|layer, _| self.structure.contains_key(layer));
} }
@ -328,8 +279,9 @@ impl DocumentMetadata {
} }
/// Calculates the selected layer bounds in document space /// Calculates the selected layer bounds in document space
pub fn selected_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> { pub fn selected_bounds_document_space(&self, include_artboards: bool, metadata: &DocumentMetadata, selected_nodes: &SelectedNodes) -> Option<[DVec2; 2]> {
self.selected_layers() selected_nodes
.selected_layers(metadata)
.filter(|&layer| include_artboards || !self.is_artboard(layer)) .filter(|&layer| include_artboards || !self.is_artboard(layer))
.filter_map(|layer| self.bounding_box_document(layer)) .filter_map(|layer| self.bounding_box_document(layer))
.reduce(Quad::combine_bounds) .reduce(Quad::combine_bounds)
@ -388,109 +340,109 @@ impl LayerNodeIdentifier {
} }
/// Access the parent layer if possible /// Access the parent layer if possible
pub fn parent(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> { pub fn parent(self, metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.parent) metadata.get_relations(self).and_then(|relations| relations.parent)
} }
/// Access the previous sibling of this layer (up the Layers panel) /// Access the previous sibling of this layer (up the Layers panel)
pub fn previous_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> { pub fn previous_sibling(self, metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.previous_sibling) metadata.get_relations(self).and_then(|relations| relations.previous_sibling)
} }
/// Access the next sibling of this layer (down the Layers panel) /// Access the next sibling of this layer (down the Layers panel)
pub fn next_sibling(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> { pub fn next_sibling(self, metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.next_sibling) metadata.get_relations(self).and_then(|relations| relations.next_sibling)
} }
/// Access the first child of this layer (top most in Layers panel) /// Access the first child of this layer (top most in Layers panel)
pub fn first_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> { pub fn first_child(self, metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.first_child) metadata.get_relations(self).and_then(|relations| relations.first_child)
} }
/// Access the last child of this layer (bottom most in Layers panel) /// Access the last child of this layer (bottom most in Layers panel)
pub fn last_child(self, document_metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> { pub fn last_child(self, metadata: &DocumentMetadata) -> Option<LayerNodeIdentifier> {
document_metadata.get_relations(self).and_then(|relations| relations.last_child) metadata.get_relations(self).and_then(|relations| relations.last_child)
} }
/// Does the layer have children? /// Does the layer have children?
pub fn has_children(self, document_metadata: &DocumentMetadata) -> bool { pub fn has_children(self, metadata: &DocumentMetadata) -> bool {
self.first_child(document_metadata).is_some() self.first_child(metadata).is_some()
} }
/// Iterator over all direct children (excluding self and recursive children) /// Iterator over all direct children (excluding self and recursive children)
pub fn children(self, document_metadata: &DocumentMetadata) -> AxisIter { pub fn children(self, metadata: &DocumentMetadata) -> AxisIter {
AxisIter { AxisIter {
layer_node: self.first_child(document_metadata), layer_node: self.first_child(metadata),
next_node: Self::next_sibling, next_node: Self::next_sibling,
document_metadata, metadata,
} }
} }
/// All ancestors of this layer, including self, going to the document root /// All ancestors of this layer, including self, going to the document root
pub fn ancestors(self, document_metadata: &DocumentMetadata) -> AxisIter { pub fn ancestors(self, metadata: &DocumentMetadata) -> AxisIter {
AxisIter { AxisIter {
layer_node: Some(self), layer_node: Some(self),
next_node: Self::parent, next_node: Self::parent,
document_metadata, metadata,
} }
} }
/// Iterator through all the last children, starting from self /// Iterator through all the last children, starting from self
pub fn last_children(self, document_metadata: &DocumentMetadata) -> AxisIter { pub fn last_children(self, metadata: &DocumentMetadata) -> AxisIter {
AxisIter { AxisIter {
layer_node: Some(self), layer_node: Some(self),
next_node: Self::last_child, next_node: Self::last_child,
document_metadata, metadata,
} }
} }
/// Iterator through all decendants, including recursive children (not including self) /// Iterator through all decendants, including recursive children (not including self)
pub fn decendants(self, document_metadata: &DocumentMetadata) -> DecendantsIter { pub fn decendants(self, metadata: &DocumentMetadata) -> DecendantsIter {
DecendantsIter { DecendantsIter {
front: self.first_child(document_metadata), front: self.first_child(metadata),
back: self.last_child(document_metadata).and_then(|child| child.last_children(document_metadata).last()), back: self.last_child(metadata).and_then(|child| child.last_children(metadata).last()),
document_metadata, metadata,
} }
} }
/// Add a child towards the top of the Layers panel /// Add a child towards the top of the Layers panel
pub fn push_front_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { pub fn push_front_child(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer"); assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer");
let parent = document_metadata.get_structure_mut(self); let parent = metadata.get_structure_mut(self);
let old_first_child = parent.first_child.replace(new); let old_first_child = parent.first_child.replace(new);
parent.last_child.get_or_insert(new); parent.last_child.get_or_insert(new);
if let Some(old_first_child) = old_first_child { if let Some(old_first_child) = old_first_child {
document_metadata.get_structure_mut(old_first_child).previous_sibling = Some(new); metadata.get_structure_mut(old_first_child).previous_sibling = Some(new);
} }
document_metadata.get_structure_mut(new).next_sibling = old_first_child; metadata.get_structure_mut(new).next_sibling = old_first_child;
document_metadata.get_structure_mut(new).parent = Some(self); metadata.get_structure_mut(new).parent = Some(self);
} }
/// Add a child towards the bottom of the Layers panel /// Add a child towards the bottom of the Layers panel
pub fn push_child(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { pub fn push_child(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer"); assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer");
let parent = document_metadata.get_structure_mut(self); let parent = metadata.get_structure_mut(self);
let old_last_child = parent.last_child.replace(new); let old_last_child = parent.last_child.replace(new);
parent.first_child.get_or_insert(new); parent.first_child.get_or_insert(new);
if let Some(old_last_child) = old_last_child { if let Some(old_last_child) = old_last_child {
document_metadata.get_structure_mut(old_last_child).next_sibling = Some(new); metadata.get_structure_mut(old_last_child).next_sibling = Some(new);
} }
document_metadata.get_structure_mut(new).previous_sibling = old_last_child; metadata.get_structure_mut(new).previous_sibling = old_last_child;
document_metadata.get_structure_mut(new).parent = Some(self); metadata.get_structure_mut(new).parent = Some(self);
} }
/// Add sibling above in the Layers panel /// Add sibling above in the Layers panel
pub fn add_before(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { pub fn add_before(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer"); assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer");
document_metadata.get_structure_mut(new).next_sibling = Some(self); metadata.get_structure_mut(new).next_sibling = Some(self);
document_metadata.get_structure_mut(new).parent = self.parent(document_metadata); metadata.get_structure_mut(new).parent = self.parent(metadata);
let old_previous_sibling = document_metadata.get_structure_mut(self).previous_sibling.replace(new); let old_previous_sibling = metadata.get_structure_mut(self).previous_sibling.replace(new);
if let Some(old_previous_sibling) = old_previous_sibling { if let Some(old_previous_sibling) = old_previous_sibling {
document_metadata.get_structure_mut(old_previous_sibling).next_sibling = Some(new); metadata.get_structure_mut(old_previous_sibling).next_sibling = Some(new);
document_metadata.get_structure_mut(new).previous_sibling = Some(old_previous_sibling); metadata.get_structure_mut(new).previous_sibling = Some(old_previous_sibling);
} else if let Some(structure) = self } else if let Some(structure) = self
.parent(document_metadata) .parent(metadata)
.map(|parent| document_metadata.get_structure_mut(parent)) .map(|parent| metadata.get_structure_mut(parent))
.filter(|structure| structure.first_child == Some(self)) .filter(|structure| structure.first_child == Some(self))
{ {
structure.first_child = Some(new); structure.first_child = Some(new);
@ -498,17 +450,17 @@ impl LayerNodeIdentifier {
} }
/// Add sibling below in the Layers panel /// Add sibling below in the Layers panel
pub fn add_after(self, document_metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) { pub fn add_after(self, metadata: &mut DocumentMetadata, new: LayerNodeIdentifier) {
assert!(!document_metadata.structure.contains_key(&new), "Cannot add already existing layer"); assert!(!metadata.structure.contains_key(&new), "Cannot add already existing layer");
document_metadata.get_structure_mut(new).previous_sibling = Some(self); metadata.get_structure_mut(new).previous_sibling = Some(self);
document_metadata.get_structure_mut(new).parent = self.parent(document_metadata); metadata.get_structure_mut(new).parent = self.parent(metadata);
let old_next_sibling = document_metadata.get_structure_mut(self).next_sibling.replace(new); let old_next_sibling = metadata.get_structure_mut(self).next_sibling.replace(new);
if let Some(old_next_sibling) = old_next_sibling { if let Some(old_next_sibling) = old_next_sibling {
document_metadata.get_structure_mut(old_next_sibling).previous_sibling = Some(new); metadata.get_structure_mut(old_next_sibling).previous_sibling = Some(new);
document_metadata.get_structure_mut(new).next_sibling = Some(old_next_sibling); metadata.get_structure_mut(new).next_sibling = Some(old_next_sibling);
} else if let Some(structure) = self } else if let Some(structure) = self
.parent(document_metadata) .parent(metadata)
.map(|parent| document_metadata.get_structure_mut(parent)) .map(|parent| metadata.get_structure_mut(parent))
.filter(|structure| structure.last_child == Some(self)) .filter(|structure| structure.last_child == Some(self))
{ {
structure.last_child = Some(new); structure.last_child = Some(new);
@ -516,18 +468,18 @@ impl LayerNodeIdentifier {
} }
/// Delete layer and all children /// Delete layer and all children
pub fn delete(self, document_metadata: &mut DocumentMetadata) { pub fn delete(self, metadata: &mut DocumentMetadata) {
let previous_sibling = self.previous_sibling(document_metadata); let previous_sibling = self.previous_sibling(metadata);
let next_sibling = self.next_sibling(document_metadata); let next_sibling = self.next_sibling(metadata);
if let Some(previous_sibling) = previous_sibling.map(|node| document_metadata.get_structure_mut(node)) { if let Some(previous_sibling) = previous_sibling.map(|node| metadata.get_structure_mut(node)) {
previous_sibling.next_sibling = next_sibling; previous_sibling.next_sibling = next_sibling;
} }
if let Some(next_sibling) = next_sibling.map(|node| document_metadata.get_structure_mut(node)) { if let Some(next_sibling) = next_sibling.map(|node| metadata.get_structure_mut(node)) {
next_sibling.previous_sibling = previous_sibling; next_sibling.previous_sibling = previous_sibling;
} }
let mut parent = self.parent(document_metadata).map(|parent| document_metadata.get_structure_mut(parent)); let mut parent = self.parent(metadata).map(|parent| metadata.get_structure_mut(parent));
if let Some(structure) = parent.as_mut().filter(|structure| structure.first_child == Some(self)) { if let Some(structure) = parent.as_mut().filter(|structure| structure.first_child == Some(self)) {
structure.first_child = next_sibling; structure.first_child = next_sibling;
} }
@ -536,22 +488,22 @@ impl LayerNodeIdentifier {
} }
let mut delete = vec![self]; let mut delete = vec![self];
delete.extend(self.decendants(document_metadata)); delete.extend(self.decendants(metadata));
for node in delete { for node in delete {
document_metadata.structure.remove(&node); metadata.structure.remove(&node);
} }
} }
pub fn exists(&self, document_metadata: &DocumentMetadata) -> bool { pub fn exists(&self, metadata: &DocumentMetadata) -> bool {
document_metadata.get_relations(*self).is_some() metadata.get_relations(*self).is_some()
} }
pub fn starts_with(&self, other: Self, document_metadata: &DocumentMetadata) -> bool { pub fn starts_with(&self, other: Self, metadata: &DocumentMetadata) -> bool {
self.ancestors(document_metadata).any(|parent| parent == other) self.ancestors(metadata).any(|parent| parent == other)
} }
pub fn child_of_root(&self, document_metadata: &DocumentMetadata) -> Self { pub fn child_of_root(&self, metadata: &DocumentMetadata) -> Self {
self.ancestors(document_metadata) self.ancestors(metadata)
.filter(|&layer| layer != LayerNodeIdentifier::ROOT) .filter(|&layer| layer != LayerNodeIdentifier::ROOT)
.last() .last()
.expect("There should be a layer before the root") .expect("There should be a layer before the root")
@ -567,7 +519,7 @@ impl LayerNodeIdentifier {
pub struct AxisIter<'a> { pub struct AxisIter<'a> {
pub layer_node: Option<LayerNodeIdentifier>, pub layer_node: Option<LayerNodeIdentifier>,
pub next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>, pub next_node: fn(LayerNodeIdentifier, &DocumentMetadata) -> Option<LayerNodeIdentifier>,
pub document_metadata: &'a DocumentMetadata, pub metadata: &'a DocumentMetadata,
} }
impl<'a> Iterator for AxisIter<'a> { impl<'a> Iterator for AxisIter<'a> {
@ -575,7 +527,7 @@ impl<'a> Iterator for AxisIter<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let layer_node = self.layer_node.take(); let layer_node = self.layer_node.take();
self.layer_node = layer_node.and_then(|node| (self.next_node)(node, self.document_metadata)); self.layer_node = layer_node.and_then(|node| (self.next_node)(node, self.metadata));
layer_node layer_node
} }
} }
@ -588,7 +540,7 @@ impl<'a> Iterator for AxisIter<'a> {
pub struct DecendantsIter<'a> { pub struct DecendantsIter<'a> {
front: Option<LayerNodeIdentifier>, front: Option<LayerNodeIdentifier>,
back: Option<LayerNodeIdentifier>, back: Option<LayerNodeIdentifier>,
document_metadata: &'a DocumentMetadata, metadata: &'a DocumentMetadata,
} }
impl<'a> Iterator for DecendantsIter<'a> { impl<'a> Iterator for DecendantsIter<'a> {
@ -602,8 +554,8 @@ impl<'a> Iterator for DecendantsIter<'a> {
let layer_node = self.front.take(); let layer_node = self.front.take();
if let Some(layer_node) = layer_node { if let Some(layer_node) = layer_node {
self.front = layer_node self.front = layer_node
.first_child(self.document_metadata) .first_child(self.metadata)
.or_else(|| layer_node.ancestors(self.document_metadata).find_map(|ancestor| ancestor.next_sibling(self.document_metadata))); .or_else(|| layer_node.ancestors(self.metadata).find_map(|ancestor| ancestor.next_sibling(self.metadata)));
} }
layer_node layer_node
} }
@ -618,9 +570,9 @@ impl<'a> DoubleEndedIterator for DecendantsIter<'a> {
let layer_node = self.back.take(); let layer_node = self.back.take();
if let Some(layer_node) = layer_node { if let Some(layer_node) = layer_node {
self.back = layer_node self.back = layer_node
.previous_sibling(self.document_metadata) .previous_sibling(self.metadata)
.and_then(|sibling| sibling.last_children(self.document_metadata).last()) .and_then(|sibling| sibling.last_children(self.metadata).last())
.or_else(|| layer_node.parent(self.document_metadata)); .or_else(|| layer_node.parent(self.metadata));
} }
layer_node layer_node
@ -659,47 +611,47 @@ pub fn is_folder(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
#[test] #[test]
fn test_tree() { fn test_tree() {
let mut document_metadata = DocumentMetadata::default(); let mut metadata = DocumentMetadata::default();
let root = document_metadata.root(); let root = metadata.root();
let document_metadata = &mut document_metadata; let metadata = &mut metadata;
root.push_child(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(3))); root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(3)));
assert_eq!(root.children(document_metadata).collect::<Vec<_>>(), vec![LayerNodeIdentifier::new_unchecked(NodeId(3))]); assert_eq!(root.children(metadata).collect::<Vec<_>>(), vec![LayerNodeIdentifier::new_unchecked(NodeId(3))]);
root.push_child(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(6))); root.push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(6)));
assert_eq!(root.children(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]); assert_eq!(root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]);
assert_eq!(root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]); assert_eq!(root.decendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), vec![NodeId(3), NodeId(6)]);
LayerNodeIdentifier::new_unchecked(NodeId(3)).add_after(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(4))); LayerNodeIdentifier::new_unchecked(NodeId(3)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(4)));
LayerNodeIdentifier::new_unchecked(NodeId(3)).add_before(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(2))); LayerNodeIdentifier::new_unchecked(NodeId(3)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(2)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).add_before(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(5))); LayerNodeIdentifier::new_unchecked(NodeId(6)).add_before(metadata, LayerNodeIdentifier::new_unchecked(NodeId(5)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).add_after(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(9))); LayerNodeIdentifier::new_unchecked(NodeId(6)).add_after(metadata, LayerNodeIdentifier::new_unchecked(NodeId(9)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).push_child(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(8))); LayerNodeIdentifier::new_unchecked(NodeId(6)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(8)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).push_front_child(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(7))); LayerNodeIdentifier::new_unchecked(NodeId(6)).push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(7)));
root.push_front_child(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(1))); root.push_front_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(1)));
assert_eq!( assert_eq!(
root.children(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(9)] vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(9)]
); );
assert_eq!( assert_eq!(
root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), root.decendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(7), NodeId(8), NodeId(9)] vec![NodeId(1), NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(6), NodeId(7), NodeId(8), NodeId(9)]
); );
assert_eq!( assert_eq!(
root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(), root.decendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(),
vec![NodeId(9), NodeId(8), NodeId(7), NodeId(6), NodeId(5), NodeId(4), NodeId(3), NodeId(2), NodeId(1)] vec![NodeId(9), NodeId(8), NodeId(7), NodeId(6), NodeId(5), NodeId(4), NodeId(3), NodeId(2), NodeId(1)]
); );
assert!(root.children(document_metadata).all(|child| child.parent(document_metadata) == Some(root))); assert!(root.children(metadata).all(|child| child.parent(metadata) == Some(root)));
LayerNodeIdentifier::new_unchecked(NodeId(6)).delete(document_metadata); LayerNodeIdentifier::new_unchecked(NodeId(6)).delete(metadata);
LayerNodeIdentifier::new_unchecked(NodeId(1)).delete(document_metadata); LayerNodeIdentifier::new_unchecked(NodeId(1)).delete(metadata);
LayerNodeIdentifier::new_unchecked(NodeId(9)).push_child(document_metadata, LayerNodeIdentifier::new_unchecked(NodeId(10))); LayerNodeIdentifier::new_unchecked(NodeId(9)).push_child(metadata, LayerNodeIdentifier::new_unchecked(NodeId(10)));
assert_eq!( assert_eq!(
root.children(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), root.children(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9)] vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9)]
); );
assert_eq!( assert_eq!(
root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(), root.decendants(metadata).map(LayerNodeIdentifier::to_node).collect::<Vec<_>>(),
vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9), NodeId(10)] vec![NodeId(2), NodeId(3), NodeId(4), NodeId(5), NodeId(9), NodeId(10)]
); );
assert_eq!( assert_eq!(
root.decendants(document_metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(), root.decendants(metadata).map(LayerNodeIdentifier::to_node).rev().collect::<Vec<_>>(),
vec![NodeId(10), NodeId(9), NodeId(5), NodeId(4), NodeId(3), NodeId(2)] vec![NodeId(10), NodeId(9), NodeId(5), NodeId(4), NodeId(3), NodeId(2)]
); );
} }

View File

@ -1,52 +0,0 @@
use graph_craft::document::NodeId;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct RawBuffer(Vec<u8>);
impl From<&[u64]> for RawBuffer {
fn from(iter: &[u64]) -> Self {
let v_from_raw: Vec<u8> = iter.iter().flat_map(|x| x.to_ne_bytes()).collect();
Self(v_from_raw)
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, specta::Type)]
pub struct JsRawBuffer(Vec<u8>);
impl From<RawBuffer> for JsRawBuffer {
fn from(buffer: RawBuffer) -> Self {
Self(buffer.0)
}
}
impl Serialize for JsRawBuffer {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut buffer = serializer.serialize_struct("Buffer", 2)?;
buffer.serialize_field("pointer", &(self.0.as_ptr() as usize))?;
buffer.serialize_field("length", &(self.0.len()))?;
buffer.end()
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub enum LayerClassification {
#[default]
Folder,
Artboard,
Layer,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct LayerPanelEntry {
pub id: NodeId,
pub name: String,
pub tooltip: String,
#[serde(rename = "layerClassification")]
pub layer_classification: LayerClassification,
pub expanded: bool,
pub disabled: bool,
#[serde(rename = "parentId")]
pub parent_id: Option<NodeId>,
pub depth: usize,
}

View File

@ -1,6 +1,6 @@
pub mod clipboards; pub mod clipboards;
pub mod document_metadata; pub mod document_metadata;
pub mod error; pub mod error;
pub mod layer_panel;
pub mod misc; pub mod misc;
pub mod nodes;
pub mod transformation; pub mod transformation;

View File

@ -0,0 +1,110 @@
use graph_craft::document::{NodeId, NodeNetwork};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct RawBuffer(Vec<u8>);
impl From<&[u64]> for RawBuffer {
fn from(iter: &[u64]) -> Self {
let v_from_raw: Vec<u8> = iter.iter().flat_map(|x| x.to_ne_bytes()).collect();
Self(v_from_raw)
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, specta::Type)]
pub struct JsRawBuffer(Vec<u8>);
impl From<RawBuffer> for JsRawBuffer {
fn from(buffer: RawBuffer) -> Self {
Self(buffer.0)
}
}
impl Serialize for JsRawBuffer {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut buffer = serializer.serialize_struct("Buffer", 2)?;
buffer.serialize_field("pointer", &(self.0.as_ptr() as usize))?;
buffer.serialize_field("length", &(self.0.len()))?;
buffer.end()
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub enum LayerClassification {
#[default]
Folder,
Artboard,
Layer,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct LayerPanelEntry {
pub id: NodeId,
pub name: String,
pub tooltip: String,
#[serde(rename = "layerClassification")]
pub layer_classification: LayerClassification,
pub expanded: bool,
pub disabled: bool,
#[serde(rename = "parentId")]
pub parent_id: Option<NodeId>,
pub depth: usize,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct SelectedNodes(pub Vec<NodeId>);
impl SelectedNodes {
pub fn layer_visible(&self, layer: LayerNodeIdentifier, network: &NodeNetwork, metadata: &DocumentMetadata) -> bool {
!layer.ancestors(metadata).any(|layer| network.disabled.contains(&layer.to_node()))
}
pub fn selected_visible_layers<'a>(&'a self, network: &'a NodeNetwork, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.selected_layers(metadata).filter(move |&layer| self.layer_visible(layer, network, metadata))
}
pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
metadata.all_layers().filter(|layer| self.0.contains(&layer.to_node()))
}
pub fn selected_layers_except_artboards<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
self.selected_layers(metadata).filter(move |&layer| !metadata.is_artboard(layer))
}
pub fn selected_layers_contains(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool {
self.selected_layers(metadata).any(|selected| selected == layer)
}
pub fn selected_nodes(&self) -> core::slice::Iter<'_, NodeId> {
self.0.iter()
}
pub fn selected_nodes_ref(&self) -> &Vec<NodeId> {
&self.0
}
pub fn has_selected_nodes(&self) -> bool {
!self.0.is_empty()
}
pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) {
self.0.retain(f);
}
pub fn set_selected_nodes(&mut self, new: Vec<NodeId>) {
self.0 = new;
}
pub fn add_selected_nodes(&mut self, iter: impl IntoIterator<Item = NodeId>) {
self.0.extend(iter);
}
pub fn clear_selected_nodes(&mut self) {
self.set_selected_nodes(Vec::new());
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
pub struct CollapsedLayers(pub Vec<LayerNodeIdentifier>);

View File

@ -163,7 +163,10 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
}; };
let copy_val = |buffer: &mut Vec<CopyBufferEntry>| { let copy_val = |buffer: &mut Vec<CopyBufferEntry>| {
for layer_path in active_document.metadata().shallowest_unique_layers(active_document.metadata().selected_layers()) { for layer_path in active_document
.metadata()
.shallowest_unique_layers(active_document.selected_nodes.selected_layers(active_document.metadata()))
{
let Some(layer) = layer_path.last().copied() else { let Some(layer) = layer_path.last().copied() else {
continue; continue;
}; };
@ -184,7 +187,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
.collect(), .collect(),
) )
.collect(), .collect(),
selected: active_document.metadata().selected_layers_contains(layer), selected: active_document.selected_nodes.selected_layers_contains(layer, active_document.metadata()),
collapsed: false, collapsed: false,
}); });
} }
@ -526,7 +529,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
); );
if let Some(document) = self.active_document() { if let Some(document) = self.active_document() {
if document.metadata().selected_layers().next().is_some() { if document.selected_nodes.selected_layers(document.metadata()).next().is_some() {
let select = actions!(PortfolioMessageDiscriminant; let select = actions!(PortfolioMessageDiscriminant;
Copy, Copy,
Cut, Cut,

View File

@ -45,7 +45,7 @@ impl Pivot {
/// Recomputes the pivot position and transform. /// Recomputes the pivot position and transform.
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
let mut layers = document.selected_visible_layers(); let mut layers = document.selected_nodes.selected_visible_layers(document.network(), document.metadata());
let Some(first) = layers.next() else { let Some(first) = layers.next() else {
// If no layers are selected then we revert things back to default // If no layers are selected then we revert things back to default
self.normalized_pivot = DVec2::splat(0.5); self.normalized_pivot = DVec2::splat(0.5);
@ -65,8 +65,9 @@ impl Pivot {
} else { } else {
// If more than one layer is selected we use the AABB with the mean of the pivots // If more than one layer is selected we use the AABB with the mean of the pivots
let xy_summation = document let xy_summation = document
.selected_visible_layers() .selected_nodes
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.document_metadata)) .selected_visible_layers(document.network(), document.metadata())
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.metadata))
.reduce(|a, b| a + b) .reduce(|a, b| a + b)
.unwrap_or_default(); .unwrap_or_default();
@ -100,7 +101,7 @@ impl Pivot {
/// Sets the viewport position of the pivot for all selected layers. /// Sets the viewport position of the pivot for all selected layers.
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) { pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
for layer in document.selected_visible_layers() { for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) {
let transform = Self::get_layer_pivot_transform(layer, document); let transform = Self::get_layer_pivot_transform(layer, document);
let pivot = transform.inverse().transform_point2(position); let pivot = transform.inverse().transform_point2(position);
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0. // Only update the pivot when computed position is finite. Infinite can happen when scale is 0.

View File

@ -266,10 +266,10 @@ impl BrushToolData {
fn load_existing_strokes(&mut self, document: &DocumentMessageHandler) -> Option<LayerNodeIdentifier> { fn load_existing_strokes(&mut self, document: &DocumentMessageHandler) -> Option<LayerNodeIdentifier> {
self.transform = DAffine2::IDENTITY; self.transform = DAffine2::IDENTITY;
if document.metadata().selected_layers().count() != 1 { if document.selected_nodes.selected_layers(document.metadata()).count() != 1 {
return None; return None;
} }
let Some(layer) = document.metadata().selected_layers().next() else { let Some(layer) = document.selected_nodes.selected_layers(document.metadata()).next() else {
return None; return None;
}; };

View File

@ -295,7 +295,7 @@ impl Fsm for GradientToolFsmState {
(_, GradientToolMessage::Overlays(mut overlay_context)) => { (_, GradientToolMessage::Overlays(mut overlay_context)) => {
let selected = tool_data.selected_gradient.as_ref(); let selected = tool_data.selected_gradient.as_ref();
for layer in document.selected_visible_layers() { for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) {
let Some(gradient) = get_gradient(layer, &document.network) else { continue }; let Some(gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document); let transform = gradient_space_transform(layer, document);
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging); let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
@ -366,7 +366,7 @@ impl Fsm for GradientToolFsmState {
self self
} }
(_, GradientToolMessage::InsertStop) => { (_, GradientToolMessage::InsertStop) => {
for layer in document.selected_visible_layers() { for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) {
let Some(mut gradient) = get_gradient(layer, &document.network) else { continue }; let Some(mut gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document); let transform = gradient_space_transform(layer, document);
@ -407,7 +407,7 @@ impl Fsm for GradientToolFsmState {
let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2); let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
let mut dragging = false; let mut dragging = false;
for layer in document.selected_visible_layers() { for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) {
let Some(gradient) = get_gradient(layer, &document.network) else { continue }; let Some(gradient) = get_gradient(layer, &document.network) else { continue };
let transform = gradient_space_transform(layer, document); let transform = gradient_space_transform(layer, document);
@ -448,7 +448,7 @@ impl Fsm for GradientToolFsmState {
// Apply the gradient to the selected layer // Apply the gradient to the selected layer
if let Some(layer) = selected_layer { if let Some(layer) = selected_layer {
if !document.metadata().selected_layers_contains(layer) { if !document.selected_nodes.selected_layers_contains(layer, document.metadata()) {
let nodes = vec![layer.to_node()]; let nodes = vec![layer.to_node()];
responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes });

View File

@ -223,7 +223,7 @@ impl PathToolData {
let _selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>(); let _selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
// Select the first point within the threshold (in pixels) // Select the first point within the threshold (in pixels)
if let Some(selected_points) = shape_editor.select_point(&document.network, &document.document_metadata, input.mouse.position, SELECTION_THRESHOLD, shift) { if let Some(selected_points) = shape_editor.select_point(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD, shift) {
self.start_dragging_point(selected_points, input, document, responses); self.start_dragging_point(selected_points, input, document, responses);
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
@ -298,7 +298,7 @@ impl PathToolData {
// Move the selected points with the mouse // Move the selected points with the mouse
let snapped_position = self.snap_manager.snap_position(responses, document, input.mouse.position); let snapped_position = self.snap_manager.snap_position(responses, document, input.mouse.position);
shape_editor.move_selected_points(&document.network, &document.document_metadata, snapped_position - self.previous_mouse_position, shift, responses); shape_editor.move_selected_points(&document.network, &document.metadata, snapped_position - self.previous_mouse_position, shift, responses);
self.previous_mouse_position = snapped_position; self.previous_mouse_position = snapped_position;
} }
} }
@ -316,7 +316,7 @@ impl Fsm for PathToolFsmState {
match (self, event) { match (self, event) {
(_, PathToolMessage::SelectionChanged) => { (_, PathToolMessage::SelectionChanged) => {
// Set the newly targeted layers to visible // Set the newly targeted layers to visible
let target_layers = document.metadata().selected_layers().collect(); let target_layers = document.selected_nodes.selected_layers(document.metadata()).collect();
shape_editor.set_selected_layers(target_layers); shape_editor.set_selected_layers(target_layers);
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
@ -362,12 +362,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos == tool_data.previous_mouse_position { if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
} else { } else {
shape_editor.select_all_in_quad( shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
&document.network,
&document.document_metadata,
[tool_data.drag_start_pos, tool_data.previous_mouse_position],
!shift_pressed,
);
} }
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
@ -381,12 +376,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos == tool_data.previous_mouse_position { if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
} else { } else {
shape_editor.select_all_in_quad( shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
&document.network,
&document.document_metadata,
[tool_data.drag_start_pos, tool_data.previous_mouse_position],
!shift_pressed,
);
} }
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
responses.add(PathToolMessage::SelectedPointUpdated); responses.add(PathToolMessage::SelectedPointUpdated);
@ -398,16 +388,16 @@ impl Fsm for PathToolFsmState {
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize); let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
let nearest_point = shape_editor let nearest_point = shape_editor
.find_nearest_point_indices(&document.network, &document.document_metadata, input.mouse.position, SELECTION_THRESHOLD) .find_nearest_point_indices(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD)
.map(|(_, nearest_point)| nearest_point); .map(|(_, nearest_point)| nearest_point);
shape_editor.delete_selected_handles_with_zero_length(&document.network, &document.document_metadata, &tool_data.opposing_handle_lengths, responses); shape_editor.delete_selected_handles_with_zero_length(&document.network, &document.metadata, &tool_data.opposing_handle_lengths, responses);
if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD && !shift_pressed { if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD && !shift_pressed {
let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == Some(point)); let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == Some(point));
if clicked_selected { if clicked_selected {
shape_editor.deselect_all(); shape_editor.deselect_all();
shape_editor.select_point(&document.network, &document.document_metadata, input.mouse.position, SELECTION_THRESHOLD, false); shape_editor.select_point(&document.network, &document.metadata, input.mouse.position, SELECTION_THRESHOLD, false);
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
} }
} }
@ -428,9 +418,9 @@ impl Fsm for PathToolFsmState {
} }
(_, PathToolMessage::InsertPoint) => { (_, PathToolMessage::InsertPoint) => {
// First we try and flip the sharpness (if they have clicked on an anchor) // First we try and flip the sharpness (if they have clicked on an anchor)
if !shape_editor.flip_sharp(&document.network, &document.document_metadata, input.mouse.position, SELECTION_TOLERANCE, responses) { if !shape_editor.flip_sharp(&document.network, &document.metadata, input.mouse.position, SELECTION_TOLERANCE, responses) {
// If not, then we try and split the path that may have been clicked upon // If not, then we try and split the path that may have been clicked upon
shape_editor.split(&document.network, &document.document_metadata, input.mouse.position, SELECTION_TOLERANCE, responses); shape_editor.split(&document.network, &document.metadata, input.mouse.position, SELECTION_TOLERANCE, responses);
} }
responses.add(PathToolMessage::SelectedPointUpdated); responses.add(PathToolMessage::SelectedPointUpdated);
@ -443,7 +433,7 @@ impl Fsm for PathToolFsmState {
} }
(_, PathToolMessage::PointerMove { .. }) => self, (_, PathToolMessage::PointerMove { .. }) => self,
(_, PathToolMessage::NudgeSelectedPoints { delta_x, delta_y }) => { (_, PathToolMessage::NudgeSelectedPoints { delta_x, delta_y }) => {
shape_editor.move_selected_points(&document.network, &document.document_metadata, (delta_x, delta_y).into(), true, responses); shape_editor.move_selected_points(&document.network, &document.metadata, (delta_x, delta_y).into(), true, responses);
PathToolFsmState::Ready PathToolFsmState::Ready
} }
@ -454,18 +444,18 @@ impl Fsm for PathToolFsmState {
} }
(_, PathToolMessage::SelectedPointXChanged { new_x }) => { (_, PathToolMessage::SelectedPointXChanged { new_x }) => {
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() { if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
shape_editor.reposition_control_point(&id, responses, &document.network, &document.document_metadata, DVec2::new(new_x, coordinates.y), layer); shape_editor.reposition_control_point(&id, responses, &document.network, &document.metadata, DVec2::new(new_x, coordinates.y), layer);
} }
PathToolFsmState::Ready PathToolFsmState::Ready
} }
(_, PathToolMessage::SelectedPointYChanged { new_y }) => { (_, PathToolMessage::SelectedPointYChanged { new_y }) => {
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() { if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
shape_editor.reposition_control_point(&id, responses, &document.network, &document.document_metadata, DVec2::new(coordinates.x, new_y), layer); shape_editor.reposition_control_point(&id, responses, &document.network, &document.metadata, DVec2::new(coordinates.x, new_y), layer);
} }
PathToolFsmState::Ready PathToolFsmState::Ready
} }
(_, PathToolMessage::SelectedPointUpdated) => { (_, PathToolMessage::SelectedPointUpdated) => {
tool_data.selection_status = get_selection_status(&document.network, &document.document_metadata, shape_editor); tool_data.selection_status = get_selection_status(&document.network, &document.metadata, shape_editor);
self self
} }
(_, PathToolMessage::ManipulatorAngleMakeSmooth) => { (_, PathToolMessage::ManipulatorAngleMakeSmooth) => {

View File

@ -720,7 +720,7 @@ fn should_extend(document: &DocumentMessageHandler, pos: DVec2, tolerance: f64)
let mut best = None; let mut best = None;
let mut best_distance_squared = tolerance * tolerance; let mut best_distance_squared = tolerance * tolerance;
for layer in document.metadata().selected_layers() { for layer in document.selected_nodes.selected_layers(document.metadata()) {
let viewspace = document.metadata().transform_to_viewport(layer); let viewspace = document.metadata().transform_to_viewport(layer);
let subpaths = get_subpaths(layer, &document.network)?; let subpaths = get_subpaths(layer, &document.network)?;

View File

@ -381,27 +381,32 @@ impl Fsm for SelectToolFsmState {
}; };
match (self, event) { match (self, event) {
(_, SelectToolMessage::Overlays(mut overlay_context)) => { (_, SelectToolMessage::Overlays(mut overlay_context)) => {
let selected_layers_count = document.metadata().selected_layers().count(); let selected_layers_count = document.selected_nodes.selected_layers(document.metadata()).count();
tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count; tool_data.selected_layers_changed = selected_layers_count != tool_data.selected_layers_count;
tool_data.selected_layers_count = selected_layers_count; tool_data.selected_layers_count = selected_layers_count;
// Outline selected layers // Outline selected layers
for layer in document.selected_visible_layers() { for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) {
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer)); overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
} }
// Get the layer the user is hovering over // Get the layer the user is hovering over
let click = document.click(input.mouse.position, &document.network); let click = document.click(input.mouse.position, &document.network);
let not_selected_click = click.filter(|&hovered_layer| !document.metadata().selected_layers_contains(hovered_layer)); let not_selected_click = click.filter(|&hovered_layer| !document.selected_nodes.selected_layers_contains(hovered_layer, document.metadata()));
if let Some(layer) = not_selected_click { if let Some(layer) = not_selected_click {
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer)); overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
} }
// Update bounds // Update bounds
let transform = document.selected_visible_layers().next().map(|layer| document.metadata().transform_to_viewport(layer)); let transform = document
.selected_nodes
.selected_visible_layers(document.network(), document.metadata())
.next()
.map(|layer| document.metadata().transform_to_viewport(layer));
let transform = transform.unwrap_or(DAffine2::IDENTITY); let transform = transform.unwrap_or(DAffine2::IDENTITY);
let bounds = document let bounds = document
.selected_visible_layers() .selected_nodes
.selected_visible_layers(document.network(), document.metadata())
.filter_map(|layer| { .filter_map(|layer| {
document document
.metadata() .metadata()
@ -462,7 +467,7 @@ impl Fsm for SelectToolFsmState {
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position)) .map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
.unwrap_or_default(); .unwrap_or_default();
let mut selected: Vec<_> = document.selected_visible_layers().collect(); let mut selected: Vec<_> = document.selected_nodes.selected_visible_layers(document.network(), document.metadata()).collect();
let intersection = document.click(input.mouse.position, &document.network); let intersection = document.click(input.mouse.position, &document.network);
// If the user is dragging the bounding box bounds, go into ResizingBounds mode. // If the user is dragging the bounding box bounds, go into ResizingBounds mode.
@ -491,7 +496,7 @@ impl Fsm for SelectToolFsmState {
&tool_data.layers_dragging, &tool_data.layers_dragging,
responses, responses,
&document.network, &document.network,
&document.document_metadata, &document.metadata,
None, None,
&ToolType::Select, &ToolType::Select,
); );
@ -510,7 +515,7 @@ impl Fsm for SelectToolFsmState {
&selected, &selected,
responses, responses,
&document.network, &document.network,
&document.document_metadata, &document.metadata,
None, None,
&ToolType::Select, &ToolType::Select,
); );
@ -630,7 +635,7 @@ impl Fsm for SelectToolFsmState {
selected, selected,
responses, responses,
&document.network, &document.network,
&document.document_metadata, &document.metadata,
None, None,
&ToolType::Select, &ToolType::Select,
); );
@ -665,7 +670,7 @@ impl Fsm for SelectToolFsmState {
&tool_data.layers_dragging, &tool_data.layers_dragging,
responses, responses,
&document.network, &document.network,
&document.document_metadata, &document.metadata,
None, None,
&ToolType::Select, &ToolType::Select,
); );
@ -723,7 +728,11 @@ impl Fsm for SelectToolFsmState {
let intersection = document.intersect_quad(quad, &document.network); let intersection = document.intersect_quad(quad, &document.network);
if let Some(path) = intersection.last() { if let Some(path) = intersection.last() {
let replacement_selected_layers: Vec<_> = document.metadata().selected_layers().filter(|&layer| !path.starts_with(layer, document.metadata())).collect(); let replacement_selected_layers: Vec<_> = document
.selected_nodes
.selected_layers(document.metadata())
.filter(|&layer| !path.starts_with(layer, document.metadata()))
.collect();
tool_data.layers_dragging.clear(); tool_data.layers_dragging.clear();
tool_data.layers_dragging.extend(replacement_selected_layers.iter()); tool_data.layers_dragging.extend(replacement_selected_layers.iter());
@ -791,7 +800,7 @@ impl Fsm for SelectToolFsmState {
(SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => { (SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
let quad = tool_data.selection_quad(); let quad = tool_data.selection_quad();
let new_selected: HashSet<_> = document.intersect_quad(quad, &document.network).collect(); let new_selected: HashSet<_> = document.intersect_quad(quad, &document.network).collect();
let current_selected: HashSet<_> = document.metadata().selected_layers().collect(); let current_selected: HashSet<_> = document.selected_nodes.selected_layers(document.metadata()).collect();
if new_selected != current_selected { if new_selected != current_selected {
tool_data.layers_dragging = new_selected.into_iter().collect(); tool_data.layers_dragging = new_selected.into_iter().collect();
responses.add(DocumentMessage::StartTransaction); responses.add(DocumentMessage::StartTransaction);
@ -804,7 +813,7 @@ impl Fsm for SelectToolFsmState {
SelectToolFsmState::Ready SelectToolFsmState::Ready
} }
(SelectToolFsmState::Ready, SelectToolMessage::Enter) => { (SelectToolFsmState::Ready, SelectToolMessage::Enter) => {
let mut selected_layers = document.metadata().selected_layers(); let mut selected_layers = document.selected_nodes.selected_layers(document.metadata());
if let Some(layer) = selected_layers.next() { if let Some(layer) = selected_layers.next() {
// Check that only one layer is selected // Check that only one layer is selected
@ -832,7 +841,7 @@ impl Fsm for SelectToolFsmState {
&tool_data.layers_dragging, &tool_data.layers_dragging,
responses, responses,
&document.network, &document.network,
&document.document_metadata, &document.metadata,
None, None,
&ToolType::Select, &ToolType::Select,
); );
@ -908,7 +917,9 @@ impl Fsm for SelectToolFsmState {
fn drag_shallowest_manipulation(responses: &mut VecDeque<Message>, selected: Vec<LayerNodeIdentifier>, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) { fn drag_shallowest_manipulation(responses: &mut VecDeque<Message>, selected: Vec<LayerNodeIdentifier>, tool_data: &mut SelectToolData, document: &DocumentMessageHandler) {
let layer = selected[0]; let layer = selected[0];
let ancestor = layer.ancestors(document.metadata()).find(|&ancestor| document.metadata().selected_layers_contains(ancestor)); let ancestor = layer
.ancestors(document.metadata())
.find(|&ancestor| document.selected_nodes.selected_layers_contains(ancestor, document.metadata()));
let new_selected = ancestor.unwrap_or_else(|| layer.child_of_root(document.metadata())); let new_selected = ancestor.unwrap_or_else(|| layer.child_of_root(document.metadata()));
@ -932,15 +943,16 @@ fn drag_deepest_manipulation(responses: &mut VecDeque<Message>, mut selected: Ve
} }
fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) { fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
if document.metadata().selected_layers_contains(layer) { if document.selected_nodes.selected_layers_contains(layer, document.metadata()) {
responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path }); responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path });
return; return;
} }
let Some(new_selected) = layer let Some(new_selected) = layer.ancestors(document.metadata()).find(|ancestor| {
.ancestors(document.metadata()) ancestor
.find(|ancestor| ancestor.parent(document.metadata()).is_some_and(|parent| document.metadata().selected_layers_contains(parent))) .parent(document.metadata())
else { .is_some_and(|parent| document.selected_nodes.selected_layers_contains(parent, document.metadata()))
}) else {
return; return;
}; };

View File

@ -344,9 +344,9 @@ impl TextToolData {
} }
fn can_edit_selected(document: &DocumentMessageHandler) -> Option<LayerNodeIdentifier> { fn can_edit_selected(document: &DocumentMessageHandler) -> Option<LayerNodeIdentifier> {
let mut selected_layers = document.metadata().selected_layers(); let mut selected_layers = document.selected_nodes.selected_layers(document.metadata());
let layer = selected_layers.next()?; let layer = selected_layers.next()?;
// Check that only one layer is selected // Check that only one layer is selected
if selected_layers.next().is_some() { if selected_layers.next().is_some() {
return None; return None;
@ -392,7 +392,7 @@ impl Fsm for TextToolFsmState {
TextToolFsmState::Editing TextToolFsmState::Editing
} }
(_, TextToolMessage::Overlays(mut overlay_context)) => { (_, TextToolMessage::Overlays(mut overlay_context)) => {
for layer in document.metadata().selected_layers() { for layer in document.selected_nodes.selected_layers(document.metadata()) {
let Some((text, font, font_size)) = graph_modification_utils::get_text(layer, &document.network) else { let Some((text, font, font_size)) = graph_modification_utils::get_text(layer, &document.network) else {
continue; continue;
}; };

View File

@ -48,7 +48,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
let using_path_tool = tool_data.active_tool_type == ToolType::Path; let using_path_tool = tool_data.active_tool_type == ToolType::Path;
let selected_layers = document.metadata().selected_layers().collect::<Vec<_>>(); let selected_layers = document.selected_nodes.selected_layers(document.metadata()).collect::<Vec<_>>();
let mut selected = Selected::new( let mut selected = Selected::new(
&mut self.original_transforms, &mut self.original_transforms,
@ -56,7 +56,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
&selected_layers, &selected_layers,
responses, responses,
&document.network, &document.network,
&document.document_metadata, &document.metadata,
Some(shape_editor), Some(shape_editor),
&tool_data.active_tool_type, &tool_data.active_tool_type,
); );
@ -222,7 +222,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
self.mouse_position = input.mouse.position; self.mouse_position = input.mouse.position;
} }
SelectionChanged => { SelectionChanged => {
let target_layers = document.metadata().selected_layers().collect(); let target_layers = document.selected_nodes.selected_layers(document.metadata()).collect();
shape_editor.set_selected_layers(target_layers); shape_editor.set_selected_layers(target_layers);
} }
TypeBackspace => self.transform_operation.grs_typed(self.typing.type_backspace(), &mut selected, self.snap), TypeBackspace => self.transform_operation.grs_typed(self.typing.type_backspace(), &mut selected, self.snap),

View File

@ -449,7 +449,7 @@ impl NodeGraphExecutor {
let render_config = RenderConfig { let render_config = RenderConfig {
viewport: Footprint { viewport: Footprint {
transform: document.document_metadata.document_to_viewport, transform: document.metadata.document_to_viewport,
resolution: viewport_resolution, resolution: viewport_resolution,
..Default::default() ..Default::default()
}, },
@ -477,7 +477,9 @@ impl NodeGraphExecutor {
// Calculate the bounding box of the region to be exported // Calculate the bounding box of the region to be exported
let bounds = match export_config.bounds { let bounds = match export_config.bounds {
ExportBounds::AllArtwork => document.metadata().document_bounds_document_space(!export_config.transparent_background), ExportBounds::AllArtwork => document.metadata().document_bounds_document_space(!export_config.transparent_background),
ExportBounds::Selection => document.metadata().selected_bounds_document_space(!export_config.transparent_background), ExportBounds::Selection => document
.metadata()
.selected_bounds_document_space(!export_config.transparent_background, document.metadata(), &document.selected_nodes),
ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id), ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id),
} }
.ok_or_else(|| "No bounding box".to_string())?; .ok_or_else(|| "No bounding box".to_string())?;
@ -558,8 +560,8 @@ impl NodeGraphExecutor {
let node_graph_output = result.map_err(|e| format!("Node graph evaluation failed: {e:?}"))?; let node_graph_output = result.map_err(|e| format!("Node graph evaluation failed: {e:?}"))?;
document.document_metadata.update_transforms(new_upstream_transforms); document.metadata.update_transforms(new_upstream_transforms);
document.document_metadata.update_click_targets(new_click_targets); document.metadata.update_click_targets(new_click_targets);
let execution_context = self.futures.remove(&execution_id).ok_or_else(|| "Invalid generation ID".to_string())?; let execution_context = self.futures.remove(&execution_id).ok_or_else(|| "Invalid generation ID".to_string())?;
if let Some(export_config) = execution_context.export_config { if let Some(export_config) = execution_context.export_config {

View File

@ -13,7 +13,7 @@ use fern::colors::{Color, ColoredLevelConfig};
// use http::{Response, StatusCode}; // use http::{Response, StatusCode};
use std::cell::RefCell; use std::cell::RefCell;
// use std::collections::HashMap; // use std::collections::HashMap;
use std::sync::Arc; // use std::sync::Arc;
// use std::sync::Mutex; // use std::sync::Mutex;
thread_local! { thread_local! {