Browse Source

Remove delete selected layer and added select closest on delete

flabbet 11 months ago
parent
commit
7b106191ad

+ 0 - 8
src/PixiEditor/Data/ShortcutActionMaps/AsepriteShortcutMap.json

@@ -192,14 +192,6 @@
       "Parameters": []
       "Parameters": []
     },
     },
     "RemoveLayer": {
     "RemoveLayer": {
-      "Command": "PixiEditor.Layer.DeleteSelected",
-      "DefaultShortcut": {
-        "key": "None",
-        "modifiers": null
-      },
-      "Parameters": []
-    },
-    "": {
       "Command": "PixiEditor.Layer.DeleteAllSelected",
       "Command": "PixiEditor.Layer.DeleteAllSelected",
       "DefaultShortcut": {
       "DefaultShortcut": {
         "key": "None",
         "key": "None",

+ 1 - 0
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -3,6 +3,7 @@ using System.Linq;
 using Avalonia.Platform;
 using Avalonia.Platform;
 using Avalonia.Threading;
 using Avalonia.Threading;
 using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Bridge;

+ 141 - 55
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -1,15 +1,11 @@
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.IO;
-using System.Linq;
-using ChunkyImageLib;
+using System.Collections.Immutable;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core;
-using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surfaces.Vector;
 using PixiEditor.DrawingApi.Core.Surfaces.Vector;
 using PixiEditor.Extensions.CommonApi.Palettes;
 using PixiEditor.Extensions.CommonApi.Palettes;
 using PixiEditor.Models.Clipboard;
 using PixiEditor.Models.Clipboard;
@@ -96,13 +92,15 @@ internal class DocumentOperationsModule : IDocumentOperations
     /// <summary>
     /// <summary>
     /// Adds a new viewport or updates a existing one
     /// Adds a new viewport or updates a existing one
     /// </summary>
     /// </summary>
-    public void AddOrUpdateViewport(ViewportInfo info) => Internals.ActionAccumulator.AddActions(new RefreshViewport_PassthroughAction(info));
+    public void AddOrUpdateViewport(ViewportInfo info) =>
+        Internals.ActionAccumulator.AddActions(new RefreshViewport_PassthroughAction(info));
 
 
     /// <summary>
     /// <summary>
     /// Deletes the viewport with the <paramref name="viewportGuid"/>
     /// Deletes the viewport with the <paramref name="viewportGuid"/>
     /// </summary>
     /// </summary>
     /// <param name="viewportGuid">The Guid of the viewport to remove</param>
     /// <param name="viewportGuid">The Guid of the viewport to remove</param>
-    public void RemoveViewport(Guid viewportGuid) => Internals.ActionAccumulator.AddActions(new RemoveViewport_PassthroughAction(viewportGuid));
+    public void RemoveViewport(Guid viewportGuid) =>
+        Internals.ActionAccumulator.AddActions(new RemoveViewport_PassthroughAction(viewportGuid));
 
 
     /// <summary>
     /// <summary>
     /// Delete the whole undo stack
     /// Delete the whole undo stack
@@ -134,10 +132,13 @@ internal class DocumentOperationsModule : IDocumentOperations
 
 
         foreach (var imageWithName in images)
         foreach (var imageWithName in images)
         {
         {
-            var layerGuid = Internals.StructureHelper.CreateNewStructureMember(StructureMemberType.Layer, Path.GetFileName(imageWithName.Name));
-            DrawImage(imageWithName.Image, new ShapeCorners(new RectD(imageWithName.Position, imageWithName.Image.Size)),
+            var layerGuid = Internals.StructureHelper.CreateNewStructureMember(StructureMemberType.Layer,
+                Path.GetFileName(imageWithName.Name));
+            DrawImage(imageWithName.Image,
+                new ShapeCorners(new RectD(imageWithName.Position, imageWithName.Image.Size)),
                 layerGuid, true, false, frame, false);
                 layerGuid, true, false, frame, false);
         }
         }
+
         Internals.ActionAccumulator.AddFinishedActions();
         Internals.ActionAccumulator.AddFinishedActions();
     }
     }
 
 
@@ -180,11 +181,28 @@ internal class DocumentOperationsModule : IDocumentOperations
     /// Deletes all members with the <paramref name="guids"/>
     /// Deletes all members with the <paramref name="guids"/>
     /// </summary>
     /// </summary>
     /// <param name="guids">The Guids of the layers to delete</param>
     /// <param name="guids">The Guids of the layers to delete</param>
-    public void DeleteStructureMembers(IReadOnlyList<Guid> guids)
+    public void DeleteStructureMembers(IReadOnlyList<Guid> guids, bool selectNext = true)
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
-        Internals.ActionAccumulator.AddFinishedActions(guids.Select(static guid => new DeleteStructureMember_Action(guid)).ToArray());
+
+        Guid closestMember = FindClosestMember(guids);
+        
+        IAction[] actions = new IAction[guids.Count + (selectNext ? 1 : 0)];
+        for (int i = 0; i < guids.Count; i++)
+        {
+            actions[i] = new DeleteStructureMember_Action(guids[i]);
+        }
+
+        if (selectNext)
+        {
+            if (closestMember != Guid.Empty)
+            {
+                actions[^1] = new SetSelectedMember_PassthroughAction(closestMember);
+            }
+        }
+
+        Internals.ActionAccumulator.AddFinishedActions(actions);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -194,7 +212,8 @@ internal class DocumentOperationsModule : IDocumentOperations
     /// <param name="anchor">Where the existing content should be put</param>
     /// <param name="anchor">Where the existing content should be put</param>
     public void ResizeCanvas(VecI newSize, ResizeAnchor anchor)
     public void ResizeCanvas(VecI newSize, ResizeAnchor anchor)
     {
     {
-        if (Internals.ChangeController.IsChangeActive || newSize.X > 9999 || newSize.Y > 9999 || newSize.X < 1 || newSize.Y < 1)
+        if (Internals.ChangeController.IsChangeActive || newSize.X > 9999 || newSize.Y > 9999 || newSize.X < 1 ||
+            newSize.Y < 1)
             return;
             return;
 
 
         if (Document.ReferenceLayerHandler.ReferenceBitmap is not null)
         if (Document.ReferenceLayerHandler.ReferenceBitmap is not null)
@@ -208,7 +227,8 @@ internal class DocumentOperationsModule : IDocumentOperations
                 BottomLeft = curShape.BottomLeft + offset,
                 BottomLeft = curShape.BottomLeft + offset,
                 BottomRight = curShape.BottomRight + offset,
                 BottomRight = curShape.BottomRight + offset,
             };
             };
-            Internals.ActionAccumulator.AddActions(new TransformReferenceLayer_Action(offsetCorners), new EndTransformReferenceLayer_Action());
+            Internals.ActionAccumulator.AddActions(new TransformReferenceLayer_Action(offsetCorners),
+                new EndTransformReferenceLayer_Action());
         }
         }
 
 
         Internals.ActionAccumulator.AddFinishedActions(new ResizeCanvas_Action(newSize, anchor));
         Internals.ActionAccumulator.AddFinishedActions(new ResizeCanvas_Action(newSize, anchor));
@@ -221,7 +241,8 @@ internal class DocumentOperationsModule : IDocumentOperations
     /// <param name="resampling">The resampling method to use</param>
     /// <param name="resampling">The resampling method to use</param>
     public void ResizeImage(VecI newSize, ResamplingMethod resampling)
     public void ResizeImage(VecI newSize, ResamplingMethod resampling)
     {
     {
-        if (Internals.ChangeController.IsChangeActive || newSize.X > 9999 || newSize.Y > 9999 || newSize.X < 1 || newSize.Y < 1)
+        if (Internals.ChangeController.IsChangeActive || newSize.X > 9999 || newSize.Y > 9999 || newSize.X < 1 ||
+            newSize.Y < 1)
             return;
             return;
 
 
         if (Document.ReferenceLayerHandler.ReferenceBitmap is not null)
         if (Document.ReferenceLayerHandler.ReferenceBitmap is not null)
@@ -235,7 +256,8 @@ internal class DocumentOperationsModule : IDocumentOperations
                 BottomLeft = curShape.BottomLeft.Multiply(scale),
                 BottomLeft = curShape.BottomLeft.Multiply(scale),
                 BottomRight = curShape.BottomRight.Multiply(scale),
                 BottomRight = curShape.BottomRight.Multiply(scale),
             };
             };
-            Internals.ActionAccumulator.AddActions(new TransformReferenceLayer_Action(offsetCorners), new EndTransformReferenceLayer_Action());
+            Internals.ActionAccumulator.AddActions(new TransformReferenceLayer_Action(offsetCorners),
+                new EndTransformReferenceLayer_Action());
         }
         }
 
 
         Internals.ActionAccumulator.AddFinishedActions(new ResizeImage_Action(newSize, resampling));
         Internals.ActionAccumulator.AddFinishedActions(new ResizeImage_Action(newSize, resampling));
@@ -250,17 +272,18 @@ internal class DocumentOperationsModule : IDocumentOperations
     {
     {
         if (Internals.ChangeController.IsChangeActive || oldColor == newColor)
         if (Internals.ChangeController.IsChangeActive || oldColor == newColor)
             return;
             return;
-        
-        Internals.ActionAccumulator.AddFinishedActions(new ReplaceColor_Action(oldColor.ToColor(), newColor.ToColor(), frame));
+
+        Internals.ActionAccumulator.AddFinishedActions(new ReplaceColor_Action(oldColor.ToColor(), newColor.ToColor(),
+            frame));
         ReplaceInPalette(oldColor, newColor);
         ReplaceInPalette(oldColor, newColor);
     }
     }
 
 
     private void ReplaceInPalette(PaletteColor oldColor, PaletteColor newColor)
     private void ReplaceInPalette(PaletteColor oldColor, PaletteColor newColor)
     {
     {
         int indexOfOldColor = Document.Palette.IndexOf(oldColor);
         int indexOfOldColor = Document.Palette.IndexOf(oldColor);
-        if(indexOfOldColor == -1)
+        if (indexOfOldColor == -1)
             return;
             return;
-        
+
         Document.Palette.RemoveAt(indexOfOldColor);
         Document.Palette.RemoveAt(indexOfOldColor);
         Document.Palette.Insert(indexOfOldColor, newColor);
         Document.Palette.Insert(indexOfOldColor, newColor);
     }
     }
@@ -286,7 +309,7 @@ internal class DocumentOperationsModule : IDocumentOperations
             return;
             return;
         Internals.ActionAccumulator.AddFinishedActions(new DeleteStructureMemberMask_Action(member.Id));
         Internals.ActionAccumulator.AddFinishedActions(new DeleteStructureMemberMask_Action(member.Id));
     }
     }
-    
+
     /// <summary>
     /// <summary>
     /// Applies the mask to the image
     /// Applies the mask to the image
     /// </summary>
     /// </summary>
@@ -294,39 +317,49 @@ internal class DocumentOperationsModule : IDocumentOperations
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
-        
-        Internals.ActionAccumulator.AddFinishedActions(new ApplyMask_Action(member.Id, frame), new DeleteStructureMemberMask_Action(member.Id));
+
+        Internals.ActionAccumulator.AddFinishedActions(new ApplyMask_Action(member.Id, frame),
+            new DeleteStructureMemberMask_Action(member.Id));
     }
     }
 
 
     /// <summary>
     /// <summary>
     /// Sets the selected structure memeber
     /// Sets the selected structure memeber
     /// </summary>
     /// </summary>
     /// <param name="memberGuid">The Guid of the member to select</param>
     /// <param name="memberGuid">The Guid of the member to select</param>
-    public void SetSelectedMember(Guid memberGuid) => Internals.ActionAccumulator.AddActions(new SetSelectedMember_PassthroughAction(memberGuid));
+    public void SetSelectedMember(Guid memberGuid) =>
+        Internals.ActionAccumulator.AddActions(new SetSelectedMember_PassthroughAction(memberGuid));
 
 
     /// <summary>
     /// <summary>
     /// Adds a member to the soft selection
     /// Adds a member to the soft selection
     /// </summary>
     /// </summary>
     /// <param name="memberGuid">The Guid of the member to add</param>
     /// <param name="memberGuid">The Guid of the member to add</param>
-    public void AddSoftSelectedMember(Guid memberGuid) => Internals.ActionAccumulator.AddActions(new AddSoftSelectedMember_PassthroughAction(memberGuid));
+    public void AddSoftSelectedMember(Guid memberGuid) =>
+        Internals.ActionAccumulator.AddActions(new AddSoftSelectedMember_PassthroughAction(memberGuid));
 
 
     /// <summary>
     /// <summary>
     /// Removes a member from the soft selection
     /// Removes a member from the soft selection
     /// </summary>
     /// </summary>
     /// <param name="memberGuid">The Guid of the member to remove</param>
     /// <param name="memberGuid">The Guid of the member to remove</param>
-    public void RemoveSoftSelectedMember(Guid memberGuid) => Internals.ActionAccumulator.AddActions(new RemoveSoftSelectedMember_PassthroughAction(memberGuid));
+    public void RemoveSoftSelectedMember(Guid memberGuid) =>
+        Internals.ActionAccumulator.AddActions(new RemoveSoftSelectedMember_PassthroughAction(memberGuid));
 
 
     /// <summary>
     /// <summary>
     /// Clears the soft selection
     /// Clears the soft selection
     /// </summary>
     /// </summary>
-    public void ClearSoftSelectedMembers() => Internals.ActionAccumulator.AddActions(new ClearSoftSelectedMembers_PassthroughAction());
-    
-    public void SetActiveFrame(int newFrame) => Internals.ActionAccumulator.AddActions(new SetActiveFrame_PassthroughAction(newFrame));
-    public void AddSelectedKeyFrame(Guid keyFrameGuid) => Internals.ActionAccumulator.AddActions(new AddSelectedKeyFrame_PassthroughAction(keyFrameGuid));
-    
-    public void RemoveSelectedKeyFrame(Guid keyFrameGuid) => Internals.ActionAccumulator.AddActions(new RemoveSelectedKeyFrame_PassthroughAction(keyFrameGuid));
-    
-    public void ClearSelectedKeyFrames() => Internals.ActionAccumulator.AddActions(new ClearSelectedKeyFrames_PassthroughAction());
+    public void ClearSoftSelectedMembers() =>
+        Internals.ActionAccumulator.AddActions(new ClearSoftSelectedMembers_PassthroughAction());
+
+    public void SetActiveFrame(int newFrame) =>
+        Internals.ActionAccumulator.AddActions(new SetActiveFrame_PassthroughAction(newFrame));
+
+    public void AddSelectedKeyFrame(Guid keyFrameGuid) =>
+        Internals.ActionAccumulator.AddActions(new AddSelectedKeyFrame_PassthroughAction(keyFrameGuid));
+
+    public void RemoveSelectedKeyFrame(Guid keyFrameGuid) =>
+        Internals.ActionAccumulator.AddActions(new RemoveSelectedKeyFrame_PassthroughAction(keyFrameGuid));
+
+    public void ClearSelectedKeyFrames() =>
+        Internals.ActionAccumulator.AddActions(new ClearSelectedKeyFrames_PassthroughAction());
 
 
     /// <summary>
     /// <summary>
     /// Undo last change
     /// Undo last change
@@ -338,6 +371,7 @@ internal class DocumentOperationsModule : IDocumentOperations
             Internals.ChangeController.MidChangeUndoInlet();
             Internals.ChangeController.MidChangeUndoInlet();
             return;
             return;
         }
         }
+
         Internals.ActionAccumulator.AddActions(new Undo_Action());
         Internals.ActionAccumulator.AddActions(new Undo_Action());
     }
     }
 
 
@@ -351,6 +385,7 @@ internal class DocumentOperationsModule : IDocumentOperations
             Internals.ChangeController.MidChangeRedoInlet();
             Internals.ChangeController.MidChangeRedoInlet();
             return;
             return;
         }
         }
+
         Internals.ActionAccumulator.AddActions(new Redo_Action());
         Internals.ActionAccumulator.AddActions(new Redo_Action());
     }
     }
 
 
@@ -359,7 +394,7 @@ internal class DocumentOperationsModule : IDocumentOperations
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
         {
         {
             Internals.ChangeController.SelectedObjectNudgedInlet(distance);
             Internals.ChangeController.SelectedObjectNudgedInlet(distance);
-        }    
+        }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -368,7 +403,8 @@ internal class DocumentOperationsModule : IDocumentOperations
     /// <param name="memberToMove">The member to move</param>
     /// <param name="memberToMove">The member to move</param>
     /// <param name="memberToMoveIntoOrNextTo">The target member</param>
     /// <param name="memberToMoveIntoOrNextTo">The target member</param>
     /// <param name="placement">Where to place the <paramref name="memberToMove"/></param>
     /// <param name="placement">Where to place the <paramref name="memberToMove"/></param>
-    public void MoveStructureMember(Guid memberToMove, Guid memberToMoveIntoOrNextTo, StructureMemberPlacement placement)
+    public void MoveStructureMember(Guid memberToMove, Guid memberToMoveIntoOrNextTo,
+        StructureMemberPlacement placement)
     {
     {
         if (Internals.ChangeController.IsChangeActive || memberToMove == memberToMoveIntoOrNextTo)
         if (Internals.ChangeController.IsChangeActive || memberToMove == memberToMoveIntoOrNextTo)
             return;
             return;
@@ -384,7 +420,7 @@ internal class DocumentOperationsModule : IDocumentOperations
             return;
             return;
 
 
         IStructureMemberHandler? node = Document.StructureHelper.FindNode<IStructureMemberHandler>(members[0]);
         IStructureMemberHandler? node = Document.StructureHelper.FindNode<IStructureMemberHandler>(members[0]);
-        
+
         if (node is null)
         if (node is null)
             return;
             return;
 
 
@@ -397,20 +433,21 @@ internal class DocumentOperationsModule : IDocumentOperations
                 parent = traversedNode;
                 parent = traversedNode;
                 return false;
                 return false;
             }
             }
-            
+
             return true;
             return true;
         });
         });
-        
+
         if (parent is null)
         if (parent is null)
             return;
             return;
-        
+
         Guid newGuid = Guid.NewGuid();
         Guid newGuid = Guid.NewGuid();
 
 
         //make a new layer, put combined image onto it, delete layers that were merged
         //make a new layer, put combined image onto it, delete layers that were merged
         Internals.ActionAccumulator.AddActions(
         Internals.ActionAccumulator.AddActions(
             new CreateStructureMember_Action(parent.Id, newGuid, StructureMemberType.Layer),
             new CreateStructureMember_Action(parent.Id, newGuid, StructureMemberType.Layer),
             new StructureMemberName_Action(newGuid, node.NodeNameBindable),
             new StructureMemberName_Action(newGuid, node.NodeNameBindable),
-            new CombineStructureMembersOnto_Action(members.ToHashSet(), newGuid, Document.AnimationHandler.ActiveFrameBindable));
+            new CombineStructureMembersOnto_Action(members.ToHashSet(), newGuid,
+                Document.AnimationHandler.ActiveFrameBindable));
         foreach (var member in members)
         foreach (var member in members)
             Internals.ActionAccumulator.AddActions(new DeleteStructureMember_Action(member));
             Internals.ActionAccumulator.AddActions(new DeleteStructureMember_Action(member));
         Internals.ActionAccumulator.AddActions(new ChangeBoundary_Action());
         Internals.ActionAccumulator.AddActions(new ChangeBoundary_Action());
@@ -460,7 +497,8 @@ internal class DocumentOperationsModule : IDocumentOperations
             Internals.ChangeController.TryStopActiveExecutor();
             Internals.ChangeController.TryStopActiveExecutor();
     }
     }
 
 
-    public void DrawImage(Surface image, ShapeCorners corners, Guid memberGuid, bool ignoreClipSymmetriesEtc, bool drawOnMask, int frame) =>
+    public void DrawImage(Surface image, ShapeCorners corners, Guid memberGuid, bool ignoreClipSymmetriesEtc,
+        bool drawOnMask, int frame) =>
         DrawImage(image, corners, memberGuid, ignoreClipSymmetriesEtc, drawOnMask, frame, true);
         DrawImage(image, corners, memberGuid, ignoreClipSymmetriesEtc, drawOnMask, frame, true);
 
 
     /// <summary>
     /// <summary>
@@ -472,7 +510,8 @@ internal class DocumentOperationsModule : IDocumentOperations
     /// <param name="ignoreClipSymmetriesEtc">Ignore selection clipping and symmetry (See DrawingChangeHelper.ApplyClipsSymmetriesEtc of UpdateableDocument)</param>
     /// <param name="ignoreClipSymmetriesEtc">Ignore selection clipping and symmetry (See DrawingChangeHelper.ApplyClipsSymmetriesEtc of UpdateableDocument)</param>
     /// <param name="drawOnMask">Draw on the mask or on the image</param>
     /// <param name="drawOnMask">Draw on the mask or on the image</param>
     /// <param name="finish">Is this a finished action</param>
     /// <param name="finish">Is this a finished action</param>
-    private void DrawImage(Surface image, ShapeCorners corners, Guid memberGuid, bool ignoreClipSymmetriesEtc, bool drawOnMask, int atFrame, bool finish)
+    private void DrawImage(Surface image, ShapeCorners corners, Guid memberGuid, bool ignoreClipSymmetriesEtc,
+        bool drawOnMask, int atFrame, bool finish)
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
@@ -490,7 +529,8 @@ internal class DocumentOperationsModule : IDocumentOperations
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
-        Internals.ActionAccumulator.AddFinishedActions(new ClipCanvas_Action(Document.AnimationHandler.ActiveFrameBindable));
+        Internals.ActionAccumulator.AddFinishedActions(
+            new ClipCanvas_Action(Document.AnimationHandler.ActiveFrameBindable));
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -505,7 +545,7 @@ internal class DocumentOperationsModule : IDocumentOperations
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
-        
+
         Internals.ActionAccumulator.AddFinishedActions(new FlipImage_Action(flipType, frame, membersToFlip));
         Internals.ActionAccumulator.AddFinishedActions(new FlipImage_Action(flipType, frame, membersToFlip));
     }
     }
 
 
@@ -523,10 +563,10 @@ internal class DocumentOperationsModule : IDocumentOperations
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
-        
+
         Internals.ActionAccumulator.AddFinishedActions(new RotateImage_Action(rotation, membersToRotate, frame));
         Internals.ActionAccumulator.AddFinishedActions(new RotateImage_Action(rotation, membersToRotate, frame));
     }
     }
-    
+
     /// <summary>
     /// <summary>
     /// Puts the content of the image in the middle of the canvas
     /// Puts the content of the image in the middle of the canvas
     /// </summary>
     /// </summary>
@@ -547,9 +587,11 @@ internal class DocumentOperationsModule : IDocumentOperations
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
 
 
-        RectD referenceImageRect = new RectD(VecD.Zero, Document.SizeBindable).AspectFit(new RectD(VecD.Zero, imageSize));
+        RectD referenceImageRect =
+            new RectD(VecD.Zero, Document.SizeBindable).AspectFit(new RectD(VecD.Zero, imageSize));
         ShapeCorners corners = new ShapeCorners(referenceImageRect);
         ShapeCorners corners = new ShapeCorners(referenceImageRect);
-        Internals.ActionAccumulator.AddFinishedActions(new SetReferenceLayer_Action(corners, imageBgra8888Bytes, imageSize));
+        Internals.ActionAccumulator.AddFinishedActions(new SetReferenceLayer_Action(corners, imageBgra8888Bytes,
+            imageSize));
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -582,14 +624,14 @@ internal class DocumentOperationsModule : IDocumentOperations
             return;
             return;
 
 
 
 
-
-        VecD size = new(Document.ReferenceLayerHandler.ReferenceBitmap.Size.X, Document.ReferenceLayerHandler.ReferenceBitmap.Size.Y);
+        VecD size = new(Document.ReferenceLayerHandler.ReferenceBitmap.Size.X,
+            Document.ReferenceLayerHandler.ReferenceBitmap.Size.Y);
         RectD referenceImageRect = new RectD(VecD.Zero, Document.SizeBindable).AspectFit(new RectD(VecD.Zero, size));
         RectD referenceImageRect = new RectD(VecD.Zero, Document.SizeBindable).AspectFit(new RectD(VecD.Zero, size));
         ShapeCorners corners = new ShapeCorners(referenceImageRect);
         ShapeCorners corners = new ShapeCorners(referenceImageRect);
         Internals.ActionAccumulator.AddFinishedActions(
         Internals.ActionAccumulator.AddFinishedActions(
             new TransformReferenceLayer_Action(corners),
             new TransformReferenceLayer_Action(corners),
             new EndTransformReferenceLayer_Action()
             new EndTransformReferenceLayer_Action()
-            );
+        );
     }
     }
 
 
     public void SelectionToMask(SelectionMode mode, int frame)
     public void SelectionToMask(SelectionMode mode, int frame)
@@ -601,7 +643,7 @@ internal class DocumentOperationsModule : IDocumentOperations
         {
         {
             Internals.ActionAccumulator.AddActions(new CreateStructureMemberMask_Action(member.Id));
             Internals.ActionAccumulator.AddActions(new CreateStructureMemberMask_Action(member.Id));
         }
         }
-        
+
         Internals.ActionAccumulator.AddFinishedActions(new SelectionToMask_Action(member.Id, mode, frame));
         Internals.ActionAccumulator.AddFinishedActions(new SelectionToMask_Action(member.Id, mode, frame));
     }
     }
 
 
@@ -622,13 +664,57 @@ internal class DocumentOperationsModule : IDocumentOperations
             Internals.ActionAccumulator.AddFinishedActions();
             Internals.ActionAccumulator.AddFinishedActions();
         }
         }
     }
     }
-    
+
     public void InvertSelection()
     public void InvertSelection()
     {
     {
         var selection = Document.SelectionPathBindable;
         var selection = Document.SelectionPathBindable;
         var inverse = new VectorPath();
         var inverse = new VectorPath();
         inverse.AddRect(new RectI(new(0, 0), Document.SizeBindable));
         inverse.AddRect(new RectI(new(0, 0), Document.SizeBindable));
 
 
-        Internals.ActionAccumulator.AddFinishedActions(new SetSelection_Action(inverse.Op(selection, VectorPathOp.Difference)));
+        Internals.ActionAccumulator.AddFinishedActions(
+            new SetSelection_Action(inverse.Op(selection, VectorPathOp.Difference)));
+    }
+
+    private Guid FindClosestMember(IReadOnlyList<Guid> guids)
+    {
+        IStructureMemberHandler? firstNode = Document.StructureHelper.FindNode<IStructureMemberHandler>(guids[0]);
+        if (firstNode is null)
+            return Guid.Empty;
+
+        INodeHandler? parent = null;
+
+        firstNode.TraverseForwards(traversedNode =>
+        {
+            if (!guids.Contains(traversedNode.Id) && traversedNode is IStructureMemberHandler)
+            {
+                parent = traversedNode;
+                return false;
+            }
+
+            return true;
+        });
+
+        if (parent is null)
+        {
+            var lastNode = Document.StructureHelper.FindNode<IStructureMemberHandler>(guids[^1]);
+            if (lastNode is null)
+                return Guid.Empty;
+            
+            lastNode.TraverseBackwards(traversedNode =>
+            {
+                if (!guids.Contains(traversedNode.Id) && traversedNode is IStructureMemberHandler)
+                {
+                    parent = traversedNode;
+                    return false;
+                }
+
+                return true;
+            });
+        }
+        
+        if (parent is null)
+            return Guid.Empty;
+
+        return parent.Id;
     }
     }
 }
 }

+ 2 - 13
src/PixiEditor/ViewModels/SubViewModels/LayersViewModel.cs

@@ -55,19 +55,6 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         return true;
         return true;
     }
     }
 
 
-    [Command.Basic("PixiEditor.Layer.DeleteSelected", "LAYER_DELETE_SELECTED", 
-        "LAYER_DELETE_SELECTED_DESCRIPTIVE", 
-        CanExecute = "PixiEditor.Layer.CanDeleteSelected", 
-        Icon = PixiPerfectIcons.Trash, AnalyticsTrack = true)]
-    public void DeleteSelected()
-    {
-        var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
-        if (member is null)
-            return;
-
-        member.Document.Operations.DeleteStructureMember(member.Id);
-    }
-
     [Evaluator.CanExecute("PixiEditor.Layer.HasSelectedMembers")]
     [Evaluator.CanExecute("PixiEditor.Layer.HasSelectedMembers")]
     public bool HasSelectedMembers()
     public bool HasSelectedMembers()
     {
     {
@@ -111,7 +98,9 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
             return;
             return;
         var selected = GetSelected();
         var selected = GetSelected();
         if (selected.Count > 0)
         if (selected.Count > 0)
+        {
             doc.Operations.DeleteStructureMembers(selected);
             doc.Operations.DeleteStructureMembers(selected);
+        }
     }
     }
 
 
     [Command.Basic("PixiEditor.Layer.NewFolder", "NEW_FOLDER", "CREATE_NEW_FOLDER", CanExecute = "PixiEditor.Layer.CanCreateNewMember",
     [Command.Basic("PixiEditor.Layer.NewFolder", "NEW_FOLDER", "CREATE_NEW_FOLDER", CanExecute = "PixiEditor.Layer.CanCreateNewMember",

+ 1 - 1
src/PixiEditor/Views/Layers/LayersManager.axaml

@@ -44,7 +44,7 @@
                     Content="{DynamicResource icon-folder-plus}"
                     Content="{DynamicResource icon-folder-plus}"
                     FlowDirection="LeftToRight"/>
                     FlowDirection="LeftToRight"/>
                 <Button 
                 <Button 
-                    Command="{xaml:Command PixiEditor.Layer.DeleteSelected}" Height="24" Width="24" uiExt:Translator.TooltipKey="LAYER_DELETE_ALL_SELECTED"
+                    Command="{xaml:Command PixiEditor.Layer.DeleteAllSelected}" Height="24" Width="24" uiExt:Translator.TooltipKey="LAYER_DELETE_ALL_SELECTED"
                     Cursor="Hand"
                     Cursor="Hand"
                     HorizontalAlignment="Stretch" Margin="0,0,5,0"
                     HorizontalAlignment="Stretch" Margin="0,0,5,0"
                     DockPanel.Dock="Left"
                     DockPanel.Dock="Left"