@@ -2785,6 +2785,7 @@ mod document_message_handler_tests {
2785
2785
assert ! ( !selected_nodes. selected_layers_contains( layers[ 1 ] , document. metadata( ) ) ) ;
2786
2786
assert ! ( selected_nodes. selected_layers_contains( layers[ 2 ] , document. metadata( ) ) ) ;
2787
2787
}
2788
+
2788
2789
#[ tokio:: test]
2789
2790
async fn test_layer_rearrangement ( ) {
2790
2791
let mut editor = EditorTestUtils :: create ( ) ;
@@ -2831,6 +2832,7 @@ mod document_message_handler_tests {
2831
2832
let new_index_middle = get_layer_index ( & mut editor, layer_middle) . await . unwrap ( ) ;
2832
2833
assert ! ( new_index_middle < initial_index_middle, "Middle layer should have moved up" ) ;
2833
2834
}
2835
+
2834
2836
#[ tokio:: test]
2835
2837
async fn test_move_folder_into_itself_doesnt_crash ( ) {
2836
2838
let mut editor = EditorTestUtils :: create ( ) ;
@@ -2859,4 +2861,116 @@ mod document_message_handler_tests {
2859
2861
editor. handle_message ( DocumentMessage :: CreateEmptyFolder ) . await ;
2860
2862
assert ! ( true , "Application didn't crash after folder move operation" ) ;
2861
2863
}
2864
+ #[ tokio:: test]
2865
+ async fn test_moving_folder_with_children ( ) {
2866
+ let mut editor = EditorTestUtils :: create ( ) ;
2867
+ editor. new_document ( ) . await ;
2868
+
2869
+ // Creating two folders at root level
2870
+ editor. handle_message ( DocumentMessage :: CreateEmptyFolder ) . await ;
2871
+ editor. handle_message ( DocumentMessage :: CreateEmptyFolder ) . await ;
2872
+
2873
+ let folder1 = editor. active_document ( ) . metadata ( ) . all_layers ( ) . next ( ) . unwrap ( ) ;
2874
+ let folder2 = editor. active_document ( ) . metadata ( ) . all_layers ( ) . nth ( 1 ) . unwrap ( ) ;
2875
+
2876
+ editor. drag_tool ( ToolType :: Rectangle , 0. , 0. , 100. , 100. , ModifierKeys :: empty ( ) ) . await ;
2877
+ let rect_layer = editor. active_document ( ) . metadata ( ) . all_layers ( ) . next ( ) . unwrap ( ) ;
2878
+
2879
+ // First move rectangle into folder1
2880
+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ rect_layer. to_node( ) ] } ) . await ;
2881
+ editor. handle_message ( DocumentMessage :: MoveSelectedLayersTo { parent : folder1, insert_index : 0 } ) . await ;
2882
+
2883
+ // Verifying rectagle is now in folder1
2884
+ let rect_parent = rect_layer. parent ( editor. active_document ( ) . metadata ( ) ) . unwrap ( ) ;
2885
+ assert_eq ! ( rect_parent, folder1, "Rectangle should be inside folder1" ) ;
2886
+
2887
+ // Moving folder1 into folder2
2888
+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ folder1. to_node( ) ] } ) . await ;
2889
+ editor. handle_message ( DocumentMessage :: MoveSelectedLayersTo { parent : folder2, insert_index : 0 } ) . await ;
2890
+
2891
+ // Verifing hirarchy: folder2 > folder1 > rectangle
2892
+ let document = editor. active_document ( ) ;
2893
+ let folder1_parent = folder1. parent ( document. metadata ( ) ) . unwrap ( ) ;
2894
+ assert_eq ! ( folder1_parent, folder2, "Folder1 should be inside folder2" ) ;
2895
+
2896
+ // Verifing rectangle moved with its parent
2897
+ let rect_parent = rect_layer. parent ( document. metadata ( ) ) . unwrap ( ) ;
2898
+ assert_eq ! ( rect_parent, folder1, "Rectangle should still be inside folder1" ) ;
2899
+
2900
+ let rect_grandparent = rect_parent. parent ( document. metadata ( ) ) . unwrap ( ) ;
2901
+ assert_eq ! ( rect_grandparent, folder2, "Rectangle's grandparent should be folder2" ) ;
2902
+ }
2903
+
2904
+ #[ tokio:: test]
2905
+ async fn test_moving_layers_retains_transforms ( ) {
2906
+ let mut editor = EditorTestUtils :: create ( ) ;
2907
+ editor. new_document ( ) . await ;
2908
+
2909
+ editor. handle_message ( DocumentMessage :: CreateEmptyFolder ) . await ;
2910
+ editor. handle_message ( DocumentMessage :: CreateEmptyFolder ) . await ;
2911
+
2912
+ let folder2 = editor. active_document ( ) . metadata ( ) . all_layers ( ) . next ( ) . unwrap ( ) ;
2913
+ let folder1 = editor. active_document ( ) . metadata ( ) . all_layers ( ) . nth ( 1 ) . unwrap ( ) ;
2914
+
2915
+ // Applying transform to folder1 (translation)
2916
+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ folder1. to_node( ) ] } ) . await ;
2917
+ editor. handle_message ( TransformLayerMessage :: BeginGrab ) . await ;
2918
+ editor. move_mouse ( 100.0 , 50.0 , ModifierKeys :: empty ( ) , MouseKeys :: NONE ) . await ;
2919
+ editor
2920
+ . handle_message ( TransformLayerMessage :: PointerMove {
2921
+ slow_key : Key :: Shift ,
2922
+ increments_key : Key :: Control ,
2923
+ } )
2924
+ . await ;
2925
+ editor. handle_message ( TransformLayerMessage :: ApplyTransformOperation { final_transform : true } ) . await ;
2926
+
2927
+ // Applying different transform to folder2 (translation)
2928
+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ folder2. to_node( ) ] } ) . await ;
2929
+ editor. handle_message ( TransformLayerMessage :: BeginGrab ) . await ;
2930
+ editor. move_mouse ( 200.0 , 100.0 , ModifierKeys :: empty ( ) , MouseKeys :: NONE ) . await ;
2931
+ editor
2932
+ . handle_message ( TransformLayerMessage :: PointerMove {
2933
+ slow_key : Key :: Shift ,
2934
+ increments_key : Key :: Control ,
2935
+ } )
2936
+ . await ;
2937
+ editor. handle_message ( TransformLayerMessage :: ApplyTransformOperation { final_transform : true } ) . await ;
2938
+
2939
+ // Creating rectangle in folder1
2940
+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ folder1. to_node( ) ] } ) . await ;
2941
+ editor. drag_tool ( ToolType :: Rectangle , 0. , 0. , 100. , 100. , ModifierKeys :: empty ( ) ) . await ;
2942
+ let rect_layer = editor. active_document ( ) . metadata ( ) . all_layers ( ) . next ( ) . unwrap ( ) ;
2943
+
2944
+ // Moving the rectangle to folder1 to ensure it's inside
2945
+ editor. handle_message ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ rect_layer. to_node( ) ] } ) . await ;
2946
+ editor. handle_message ( DocumentMessage :: MoveSelectedLayersTo { parent : folder1, insert_index : 0 } ) . await ;
2947
+
2948
+ editor. handle_message ( TransformLayerMessage :: BeginGrab ) . await ;
2949
+ editor. move_mouse ( 50.0 , 25.0 , ModifierKeys :: empty ( ) , MouseKeys :: NONE ) . await ;
2950
+ editor
2951
+ . handle_message ( TransformLayerMessage :: PointerMove {
2952
+ slow_key : Key :: Shift ,
2953
+ increments_key : Key :: Control ,
2954
+ } )
2955
+ . await ;
2956
+ editor. handle_message ( TransformLayerMessage :: ApplyTransformOperation { final_transform : true } ) . await ;
2957
+
2958
+ // Rectangle's viewport position before moving
2959
+ let document = editor. active_document ( ) ;
2960
+ let rect_bbox_before = document. metadata ( ) . bounding_box_viewport ( rect_layer) . unwrap ( ) ;
2961
+
2962
+ // Moving rectangle from folder1 --> folder2
2963
+ editor. handle_message ( DocumentMessage :: MoveSelectedLayersTo { parent : folder2, insert_index : 0 } ) . await ;
2964
+
2965
+ // Rectangle's viewport position after moving
2966
+ let document = editor. active_document ( ) ;
2967
+ let rect_bbox_after = document. metadata ( ) . bounding_box_viewport ( rect_layer) . unwrap ( ) ;
2968
+
2969
+ // Verifing the rectangle maintains approximately the same position in viewport space
2970
+ let before_center = ( rect_bbox_before[ 0 ] + rect_bbox_before[ 1 ] ) / 2.0 ;
2971
+ let after_center = ( rect_bbox_after[ 0 ] + rect_bbox_after[ 1 ] ) / 2.0 ;
2972
+ let distance = before_center. distance ( after_center) ;
2973
+
2974
+ assert ! ( distance < 1.0 , "Rectangle should maintain its viewport position after moving between transformed groups" ) ;
2975
+ }
2862
2976
}
0 commit comments