@@ -10,6 +10,7 @@ use crate::messages::dialog::simple_dialogs;
10
10
use crate :: messages:: frontend:: utility_types:: FrontendDocumentDetails ;
11
11
use crate :: messages:: layout:: utility_types:: widget_prelude:: * ;
12
12
use crate :: messages:: portfolio:: document:: DocumentMessageData ;
13
+ use crate :: messages:: portfolio:: document:: graph_operation:: utility_types:: TransformIn ;
13
14
use crate :: messages:: portfolio:: document:: node_graph:: document_node_definitions:: resolve_document_node_type;
14
15
use crate :: messages:: portfolio:: document:: utility_types:: clipboards:: { Clipboard , CopyBufferEntry , INTERNAL_CLIPBOARD_COUNT } ;
15
16
use crate :: messages:: portfolio:: document:: utility_types:: nodes:: SelectedNodes ;
@@ -18,9 +19,10 @@ use crate::messages::prelude::*;
18
19
use crate :: messages:: tool:: utility_types:: { HintData , HintGroup , ToolType } ;
19
20
use crate :: node_graph_executor:: { ExportConfig , NodeGraphExecutor } ;
20
21
use bezier_rs:: Subpath ;
21
- use glam:: IVec2 ;
22
+ use glam:: { DAffine2 , DVec2 , IVec2 } ;
22
23
use graph_craft:: document:: value:: TaggedValue ;
23
24
use graph_craft:: document:: { DocumentNodeImplementation , NodeId , NodeInput } ;
25
+ use graphene_core:: renderer:: Quad ;
24
26
use graphene_core:: text:: { Font , TypesettingConfig } ;
25
27
use graphene_std:: vector:: style:: { Fill , FillType , Gradient } ;
26
28
use graphene_std:: vector:: { VectorData , VectorDataTable } ;
@@ -1003,6 +1005,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
1003
1005
if let Some ( document) = self . active_document ( ) {
1004
1006
if let Ok ( data) = serde_json:: from_str :: < Vec < CopyBufferEntry > > ( & data) {
1005
1007
let parent = document. new_layer_parent ( false ) ;
1008
+ let mut layers = Vec :: new ( ) ;
1006
1009
1007
1010
let mut added_nodes = false ;
1008
1011
@@ -1012,16 +1015,126 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
1012
1015
responses. add ( DocumentMessage :: AddTransaction ) ;
1013
1016
added_nodes = true ;
1014
1017
}
1018
+
1015
1019
document. load_layer_resources ( responses) ;
1016
1020
let new_ids: HashMap < _ , _ > = entry. nodes . iter ( ) . map ( |( id, _) | ( * id, NodeId :: new ( ) ) ) . collect ( ) ;
1017
1021
let layer = LayerNodeIdentifier :: new_unchecked ( new_ids[ & NodeId ( 0 ) ] ) ;
1018
1022
responses. add ( NodeGraphMessage :: AddNodes { nodes : entry. nodes , new_ids } ) ;
1019
1023
responses. add ( NodeGraphMessage :: MoveLayerToStack { layer, parent, insert_index : 0 } ) ;
1024
+ layers. push ( layer) ;
1020
1025
}
1026
+
1021
1027
responses. add ( NodeGraphMessage :: RunDocumentGraph ) ;
1028
+ responses. add ( Message :: StartBuffer ) ;
1029
+ responses. add ( PortfolioMessage :: CenterPastedLayers { layers } ) ;
1022
1030
}
1023
1031
}
1024
1032
}
1033
+ PortfolioMessage :: CenterPastedLayers { layers } => {
1034
+ if let Some ( document) = self . active_document_mut ( ) {
1035
+ let viewport_bounds_quad_pixels = Quad :: from_box ( [ DVec2 :: ZERO , ipp. viewport_bounds . size ( ) ] ) ;
1036
+ let viewport_center_pixels = viewport_bounds_quad_pixels. center ( ) ; // In viewport pixel coordinates
1037
+
1038
+ let doc_to_viewport_transform = document. metadata ( ) . document_to_viewport ;
1039
+ let viewport_to_doc_transform = doc_to_viewport_transform. inverse ( ) ;
1040
+
1041
+ let viewport_quad_doc_space = viewport_to_doc_transform * viewport_bounds_quad_pixels;
1042
+
1043
+ let mut top_level_items_to_center: Vec < LayerNodeIdentifier > = Vec :: new ( ) ;
1044
+ let mut artboards_in_selection: Vec < LayerNodeIdentifier > = Vec :: new ( ) ;
1045
+
1046
+ for & layer_id in & layers {
1047
+ if document. network_interface . is_artboard ( & layer_id. to_node ( ) , & document. node_graph_handler . network ) {
1048
+ artboards_in_selection. push ( layer_id) ;
1049
+ }
1050
+ }
1051
+
1052
+ for & layer_id in & layers {
1053
+ let is_child_of_selected_artboard = artboards_in_selection. iter ( ) . any ( |& artboard_id| {
1054
+ if layer_id == artboard_id {
1055
+ return false ;
1056
+ }
1057
+ layer_id. ancestors ( document. metadata ( ) ) . any ( |ancestor| ancestor == artboard_id)
1058
+ } ) ;
1059
+
1060
+ if !is_child_of_selected_artboard {
1061
+ top_level_items_to_center. push ( layer_id) ;
1062
+ }
1063
+ }
1064
+
1065
+ if top_level_items_to_center. is_empty ( ) {
1066
+ return ;
1067
+ }
1068
+
1069
+ let mut combined_min_doc = DVec2 :: MAX ;
1070
+ let mut combined_max_doc = DVec2 :: MIN ;
1071
+ let mut has_any_bounds = false ;
1072
+
1073
+ for & item_id in & top_level_items_to_center {
1074
+ if let Some ( bounds_doc) = document. metadata ( ) . bounding_box_document ( item_id) {
1075
+ combined_min_doc = combined_min_doc. min ( bounds_doc[ 0 ] ) ;
1076
+ combined_max_doc = combined_max_doc. max ( bounds_doc[ 1 ] ) ;
1077
+ has_any_bounds = true ;
1078
+ }
1079
+ }
1080
+
1081
+ if !has_any_bounds {
1082
+ return ;
1083
+ }
1084
+
1085
+ let combined_bounds_doc_quad = Quad :: from_box ( [ combined_min_doc, combined_max_doc] ) ;
1086
+
1087
+ if combined_bounds_doc_quad. intersects ( viewport_quad_doc_space) {
1088
+ return ;
1089
+ }
1090
+
1091
+ let combined_center_doc = combined_bounds_doc_quad. center ( ) ;
1092
+ let combined_center_viewport_pixels = doc_to_viewport_transform. transform_point2 ( combined_center_doc) ;
1093
+ let translation_viewport_pixels_rounded = ( viewport_center_pixels - combined_center_viewport_pixels) . round ( ) ;
1094
+
1095
+ let final_translation_offset_doc = viewport_to_doc_transform. transform_vector2 ( translation_viewport_pixels_rounded) ;
1096
+
1097
+ if final_translation_offset_doc. abs_diff_eq ( glam:: DVec2 :: ZERO , 1e-9 ) {
1098
+ return ;
1099
+ }
1100
+
1101
+ responses. add ( DocumentMessage :: AddTransaction ) ;
1102
+
1103
+ for & item_id in & top_level_items_to_center {
1104
+ if document. network_interface . is_artboard ( & item_id. to_node ( ) , & document. node_graph_handler . network ) {
1105
+ if let Some ( bounds_doc) = document. metadata ( ) . bounding_box_document ( item_id) {
1106
+ let current_artboard_origin_doc = bounds_doc[ 0 ] ;
1107
+ let dimensions_doc = bounds_doc[ 1 ] - bounds_doc[ 0 ] ;
1108
+ let new_artboard_origin_doc = current_artboard_origin_doc + final_translation_offset_doc;
1109
+
1110
+ responses. add ( GraphOperationMessage :: ResizeArtboard {
1111
+ layer : item_id,
1112
+ location : new_artboard_origin_doc. round ( ) . as_ivec2 ( ) ,
1113
+ dimensions : dimensions_doc. round ( ) . as_ivec2 ( ) ,
1114
+ } ) ;
1115
+ }
1116
+ } else {
1117
+ let current_abs_doc_transform = document. metadata ( ) . transform_to_document ( item_id) ;
1118
+
1119
+ let new_abs_doc_transform = DAffine2 {
1120
+ matrix2 : current_abs_doc_transform. matrix2 ,
1121
+ translation : current_abs_doc_transform. translation + final_translation_offset_doc,
1122
+ } ;
1123
+
1124
+ let transform = doc_to_viewport_transform * new_abs_doc_transform;
1125
+
1126
+ responses. add ( GraphOperationMessage :: TransformSet {
1127
+ layer : item_id,
1128
+ transform,
1129
+ transform_in : TransformIn :: Viewport ,
1130
+ skip_rerender : false ,
1131
+ } ) ;
1132
+ }
1133
+ }
1134
+
1135
+ responses. add ( NodeGraphMessage :: RunDocumentGraph ) ;
1136
+ }
1137
+ }
1025
1138
PortfolioMessage :: PasteImage {
1026
1139
name,
1027
1140
image,
0 commit comments