@@ -7,6 +7,7 @@ use crate::messages::debug::utility_types::MessageLoggingVerbosity;
7
7
use crate :: messages:: dialog:: simple_dialogs;
8
8
use crate :: messages:: frontend:: utility_types:: FrontendDocumentDetails ;
9
9
use crate :: messages:: layout:: utility_types:: widget_prelude:: * ;
10
+ use crate :: messages:: portfolio:: document:: graph_operation:: utility_types:: ModifyInputsContext ;
10
11
use crate :: messages:: portfolio:: document:: graph_operation:: utility_types:: TransformIn ;
11
12
use crate :: messages:: portfolio:: document:: node_graph:: document_node_definitions:: resolve_document_node_type;
12
13
use crate :: messages:: portfolio:: document:: utility_types:: clipboards:: { Clipboard , CopyBufferEntry , INTERNAL_CLIPBOARD_COUNT } ;
@@ -19,7 +20,7 @@ use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
19
20
use graphene_core:: renderer:: Quad ;
20
21
21
22
use bezier_rs:: Subpath ;
22
- use glam:: IVec2 ;
23
+ use glam:: { DAffine2 , DVec2 , IVec2 } ;
23
24
use graph_craft:: document:: value:: TaggedValue ;
24
25
use graph_craft:: document:: { DocumentNodeImplementation , NodeId , NodeInput } ;
25
26
use graphene_core:: text:: { Font , TypesettingConfig } ;
@@ -886,53 +887,82 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
886
887
}
887
888
responses. add ( NodeGraphMessage :: RunDocumentGraph ) ;
888
889
}
890
+ // Message to start paste operation
889
891
PortfolioMessage :: PasteSerializedData { data } => {
890
892
if let Some ( document) = self . active_document ( ) {
891
893
if let Ok ( data) = serde_json:: from_str :: < Vec < CopyBufferEntry > > ( & data) {
892
894
let parent = document. new_layer_parent ( false ) ;
893
- let transform = document. metadata ( ) . document_to_viewport ;
894
-
895
- // Check parent bounds first since children will be pasted at same position
896
- if let Some ( parent_bounds) = document. metadata ( ) . bounding_box_document ( parent) {
897
- let viewport_bounds = Quad :: from_box_at_zero ( ipp. viewport_bounds . size ( ) ) ;
898
- let quad = transform * Quad :: from_box ( parent_bounds) ;
899
-
900
- // Calculate the translation needed to center the parent
901
- let translation = viewport_bounds. center ( ) - quad. center ( ) ;
902
- let centering_transform = quad
903
- . 0
904
- . into_iter ( )
905
- . all ( |point| !viewport_bounds. contains ( point) )
906
- . then_some ( glam:: DAffine2 :: from_translation ( translation. round ( ) ) ) ;
907
-
908
- let mut added_nodes = false ;
909
-
910
- for entry in data. into_iter ( ) . rev ( ) {
911
- if !added_nodes {
912
- responses. add ( DocumentMessage :: DeselectAllLayers ) ;
913
- responses. add ( DocumentMessage :: AddTransaction ) ;
914
- added_nodes = true ;
915
- }
895
+ let mut layers = Vec :: new ( ) ;
896
+
897
+ // 1. Create all layers first
898
+ let mut added_nodes = false ;
899
+ for entry in data. into_iter ( ) . rev ( ) {
900
+ if !added_nodes {
901
+ responses. add ( DocumentMessage :: DeselectAllLayers ) ;
902
+ responses. add ( DocumentMessage :: AddTransaction ) ;
903
+ added_nodes = true ;
904
+ }
905
+
906
+ document. load_layer_resources ( responses) ;
907
+ let new_ids: HashMap < _ , _ > = entry. nodes . iter ( ) . map ( |( id, _) | ( * id, NodeId :: new ( ) ) ) . collect ( ) ;
908
+ let layer = LayerNodeIdentifier :: new_unchecked ( new_ids[ & NodeId ( 0 ) ] ) ;
909
+ responses. add ( NodeGraphMessage :: AddNodes { nodes : entry. nodes , new_ids } ) ;
910
+ responses. add ( NodeGraphMessage :: MoveLayerToStack { layer, parent, insert_index : 0 } ) ;
911
+ layers. push ( layer) ;
912
+ }
913
+
914
+ // 2. Run graph to ensure nodes are created
915
+ responses. add ( NodeGraphMessage :: RunDocumentGraph ) ;
916
+
917
+ // 3. Queue centering operation for after graph execution
918
+ responses. add ( PortfolioMessage :: CenterPastedLayers { layers } ) ;
919
+ }
920
+ }
921
+ }
916
922
917
- document. load_layer_resources ( responses) ;
918
- let new_ids: HashMap < _ , _ > = entry. nodes . iter ( ) . map ( |( id, _) | ( * id, NodeId :: new ( ) ) ) . collect ( ) ;
919
- let layer = LayerNodeIdentifier :: new_unchecked ( new_ids[ & NodeId ( 0 ) ] ) ;
920
- responses. add ( NodeGraphMessage :: AddNodes { nodes : entry. nodes , new_ids } ) ;
921
- responses. add ( NodeGraphMessage :: MoveLayerToStack { layer, parent, insert_index : 0 } ) ;
922
-
923
- // Apply the same translation to all layers
924
- if let Some ( transform) = centering_transform {
925
- responses. add ( GraphOperationMessage :: TransformChange {
926
- layer,
927
- transform,
928
- transform_in : TransformIn :: Viewport ,
929
- skip_rerender : false ,
930
- } ) ;
923
+ // New message - handles centering after graph execution
924
+ PortfolioMessage :: CenterPastedLayers { layers } => {
925
+ use crate :: messages:: portfolio:: document:: graph_operation:: transform_utils;
926
+ if let Some ( document) = self . active_document_mut ( ) {
927
+ let viewport_bounds = Quad :: from_box_at_zero ( ipp. viewport_bounds . size ( ) ) ;
928
+ let viewport_center = viewport_bounds. center ( ) ;
929
+
930
+ let mut positions = Vec :: new ( ) ;
931
+
932
+ // Get positions from Transform nodes directly
933
+ for layer in & layers {
934
+ if let Some ( mut modify_inputs) = ModifyInputsContext :: new_with_layer ( * layer, & mut document. network_interface , responses) {
935
+ if let Some ( transform_node_id) = modify_inputs. existing_node_id ( "Transform" , true ) {
936
+ if let Some ( network) = modify_inputs. network_interface . network ( & [ ] ) {
937
+ if let Some ( node) = network. nodes . get ( & transform_node_id) {
938
+ let current_transform = transform_utils:: get_current_transform ( & node. inputs ) ;
939
+ positions. push ( ( * layer, current_transform. translation ) ) ;
940
+ }
931
941
}
932
942
}
933
- responses. add ( NodeGraphMessage :: RunDocumentGraph ) ;
934
943
}
935
944
}
945
+
946
+ if !positions. is_empty ( ) {
947
+ // Calculate mean position
948
+ let mean_pos = positions. iter ( ) . fold ( glam:: DVec2 :: ZERO , |acc, ( _, pos) | acc + * pos) / positions. len ( ) as f64 ;
949
+ let mut transform = document. metadata ( ) . document_to_viewport ;
950
+
951
+ // Center each layer maintaining relative positions
952
+ for ( layer, pos) in positions {
953
+ let offset_from_center = pos - mean_pos;
954
+ let new_pos = viewport_center + transform. transform_vector2 ( offset_from_center) ;
955
+ transform. translation = new_pos;
956
+
957
+ responses. add ( GraphOperationMessage :: TransformSet {
958
+ layer,
959
+ transform,
960
+ transform_in : TransformIn :: Viewport ,
961
+ skip_rerender : false ,
962
+ } ) ;
963
+ }
964
+ responses. add ( NodeGraphMessage :: RunDocumentGraph ) ;
965
+ }
936
966
}
937
967
}
938
968
PortfolioMessage :: PasteImage {
0 commit comments