Skip to content

Commit 58660f5

Browse files
0HyperCubeKeavon
andauthored
Allow groups to work with the node graph (#1452)
* Initial groups * Improve graph arangement * Fix selecting nested layers * Code review pass * Change log --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent f4ec76f commit 58660f5

19 files changed

+393
-302
lines changed

document-legacy/src/document_metadata.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ impl DocumentMetadata {
7777
self.structure.entry(node_identifier).or_default()
7878
}
7979

80+
/// Layers excluding ones that are children of other layers in the list.
8081
pub fn shallowest_unique_layers(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<Vec<LayerNodeIdentifier>> {
8182
let mut sorted_layers = layers
8283
.map(|layer| {
@@ -90,6 +91,34 @@ impl DocumentMetadata {
9091
sorted_layers.dedup_by(|a, b| a.starts_with(b));
9192
sorted_layers
9293
}
94+
95+
/// Ancestor that is shared by all layers and that is deepest (more nested). May be the root layer.
96+
pub fn deepest_common_ancestor(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> LayerNodeIdentifier {
97+
layers
98+
.map(|layer| {
99+
let mut layer_path = layer.ancestors(self).skip(1).collect::<Vec<_>>();
100+
layer_path.reverse();
101+
layer_path
102+
})
103+
.reduce(|mut a, b| {
104+
a.truncate(a.iter().zip(b.iter()).position(|(&a, &b)| a != b).unwrap_or_else(|| a.len().min(b.len())));
105+
a
106+
})
107+
.and_then(|path| path.last().copied())
108+
.unwrap_or(LayerNodeIdentifier::ROOT)
109+
}
110+
111+
/// Filter out non folder layers
112+
pub fn folders<'a>(&'a self, layers: impl Iterator<Item = LayerNodeIdentifier> + 'a) -> impl Iterator<Item = LayerNodeIdentifier> + 'a {
113+
layers.filter(|layer| layer.has_children(self))
114+
}
115+
116+
/// Folders sorted from most nested to least nested
117+
pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<LayerNodeIdentifier> {
118+
let mut folders: Vec<_> = self.folders(layers).collect();
119+
folders.sort_by_cached_key(|a| std::cmp::Reverse(a.ancestors(self).count()));
120+
folders
121+
}
93122
}
94123

95124
// selected layer modifications
@@ -146,7 +175,7 @@ impl DocumentMetadata {
146175
}
147176

148177
fn first_child_layer<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
149-
graph.primary_flow_from_opt(Some(node.inputs[0].as_node()?)).find(|(node, _)| node.name == "Layer")
178+
graph.primary_flow_from_node(Some(node.inputs[0].as_node()?)).find(|(node, _)| node.name == "Layer")
150179
}
151180
fn sibling_below<'a>(graph: &'a NodeNetwork, node: &DocumentNode) -> Option<(&'a DocumentNode, NodeId)> {
152181
node.inputs[7].as_node().and_then(|id| graph.nodes.get(&id).filter(|node| node.name == "Layer").map(|node| (node, id)))
@@ -178,7 +207,7 @@ impl DocumentMetadata {
178207
}
179208

180209
fn is_artboard(layer: LayerNodeIdentifier, network: &NodeNetwork) -> bool {
181-
network.primary_flow_from_opt(Some(layer.to_node())).any(|(node, _)| node.name == "Artboard")
210+
network.primary_flow_from_node(Some(layer.to_node())).any(|(node, _)| node.name == "Artboard")
182211
}
183212

184213
// click targets
@@ -299,6 +328,7 @@ impl LayerNodeIdentifier {
299328
}
300329

301330
/// Construct a [`LayerNodeIdentifier`], debug asserting that it is a layer node
331+
#[track_caller]
302332
pub fn new(node_id: NodeId, network: &NodeNetwork) -> Self {
303333
debug_assert!(
304334
is_layer_node(node_id, network),

document-legacy/src/response.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ pub enum DocumentResponse {
2222
LayerChanged {
2323
path: Vec<LayerId>,
2424
},
25-
MoveSelectedLayersTo {
26-
folder_path: Vec<LayerId>,
27-
insert_index: isize,
28-
reverse_index: bool,
29-
},
3025
DeletedSelectedManipulatorPoints,
3126
}
3227

@@ -39,7 +34,6 @@ impl fmt::Display for DocumentResponse {
3934
DocumentResponse::LayerChanged { .. } => write!(f, "LayerChanged"),
4035
DocumentResponse::DeletedLayer { .. } => write!(f, "DeleteLayer"),
4136
DocumentResponse::DeletedSelectedManipulatorPoints { .. } => write!(f, "DeletedSelectedManipulatorPoints"),
42-
DocumentResponse::MoveSelectedLayersTo { .. } => write!(f, "MoveSelectedLayersTo"),
4337
}
4438
}
4539
}

editor/src/dispatcher.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ mod test {
302302
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
303303
editor.handle_message(PortfolioMessage::PasteIntoFolder {
304304
clipboard: Clipboard::Internal,
305-
folder_path: vec![],
305+
parent: LayerNodeIdentifier::ROOT,
306306
insert_index: -1,
307307
});
308308
let document_after_copy = editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().document_legacy.clone();
@@ -341,7 +341,7 @@ mod test {
341341
editor.handle_message(PortfolioMessage::Copy { clipboard: Clipboard::Internal });
342342
editor.handle_message(PortfolioMessage::PasteIntoFolder {
343343
clipboard: Clipboard::Internal,
344-
folder_path: vec![],
344+
parent: LayerNodeIdentifier::ROOT,
345345
insert_index: -1,
346346
});
347347

@@ -407,12 +407,12 @@ mod test {
407407
editor.handle_message(DocumentMessage::DeleteSelectedLayers);
408408
editor.handle_message(PortfolioMessage::PasteIntoFolder {
409409
clipboard: Clipboard::Internal,
410-
folder_path: vec![],
410+
parent: LayerNodeIdentifier::ROOT,
411411
insert_index: -1,
412412
});
413413
editor.handle_message(PortfolioMessage::PasteIntoFolder {
414414
clipboard: Clipboard::Internal,
415-
folder_path: vec![],
415+
parent: LayerNodeIdentifier::ROOT,
416416
insert_index: -1,
417417
});
418418

@@ -479,12 +479,12 @@ mod test {
479479
editor.draw_rect(0., 800., 12., 200.);
480480
editor.handle_message(PortfolioMessage::PasteIntoFolder {
481481
clipboard: Clipboard::Internal,
482-
folder_path: vec![],
482+
parent: LayerNodeIdentifier::ROOT,
483483
insert_index: -1,
484484
});
485485
editor.handle_message(PortfolioMessage::PasteIntoFolder {
486486
clipboard: Clipboard::Internal,
487-
folder_path: vec![],
487+
parent: LayerNodeIdentifier::ROOT,
488488
insert_index: -1,
489489
});
490490

editor/src/messages/portfolio/document/document_message.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate,
55
use crate::messages::prelude::*;
66

77
use document_legacy::document::Document as DocumentLegacy;
8+
use document_legacy::document_metadata::LayerNodeIdentifier;
89
use document_legacy::layers::blend_mode::BlendMode;
910
use document_legacy::layers::style::ViewMode;
1011
use document_legacy::LayerId;
@@ -106,9 +107,8 @@ pub enum DocumentMessage {
106107
affected_layer_path: Vec<LayerId>,
107108
},
108109
MoveSelectedLayersTo {
109-
folder_path: Vec<LayerId>,
110+
parent: LayerNodeIdentifier,
110111
insert_index: isize,
111-
reverse_index: bool,
112112
},
113113
NudgeSelectedLayers {
114114
delta_x: f64,
@@ -169,6 +169,9 @@ pub enum DocumentMessage {
169169
SetOverlaysVisibility {
170170
visible: bool,
171171
},
172+
SetRangeSelectionLayer {
173+
new_layer: Option<LayerNodeIdentifier>,
174+
},
172175
SetSelectedLayers {
173176
replacement_selected_layers: Vec<Vec<LayerId>>,
174177
},
@@ -189,9 +192,6 @@ pub enum DocumentMessage {
189192
},
190193
Undo,
191194
UndoFinished,
192-
UngroupLayers {
193-
folder_path: Vec<LayerId>,
194-
},
195195
UngroupSelectedLayers,
196196
UpdateDocumentTransform {
197197
transform: glam::DAffine2,

0 commit comments

Comments
 (0)