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 layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_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.metadata.all_layers().collect::<Vec<_>>();
assert_eq!(layers_before_copy.len(), 3);
assert_eq!(layers_after_copy.len(), 4);
@ -329,7 +329,7 @@ mod test {
let mut editor = create_editor_with_three_layers();
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(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 layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_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.metadata.all_layers().collect::<Vec<_>>();
assert_eq!(layers_before_copy.len(), 3);
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 layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_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.metadata.all_layers().collect::<Vec<_>>();
let [original_folder, original_freehand, original_line, original_ellipse, original_polygon, original_rect] = layers_before_copy[..] else {
panic!("Layers before incorrect");
};
@ -413,7 +413,7 @@ mod test {
let mut editor = create_editor_with_three_layers();
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 shape_id = layers.next().expect("shape");
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 layers_before_copy = document_before_copy.document_metadata.all_layers().collect::<Vec<_>>();
let layers_after_copy = document_after_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.metadata.all_layers().collect::<Vec<_>>();
assert_eq!(layers_before_copy.len(), 3);
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() {
let mut index = 0;
let artboards = document
.document_metadata
.metadata
.all_layers()
.filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network, "Artboard"))
.map(|layer| {
@ -92,7 +92,7 @@ impl MessageHandler<DialogMessage, DialogData<'_>> for DialogMessageHandler {
self.export_dialog = ExportDialogMessageHandler {
scale_factor: 1.,
artboards,
has_selection: document.metadata().selected_layers().next().is_some(),
has_selection: document.selected_nodes.selected_layers(document.metadata()).next().is_some(),
..Default::default()
};
self.export_dialog.send_dialog_to_frontend(responses);

View file

@ -1,7 +1,7 @@
use super::utility_types::{FrontendDocumentDetails, MouseCursorIcon};
use crate::messages::layout::utility_types::widget_prelude::*;
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::tool::utility_types::HintData;

View file

@ -1,15 +1,16 @@
use super::utility_types::error::EditorError;
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::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::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::utility_types::clipboards::Clipboard;
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::nodes::RawBuffer;
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::*;
use crate::messages::tool::common_functionality::graph_modification_utils::{get_blend_mode, get_opacity};
@ -48,6 +49,10 @@ pub struct DocumentMessageHandler {
// ============================================
#[serde(default = "default_network")]
pub network: NodeNetwork,
#[serde(default = "default_selected_nodes")]
pub selected_nodes: SelectedNodes,
#[serde(default = "default_collapsed")]
pub collapsed: CollapsedLayers,
#[serde(default = "default_name")]
pub name: String,
#[serde(default = "default_commit_hash")]
@ -62,8 +67,6 @@ pub struct DocumentMessageHandler {
overlays_visible: bool,
#[serde(default = "default_rulers_visible")]
pub rulers_visible: bool,
#[serde(default = "default_collapsed")]
pub collapsed: Vec<LayerNodeIdentifier>,
// =============================================
// Fields omitted from the saved document format
// =============================================
@ -85,7 +88,7 @@ pub struct DocumentMessageHandler {
#[serde(skip)]
layer_range_selection_reference: Option<LayerNodeIdentifier>,
#[serde(skip)]
pub document_metadata: DocumentMetadata,
pub metadata: DocumentMetadata,
}
impl Default for DocumentMessageHandler {
@ -102,6 +105,8 @@ impl Default for DocumentMessageHandler {
// Fields that are saved in the document format
// ============================================
network: root_network(),
selected_nodes: SelectedNodes::default(),
collapsed: CollapsedLayers::default(),
name: DEFAULT_DOCUMENT_NAME.to_string(),
commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(),
navigation: PTZ::default(),
@ -109,7 +114,6 @@ impl Default for DocumentMessageHandler {
view_mode: ViewMode::default(),
overlays_visible: true,
rulers_visible: true,
collapsed: Vec::new(),
// =============================================
// Fields omitted from the saved document format
// =============================================
@ -121,7 +125,7 @@ impl Default for DocumentMessageHandler {
graph_view_overlay_open: false,
snapping_state: SnappingState::default(),
layer_range_selection_reference: None,
document_metadata: Default::default(),
metadata: Default::default(),
}
}
}
@ -131,6 +135,14 @@ fn default_network() -> NodeNetwork {
DocumentMessageHandler::default().network
}
#[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 {
DocumentMessageHandler::default().name
}
@ -158,10 +170,6 @@ fn default_overlays_visible() -> bool {
fn default_rulers_visible() -> bool {
DocumentMessageHandler::default().rulers_visible
}
#[inline(always)]
fn default_collapsed() -> Vec<LayerNodeIdentifier> {
DocumentMessageHandler::default().collapsed
}
fn root_network() -> NodeNetwork {
{
@ -245,13 +253,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
self.navigation_handler.process_message(
message,
responses,
(
&self.document_metadata,
document_bounds,
ipp,
self.selected_visible_layers_bounding_box_viewport(),
&mut self.navigation,
),
(&self.metadata, document_bounds, ipp, self.selected_visible_layers_bounding_box_viewport(), &mut self.navigation),
);
}
#[remain::unsorted]
@ -265,7 +267,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
executor,
document_name: self.name.as_str(),
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
.process_message(message, responses, (persistent_data, properties_panel_message_handler_data));
@ -277,7 +280,8 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses,
NodeGraphHandlerData {
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_name: self.name.as_str(),
collapsed: &mut self.collapsed,
@ -287,7 +291,17 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
);
}
#[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
AbortTransaction => {
@ -312,7 +326,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
AlignAggregate::Max => combined_box[1],
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 {
continue;
};
@ -366,7 +380,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
self.backup(responses);
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() });
}
@ -381,7 +395,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
DocumentStructureChanged => {
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();
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() {
let center = (max + min) / 2.;
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 {
layer,
transform: DAffine2::from_scale(scale),
@ -426,7 +440,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
GroupSelectedLayers => {
// 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());
@ -467,7 +484,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
}
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
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 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
if !ipp.keyboard.key(resize) {
responses.add(GraphOperationMessage::TransformChange {
@ -506,7 +523,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
});
}
// 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 new_size = size + if opposite_corner { -delta } else { delta };
let enlargement_factor = new_size / size;
@ -636,8 +653,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
})
}
SelectAllLayers => {
let all = self.metadata().all_layers_except_artboards().map(|layer| layer.to_node()).collect();
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: all });
let metadata = self.metadata();
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 => {
responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: 1 });
@ -674,7 +693,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
} else {
if 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] });
} else {
responses.add_front(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
@ -700,7 +719,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
SetBlendModeForSelectedLayers { blend_mode } => {
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 });
}
}
@ -708,7 +727,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
self.backup(responses);
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 });
}
}
@ -742,10 +761,10 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
StartTransaction => self.backup(responses),
ToggleLayerExpansion { id } => {
let layer = LayerNodeIdentifier::new(id, self.network());
if self.collapsed.contains(&layer) {
self.collapsed.retain(|&collapsed_layer| collapsed_layer != layer);
if self.collapsed.0.contains(&layer) {
self.collapsed.0.retain(|&collapsed_layer| collapsed_layer != layer);
} else {
self.collapsed.push(layer);
self.collapsed.0.push(layer);
}
responses.add(NodeGraphMessage::RunDocumentGraph);
}
@ -761,7 +780,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
UngroupSelectedLayers => {
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 {
// Select all the children of the folder
@ -784,7 +803,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
responses.add(DocumentMessage::CommitTransaction);
}
UpdateDocumentTransform { transform } => {
self.document_metadata.document_to_viewport = transform;
self.metadata.document_to_viewport = transform;
responses.add(DocumentMessage::RenderRulers);
responses.add(DocumentMessage::RenderScrollbars);
responses.add(NodeGraphMessage::RunDocumentGraph);
@ -810,44 +829,28 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> for DocumentMessageHand
}
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
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;
self.document_metadata
let document_quad = self.metadata.document_to_viewport.inverse() * viewport_quad;
self.metadata
.root()
.decendants(&self.document_metadata)
.filter(|&layer| self.layer_visible(layer))
.decendants(&self.metadata)
.filter(|&layer| self.selected_nodes.layer_visible(layer, &self.network(), &self.metadata()))
.filter(|&layer| !is_artboard(layer, network))
.filter_map(|layer| self.document_metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| {
target
.iter()
.any(move |target| target.intersect_rectangle(document_quad, self.document_metadata.transform_to_document(*layer)))
})
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(move |target| target.intersect_rectangle(document_quad, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
/// Find all of the layers that were clicked on from a viewport space location
pub fn click_xray(&self, viewport_location: DVec2) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
let point = self.document_metadata.document_to_viewport.inverse().transform_point2(viewport_location);
self.document_metadata
let point = self.metadata.document_to_viewport.inverse().transform_point2(viewport_location);
self.metadata
.root()
.decendants(&self.document_metadata)
.filter(|&layer| self.layer_visible(layer))
.filter_map(|layer| self.document_metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| {
target
.iter()
.any(|target: &ClickTarget| target.intersect_point(point, self.document_metadata.transform_to_document(*layer)))
})
.decendants(&self.metadata)
.filter(|&layer| self.selected_nodes.layer_visible(layer, &self.network(), &self.metadata()))
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
.filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer))))
.map(|(layer, _)| layer)
}
@ -858,8 +861,9 @@ impl DocumentMessageHandler {
/// Get the combined bounding box of the click targets of the selected visible layers in viewport space
pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_visible_layers()
.filter_map(|layer| self.document_metadata.bounding_box_viewport(layer))
self.selected_nodes
.selected_visible_layers(&self.network(), &self.metadata())
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
.reduce(graphene_core::renderer::Quad::combine_bounds)
}
@ -868,7 +872,7 @@ impl DocumentMessageHandler {
}
pub fn metadata(&self) -> &DocumentMetadata {
&self.document_metadata
&self.metadata
}
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 {
let mut document = Self { name, ..Self::default() };
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 });
document
@ -909,7 +913,7 @@ impl DocumentMessageHandler {
for layer_node in folder.children(self.metadata()) {
data_section.push(layer_node.to_node().0);
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);
// TODO: Skip if folder is not expanded.
@ -1066,7 +1070,7 @@ impl DocumentMessageHandler {
pub fn new_layer_parent(&self) -> LayerNodeIdentifier {
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())
}
@ -1278,7 +1282,7 @@ impl DocumentMessageHandler {
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).
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.
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>) {
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() {
-1 => selected_layers.next(),
@ -1429,7 +1433,7 @@ impl DocumentMessageHandler {
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;
DeleteSelectedLayers,
DuplicateSelectedLayers,

View file

@ -54,7 +54,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
&mut self,
message: NavigationMessage,
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::*;
@ -73,8 +73,8 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
bounds: [pos1, pos2],
prevent_zoom_past_100,
} => {
let v1 = document_metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
let v2 = document_metadata.document_to_viewport.inverse().transform_point2(ipp.viewport_bounds.size());
let v1 = metadata.document_to_viewport.inverse().transform_point2(DVec2::ZERO);
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 size = (pos2 - pos1) / (v2 - v1);
@ -96,7 +96,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
}
FitViewportToSelection => {
if let Some(bounds) = selection_bounds {
let transform = document_metadata.document_to_viewport.inverse();
let transform = metadata.document_to_viewport.inverse();
responses.add(FitViewportToBounds {
bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])],
prevent_zoom_past_100: false,
@ -257,7 +257,7 @@ impl MessageHandler<NavigationMessage, (&DocumentMetadata, Option<[DVec2; 2]>, &
responses.add(TransformCanvasEnd { abort_transform });
}
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;
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 };
}
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;
responses.add(BroadcastEvent::DocumentIsDirty);

View file

@ -1,5 +1,6 @@
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::nodes::{CollapsedLayers, SelectedNodes};
use crate::messages::prelude::*;
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 {
warn!("Deleting layer node that does not exist");
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(NodeGraphMessage::RunDocumentGraph);
}
}
impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler)> for GraphOperationMessageHandler {
fn process_message(
&mut self,
message: GraphOperationMessage,
responses: &mut VecDeque<Message>,
(document_network, document_metadata, collapsed, node_graph): (&mut NodeNetwork, &mut DocumentMetadata, &mut Vec<LayerNodeIdentifier>, &mut NodeGraphMessageHandler),
) {
pub struct GraphOperationHandlerData<'a> {
pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub selected_nodes: &'a mut SelectedNodes,
pub collapsed: &'a mut CollapsedLayers,
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 {
GraphOperationMessage::FillSet { layer, fill } => {
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) {
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 {
id,
@ -698,14 +710,14 @@ impl MessageHandler<GraphOperationMessage, (&mut NodeNetwork, &mut DocumentMetad
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 } => {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) {
modify_inputs.insert_vector_data(subpaths, layer);
}
load_network_structure(document_network, document_metadata, collapsed);
load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
}
GraphOperationMessage::NewTextLayer {
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) {
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 } => {
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 } => {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
modify_inputs.delete_layer(id);
load_network_structure(document_network, document_metadata, collapsed);
modify_inputs.delete_layer(id, selected_nodes);
load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
}
GraphOperationMessage::ClearArtboards => {
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::<Vec<_>>();
for layer in layer_nodes {
if modify_inputs.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>) {
document_metadata.load_structure(document_network);
collapsed.retain(|&layer| document_metadata.layer_exists(layer));
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, selected_nodes);
collapsed.0.retain(|&layer| document_metadata.layer_exists(layer));
}

View file

@ -52,11 +52,11 @@ pub struct LayerBounds {
impl LayerBounds {
/// 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 {
bounds: document_metadata.nonzero_bounding_box(layer),
bounds: metadata.nonzero_bounding_box(layer),
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::layout::utility_types::widget_prelude::*;
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 graph_craft::document::value::TaggedValue;
@ -174,20 +174,20 @@ impl NodeGraphMessageHandler {
}
/// 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) {
let mut widgets = Vec::new();
// Don't allow disabling input or output nodes
let mut selected_nodes = document_metadata.selected_nodes().filter(|&&id| !network.inputs.contains(&id) && !network.original_outputs_contain(id));
let mut 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 selected_nodes.next().is_some() {
if selection.next().is_some() {
// 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
let multiple_nodes = selected_nodes.next().is_some();
let multiple_nodes = selection.next().is_some();
// Generate the enable or disable button accordingly
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
let mut selected_nodes = document_metadata.selected_nodes();
if let (Some(&node_id), None) = (selected_nodes.next(), selected_nodes.next()) {
let mut selection = selected_nodes.selected_nodes();
if let (Some(&node_id), None) = (selection.next(), selection.next()) {
// Is this node the current output
let is_output = network.outputs_contain(node_id);
@ -225,7 +225,7 @@ impl NodeGraphMessageHandler {
}
/// 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;
for segment in &self.network {
@ -239,7 +239,7 @@ impl NodeGraphMessageHandler {
// First, we filter all the selections into layers and nodes
let (mut layers, mut nodes) = (Vec::new(), Vec::new());
for node_id in context.metadata.selected_nodes() {
for node_id in selected_nodes.selected_nodes() {
if let Some(layer_or_node) = network.nodes.get(node_id) {
if layer_or_node.is_layer() {
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>) {
document_metadata.load_structure(&network);
fn send_graph(
&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
.nodes
@ -371,9 +379,9 @@ impl NodeGraphMessageHandler {
if node.is_layer() {
let layer = LayerNodeIdentifier::new(node_id, network);
let layer_classification = {
if document_metadata.is_artboard(layer) {
if metadata.is_artboard(layer) {
LayerClassification::Artboard
} else if document_metadata.is_folder(layer) {
} else if metadata.is_folder(layer) {
LayerClassification::Folder
} else {
LayerClassification::Layer
@ -391,9 +399,9 @@ impl NodeGraphMessageHandler {
let data = LayerPanelEntry {
id: node_id,
layer_classification,
expanded: layer.has_children(document_metadata) && !collapsed.contains(&layer),
depth: layer.ancestors(document_metadata).count() - 1,
parent_id: layer.parent(document_metadata).map(|parent| parent.to_node()),
expanded: layer.has_children(metadata) && !collapsed.0.contains(&layer),
depth: layer.ancestors(metadata).count() - 1,
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?
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?
@ -413,10 +421,10 @@ impl NodeGraphMessageHandler {
}
/// 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>) {
self.update_selection_action_buttons(document_network, document_metadata, responses);
fn update_selected(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque<Message>) {
self.update_selection_action_buttons(document_network, selected_nodes, responses);
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.
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 {
return false;
};
@ -495,7 +503,7 @@ impl NodeGraphMessageHandler {
return false;
}
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);
true
}
@ -521,9 +529,10 @@ impl NodeGraphMessageHandler {
pub struct NodeGraphHandlerData<'a> {
pub document_network: &'a mut NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub selected_nodes: &'a mut SelectedNodes,
pub document_id: DocumentId,
pub document_name: &'a str,
pub collapsed: &'a mut Vec<LayerNodeIdentifier>,
pub collapsed: &'a mut CollapsedLayers,
pub input: &'a InputPreprocessorMessageHandler,
pub graph_view_overlay_open: bool,
}
@ -533,6 +542,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
let NodeGraphHandlerData {
document_network,
document_metadata,
selected_nodes,
document_id,
collapsed,
graph_view_overlay_open,
@ -545,14 +555,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
on: BroadcastEvent::SelectionChanged,
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 => {
self.update_selection_action_buttons(document_network, document_metadata, responses);
self.update_selected(document_network, document_metadata, responses);
if document_metadata.selected_layers().count() <= 1 {
self.update_selection_action_buttons(document_network, selected_nodes, responses);
self.update_selected(document_network, selected_nodes, responses);
if selected_nodes.selected_layers(document_metadata).count() <= 1 {
responses.add(DocumentMessage::SetRangeSelectionLayer {
new_layer: document_metadata.selected_layers().next(),
new_layer: selected_nodes.selected_layers(document_metadata).next(),
});
}
responses.add(NodeGraphMessage::RunDocumentGraph);
@ -594,7 +604,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
};
// 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();
// 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 });
}
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 } => {
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 });
}
if let Some(network) = document_network.nested_network(&self.network) {
// Only generate node graph if one of the selected nodes is connected to the output
if document_metadata.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
if selected_nodes.selected_nodes().any(|&node_id| network.connected_to_output(node_id)) {
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) {
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 => {
if let Some(network) = document_network.nested_network(&self.network) {
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);
// Copy the selected nodes
let copied_nodes = Self::copy_nodes(network, new_ids).collect::<Vec<_>>();
// Select the new nodes
document_metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
selected_nodes.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id));
responses.add(BroadcastEvent::SelectionChanged);
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 });
}
self.update_selected(document_network, document_metadata, responses);
self.update_selected(document_network, selected_nodes, responses);
}
}
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
document_metadata.clear_selected_nodes();
selected_nodes.clear_selected_nodes();
responses.add(BroadcastEvent::SelectionChanged);
for _ in 0..depth_of_nesting {
self.network.pop();
}
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 } => {
let Some(network) = document_network.nested_network(&self.network) else {
@ -761,12 +771,12 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
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) {
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 } => {
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 });
}
NodeGraphMessage::SelectedNodesAdd { nodes } => {
document_metadata.add_selected_nodes(nodes);
selected_nodes.add_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged);
}
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);
}
NodeGraphMessage::SelectedNodesSet { nodes } => {
document_metadata.set_selected_nodes(nodes);
selected_nodes.set_selected_nodes(nodes);
responses.add(BroadcastEvent::SelectionChanged);
responses.add(PropertiesPanelMessage::Refresh);
}
NodeGraphMessage::SendGraph => {
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 } => {
@ -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();
*node_input = input;
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 => {
if let Some(network) = document_network.nested_network(&self.network) {
responses.add(DocumentMessage::StartTransaction);
let new_hidden = !document_metadata.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in document_metadata.selected_nodes() {
let new_hidden = !selected_nodes.selected_nodes().any(|id| network.disabled.contains(id));
for &node_id in selected_nodes.selected_nodes() {
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);
}
}
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 } => {
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) {
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);
}
NodeGraphMessage::UpdateNewNodeGraph => {
if let Some(network) = document_network.nested_network(&self.network) {
document_metadata.clear_selected_nodes();
selected_nodes.clear_selected_nodes();
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();
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 } => {
self.resolved_types = resolved_types;
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 {

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
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();
assert_eq!(inputs.len(), self.inputs.len(), "Inputs passed from the graph must be equal to the number required");
DocumentNode {
@ -2927,7 +2927,7 @@ impl DocumentNodeDefinition {
inputs,
has_primary_output: self.has_primary_output,
implementation: self.generate_implementation(),
metadata: document_metadata,
metadata,
manual_composition: self.manual_composition.clone(),
..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.
/// `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 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

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) {
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 transform = document.metadata().transform_to_viewport(layer);
let selected = shape_editor.selected_shape_state.get(&layer);

View file

@ -15,10 +15,10 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
let PropertiesPanelMessageHandlerData {
node_graph_message_handler,
executor,
document_network,
document_metadata,
document_network: network,
document_metadata: metadata,
selected_nodes,
document_name,
..
} = data;
match message {
@ -38,11 +38,11 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
responses,
nested_path: &node_graph_message_handler.network,
executor,
network: document_network,
metadata: document_metadata,
network,
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 {
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::nodes::SelectedNodes;
use crate::messages::prelude::NodeGraphMessageHandler;
use crate::node_graph_executor::NodeGraphExecutor;
@ -8,6 +9,7 @@ pub struct PropertiesPanelMessageHandlerData<'a> {
pub document_name: &'a str,
pub document_network: &'a NodeNetwork,
pub document_metadata: &'a mut DocumentMetadata,
pub selected_nodes: &'a SelectedNodes,
pub node_graph_message_handler: &'a NodeGraphMessageHandler,
pub executor: &'a mut NodeGraphExecutor,
}

View file

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

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 document_metadata;
pub mod error;
pub mod layer_panel;
pub mod misc;
pub mod nodes;
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>| {
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 {
continue;
};
@ -184,7 +187,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
.collect(),
)
.collect(),
selected: active_document.metadata().selected_layers_contains(layer),
selected: active_document.selected_nodes.selected_layers_contains(layer, active_document.metadata()),
collapsed: false,
});
}
@ -526,7 +529,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
);
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;
Copy,
Cut,

View file

@ -45,7 +45,7 @@ impl Pivot {
/// Recomputes the pivot position and transform.
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 {
// If no layers are selected then we revert things back to default
self.normalized_pivot = DVec2::splat(0.5);
@ -65,8 +65,9 @@ impl Pivot {
} else {
// If more than one layer is selected we use the AABB with the mean of the pivots
let xy_summation = document
.selected_visible_layers()
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.document_metadata))
.selected_nodes
.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)
.unwrap_or_default();
@ -100,7 +101,7 @@ impl Pivot {
/// Sets the viewport position of the pivot for all selected layers.
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
for layer in document.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 pivot = transform.inverse().transform_point2(position);
// 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> {
self.transform = DAffine2::IDENTITY;
if document.metadata().selected_layers().count() != 1 {
if document.selected_nodes.selected_layers(document.metadata()).count() != 1 {
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;
};

View file

@ -295,7 +295,7 @@ impl Fsm for GradientToolFsmState {
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
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 transform = gradient_space_transform(layer, document);
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
@ -366,7 +366,7 @@ impl Fsm for GradientToolFsmState {
self
}
(_, 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 transform = gradient_space_transform(layer, document);
@ -407,7 +407,7 @@ impl Fsm for GradientToolFsmState {
let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
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 transform = gradient_space_transform(layer, document);
@ -448,7 +448,7 @@ impl Fsm for GradientToolFsmState {
// Apply the gradient to the 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()];
responses.add(NodeGraphMessage::SelectedNodesSet { nodes });

View file

@ -223,7 +223,7 @@ impl PathToolData {
let _selected_layers = shape_editor.selected_layers().cloned().collect::<Vec<_>>();
// Select the first point within the threshold (in pixels)
if let Some(selected_points) = shape_editor.select_point(&document.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);
responses.add(OverlaysMessage::Draw);
@ -298,7 +298,7 @@ impl PathToolData {
// Move the selected points with the mouse
let snapped_position = self.snap_manager.snap_position(responses, document, input.mouse.position);
shape_editor.move_selected_points(&document.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;
}
}
@ -316,7 +316,7 @@ impl Fsm for PathToolFsmState {
match (self, event) {
(_, PathToolMessage::SelectionChanged) => {
// 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);
responses.add(OverlaysMessage::Draw);
@ -362,12 +362,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
} else {
shape_editor.select_all_in_quad(
&document.network,
&document.document_metadata,
[tool_data.drag_start_pos, tool_data.previous_mouse_position],
!shift_pressed,
);
shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
}
responses.add(OverlaysMessage::Draw);
@ -381,12 +376,7 @@ impl Fsm for PathToolFsmState {
if tool_data.drag_start_pos == tool_data.previous_mouse_position {
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] });
} else {
shape_editor.select_all_in_quad(
&document.network,
&document.document_metadata,
[tool_data.drag_start_pos, tool_data.previous_mouse_position],
!shift_pressed,
);
shape_editor.select_all_in_quad(&document.network, &document.metadata, [tool_data.drag_start_pos, tool_data.previous_mouse_position], !shift_pressed);
}
responses.add(OverlaysMessage::Draw);
responses.add(PathToolMessage::SelectedPointUpdated);
@ -398,16 +388,16 @@ impl Fsm for PathToolFsmState {
let shift_pressed = input.keyboard.get(shift_mirror_distance as usize);
let nearest_point = shape_editor
.find_nearest_point_indices(&document.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);
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 {
let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == Some(point));
if clicked_selected {
shape_editor.deselect_all();
shape_editor.select_point(&document.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);
}
}
@ -428,9 +418,9 @@ impl Fsm for PathToolFsmState {
}
(_, PathToolMessage::InsertPoint) => {
// First we try and flip the sharpness (if they have clicked on an anchor)
if !shape_editor.flip_sharp(&document.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
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);
@ -443,7 +433,7 @@ impl Fsm for PathToolFsmState {
}
(_, PathToolMessage::PointerMove { .. }) => self,
(_, 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
}
@ -454,18 +444,18 @@ impl Fsm for PathToolFsmState {
}
(_, PathToolMessage::SelectedPointXChanged { new_x }) => {
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
shape_editor.reposition_control_point(&id, responses, &document.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
}
(_, PathToolMessage::SelectedPointYChanged { new_y }) => {
if let Some(&SingleSelectedPoint { coordinates, id, layer, .. }) = tool_data.selection_status.as_one() {
shape_editor.reposition_control_point(&id, responses, &document.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
}
(_, 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
}
(_, PathToolMessage::ManipulatorAngleMakeSmooth) => {

View file

@ -720,7 +720,7 @@ fn should_extend(document: &DocumentMessageHandler, pos: DVec2, tolerance: f64)
let mut best = None;
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 subpaths = get_subpaths(layer, &document.network)?;

View file

@ -381,27 +381,32 @@ impl Fsm for SelectToolFsmState {
};
match (self, event) {
(_, 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_count = selected_layers_count;
// 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));
}
// Get the layer the user is hovering over
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 {
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
}
// 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 bounds = document
.selected_visible_layers()
.selected_nodes
.selected_visible_layers(document.network(), document.metadata())
.filter_map(|layer| {
document
.metadata()
@ -462,7 +467,7 @@ impl Fsm for SelectToolFsmState {
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
.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);
// 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,
responses,
&document.network,
&document.document_metadata,
&document.metadata,
None,
&ToolType::Select,
);
@ -510,7 +515,7 @@ impl Fsm for SelectToolFsmState {
&selected,
responses,
&document.network,
&document.document_metadata,
&document.metadata,
None,
&ToolType::Select,
);
@ -630,7 +635,7 @@ impl Fsm for SelectToolFsmState {
selected,
responses,
&document.network,
&document.document_metadata,
&document.metadata,
None,
&ToolType::Select,
);
@ -665,7 +670,7 @@ impl Fsm for SelectToolFsmState {
&tool_data.layers_dragging,
responses,
&document.network,
&document.document_metadata,
&document.metadata,
None,
&ToolType::Select,
);
@ -723,7 +728,11 @@ impl Fsm for SelectToolFsmState {
let intersection = document.intersect_quad(quad, &document.network);
if let Some(path) = intersection.last() {
let replacement_selected_layers: Vec<_> = document.metadata().selected_layers().filter(|&layer| !path.starts_with(layer, document.metadata())).collect();
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.extend(replacement_selected_layers.iter());
@ -791,7 +800,7 @@ impl Fsm for SelectToolFsmState {
(SelectToolFsmState::DrawingBox, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
let quad = tool_data.selection_quad();
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 {
tool_data.layers_dragging = new_selected.into_iter().collect();
responses.add(DocumentMessage::StartTransaction);
@ -804,7 +813,7 @@ impl Fsm for SelectToolFsmState {
SelectToolFsmState::Ready
}
(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() {
// Check that only one layer is selected
@ -832,7 +841,7 @@ impl Fsm for SelectToolFsmState {
&tool_data.layers_dragging,
responses,
&document.network,
&document.document_metadata,
&document.metadata,
None,
&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) {
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()));
@ -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>) {
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 });
return;
}
let Some(new_selected) = layer
.ancestors(document.metadata())
.find(|ancestor| ancestor.parent(document.metadata()).is_some_and(|parent| document.metadata().selected_layers_contains(parent)))
else {
let Some(new_selected) = layer.ancestors(document.metadata()).find(|ancestor| {
ancestor
.parent(document.metadata())
.is_some_and(|parent| document.selected_nodes.selected_layers_contains(parent, document.metadata()))
}) else {
return;
};

View file

@ -344,9 +344,9 @@ impl TextToolData {
}
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()?;
// Check that only one layer is selected
if selected_layers.next().is_some() {
return None;
@ -392,7 +392,7 @@ impl Fsm for TextToolFsmState {
TextToolFsmState::Editing
}
(_, 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 {
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 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(
&mut self.original_transforms,
@ -56,7 +56,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
&selected_layers,
responses,
&document.network,
&document.document_metadata,
&document.metadata,
Some(shape_editor),
&tool_data.active_tool_type,
);
@ -222,7 +222,7 @@ impl<'a> MessageHandler<TransformLayerMessage, TransformData<'a>> for TransformL
self.mouse_position = input.mouse.position;
}
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);
}
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 {
viewport: Footprint {
transform: document.document_metadata.document_to_viewport,
transform: document.metadata.document_to_viewport,
resolution: viewport_resolution,
..Default::default()
},
@ -477,7 +477,9 @@ impl NodeGraphExecutor {
// Calculate the bounding box of the region to be exported
let bounds = match export_config.bounds {
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),
}
.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:?}"))?;
document.document_metadata.update_transforms(new_upstream_transforms);
document.document_metadata.update_click_targets(new_click_targets);
document.metadata.update_transforms(new_upstream_transforms);
document.metadata.update_click_targets(new_click_targets);
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 {

View file

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