Browse Source

Move layers upwards/downwards

Equbuxu 3 years ago
parent
commit
7f616313d8

+ 1 - 1
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -87,7 +87,7 @@ internal static class ClipboardController
         {
         {
             MemoryStream memoryStream = new();
             MemoryStream memoryStream = new();
             PixiParser.Serialize(document, memoryStream);
             PixiParser.Serialize(document, memoryStream);
-            data.SetData("PIXI", memoryStream); // PIXI, supports transparency, layers, groups and swatches
+            data.SetData("PIXI", memoryStream); // PIXI, supports transparency, layers, folders and swatches
             ClipboardHelper.TrySetDataObject(data, true);
             ClipboardHelper.TrySetDataObject(data, true);
         }
         }
         
         

+ 2 - 2
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -183,7 +183,7 @@ internal class ActionAccumulator
                     break;
                     break;
                 case PreviewDirty_RenderInfo info:
                 case PreviewDirty_RenderInfo info:
                     {
                     {
-                        var bitmap = helpers.StructureHelper.Find(info.GuidValue)?.PreviewBitmap;
+                        var bitmap = document.StructureViewModel.Find(info.GuidValue)?.PreviewBitmap;
                         if (bitmap is null)
                         if (bitmap is null)
                             continue;
                             continue;
                         bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
                         bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
@@ -191,7 +191,7 @@ internal class ActionAccumulator
                     break;
                     break;
                 case MaskPreviewDirty_RenderInfo info:
                 case MaskPreviewDirty_RenderInfo info:
                     {
                     {
-                        var bitmap = helpers.StructureHelper.Find(info.GuidValue)?.MaskPreviewBitmap;
+                        var bitmap = document.StructureViewModel.Find(info.GuidValue)?.MaskPreviewBitmap;
                         if (bitmap is null)
                         if (bitmap is null)
                             continue;
                             continue;
                         bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
                         bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));

+ 4 - 71
src/PixiEditor/Models/DocumentModels/DocumentStructureHelper.cs

@@ -37,7 +37,7 @@ internal class DocumentStructureHelper
         {
         {
             Guid guid = Guid.NewGuid();
             Guid guid = Guid.NewGuid();
             //put member above the layer
             //put member above the layer
-            List<StructureMemberViewModel>? path = FindPath(layer.GuidValue);
+            List<StructureMemberViewModel>? path = doc.StructureViewModel.FindPath(layer.GuidValue);
             if (path.Count < 2)
             if (path.Count < 2)
                 throw new InvalidOperationException("Couldn't find a path to the selected member");
                 throw new InvalidOperationException("Couldn't find a path to the selected member");
             FolderViewModel? parent = (FolderViewModel)path[1];
             FolderViewModel? parent = (FolderViewModel)path[1];
@@ -48,73 +48,6 @@ internal class DocumentStructureHelper
         throw new ArgumentException($"Unknown member type: {type}");
         throw new ArgumentException($"Unknown member type: {type}");
     }
     }
 
 
-    public StructureMemberViewModel FindOrThrow(Guid guid) => Find(guid) ?? throw new ArgumentException("Could not find member with guid " + guid.ToString());
-    public StructureMemberViewModel? Find(Guid guid)
-    {
-        List<StructureMemberViewModel>? list = FindPath(guid);
-        return list.Count > 0 ? list[0] : null;
-    }
-
-    public StructureMemberViewModel? FindFirstWhere(Predicate<StructureMemberViewModel> predicate)
-    {
-        return FindFirstWhere(predicate, doc.StructureRoot);
-    }
-    private StructureMemberViewModel? FindFirstWhere(Predicate<StructureMemberViewModel> predicate, FolderViewModel folderVM)
-    {
-        foreach (StructureMemberViewModel? child in folderVM.Children)
-        {
-            if (predicate(child))
-                return child;
-            if (child is FolderViewModel innerFolderVM)
-            {
-                StructureMemberViewModel? result = FindFirstWhere(predicate, innerFolderVM);
-                if (result is not null)
-                    return result;
-            }
-        }
-        return null;
-    }
-
-    public (StructureMemberViewModel, FolderViewModel) FindChildAndParentOrThrow(Guid childGuid)
-    {
-        List<StructureMemberViewModel>? path = FindPath(childGuid);
-        if (path.Count < 2)
-            throw new ArgumentException("Couldn't find child and parent");
-        return (path[0], (FolderViewModel)path[1]);
-    }
-    public List<StructureMemberViewModel> FindPath(Guid guid)
-    {
-        List<StructureMemberViewModel>? list = new List<StructureMemberViewModel>();
-        if (FillPath(doc.StructureRoot, guid, list))
-            list.Add(doc.StructureRoot);
-        return list;
-    }
-
-    private bool FillPath(FolderViewModel folder, Guid guid, List<StructureMemberViewModel> toFill)
-    {
-        if (folder.GuidValue == guid)
-        {
-            return true;
-        }
-        foreach (StructureMemberViewModel? member in folder.Children)
-        {
-            if (member is LayerViewModel childLayer && childLayer.GuidValue == guid)
-            {
-                toFill.Add(member);
-                return true;
-            }
-            if (member is FolderViewModel childFolder)
-            {
-                if (FillPath(childFolder, guid, toFill))
-                {
-                    toFill.Add(childFolder);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     private void HandleMoveInside(List<StructureMemberViewModel> memberToMovePath, List<StructureMemberViewModel> memberToMoveIntoPath)
     private void HandleMoveInside(List<StructureMemberViewModel> memberToMovePath, List<StructureMemberViewModel> memberToMoveIntoPath)
     {
     {
         if (memberToMoveIntoPath[0] is not FolderViewModel folder || memberToMoveIntoPath.Contains(memberToMovePath[0]))
         if (memberToMoveIntoPath[0] is not FolderViewModel folder || memberToMoveIntoPath.Contains(memberToMovePath[0]))
@@ -153,8 +86,8 @@ internal class DocumentStructureHelper
 
 
     public void TryMoveStructureMember(Guid memberToMove, Guid memberToMoveIntoOrNextTo, StructureMemberPlacement placement)
     public void TryMoveStructureMember(Guid memberToMove, Guid memberToMoveIntoOrNextTo, StructureMemberPlacement placement)
     {
     {
-        List<StructureMemberViewModel> memberPath = FindPath(memberToMove);
-        List<StructureMemberViewModel> refPath = FindPath(memberToMoveIntoOrNextTo);
+        List<StructureMemberViewModel> memberPath = doc.StructureViewModel.FindPath(memberToMove);
+        List<StructureMemberViewModel> refPath = doc.StructureViewModel.FindPath(memberToMoveIntoOrNextTo);
         if (memberPath.Count < 2 || refPath.Count < 2)
         if (memberPath.Count < 2 || refPath.Count < 2)
             return;
             return;
         switch (placement)
         switch (placement)
@@ -177,7 +110,7 @@ internal class DocumentStructureHelper
                         HandleMoveAboveBelow(memberPath, refPath, false);
                         HandleMoveAboveBelow(memberPath, refPath, false);
                         break;
                         break;
                     }
                     }
-                    HandleMoveAboveBelow(memberPath, FindPath(refPath[1].GuidValue), false);
+                    HandleMoveAboveBelow(memberPath, doc.StructureViewModel.FindPath(refPath[1].GuidValue), false);
                 }
                 }
                 break;
                 break;
         }
         }

+ 15 - 15
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -105,7 +105,7 @@ internal class DocumentUpdater
 
 
     private void ProcessRemoveSoftSelectedMember(RemoveSoftSelectedMember_PassthroughAction info)
     private void ProcessRemoveSoftSelectedMember(RemoveSoftSelectedMember_PassthroughAction info)
     {
     {
-        StructureMemberViewModel? member = helper.StructureHelper.Find(info.GuidValue);
+        StructureMemberViewModel? member = doc.StructureViewModel.Find(info.GuidValue);
         if (member is null || member.Selection == StructureMemberSelectionType.Hard)
         if (member is null || member.Selection == StructureMemberSelectionType.Hard)
             return;
             return;
         if (member.Selection != StructureMemberSelectionType.Soft)
         if (member.Selection != StructureMemberSelectionType.Soft)
@@ -129,7 +129,7 @@ internal class DocumentUpdater
 
 
     private void ProcessAddSoftSelectedMember(AddSoftSelectedMember_PassthroughAction info)
     private void ProcessAddSoftSelectedMember(AddSoftSelectedMember_PassthroughAction info)
     {
     {
-        StructureMemberViewModel? member = helper.StructureHelper.Find(info.GuidValue);
+        StructureMemberViewModel? member = doc.StructureViewModel.Find(info.GuidValue);
         if (member is null || member.Selection == StructureMemberSelectionType.Hard)
         if (member is null || member.Selection == StructureMemberSelectionType.Hard)
             return;
             return;
         member.Selection = StructureMemberSelectionType.Soft;
         member.Selection = StructureMemberSelectionType.Soft;
@@ -144,7 +144,7 @@ internal class DocumentUpdater
             oldMember.Selection = StructureMemberSelectionType.None;
             oldMember.Selection = StructureMemberSelectionType.None;
             oldMember.RaisePropertyChanged(nameof(oldMember.Selection));
             oldMember.RaisePropertyChanged(nameof(oldMember.Selection));
         }
         }
-        StructureMemberViewModel? member = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? member = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         member.Selection = StructureMemberSelectionType.Hard;
         member.Selection = StructureMemberSelectionType.Hard;
         member.RaisePropertyChanged(nameof(member.Selection));
         member.RaisePropertyChanged(nameof(member.Selection));
         doc.InternalSetSelectedMember(member);
         doc.InternalSetSelectedMember(member);
@@ -161,13 +161,13 @@ internal class DocumentUpdater
 
 
     private void ProcessMaskIsVisible(StructureMemberMaskIsVisible_ChangeInfo info)
     private void ProcessMaskIsVisible(StructureMemberMaskIsVisible_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? member = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? member = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         member.SetMaskIsVisible(info.IsVisible);
         member.SetMaskIsVisible(info.IsVisible);
     }
     }
 
 
     private void ProcessClipToMemberBelow(StructureMemberClipToMemberBelow_ChangeInfo info)
     private void ProcessClipToMemberBelow(StructureMemberClipToMemberBelow_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? member = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? member = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         member.SetClipToMemberBelowEnabled(info.ClipToMemberBelow);
         member.SetClipToMemberBelowEnabled(info.ClipToMemberBelow);
     }
     }
 
 
@@ -194,19 +194,19 @@ internal class DocumentUpdater
 
 
     private void ProcessLayerLockTransparency(LayerLockTransparency_ChangeInfo info)
     private void ProcessLayerLockTransparency(LayerLockTransparency_ChangeInfo info)
     {
     {
-        LayerViewModel? layer = (LayerViewModel)helper.StructureHelper.FindOrThrow(info.GuidValue);
+        LayerViewModel? layer = (LayerViewModel)doc.StructureViewModel.FindOrThrow(info.GuidValue);
         layer.SetLockTransparency(info.LockTransparency);
         layer.SetLockTransparency(info.LockTransparency);
     }
     }
 
 
     private void ProcessStructureMemberBlendMode(StructureMemberBlendMode_ChangeInfo info)
     private void ProcessStructureMemberBlendMode(StructureMemberBlendMode_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? memberVm = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? memberVm = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         memberVm.SetBlendMode(info.BlendMode);
         memberVm.SetBlendMode(info.BlendMode);
     }
     }
 
 
     private void ProcessStructureMemberMask(StructureMemberMask_ChangeInfo info)
     private void ProcessStructureMemberMask(StructureMemberMask_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? memberVm = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? memberVm = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         memberVm.MaskPreviewSurface?.Dispose();
         memberVm.MaskPreviewSurface?.Dispose();
         memberVm.MaskPreviewSurface = null;
         memberVm.MaskPreviewSurface = null;
         memberVm.MaskPreviewBitmap = null;
         memberVm.MaskPreviewBitmap = null;
@@ -301,7 +301,7 @@ internal class DocumentUpdater
 
 
     private void ProcessCreateStructureMember(CreateStructureMember_ChangeInfo info)
     private void ProcessCreateStructureMember(CreateStructureMember_ChangeInfo info)
     {
     {
-        FolderViewModel? parentFolderVM = (FolderViewModel)helper.StructureHelper.FindOrThrow(info.ParentGuid);
+        FolderViewModel? parentFolderVM = (FolderViewModel)doc.StructureViewModel.FindOrThrow(info.ParentGuid);
 
 
         StructureMemberViewModel memberVM;
         StructureMemberViewModel memberVM;
         if (info is CreateLayer_ChangeInfo layerInfo)
         if (info is CreateLayer_ChangeInfo layerInfo)
@@ -353,7 +353,7 @@ internal class DocumentUpdater
 
 
     private void ProcessDeleteStructureMember(DeleteStructureMember_ChangeInfo info)
     private void ProcessDeleteStructureMember(DeleteStructureMember_ChangeInfo info)
     {
     {
-        (StructureMemberViewModel memberVM, FolderViewModel folderVM) = helper.StructureHelper.FindChildAndParentOrThrow(info.GuidValue);
+        (StructureMemberViewModel memberVM, FolderViewModel folderVM) = doc.StructureViewModel.FindChildAndParentOrThrow(info.GuidValue);
         folderVM.Children.Remove(memberVM);
         folderVM.Children.Remove(memberVM);
         if (doc.SelectedStructureMember == memberVM)
         if (doc.SelectedStructureMember == memberVM)
             doc.InternalSetSelectedMember(null);
             doc.InternalSetSelectedMember(null);
@@ -362,27 +362,27 @@ internal class DocumentUpdater
 
 
     private void ProcessUpdateStructureMemberIsVisible(StructureMemberIsVisible_ChangeInfo info)
     private void ProcessUpdateStructureMemberIsVisible(StructureMemberIsVisible_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? memberVM = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? memberVM = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         memberVM.SetIsVisible(info.IsVisible);
         memberVM.SetIsVisible(info.IsVisible);
     }
     }
 
 
     private void ProcessUpdateStructureMemberName(StructureMemberName_ChangeInfo info)
     private void ProcessUpdateStructureMemberName(StructureMemberName_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? memberVM = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? memberVM = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         memberVM.SetName(info.Name);
         memberVM.SetName(info.Name);
     }
     }
 
 
     private void ProcessUpdateStructureMemberOpacity(StructureMemberOpacity_ChangeInfo info)
     private void ProcessUpdateStructureMemberOpacity(StructureMemberOpacity_ChangeInfo info)
     {
     {
-        StructureMemberViewModel? memberVM = helper.StructureHelper.FindOrThrow(info.GuidValue);
+        StructureMemberViewModel? memberVM = doc.StructureViewModel.FindOrThrow(info.GuidValue);
         memberVM.SetOpacity(info.Opacity);
         memberVM.SetOpacity(info.Opacity);
     }
     }
 
 
     private void ProcessMoveStructureMember(MoveStructureMember_ChangeInfo info)
     private void ProcessMoveStructureMember(MoveStructureMember_ChangeInfo info)
     {
     {
-        (StructureMemberViewModel memberVM, FolderViewModel curFolderVM) = helper.StructureHelper.FindChildAndParentOrThrow(info.GuidValue);
+        (StructureMemberViewModel memberVM, FolderViewModel curFolderVM) = doc.StructureViewModel.FindChildAndParentOrThrow(info.GuidValue);
 
 
-        FolderViewModel? targetFolderVM = (FolderViewModel)helper.StructureHelper.FindOrThrow(info.ParentToGuid);
+        FolderViewModel? targetFolderVM = (FolderViewModel)doc.StructureViewModel.FindOrThrow(info.ParentToGuid);
 
 
         curFolderVM.Children.Remove(memberVM);
         curFolderVM.Children.Remove(memberVM);
         targetFolderVM.Children.Insert(info.NewIndex, memberVM);
         targetFolderVM.Children.Insert(info.NewIndex, memberVM);

+ 2 - 2
src/PixiEditor/Models/Rendering/WriteableBitmapUpdater.cs

@@ -196,7 +196,7 @@ internal class WriteableBitmapUpdater
         // update previews of individual members
         // update previews of individual members
         foreach (var (guid, chunks) in imagePreviewChunks)
         foreach (var (guid, chunks) in imagePreviewChunks)
         {
         {
-            var memberVM = helpers.StructureHelper.Find(guid);
+            var memberVM = doc.StructureViewModel.Find(guid);
             if (memberVM is null)
             if (memberVM is null)
                 continue;
                 continue;
             var member = helpers.Tracker.Document.FindMemberOrThrow(guid);
             var member = helpers.Tracker.Document.FindMemberOrThrow(guid);
@@ -245,7 +245,7 @@ internal class WriteableBitmapUpdater
     {
     {
         foreach (var (guid, chunks) in maskPreviewChunks)
         foreach (var (guid, chunks) in maskPreviewChunks)
         {
         {
-            var memberVM = helpers.StructureHelper.Find(guid);
+            var memberVM = doc.StructureViewModel.Find(guid);
             if (memberVM is null || !memberVM.HasMaskBindable)
             if (memberVM is null || !memberVM.HasMaskBindable)
                 continue;
                 continue;
 
 

+ 83 - 0
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentStructureViewModel.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PixiEditor.ViewModels.SubViewModels.Document;
+#nullable enable
+internal class DocumentStructureViewModel
+{
+    private readonly DocumentViewModel doc;
+    public DocumentStructureViewModel(DocumentViewModel owner)
+    {
+        this.doc = owner;
+    }
+
+    public StructureMemberViewModel FindOrThrow(Guid guid) => Find(guid) ?? throw new ArgumentException("Could not find member with guid " + guid.ToString());
+    public StructureMemberViewModel? Find(Guid guid)
+    {
+        List<StructureMemberViewModel>? list = FindPath(guid);
+        return list.Count > 0 ? list[0] : null;
+    }
+
+    public StructureMemberViewModel? FindFirstWhere(Predicate<StructureMemberViewModel> predicate)
+    {
+        return FindFirstWhere(predicate, doc.StructureRoot);
+    }
+    private StructureMemberViewModel? FindFirstWhere(Predicate<StructureMemberViewModel> predicate, FolderViewModel folderVM)
+    {
+        foreach (StructureMemberViewModel? child in folderVM.Children)
+        {
+            if (predicate(child))
+                return child;
+            if (child is FolderViewModel innerFolderVM)
+            {
+                StructureMemberViewModel? result = FindFirstWhere(predicate, innerFolderVM);
+                if (result is not null)
+                    return result;
+            }
+        }
+        return null;
+    }
+
+    public (StructureMemberViewModel, FolderViewModel) FindChildAndParentOrThrow(Guid childGuid)
+    {
+        List<StructureMemberViewModel>? path = FindPath(childGuid);
+        if (path.Count < 2)
+            throw new ArgumentException("Couldn't find child and parent");
+        return (path[0], (FolderViewModel)path[1]);
+    }
+    public List<StructureMemberViewModel> FindPath(Guid guid)
+    {
+        List<StructureMemberViewModel>? list = new List<StructureMemberViewModel>();
+        if (FillPath(doc.StructureRoot, guid, list))
+            list.Add(doc.StructureRoot);
+        return list;
+    }
+
+    private bool FillPath(FolderViewModel folder, Guid guid, List<StructureMemberViewModel> toFill)
+    {
+        if (folder.GuidValue == guid)
+        {
+            return true;
+        }
+        foreach (StructureMemberViewModel? member in folder.Children)
+        {
+            if (member is LayerViewModel childLayer && childLayer.GuidValue == guid)
+            {
+                toFill.Add(member);
+                return true;
+            }
+            if (member is FolderViewModel childFolder)
+            {
+                if (FillPath(childFolder, guid, toFill))
+                {
+                    toFill.Add(childFolder);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}

+ 3 - 0
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -34,6 +34,8 @@ internal class DocumentViewModel : NotifyableObject
 
 
     public FolderViewModel StructureRoot { get; }
     public FolderViewModel StructureRoot { get; }
 
 
+    public DocumentStructureViewModel StructureViewModel { get; }
+
     public int Width => size.X;
     public int Width => size.X;
     public int Height => size.Y;
     public int Height => size.Y;
 
 
@@ -124,6 +126,7 @@ internal class DocumentViewModel : NotifyableObject
     {
     {
         //Name = name;
         //Name = name;
         Helpers = new DocumentHelpers(this);
         Helpers = new DocumentHelpers(this);
+        StructureViewModel = new DocumentStructureViewModel(this);
         StructureRoot = new FolderViewModel(this, Helpers, Helpers.Tracker.Document.StructureRoot.GuidValue);
         StructureRoot = new FolderViewModel(this, Helpers, Helpers.Tracker.Document.StructureRoot.GuidValue);
 
 
         TransformViewModel = new();
         TransformViewModel = new();

+ 65 - 30
src/PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs

@@ -2,6 +2,8 @@
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.Attributes.Commands;
 using PixiEditor.Models.Commands.Attributes.Commands;
+using PixiEditor.Models.Enums;
+using PixiEditor.ViewModels.SubViewModels.Document;
 
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 #nullable enable
 #nullable enable
@@ -14,11 +16,16 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     {
     {
     }
     }
 
 
-    public void CreateGroupFromActiveLayers(object parameter)
+    public void CreateFolderFromActiveLayers(object parameter)
     {
     {
 
 
     }
     }
 
 
+    public bool CanCreateFolderFromSelected(object obj)
+    {
+        return false;
+    }
+
     [Evaluator.CanExecute("PixiEditor.Layer.CanDeleteSelected")]
     [Evaluator.CanExecute("PixiEditor.Layer.CanDeleteSelected")]
     public bool CanDeleteSelected(object parameter)
     public bool CanDeleteSelected(object parameter)
     {
     {
@@ -28,7 +35,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         return true;
         return true;
     }
     }
 
 
-    [Command.Basic("PixiEditor.Layer.DeleteSelected", "Delete active layer/folder", "", CanExecute = "PixiEditor.Layer.CanDeleteSelected")]
+    [Command.Basic("PixiEditor.Layer.DeleteSelected", "Delete active layer/folder", "Delete active layer or folder", CanExecute = "PixiEditor.Layer.CanDeleteSelected")]
     public void DeleteSelected(object parameter)
     public void DeleteSelected(object parameter)
     {
     {
         var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
         var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
@@ -46,7 +53,7 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         return doc.SelectedStructureMember is not null || doc.SoftSelectedStructureMembers.Count > 0;
         return doc.SelectedStructureMember is not null || doc.SoftSelectedStructureMembers.Count > 0;
     }
     }
 
 
-    [Command.Basic("PixiEditor.Layer.DeleteAllSelected", "Delete all selected layers/folders", "", CanExecute = "PixiEditor.Layer.CanDeleteAllSelected")]
+    [Command.Basic("PixiEditor.Layer.DeleteAllSelected", "Delete all selected layers/folders", "Delete all selected layers and/or folders", CanExecute = "PixiEditor.Layer.CanDeleteAllSelected")]
     public void DeleteAllSelected(object parameter)
     public void DeleteAllSelected(object parameter)
     {
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
@@ -67,16 +74,6 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         doc.CreateStructureMember(StructureMemberType.Folder);
         doc.CreateStructureMember(StructureMemberType.Folder);
     }
     }
 
 
-    public bool CanMergeSelected(object obj)
-    {
-        return false;
-    }
-
-    public bool CanCreateGroupFromSelected(object obj)
-    {
-        return false;
-    }
-
     [Command.Basic("PixiEditor.Layer.NewLayer", "New Layer", "Create new layer", CanExecute = "PixiEditor.Layer.CanCreateNewMember", Key = Key.N, Modifiers = ModifierKeys.Control | ModifierKeys.Shift, IconPath = "Layer-add.png")]
     [Command.Basic("PixiEditor.Layer.NewLayer", "New Layer", "Create new layer", CanExecute = "PixiEditor.Layer.CanCreateNewMember", Key = Key.N, Modifiers = ModifierKeys.Control | ModifierKeys.Shift, IconPath = "Layer-add.png")]
     public void NewLayer(object parameter)
     public void NewLayer(object parameter)
     {
     {
@@ -132,22 +129,60 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
         return false;
         return false;
     }
     }
 
 
-    public void MoveLayerToFront(object parameter)
-    {
-
-    }
-
-    public void MoveLayerToBack(object parameter)
+    private bool CanMoveSelectedMember(bool upwards)
     {
     {
-
+        var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
+        var member = doc?.SelectedStructureMember;
+        if (member is null)
+            return false;
+        var path = doc!.StructureViewModel.FindPath(member.GuidValue);
+        if (path.Count < 2)
+            return false;
+        var parent = (FolderViewModel)path[1];
+        int index = parent.Children.IndexOf(path[0]);
+        if (upwards && index == parent.Children.Count - 1)
+            return false;
+        if (!upwards && index == 0)
+            return false;
+        return true;
     }
     }
 
 
-    public bool CanMoveToFront(object property)
+    private void MoveSelectedMember(bool upwards)
     {
     {
-        return false;
-    }
+        var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
+        var member = Owner.DocumentManagerSubViewModel.ActiveDocument?.SelectedStructureMember;
+        if (member is null)
+            return;
+        var path = doc!.StructureViewModel.FindPath(member.GuidValue);
+        if (path.Count < 2)
+            return;
+        var parent = (FolderViewModel)path[1];
+        int curIndex = parent.Children.IndexOf(path[0]);
+        if (upwards)
+        {
+            if (curIndex == parent.Children.Count - 1)
+                return;
+            doc.MoveStructureMember(member.GuidValue, parent.Children[curIndex + 1].GuidValue, StructureMemberPlacement.Above);
+        }
+        else
+        {
+            if (curIndex == 0)
+                return;
+            doc.MoveStructureMember(member.GuidValue, parent.Children[curIndex - 1].GuidValue, StructureMemberPlacement.Below);
+        }
+    }
+
+    [Evaluator.CanExecute("PixiEditor.Layer.CanMoveSelectedMemberUpwards")]
+    public bool CanMoveSelectedMemberUpwards(object property) => CanMoveSelectedMember(true);
+    [Evaluator.CanExecute("PixiEditor.Layer.CanMoveSelectedMemberDownwards")]
+    public bool CanMoveSelectedMemberDownwards(object property) => CanMoveSelectedMember(false);
+
+    [Command.Basic("PixiEditor.Layer.MoveSelectedMemberUpwards", "Move selected layer or folder upwards", "Move selected layer or folder upwards", CanExecute = "PixiEditor.Layer.CanMoveSelectedMemberUpwards")]
+    public void MoveSelectedMemberUpwards(object parameter) => MoveSelectedMember(true);
+    [Command.Basic("PixiEditor.Layer.MoveSelectedMemberDownwards", "Move selected layer or folder downwards", "Move selected layer or folder downwards", CanExecute = "PixiEditor.Layer.CanMoveSelectedMemberDownwards")]
+    public void MoveSelectedMemberDownwards(object parameter) => MoveSelectedMember(false);
 
 
-    public bool CanMoveToBack(object property)
+    public bool CanMergeSelected(object obj)
     {
     {
         return false;
         return false;
     }
     }
@@ -157,23 +192,23 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
 
 
     }
     }
 
 
-    public void MergeWithAbove(object parameter)
+    public bool CanMergeWithAbove(object property)
     {
     {
-
+        return false;
     }
     }
 
 
-    public void MergeWithBelow(object parameter)
+    public void MergeWithAbove(object parameter)
     {
     {
 
 
     }
     }
 
 
-    public bool CanMergeWithAbove(object property)
+    public bool CanMergeWithBelow(object property)
     {
     {
         return false;
         return false;
     }
     }
 
 
-    public bool CanMergeWithBelow(object property)
+    public void MergeWithBelow(object parameter)
     {
     {
-        return false;
+
     }
     }
 }
 }

+ 3 - 10
src/PixiEditor/Views/UserControls/Layers/LayerControl.xaml

@@ -75,16 +75,9 @@
                 <MenuItem Header="Delete" Command="{cmds:Command PixiEditor.Layer.DeleteAllSelected}"/>
                 <MenuItem Header="Delete" Command="{cmds:Command PixiEditor.Layer.DeleteAllSelected}"/>
                 <MenuItem Header="Rename" Click="RenameMenuItem_Click"/>
                 <MenuItem Header="Rename" Click="RenameMenuItem_Click"/>
 
 
-                <MenuItem Header="Move to front"
-                                     Command="{Binding PlacementTarget.Tag.LayerCommandsViewModel.MoveToFrontCommand,
-                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-                           CommandParameter="{Binding PlacementTarget.Tag.ContainerIndex, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
-                </MenuItem>
-                <MenuItem Header="Move to back"
-                                    Command="{Binding PlacementTarget.Tag.LayerCommandsViewModel.MoveToBackCommand, 
-                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}" 
-                           CommandParameter="{Binding PlacementTarget.Tag.ContainerIndex, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
-                </MenuItem>
+                <MenuItem Header="Move upwards" Command="{cmds:Command PixiEditor.Layer.MoveSelectedMemberUpwards}"/>
+                <MenuItem Header="Move downwards" Command="{cmds:Command PixiEditor.Layer.MoveSelectedMemberDownwards}"/>
+
                 <Separator/>
                 <Separator/>
                 <MenuItem Header="Merge selected"
                 <MenuItem Header="Merge selected"
                                      Command="{Binding PlacementTarget.Tag.LayerCommandsViewModel.MergeSelectedCommand, 
                                      Command="{Binding PlacementTarget.Tag.LayerCommandsViewModel.MergeSelectedCommand, 

+ 2 - 2
src/PixiEditor/Views/UserControls/Layers/LayersManager.xaml

@@ -34,7 +34,7 @@
                         </Button.Background>
                         </Button.Background>
                     </Button>
                     </Button>
                     <Button Command="{commands:Command PixiEditor.Layer.NewFolder}" 
                     <Button Command="{commands:Command PixiEditor.Layer.NewFolder}" 
-                        Height="24" Width="24" ToolTip="New Group" Cursor="Hand"
+                        Height="24" Width="24" ToolTip="New Folder" Cursor="Hand"
                                                 HorizontalAlignment="Stretch" Margin="5"
                                                 HorizontalAlignment="Stretch" Margin="5"
                                                 Style="{StaticResource ToolButtonStyle}">
                                                 Style="{StaticResource ToolButtonStyle}">
                         <Button.Background>
                         <Button.Background>
@@ -131,7 +131,7 @@
                         <layerUserControls:FolderControl
                         <layerUserControls:FolderControl
                             Folder="{Binding}"
                             Folder="{Binding}"
                             MouseDown="FolderControl_MouseDown"
                             MouseDown="FolderControl_MouseDown"
-                            MouseMove="LayerGroup_MouseMove"/>
+                            MouseMove="Folder_MouseMove"/>
                     </HierarchicalDataTemplate>
                     </HierarchicalDataTemplate>
                     <DataTemplate DataType="{x:Type docVm:LayerViewModel}">
                     <DataTemplate DataType="{x:Type docVm:LayerViewModel}">
                         <layerUserControls:LayerControl
                         <layerUserControls:LayerControl

+ 1 - 1
src/PixiEditor/Views/UserControls/Layers/LayersManager.xaml.cs

@@ -38,7 +38,7 @@ internal partial class LayersManager : UserControl
         }
         }
     }
     }
 
 
-    private void LayerGroup_MouseMove(object? sender, System.Windows.Input.MouseEventArgs? e)
+    private void Folder_MouseMove(object? sender, System.Windows.Input.MouseEventArgs? e)
     {
     {
         if (e is null)
         if (e is null)
             return;
             return;