@@ -3,15 +3,17 @@ use graphene_core::renderer::ClickTarget;
3
3
use std:: collections:: HashMap ;
4
4
use std:: num:: NonZeroU64 ;
5
5
6
- use graph_craft:: document:: { NodeId , NodeNetwork } ;
6
+ use graph_craft:: document:: { DocumentNode , NodeId , NodeNetwork } ;
7
7
8
8
use graphene_core:: renderer:: Quad ;
9
9
10
10
#[ derive( Debug , Clone ) ]
11
11
pub struct DocumentMetadata {
12
12
transforms : HashMap < LayerNodeIdentifier , DAffine2 > ,
13
+ upstream_transforms : HashMap < NodeId , DAffine2 > ,
13
14
structure : HashMap < LayerNodeIdentifier , NodeRelations > ,
14
15
click_targets : HashMap < LayerNodeIdentifier , Vec < ClickTarget > > ,
16
+ selected_nodes : Vec < NodeId > ,
15
17
/// Transform from document space to viewport space.
16
18
pub document_to_viewport : DAffine2 ,
17
19
}
@@ -20,13 +22,17 @@ impl Default for DocumentMetadata {
20
22
fn default ( ) -> Self {
21
23
Self {
22
24
transforms : HashMap :: new ( ) ,
25
+ upstream_transforms : HashMap :: new ( ) ,
23
26
click_targets : HashMap :: new ( ) ,
24
27
structure : HashMap :: from_iter ( [ ( LayerNodeIdentifier :: ROOT , NodeRelations :: default ( ) ) ] ) ,
28
+ selected_nodes : Vec :: new ( ) ,
25
29
document_to_viewport : DAffine2 :: IDENTITY ,
26
30
}
27
31
}
28
32
}
33
+ pub struct SelectionChanged ;
29
34
35
+ // layer iters
30
36
impl DocumentMetadata {
31
37
/// Get the root layer from the document
32
38
pub const fn root ( & self ) -> LayerNodeIdentifier {
@@ -38,15 +44,27 @@ impl DocumentMetadata {
38
44
}
39
45
40
46
pub fn selected_layers ( & self ) -> impl Iterator < Item = LayerNodeIdentifier > + ' _ {
41
- self . all_layers ( )
47
+ self . all_layers ( ) . filter ( |layer| self . selected_nodes . contains ( & layer . to_node ( ) ) )
42
48
}
43
49
44
50
pub fn selected_layers_contains ( & self , layer : LayerNodeIdentifier ) -> bool {
45
51
self . selected_layers ( ) . any ( |selected| selected == layer)
46
52
}
47
53
48
54
pub fn selected_visible_layers ( & self ) -> impl Iterator < Item = LayerNodeIdentifier > + ' _ {
49
- self . all_layers ( )
55
+ self . selected_layers ( )
56
+ }
57
+
58
+ pub fn selected_nodes ( & self ) -> core:: slice:: Iter < ' _ , NodeId > {
59
+ self . selected_nodes . iter ( )
60
+ }
61
+
62
+ pub fn selected_nodes_ref ( & self ) -> & Vec < NodeId > {
63
+ & self . selected_nodes
64
+ }
65
+
66
+ pub fn has_selected_nodes ( & self ) -> bool {
67
+ !self . selected_nodes . is_empty ( )
50
68
}
51
69
52
70
/// Access the [`NodeRelations`] of a layer
@@ -59,35 +77,125 @@ impl DocumentMetadata {
59
77
self . structure . entry ( node_identifier) . or_default ( )
60
78
}
61
79
62
- /// Update the cached transforms of the layers
63
- pub fn update_transforms ( & mut self , new_transforms : HashMap < LayerNodeIdentifier , DAffine2 > ) {
64
- self . transforms = new_transforms;
80
+ pub fn shallowest_unique_layers < ' a > ( & self , layers : impl Iterator < Item = & ' a LayerNodeIdentifier > ) -> Vec < Vec < LayerNodeIdentifier > > {
81
+ let mut sorted_layers = layers
82
+ . map ( |layer| {
83
+ let mut layer_path = layer. ancestors ( self ) . collect :: < Vec < _ > > ( ) ;
84
+ layer_path. reverse ( ) ;
85
+ layer_path
86
+ } )
87
+ . collect :: < Vec < _ > > ( ) ;
88
+ sorted_layers. sort ( ) ;
89
+ // Sorting here creates groups of similar UUID paths
90
+ sorted_layers. dedup_by ( |a, b| a. starts_with ( b) ) ;
91
+ sorted_layers
65
92
}
93
+ }
66
94
67
- /// Update the cached click targets of the layers
68
- pub fn update_click_targets ( & mut self , new_click_targets : HashMap < LayerNodeIdentifier , Vec < ClickTarget > > ) {
69
- self . click_targets = new_click_targets;
95
+ // selected layer modifications
96
+ impl DocumentMetadata {
97
+ #[ must_use]
98
+ pub fn retain_selected_nodes ( & mut self , f : impl FnMut ( & NodeId ) -> bool ) -> SelectionChanged {
99
+ self . selected_nodes . retain ( f) ;
100
+ SelectionChanged
101
+ }
102
+ #[ must_use]
103
+ pub fn set_selected_nodes ( & mut self , new : Vec < NodeId > ) -> SelectionChanged {
104
+ self . selected_nodes = new;
105
+ SelectionChanged
106
+ }
107
+ #[ must_use]
108
+ pub fn add_selected_nodes ( & mut self , iter : impl IntoIterator < Item = NodeId > ) -> SelectionChanged {
109
+ self . selected_nodes . extend ( iter) ;
110
+ SelectionChanged
111
+ }
112
+ #[ must_use]
113
+ pub fn clear_selected_nodes ( & mut self ) -> SelectionChanged {
114
+ self . set_selected_nodes ( Vec :: new ( ) )
115
+ }
116
+
117
+ /// Loads the structure of layer nodes from a node graph.
118
+ pub fn load_structure ( & mut self , graph : & NodeNetwork ) {
119
+ self . structure = HashMap :: from_iter ( [ ( LayerNodeIdentifier :: ROOT , NodeRelations :: default ( ) ) ] ) ;
120
+
121
+ let id = graph. outputs [ 0 ] . node_id ;
122
+ let Some ( output_node) = graph. nodes . get ( & id) else {
123
+ return ;
124
+ } ;
125
+ let Some ( ( layer_node, node_id) ) = first_child_layer ( graph, output_node, id) else {
126
+ return ;
127
+ } ;
128
+ let parent = LayerNodeIdentifier :: ROOT ;
129
+ let mut stack = vec ! [ ( layer_node, node_id, parent) ] ;
130
+ while let Some ( ( node, id, parent) ) = stack. pop ( ) {
131
+ let mut current = Some ( ( node, id) ) ;
132
+ while let Some ( & ( current_node, current_id) ) = current. as_ref ( ) {
133
+ let current_identifier = LayerNodeIdentifier :: new_unchecked ( current_id) ;
134
+ if !self . structure . contains_key ( & current_identifier) {
135
+ parent. push_child ( self , current_identifier) ;
136
+
137
+ if let Some ( ( child_node, child_id) ) = first_child_layer ( graph, current_node, current_id) {
138
+ stack. push ( ( child_node, child_id, current_identifier) ) ;
139
+ }
140
+ }
141
+
142
+ current = sibling_below ( graph, current_node, current_id) ;
143
+ }
144
+ }
70
145
}
146
+ }
71
147
72
- /// Access the cached transformation from document space to layer space
73
- pub fn transform_from_document ( & self , layer : LayerNodeIdentifier ) -> DAffine2 {
148
+ fn first_child_layer < ' a > ( graph : & ' a NodeNetwork , node : & DocumentNode , id : NodeId ) -> Option < ( & ' a DocumentNode , NodeId ) > {
149
+ graph. primary_flow_from_opt ( Some ( node. inputs [ 0 ] . as_node ( ) ?) ) . find ( |( node, _) | node. name == "Layer" )
150
+ }
151
+ fn sibling_below < ' a > ( graph : & ' a NodeNetwork , node : & DocumentNode , id : NodeId ) -> Option < ( & ' a DocumentNode , NodeId ) > {
152
+ node. inputs [ 7 ] . as_node ( ) . and_then ( |id| graph. nodes . get ( & id) . filter ( |node| node. name == "Layer" ) . map ( |node| ( node, id) ) )
153
+ }
154
+
155
+ // transforms
156
+ impl DocumentMetadata {
157
+ /// Update the cached transforms of the layers
158
+ pub fn update_transforms ( & mut self , new_transforms : HashMap < LayerNodeIdentifier , DAffine2 > , new_upstream_transforms : HashMap < NodeId , DAffine2 > ) {
159
+ self . transforms = new_transforms;
160
+ self . upstream_transforms = new_upstream_transforms;
161
+ }
162
+
163
+ /// Access the cached transformation to document space from layer space
164
+ pub fn transform_to_document ( & self , layer : LayerNodeIdentifier ) -> DAffine2 {
74
165
self . transforms . get ( & layer) . copied ( ) . unwrap_or_else ( || {
75
- warn ! ( "Tried to access transform of bad layer" ) ;
166
+ warn ! ( "Tried to access transform of bad layer {layer:?} " ) ;
76
167
DAffine2 :: IDENTITY
77
168
} )
78
169
}
79
170
80
- pub fn transform_from_viewport ( & self , layer : LayerNodeIdentifier ) -> DAffine2 {
81
- self . document_to_viewport * self . transform_from_document ( layer)
171
+ pub fn transform_to_viewport ( & self , layer : LayerNodeIdentifier ) -> DAffine2 {
172
+ self . document_to_viewport * self . transform_to_document ( layer)
173
+ }
174
+
175
+ pub fn upstream_transform ( & self , node_id : NodeId ) -> DAffine2 {
176
+ self . upstream_transforms . get ( & node_id) . copied ( ) . unwrap_or ( DAffine2 :: IDENTITY )
177
+ }
178
+ }
179
+
180
+ fn is_artboard ( layer : LayerNodeIdentifier , network : & NodeNetwork ) -> bool {
181
+ network. primary_flow_from_opt ( Some ( layer. to_node ( ) ) ) . any ( |( node, _) | node. name == "Artboard" )
182
+ }
183
+
184
+ // click targets
185
+ impl DocumentMetadata {
186
+ /// Update the cached click targets of the layers
187
+ pub fn update_click_targets ( & mut self , new_click_targets : HashMap < LayerNodeIdentifier , Vec < ClickTarget > > ) {
188
+ self . click_targets = new_click_targets;
82
189
}
83
190
84
191
/// Runs an intersection test with all layers and a viewport space quad
85
- pub fn intersect_quad ( & self , viewport_quad : Quad ) -> Option < LayerNodeIdentifier > {
192
+ pub fn intersect_quad < ' a > ( & ' a self , viewport_quad : Quad , network : & ' a NodeNetwork ) -> impl Iterator < Item = LayerNodeIdentifier > + ' a {
86
193
let document_quad = self . document_to_viewport . inverse ( ) * viewport_quad;
87
194
self . root ( )
88
195
. decendants ( self )
196
+ . filter ( |& layer| !is_artboard ( layer, network) )
89
197
. filter_map ( |layer| self . click_targets . get ( & layer) . map ( |targets| ( layer, targets) ) )
90
- . find ( |( layer, target) | target. iter ( ) . any ( |target| target. intersect_rectangle ( document_quad, self . transform_from_document ( * layer) ) ) )
198
+ . filter ( move |( layer, target) | target. iter ( ) . any ( move |target| target. intersect_rectangle ( document_quad, self . transform_to_document ( * layer) ) ) )
91
199
. map ( |( layer, _) | layer)
92
200
}
93
201
@@ -97,13 +205,13 @@ impl DocumentMetadata {
97
205
self . root ( )
98
206
. decendants ( self )
99
207
. filter_map ( |layer| self . click_targets . get ( & layer) . map ( |targets| ( layer, targets) ) )
100
- . filter ( move |( layer, target) | target. iter ( ) . any ( |target : & ClickTarget | target. intersect_point ( point, self . transform_from_document ( * layer) ) ) )
208
+ . filter ( move |( layer, target) | target. iter ( ) . any ( |target : & ClickTarget | target. intersect_point ( point, self . transform_to_document ( * layer) ) ) )
101
209
. map ( |( layer, _) | layer)
102
210
}
103
211
104
212
/// Find the layer that has been clicked on from a viewport space location
105
- pub fn click ( & self , viewport_location : DVec2 ) -> Option < LayerNodeIdentifier > {
106
- self . click_xray ( viewport_location) . next ( )
213
+ pub fn click ( & self , viewport_location : DVec2 , network : & NodeNetwork ) -> Option < LayerNodeIdentifier > {
214
+ self . click_xray ( viewport_location) . filter ( | & layer| ! is_artboard ( layer , network ) ) . next ( )
107
215
}
108
216
109
217
/// Get the bounding box of the click target of the specified layer in the specified transform space
@@ -115,14 +223,47 @@ impl DocumentMetadata {
115
223
. reduce ( Quad :: combine_bounds)
116
224
}
117
225
226
+ /// Calculate the corners of the bounding box but with a nonzero size.
227
+ ///
228
+ /// If the layer bounds are `0` in either axis then they are changed to be `1`.
229
+ pub fn nonzero_bounding_box ( & self , layer : LayerNodeIdentifier ) -> [ DVec2 ; 2 ] {
230
+ let [ bounds_min, mut bounds_max] = self . bounding_box_with_transform ( layer, DAffine2 :: IDENTITY ) . unwrap_or_default ( ) ;
231
+
232
+ let bounds_size = bounds_max - bounds_min;
233
+ if bounds_size. x < 1e-10 {
234
+ bounds_max. x = bounds_min. x + 1. ;
235
+ }
236
+ if bounds_size. y < 1e-10 {
237
+ bounds_max. y = bounds_min. y + 1. ;
238
+ }
239
+
240
+ [ bounds_min, bounds_max]
241
+ }
242
+
118
243
/// Get the bounding box of the click target of the specified layer in document space
119
244
pub fn bounding_box_document ( & self , layer : LayerNodeIdentifier ) -> Option < [ DVec2 ; 2 ] > {
120
- self . bounding_box_with_transform ( layer, self . transform_from_document ( layer) )
245
+ self . bounding_box_with_transform ( layer, self . transform_to_document ( layer) )
121
246
}
122
247
123
248
/// Get the bounding box of the click target of the specified layer in viewport space
124
249
pub fn bounding_box_viewport ( & self , layer : LayerNodeIdentifier ) -> Option < [ DVec2 ; 2 ] > {
125
- self . bounding_box_with_transform ( layer, self . transform_from_viewport ( layer) )
250
+ self . bounding_box_with_transform ( layer, self . transform_to_viewport ( layer) )
251
+ }
252
+
253
+ pub fn selected_visible_layers_bounding_box_viewport ( & self ) -> Option < [ DVec2 ; 2 ] > {
254
+ self . selected_layers ( ) . filter_map ( |layer| self . bounding_box_viewport ( layer) ) . reduce ( Quad :: combine_bounds)
255
+ }
256
+
257
+ /// Calculates the document bounds used for scrolling and centring (the layer bounds or the artboard (if applicable))
258
+ pub fn document_bounds ( & self ) -> Option < [ DVec2 ; 2 ] > {
259
+ self . all_layers ( ) . filter_map ( |layer| self . bounding_box_viewport ( layer) ) . reduce ( Quad :: combine_bounds)
260
+ }
261
+
262
+ pub fn layer_outline ( & self , layer : LayerNodeIdentifier ) -> graphene_core:: vector:: Subpath {
263
+ let Some ( click_targets) = self . click_targets . get ( & layer) else {
264
+ return graphene_core:: vector:: Subpath :: new ( ) ;
265
+ } ;
266
+ graphene_core:: vector:: Subpath :: from_bezier_rs ( click_targets. iter ( ) . map ( |click_target| & click_target. subpath ) )
126
267
}
127
268
}
128
269
@@ -242,7 +383,7 @@ impl LayerNodeIdentifier {
242
383
pub fn decendants ( self , document_metadata : & DocumentMetadata ) -> DecendantsIter {
243
384
DecendantsIter {
244
385
front : self . first_child ( document_metadata) ,
245
- back : self . last_child ( document_metadata) ,
386
+ back : self . last_child ( document_metadata) . and_then ( |child| child . last_children ( document_metadata ) . last ( ) ) ,
246
387
document_metadata,
247
388
}
248
389
}
@@ -339,6 +480,17 @@ impl LayerNodeIdentifier {
339
480
pub fn exists ( & self , document_metadata : & DocumentMetadata ) -> bool {
340
481
document_metadata. get_relations ( * self ) . is_some ( )
341
482
}
483
+
484
+ pub fn starts_with ( & self , other : Self , document_metadata : & DocumentMetadata ) -> bool {
485
+ self . ancestors ( document_metadata) . any ( |parent| parent == other)
486
+ }
487
+
488
+ pub fn child_of_root ( & self , document_metadata : & DocumentMetadata ) -> Self {
489
+ self . ancestors ( document_metadata)
490
+ . filter ( |& layer| layer != LayerNodeIdentifier :: ROOT )
491
+ . last ( )
492
+ . expect ( "There should be a layer before the root" )
493
+ }
342
494
}
343
495
344
496
impl From < NodeId > for LayerNodeIdentifier {
@@ -457,7 +609,8 @@ fn test_tree() {
457
609
assert ! ( root. children( document_metadata) . all( |child| child. parent( document_metadata) == Some ( root) ) ) ;
458
610
LayerNodeIdentifier :: new_unchecked ( 6 ) . delete ( document_metadata) ;
459
611
LayerNodeIdentifier :: new_unchecked ( 1 ) . delete ( document_metadata) ;
612
+ LayerNodeIdentifier :: new_unchecked ( 9 ) . push_child ( document_metadata, LayerNodeIdentifier :: new_unchecked ( 10 ) ) ;
460
613
assert_eq ! ( root. children( document_metadata) . map( LayerNodeIdentifier :: to_node) . collect:: <Vec <_>>( ) , vec![ 2 , 3 , 4 , 5 , 9 ] ) ;
461
- assert_eq ! ( root. decendants( document_metadata) . map( LayerNodeIdentifier :: to_node) . collect:: <Vec <_>>( ) , vec![ 2 , 3 , 4 , 5 , 9 ] ) ;
462
- assert_eq ! ( root. decendants( document_metadata) . map( LayerNodeIdentifier :: to_node) . rev( ) . collect:: <Vec <_>>( ) , vec![ 9 , 5 , 4 , 3 , 2 ] ) ;
614
+ assert_eq ! ( root. decendants( document_metadata) . map( LayerNodeIdentifier :: to_node) . collect:: <Vec <_>>( ) , vec![ 2 , 3 , 4 , 5 , 9 , 10 ] ) ;
615
+ assert_eq ! ( root. decendants( document_metadata) . map( LayerNodeIdentifier :: to_node) . rev( ) . collect:: <Vec <_>>( ) , vec![ 10 , 9 , 5 , 4 , 3 , 2 ] ) ;
463
616
}
0 commit comments