Browse Source

Undo LayerStructure bug wip

flabbet 4 years ago
parent
commit
82b667d133

+ 4 - 1
PixiEditor/Models/DataHolders/Document/Document.Constructors.cs

@@ -32,7 +32,10 @@ namespace PixiEditor.Models.DataHolders
 
         private void Groups_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
         {
-            RaisePropertyChanged(nameof(LayerStructure));
+            if (e.OldItems != e.NewItems)
+            {
+                RaisePropertyChanged(nameof(LayerStructure));
+            }
         }
 
         private void Layers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

+ 38 - 31
PixiEditor/Models/DataHolders/Document/Document.Layers.cs

@@ -5,7 +5,6 @@ using System.Collections.ObjectModel;
 using System.Linq;
 using System.Windows;
 using System.Windows.Media.Imaging;
-using GalaSoft.MvvmLight.Messaging;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Layers;
@@ -38,15 +37,8 @@ namespace PixiEditor.Models.DataHolders
             get => layerStructure;
             set
             {
-                if (layerStructure != null)
-                {
-                    layerStructure.Groups.CollectionChanged -= Groups_CollectionChanged;
-                    layerStructure.LayerStructureChanged -= LayerStructure_LayerStructureChanged;
-                }
-
-                SetProperty(ref layerStructure, value);
-                value.Groups.CollectionChanged += Groups_CollectionChanged;
-                value.LayerStructureChanged += LayerStructure_LayerStructureChanged;
+                layerStructure = value;
+                RaisePropertyChanged(nameof(LayerStructure));
             }
         }
 
@@ -108,11 +100,11 @@ namespace PixiEditor.Models.DataHolders
 
             int oldIndex = Layers.IndexOf(layer);
 
-            var oldLayerStrcuture = LayerStructure.Clone();
+            var oldLayerStrcutureGroups = LayerStructure.CloneGroups();
 
             MoveLayerInStructureProcess(args);
 
-            AddLayerStructureToUndo(oldLayerStrcuture);
+            AddLayerStructureToUndo(oldLayerStrcutureGroups);
 
             UndoManager.AddUndoChange(new Change(
                 ReverseMoveLayerInStructureProcess,
@@ -146,7 +138,7 @@ namespace PixiEditor.Models.DataHolders
                 oldAbove = true;
             }
 
-            var oldLayerStructure = LayerStructure.Clone();
+            var oldLayerStructure = LayerStructure.CloneGroups();
 
             MoveGroupInStructureProcess(args);
 
@@ -312,7 +304,7 @@ namespace PixiEditor.Models.DataHolders
                 return;
             }
 
-            var oldLayerStructure = LayerStructure.Clone();
+            var oldLayerStructure = LayerStructure.CloneGroups();
 
             Layer[] layers = Layers.Where(x => x.IsActive).ToArray();
             int firstIndex = Layers.IndexOf(layers[0]);
@@ -332,10 +324,14 @@ namespace PixiEditor.Models.DataHolders
             SetNextLayerAsActive(firstIndex);
         }
 
-        public void AddLayerStructureToUndo(LayerStructure oldLayerStructure)
+        public void AddLayerStructureToUndo(ObservableCollection<GuidStructureItem> oldLayerStructureGroups)
         {
             UndoManager.AddUndoChange(
-                new Change(nameof(LayerStructure), oldLayerStructure, LayerStructure.Clone(), root: this));
+                new Change(
+                    BuildLayerStructureProcess,
+                    new[] { oldLayerStructureGroups },
+                    BuildLayerStructureProcess,
+                    new[] { LayerStructure.CloneGroups() }));
         }
 
         public Layer MergeLayers(Layer[] layersToMerge, bool nameOfLast, int index)
@@ -363,7 +359,7 @@ namespace PixiEditor.Models.DataHolders
 
             Layer placeholderLayer = new("_placeholder");
             Layers.Insert(index, placeholderLayer);
-            LayerStructure.AssignParent(placeholderLayer.LayerGuid, groupParent);
+            LayerStructure.AssignParent(placeholderLayer.LayerGuid, groupParent.GroupGuid);
 
             for (int i = 0; i < layersToMerge.Length - 1; i++)
             {
@@ -374,7 +370,7 @@ namespace PixiEditor.Models.DataHolders
             }
 
             Layers.Insert(index, mergedLayer);
-            LayerStructure.AssignParent(mergedLayer.LayerGuid, groupParent);
+            LayerStructure.AssignParent(mergedLayer.LayerGuid, groupParent.GroupGuid);
 
             RemoveLayer(placeholderLayer, false);
 
@@ -394,7 +390,7 @@ namespace PixiEditor.Models.DataHolders
 
             IEnumerable<Layer> undoArgs = layersToMerge;
 
-            var oldLayerStructure = LayerStructure.Clone();
+            var oldLayerStructure = LayerStructure.CloneGroups();
 
             StorageBasedChange undoChange = new(this, undoArgs);
 
@@ -415,6 +411,17 @@ namespace PixiEditor.Models.DataHolders
             return layer;
         }
 
+        private void BuildLayerStructureProcess(object[] parameters)
+        {
+            if(parameters.Length > 0 && parameters[0] is ObservableCollection<GuidStructureItem> groups)
+            {
+                LayerStructure.Groups.CollectionChanged -= Groups_CollectionChanged;
+                LayerStructure.Groups = LayerStructure.CloneGroups(groups);
+                LayerStructure.Groups.CollectionChanged += Groups_CollectionChanged;
+                RaisePropertyChanged(nameof(LayerStructure));
+            }
+        }
+
         private void ReverseMoveLayerInStructureProcess(object[] props)
         {
             int indexTo = (int)props[0];
@@ -422,15 +429,15 @@ namespace PixiEditor.Models.DataHolders
 
             Guid layerAtOldIndex = Layers[indexTo].LayerGuid;
 
-            var startFolder = LayerStructure.GetGroupByLayer(layerGuid);
+            var startGroup = LayerStructure.GetGroupByLayer(layerGuid);
 
-            LayerStructure.PreMoveReassignBounds(startFolder, layerGuid);
+            LayerStructure.PreMoveReassignBounds(new GroupData(startGroup?.GroupGuid), layerGuid);
 
             Layers.Move(Layers.IndexOf(Layers.First(x => x.LayerGuid == layerGuid)), indexTo);
 
-            var newFolder = LayerStructure.GetGroupByLayer(layerAtOldIndex);
+            var newGroup = LayerStructure.GetGroupByLayer(layerAtOldIndex);
 
-            LayerStructure.PostMoveReassignBounds(newFolder, layerGuid);
+            LayerStructure.PostMoveReassignBounds(new GroupData(newGroup?.GroupGuid), layerGuid);
 
             RaisePropertyChanged(nameof(LayerStructure));
         }
@@ -526,17 +533,17 @@ namespace PixiEditor.Models.DataHolders
 
         private void MoveGroupInStructureProcess(object[] parameter)
         {
-            Guid folderGuid = (Guid)parameter[0];
+            Guid groupGuid = (Guid)parameter[0];
             Guid referenceLayerGuid = (Guid)parameter[1];
             bool above = (bool)parameter[2];
 
-            GuidStructureItem group = LayerStructure.GetGroupByGuid(folderGuid);
+            GuidStructureItem group = LayerStructure.GetGroupByGuid(groupGuid);
             GuidStructureItem referenceLayergroup = LayerStructure.GetGroupByLayer(referenceLayerGuid);
 
             Layer referenceLayer = Layers.First(x => x.LayerGuid == referenceLayerGuid);
 
             int layerIndex = Layers.IndexOf(referenceLayer);
-            int folderTopIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == group.EndLayerGuid));
+            int folderTopIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == group?.EndLayerGuid));
             int oldIndex = folderTopIndex;
 
             if (layerIndex < folderTopIndex)
@@ -547,11 +554,11 @@ namespace PixiEditor.Models.DataHolders
 
             int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
 
-            LayerStructure.MoveGroup(folderGuid, group.Parent, newIndex);
+            LayerStructure.MoveGroup(groupGuid, group?.Parent?.GroupGuid, newIndex);
 
             ReassignParent(group, referenceLayergroup);
 
-            LayerStructure.PostMoveReassignBounds(group.Parent, group);
+            LayerStructure.PostMoveReassignBounds(new GroupData(group?.Parent?.GroupGuid), new GroupData(group.GroupGuid));
         }
 
         private void ReassignParent(GuidStructureItem folder, GuidStructureItem referenceLayerFolder)
@@ -603,15 +610,15 @@ namespace PixiEditor.Models.DataHolders
             int oldIndex = Layers.IndexOf(Layers.First(x => x.LayerGuid == layer));
             int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
 
-            var startFolder = LayerStructure.GetGroupByLayer(layer);
+            var startGroup = LayerStructure.GetGroupByLayer(layer);
 
-            LayerStructure.PreMoveReassignBounds(startFolder, layer);
+            LayerStructure.PreMoveReassignBounds(new GroupData(startGroup?.GroupGuid), layer);
 
             Layers.Move(oldIndex, newIndex);
 
             var newFolder = LayerStructure.GetGroupByLayer(referenceLayer);
 
-            LayerStructure.PostMoveReassignBounds(newFolder, layer);
+            LayerStructure.PostMoveReassignBounds(new GroupData(newFolder?.GroupGuid), layer);
 
             if (Layers.IndexOf(ActiveLayer) == oldIndex)
             {

+ 8 - 6
PixiEditor/Models/Layers/FolderData.cs → PixiEditor/Models/Layers/GroupData.cs

@@ -1,17 +1,19 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace PixiEditor.Models.Layers
 {
-    public record FolderData
+    public record GroupData
     {
         public int TopIndex { get; set; }
         public int BottomIndex { get; set; }
+        public Guid? GroupGuid { get; set; }
 
-        public FolderData(int topIndex, int bottomIndex)
+        public GroupData(Guid? groupGuid)
+        {
+            GroupGuid = groupGuid;
+        }
+
+        public GroupData(int topIndex, int bottomIndex)
         {
             TopIndex = topIndex;
             BottomIndex = bottomIndex;

+ 34 - 3
PixiEditor/Models/Layers/GuidStructureItem.cs

@@ -7,7 +7,7 @@ using PixiEditor.Helpers;
 namespace PixiEditor.Models.Layers
 {
     [DebuggerDisplay("{Name} - {GroupGuid}")]
-    public class GuidStructureItem : NotifyableObject
+    public class GuidStructureItem : NotifyableObject, ICloneable
     {
         public event EventHandler GroupsChanged;
 
@@ -80,11 +80,11 @@ namespace PixiEditor.Models.Layers
             string name,
             Guid startLayerGuid,
             Guid endLayerGuid,
-            IEnumerable<GuidStructureItem> subfolders,
+            IEnumerable<GuidStructureItem> subgroups,
             GuidStructureItem parent)
         {
             Name = name;
-            Subgroups = new ObservableCollection<GuidStructureItem>(subfolders);
+            Subgroups = new ObservableCollection<GuidStructureItem>(subgroups);
             GroupGuid = Guid.NewGuid();
             Parent = parent;
             StartLayerGuid = startLayerGuid;
@@ -102,6 +102,37 @@ namespace PixiEditor.Models.Layers
             Subgroups.CollectionChanged += Subgroups_CollectionChanged;
         }
 
+        public override int GetHashCode()
+        {
+            return GroupGuid.GetHashCode();
+        }
+
+        public GuidStructureItem CloneGroup()
+        {
+            GuidStructureItem item = new(Name, StartLayerGuid, EndLayerGuid, Array.Empty<GuidStructureItem>(), Parent?.CloneGroup())
+            {
+                GroupGuid = GroupGuid,
+                IsExpanded = isExpanded,
+                IsRenaming = isRenaming
+            };
+
+            if(Subgroups.Count > 0)
+            {
+                item.Subgroups = new ObservableCollection<GuidStructureItem>();
+                for (int i = 0; i < Subgroups.Count; i++)
+                {
+                    item.Subgroups.Add(item.CloneGroup());
+                }
+            }
+
+            return item;
+        }
+
+        public object Clone()
+        {
+            return CloneGroup();
+        }
+
         private void Subgroups_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
         {
             GroupsChanged?.Invoke(this, EventArgs.Empty);

+ 103 - 74
PixiEditor/Models/Layers/LayerStructure.cs

@@ -2,10 +2,19 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
+using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.DataHolders;
 
 namespace PixiEditor.Models.Layers
 {
+    // Notice for further developemnt. Remember to expose only GroupData classes if you want to modify this LayerStructure groups
+    // LayerStructure should figure out the GuidStructureItem from its internal data. This will ensure that data will
+    // modify correctly.
+    // You should pass GuidStructureItem for operating on protected and private methods for faster data manipulation.
+
+    /// <summary>
+    /// Class containing layer groups structure and methods to operate on it.
+    /// </summary>
     public class LayerStructure
     {
         public event EventHandler LayerStructureChanged;
@@ -29,30 +38,22 @@ namespace PixiEditor.Models.Layers
             return GetGroupByLayer(layerGuid, Groups);
         }
 
-        public LayerStructure Clone()
-        {
-            return new(CloneGroups(Groups), Owner);
-        }
-
-        private ObservableCollection<GuidStructureItem> CloneGroups(ObservableCollection<GuidStructureItem> groups)
+        public static ObservableCollection<GuidStructureItem> CloneGroups(ObservableCollection<GuidStructureItem> groups)
         {
             ObservableCollection<GuidStructureItem> outputGroups = new();
             foreach (var group in groups.ToArray())
             {
-                outputGroups.Add(new(group.Name, group.StartLayerGuid, group.EndLayerGuid, group.Subgroups, group.Parent)
-                {
-                    GroupGuid = group.GroupGuid,
-                    IsExpanded = group.IsExpanded
-                });
-                if(group.Subgroups.Count > 0)
-                {
-                    outputGroups[^1].Subgroups = CloneGroups(group.Subgroups);
-                }
+                outputGroups.Add(group.CloneGroup());
             }
 
             return outputGroups;
         }
 
+        public ObservableCollection<GuidStructureItem> CloneGroups()
+        {
+            return CloneGroups(Groups);
+        }
+
         // This will allow to add new group with multiple layers and groups at once. Not working well, todo fix
         /*public GuidStructureItem AddNewGroup(string groupName, IEnumerable<Layer> layers, Guid activeLayer)
         {
@@ -95,7 +96,7 @@ namespace PixiEditor.Models.Layers
         public GuidStructureItem AddNewGroup(string groupName, Guid childLayer)
         {
             var parent = GetGroupByLayer(childLayer);
-            GuidStructureItem group = new (groupName, childLayer);
+            GuidStructureItem group = new(groupName, childLayer);
             if (parent == null)
             {
                 Groups.Add(group);
@@ -113,9 +114,10 @@ namespace PixiEditor.Models.Layers
         }
 
 #nullable enable
-        public void MoveGroup(Guid groupGuid, GuidStructureItem? parentGroup, int newIndex)
+        public void MoveGroup(Guid groupGuid, Guid? parentGroupGuid, int newIndex)
         {
             var group = GetGroupByGuid(groupGuid);
+            var parentGroup = GetGroupByGuid(parentGroupGuid);
             bool reverseOrder = true;
             int groupTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == group.EndLayerGuid));
             int groupBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == group.StartLayerGuid));
@@ -135,19 +137,24 @@ namespace PixiEditor.Models.Layers
 
             PreMoveReassignBounds(parentGroup, group);
 
-            List<Guid> layersInOrder = GetLayersInOrder(new FolderData(groupTopIndex, groupBottomIndex));
+            List<Guid> layersInOrder = GetLayersInOrder(new GroupData(groupTopIndex, groupBottomIndex));
 
             MoveLayersInGroup(layersInOrder, difference, reverseOrder);
 
             LayerStructureChanged?.Invoke(this, EventArgs.Empty);
         }
 
-        public void PreMoveReassignBounds(GuidStructureItem? parentGroup, Guid layer)
+        public void PreMoveReassignBounds(GroupData parentGroup, Guid layer)
+        {
+            PreMoveReassignBounds(GetGroupByGuid(parentGroup.GroupGuid), layer);
+        }
+
+        protected void PreMoveReassignBounds(GuidStructureItem? parentGroup, Guid layer)
         {
             if (parentGroup != null)
             {
-                Guid? oldStart = parentGroup.StartLayerGuid;
-                Guid? oldEnd = parentGroup.EndLayerGuid;
+                Guid oldStart = parentGroup.StartLayerGuid;
+                Guid oldEnd = parentGroup.EndLayerGuid;
                 GuidStructureItem parentOfParent = parentGroup.Parent;
                 if (parentGroup.Subgroups.Count == 0 && parentGroup.StartLayerGuid == layer && parentGroup.EndLayerGuid == layer)
                 {
@@ -173,12 +180,17 @@ namespace PixiEditor.Models.Layers
             }
         }
 
-        public void PreMoveReassignBounds(GuidStructureItem? parentGroup, GuidStructureItem group)
+        public void PreMoveReassignBounds(GroupData parentGroup, GroupData group)
+        {
+            PreMoveReassignBounds(GetGroupByGuid(parentGroup.GroupGuid), GetGroupByGuid(group.GroupGuid));
+        }
+
+        protected void PreMoveReassignBounds(GuidStructureItem? parentGroup, GuidStructureItem group)
         {
             if (parentGroup != null)
             {
-                Guid? oldStart = parentGroup.StartLayerGuid;
-                Guid? oldEnd = parentGroup.EndLayerGuid;
+                Guid oldStart = parentGroup.StartLayerGuid;
+                Guid oldEnd = parentGroup.EndLayerGuid;
 
                 if (parentGroup.Subgroups.Count == 1 && parentGroup.StartLayerGuid == group.StartLayerGuid && parentGroup.EndLayerGuid == group.EndLayerGuid)
                 {
@@ -186,14 +198,14 @@ namespace PixiEditor.Models.Layers
                 }
                 else
                 {
-                    if (group.EndLayerGuid == parentGroup.EndLayerGuid && group.StartLayerGuid != null)
+                    if (group.EndLayerGuid == parentGroup.EndLayerGuid)
                     {
-                        parentGroup.EndLayerGuid = FindBoundLayer(parentGroup, (Guid)group.StartLayerGuid, false);
+                        parentGroup.EndLayerGuid = FindBoundLayer(parentGroup, group.StartLayerGuid, false);
                     }
 
-                    if (group.StartLayerGuid == parentGroup.StartLayerGuid && group.EndLayerGuid != null)
+                    if (group.StartLayerGuid == parentGroup.StartLayerGuid)
                     {
-                        parentGroup.StartLayerGuid = FindBoundLayer(parentGroup, (Guid)group.EndLayerGuid, true);
+                        parentGroup.StartLayerGuid = FindBoundLayer(parentGroup, group.EndLayerGuid, true);
                     }
                 }
 
@@ -212,21 +224,21 @@ namespace PixiEditor.Models.Layers
         /// <returns>True if group is nested inside parent, false if not.</returns>
         public bool IsChildOf(GuidStructureItem group, GuidStructureItem parent)
         {
-            if(group == null)
+            if (group == null)
             {
                 return false;
             }
 
             foreach (var subgroup in parent.Subgroups)
             {
-                if(subgroup == group)
+                if (subgroup == group)
                 {
                     return true;
                 }
 
-                if(subgroup.Subgroups.Count > 0)
+                if (subgroup.Subgroups.Count > 0)
                 {
-                    if(IsChildOf(group, subgroup))
+                    if (IsChildOf(group, subgroup))
                     {
                         return true;
                     }
@@ -246,7 +258,7 @@ namespace PixiEditor.Models.Layers
         {
             var layerParent = GetGroupByLayer(layerGuid);
 
-            if(layerParent == parent)
+            if (layerParent == parent)
             {
                 return true;
             }
@@ -255,7 +267,7 @@ namespace PixiEditor.Models.Layers
                 GuidStructureItem nextParent = parent;
                 while (nextParent.Parent != null)
                 {
-                    if(nextParent == parent)
+                    if (nextParent == parent)
                     {
                         return true;
                     }
@@ -267,7 +279,12 @@ namespace PixiEditor.Models.Layers
             return false;
         }
 
-        public void PostMoveReassignBounds(GuidStructureItem? parentGroup, Guid layerGuid)
+        public void PostMoveReassignBounds(GroupData parentGroup, Guid layerGuid)
+        {
+            PostMoveReassignBounds(GetGroupByGuid(parentGroup.GroupGuid), layerGuid);
+        }
+
+        protected void PostMoveReassignBounds(GuidStructureItem? parentGroup, Guid layerGuid)
         {
             if (parentGroup != null)
             {
@@ -302,36 +319,37 @@ namespace PixiEditor.Models.Layers
             }
         }
 
-        public void PostMoveReassignBounds(GuidStructureItem? parentGroup, GuidStructureItem group)
+        public void PostMoveReassignBounds(GroupData parentGroup, GroupData group)
+        {
+            PostMoveReassignBounds(GetGroupByGuid(parentGroup.GroupGuid), GetGroupByGuid(group.GroupGuid));
+        }
+
+        protected void PostMoveReassignBounds(GuidStructureItem? parentGroup, GuidStructureItem group)
         {
             if (parentGroup != null)
             {
-                Guid? oldStart = parentGroup.StartLayerGuid;
-                Guid? oldEnd = parentGroup.EndLayerGuid;
-
-                if (group.StartLayerGuid != null && group.EndLayerGuid != null)
-                {
-                    int folderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == group.EndLayerGuid));
-                    int folderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == group.StartLayerGuid));
+                Guid oldStart = parentGroup.StartLayerGuid;
+                Guid oldEnd = parentGroup.EndLayerGuid;
+                int folderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == group.EndLayerGuid));
+                int folderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == group.StartLayerGuid));
 
-                    int parentFolderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == parentGroup.EndLayerGuid));
-                    int parentFolderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == parentGroup.StartLayerGuid));
+                int parentFolderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == parentGroup.EndLayerGuid));
+                int parentFolderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == parentGroup.StartLayerGuid));
 
-                    int finalTopIndex = Math.Max(folderTopIndex, parentFolderTopIndex);
-                    int finalBottomIndex = Math.Min(folderBottomIndex, parentFolderBottomIndex);
+                int finalTopIndex = Math.Max(folderTopIndex, parentFolderTopIndex);
+                int finalBottomIndex = Math.Min(folderBottomIndex, parentFolderBottomIndex);
 
-                    Guid? topBoundLayer = FindBoundLayer((Guid)group.StartLayerGuid, finalTopIndex, finalBottomIndex, false);
-                    Guid? bottomBoundLayer = FindBoundLayer((Guid)group.EndLayerGuid, finalTopIndex, finalBottomIndex, true);
+                Guid topBoundLayer = FindBoundLayer(group.StartLayerGuid, finalTopIndex, finalBottomIndex, false);
+                Guid bottomBoundLayer = FindBoundLayer(group.EndLayerGuid, finalTopIndex, finalBottomIndex, true);
 
-                    if (topBoundLayer == parentGroup.EndLayerGuid)
-                    {
-                        parentGroup.EndLayerGuid = group.EndLayerGuid;
-                    }
+                if (topBoundLayer == parentGroup.EndLayerGuid)
+                {
+                    parentGroup.EndLayerGuid = group.EndLayerGuid;
+                }
 
-                    if (bottomBoundLayer == parentGroup.StartLayerGuid)
-                    {
-                        parentGroup.StartLayerGuid = group.StartLayerGuid;
-                    }
+                if (bottomBoundLayer == parentGroup.StartLayerGuid)
+                {
+                    parentGroup.StartLayerGuid = group.StartLayerGuid;
                 }
 
                 if (parentGroup.Parent != null)
@@ -341,10 +359,15 @@ namespace PixiEditor.Models.Layers
             }
         }
 
-        public void AssignParent(Guid layer, GuidStructureItem parent)
+        public void AssignParent(Guid layer, Guid? parent)
+        {
+            AssignParent(layer, parent.HasValue ? GetGroupByGuid(parent) : null);
+        }
+
+        protected void AssignParent(Guid layer, GuidStructureItem? parent)
         {
             var currentParent = GetGroupByLayer(layer);
-            if(currentParent != null)
+            if (currentParent != null)
             {
                 PreMoveReassignBounds(currentParent, layer);
             }
@@ -354,7 +377,7 @@ namespace PixiEditor.Models.Layers
             LayerStructureChanged?.Invoke(this, EventArgs.Empty);
         }
 
-        public List<Guid> GetLayersInOrder(FolderData folder)
+        public List<Guid> GetLayersInOrder(GroupData folder)
         {
             List<Guid> layerGuids = new();
             int minIndex = folder.BottomIndex;
@@ -381,7 +404,7 @@ namespace PixiEditor.Models.Layers
             int indexTop = Owner.Layers.IndexOf(layerTop);
             int indexBottom = Owner.Layers.IndexOf(layerBottom);
 
-            return GetLayersInOrder(new FolderData(indexTop, indexBottom));
+            return GetLayersInOrder(new GroupData(indexTop, indexBottom));
         }
 
         /// <summary>
@@ -423,8 +446,14 @@ namespace PixiEditor.Models.Layers
 
         private void ApplyBoundsToParents(GuidStructureItem parent, GuidStructureItem group, Guid? oldStart, Guid? oldEnd)
         {
-            Guid? parentOldStart = parent.StartLayerGuid;
-            Guid? parentOldEnd = parent.EndLayerGuid;
+            Guid parentOldStart = parent.StartLayerGuid;
+            Guid parentOldEnd = parent.EndLayerGuid;
+
+            if (parent.Subgroups.Count == 0)
+            {
+                RemoveGroup(parent);
+            }
+
             if (parent.StartLayerGuid == oldStart)
             {
                 parent.StartLayerGuid = group.StartLayerGuid;
@@ -445,7 +474,7 @@ namespace PixiEditor.Models.Layers
         {
             return GetNextLayerGuid(
                    layerGuid,
-                   GetLayersInOrder(new FolderData(parentFolderTopIndex, parentFolderBottomIndex)),
+                   GetLayersInOrder(new GroupData(parentFolderTopIndex, parentFolderBottomIndex)),
                    above);
         }
 
@@ -457,7 +486,7 @@ namespace PixiEditor.Models.Layers
             return FindBoundLayer(layerGuid, parentFolderTopIndex, parentFolderBottomIndex, above);
         }
 
-        private Guid GetNextLayerGuid(Guid layer, List<Guid> allLayers, bool above)
+        private static Guid GetNextLayerGuid(Guid layer, List<Guid> allLayers, bool above)
         {
             int indexOfLayer = allLayers.IndexOf(layer);
 
@@ -488,12 +517,12 @@ namespace PixiEditor.Models.Layers
             {
                 int topIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == currentGroup.EndLayerGuid));
                 int bottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.LayerGuid == currentGroup.StartLayerGuid));
-                var layers = GetLayersInOrder(new FolderData(topIndex, bottomIndex));
+                var layers = GetLayersInOrder(new GroupData(topIndex, bottomIndex));
 
                 if (currentGroup.Subgroups.Count > 0)
                 {
                     var group = GetGroupByLayer(layerGuid, currentGroup.Subgroups);
-                    if(group != null)
+                    if (group != null)
                     {
                         return group;
                     }
@@ -508,19 +537,19 @@ namespace PixiEditor.Models.Layers
             return null;
         }
 
-        private GuidStructureItem GetGroupByGuid(Guid? folderGuid, IEnumerable<GuidStructureItem> folders)
+        private GuidStructureItem GetGroupByGuid(Guid? groupGuid, IEnumerable<GuidStructureItem> groups)
         {
-            foreach (var folder in folders)
+            foreach (var group in groups)
             {
-                if (folder.GroupGuid == folderGuid)
+                if (group.GroupGuid == groupGuid)
                 {
-                    return folder;
+                    return group;
                 }
 
-                if (folder.Subgroups.Count > 0)
+                if (group.Subgroups.Count > 0)
                 {
-                    var guid = GetGroupByGuid(folderGuid, folder.Subgroups);
-                    if(guid != null)
+                    var guid = GetGroupByGuid(groupGuid, group.Subgroups);
+                    if (guid != null)
                     {
                         return guid;
                     }

+ 7 - 1
PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs

@@ -110,7 +110,13 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 
         public void NewGroup(object parameter)
         {
-            Owner.BitmapManager.ActiveDocument?.LayerStructure.AddNewGroup($"{Owner.BitmapManager.ActiveLayer.Name} Group", Owner.BitmapManager.ActiveLayer.LayerGuid);
+            var doc = Owner.BitmapManager.ActiveDocument;
+            if (doc != null)
+            {
+                var lastGroups = doc.LayerStructure.CloneGroups();
+                doc.LayerStructure.AddNewGroup($"{doc.ActiveLayer.Name} Group", doc.ActiveLayer.LayerGuid);
+                doc.AddLayerStructureToUndo(lastGroups);
+            }
         }
 
         public bool CanAddNewGroup(object property)

+ 2 - 2
PixiEditor/Views/UserControls/LayerGroupControl.xaml.cs

@@ -156,7 +156,7 @@ namespace PixiEditor.Views.UserControls
                 Guid group = data.Layer.LayerGuid;
 
                 data.LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.MoveLayerInStructure(group, referenceLayer, above);
-                data.LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure.AssignParent(group, GroupData.Parent);
+                data.LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure.AssignParent(group, GroupData.Parent.GroupGuid);
             }
 
             if (dataObj.GetDataPresent("PixiEditor.Views.UserControls.LayerGroupControl"))
@@ -179,7 +179,7 @@ namespace PixiEditor.Views.UserControls
                 Layer tempLayer = new("_temp");
                 document.Layers.Insert(indexOfReferenceLayer, tempLayer);
 
-                document.LayerStructure.AssignParent(tempLayer.LayerGuid, GroupData.Parent);
+                document.LayerStructure.AssignParent(tempLayer.LayerGuid, GroupData.Parent.GroupGuid);
                 document.MoveGroupInStructure(group, tempLayer.LayerGuid, above);
                 document.LayerStructure.AssignParent(tempLayer.LayerGuid, null);
                 document.RemoveLayer(tempLayer, false);

+ 3 - 2
PixiEditor/Views/UserControls/RawLayersViewer.xaml

@@ -38,8 +38,9 @@
                 <DataTemplate>
                     <Border BorderThickness="1" BorderBrush="Black">
                     <StackPanel>
-                        <Label Foreground="White" Content="{Binding Name}"/>
-                        <StackPanel Orientation="Horizontal">
+                            <Label Foreground="White" Content="{Binding Name}"/>
+                            <Label Foreground="White" Content="{Binding GroupGuid}"/>
+                            <StackPanel Orientation="Horizontal">
                             <TextBlock Foreground="White" Text="Parent: "/>
                                 <TextBlock Foreground="Wheat" Text="{Binding Parent.Name}"/>
                         </StackPanel>