Ver código fonte

Layers drag n drop

Equbuxu 3 anos atrás
pai
commit
72c2b01365

+ 73 - 31
src/PixiEditor/Models/DocumentModels/DocumentStructureHelper.cs

@@ -1,5 +1,5 @@
-using PixiEditor.ChangeableDocument.Actions.Generated;
-using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Models.DocumentModels;
@@ -16,10 +16,10 @@ internal class DocumentStructureHelper
 
     public void CreateNewStructureMember(StructureMemberType type)
     {
-        var member = doc.SelectedStructureMember;
+        StructureMemberViewModel? member = doc.SelectedStructureMember;
         if (member is null)
         {
-            var guid = Guid.NewGuid();
+            Guid guid = Guid.NewGuid();
             //put member on top
             helpers.ActionAccumulator.AddActions(new CreateStructureMember_Action(doc.StructureRoot.GuidValue, guid, doc.StructureRoot.Children.Count, type));
             helpers.ActionAccumulator.AddFinishedActions(new StructureMemberName_Action(guid, type == StructureMemberType.Layer ? "New Layer" : "New Folder"));
@@ -27,7 +27,7 @@ internal class DocumentStructureHelper
         }
         if (member is FolderViewModel folder)
         {
-            var guid = Guid.NewGuid();
+            Guid guid = Guid.NewGuid();
             //put member inside folder on top
             helpers.ActionAccumulator.AddActions(new CreateStructureMember_Action(folder.GuidValue, guid, folder.Children.Count, type));
             helpers.ActionAccumulator.AddFinishedActions(new StructureMemberName_Action(guid, type == StructureMemberType.Layer ? "New Layer" : "New Folder"));
@@ -35,12 +35,12 @@ internal class DocumentStructureHelper
         }
         if (member is LayerViewModel layer)
         {
-            var guid = Guid.NewGuid();
+            Guid guid = Guid.NewGuid();
             //put member above the layer
-            var path = FindPath(layer.GuidValue);
+            List<StructureMemberViewModel>? path = FindPath(layer.GuidValue);
             if (path.Count < 2)
                 throw new InvalidOperationException("Couldn't find a path to the selected member");
-            var parent = (FolderViewModel)path[1];
+            FolderViewModel? parent = (FolderViewModel)path[1];
             helpers.ActionAccumulator.AddActions(new CreateStructureMember_Action(parent.GuidValue, guid, parent.Children.IndexOf(layer) + 1, type));
             helpers.ActionAccumulator.AddFinishedActions(new StructureMemberName_Action(guid, type == StructureMemberType.Layer ? "New Layer" : "New Folder"));
             return;
@@ -51,7 +51,7 @@ internal class DocumentStructureHelper
     public StructureMemberViewModel FindOrThrow(Guid guid) => Find(guid) ?? throw new ArgumentException("Could not find member with guid " + guid.ToString());
     public StructureMemberViewModel? Find(Guid guid)
     {
-        var list = FindPath(guid);
+        List<StructureMemberViewModel>? list = FindPath(guid);
         return list.Count > 0 ? list[0] : null;
     }
 
@@ -61,13 +61,13 @@ internal class DocumentStructureHelper
     }
     private StructureMemberViewModel? FindFirstWhere(Predicate<StructureMemberViewModel> predicate, FolderViewModel folderVM)
     {
-        foreach (var child in folderVM.Children)
+        foreach (StructureMemberViewModel? child in folderVM.Children)
         {
             if (predicate(child))
                 return child;
             if (child is FolderViewModel innerFolderVM)
             {
-                var result = FindFirstWhere(predicate, innerFolderVM);
+                StructureMemberViewModel? result = FindFirstWhere(predicate, innerFolderVM);
                 if (result is not null)
                     return result;
             }
@@ -77,14 +77,14 @@ internal class DocumentStructureHelper
 
     public (StructureMemberViewModel, FolderViewModel) FindChildAndParentOrThrow(Guid childGuid)
     {
-        var path = FindPath(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)
     {
-        var list = new List<StructureMemberViewModel>();
+        List<StructureMemberViewModel>? list = new List<StructureMemberViewModel>();
         if (FillPath(doc.StructureRoot, guid, list))
             list.Add(doc.StructureRoot);
         return list;
@@ -96,7 +96,7 @@ internal class DocumentStructureHelper
         {
             return true;
         }
-        foreach (var member in folder.Children)
+        foreach (StructureMemberViewModel? member in folder.Children)
         {
             if (member is LayerViewModel childLayer && childLayer.GuidValue == guid)
             {
@@ -115,29 +115,71 @@ internal class DocumentStructureHelper
         return false;
     }
 
-    public void MoveStructureMember(Guid guid, bool toSmallerIndex)
+    private void HandleMoveInside(List<StructureMemberViewModel> memberToMovePath, List<StructureMemberViewModel> memberToMoveIntoPath)
     {
-        var path = FindPath(guid);
-        if (path.Count < 2)
-            throw new ArgumentException("Couldn't find the member to be moved");
-        if (path.Count == 2)
-        {
-            int curIndex = doc.StructureRoot.Children.IndexOf(path[0]);
-            if ((curIndex == 0 && toSmallerIndex) || (curIndex == doc.StructureRoot.Children.Count - 1 && !toSmallerIndex))
-                return;
-            helpers.ActionAccumulator.AddFinishedActions(new MoveStructureMember_Action(guid, doc.StructureRoot.GuidValue, toSmallerIndex ? curIndex - 1 : curIndex + 1));
+        if (memberToMoveIntoPath[0] is not FolderViewModel folder)
             return;
-        }
-        var folder = (FolderViewModel)path[1];
-        int index = folder.Children.IndexOf(path[0]);
-        if ((toSmallerIndex && index > 0) || (!toSmallerIndex && index < folder.Children.Count - 1))
+        int index = folder.Children.Count;
+        if (memberToMoveIntoPath[0].GuidValue == memberToMovePath[1].GuidValue) // member is already in this folder
+            index--;
+        helpers.ActionAccumulator.AddFinishedActions(new MoveStructureMember_Action(memberToMovePath[0].GuidValue, folder.GuidValue, index));
+        return;
+    }
+
+    private void HandleMoveAboveBelow(List<StructureMemberViewModel> memberToMovePath, List<StructureMemberViewModel> memberToMoveRelativeToPath, bool above)
+    {
+        FolderViewModel targetFolder = (FolderViewModel)memberToMoveRelativeToPath[1];
+        if (memberToMovePath[1].GuidValue == memberToMoveRelativeToPath[1].GuidValue)
         {
-            helpers.ActionAccumulator.AddFinishedActions(new MoveStructureMember_Action(guid, path[1].GuidValue, toSmallerIndex ? index - 1 : index + 1));
+            // members are in the same folder
+            int indexOfMemberToMove = targetFolder.Children.IndexOf(memberToMovePath[0]);
+            int indexOfMemberToMoveAbove = targetFolder.Children.IndexOf(memberToMoveRelativeToPath[0]);
+            int index = indexOfMemberToMoveAbove;
+            if (above)
+                index++;
+            if (indexOfMemberToMove < indexOfMemberToMoveAbove)
+                index--;
+            helpers.ActionAccumulator.AddFinishedActions(new MoveStructureMember_Action(memberToMovePath[0].GuidValue, targetFolder.GuidValue, index));
         }
         else
         {
-            int parentIndex = ((FolderViewModel)path[2]).Children.IndexOf(folder);
-            helpers.ActionAccumulator.AddFinishedActions(new MoveStructureMember_Action(guid, path[2].GuidValue, toSmallerIndex ? parentIndex : parentIndex + 1));
+            // members are in different folders
+            int index = targetFolder.Children.IndexOf(memberToMoveRelativeToPath[0]);
+            if (above)
+                index++;
+            helpers.ActionAccumulator.AddFinishedActions(new MoveStructureMember_Action(memberToMovePath[0].GuidValue, targetFolder.GuidValue, index));
+        }
+    }
+
+    public void TryMoveStructureMember(Guid memberToMove, Guid memberToMoveIntoOrNextTo, StructureMemberPlacement placement)
+    {
+        List<StructureMemberViewModel> memberPath = FindPath(memberToMove);
+        List<StructureMemberViewModel> refPath = FindPath(memberToMoveIntoOrNextTo);
+        if (memberPath.Count < 2 || refPath.Count < 2)
+            return;
+        switch (placement)
+        {
+            case StructureMemberPlacement.Above:
+                HandleMoveAboveBelow(memberPath, refPath, true);
+                break;
+            case StructureMemberPlacement.Below:
+                HandleMoveAboveBelow(memberPath, refPath, false);
+                break;
+            case StructureMemberPlacement.Inside:
+                HandleMoveInside(memberPath, refPath);
+                break;
+            case StructureMemberPlacement.BelowOutsideFolder:
+                {
+                    FolderViewModel refFolder = (FolderViewModel)refPath[1];
+                    int refIndexInParent = refFolder.Children.IndexOf(refPath[0]);
+                    if (refIndexInParent > 0 || refPath.Count == 2)
+                    {
+                        HandleMoveAboveBelow(memberPath, refPath, false);
+                        break;
+                    }
+                    HandleMoveAboveBelow(memberPath, FindPath(refPath[1].GuidValue), false);
+                }
+                break;
         }
     }
 }

+ 8 - 0
src/PixiEditor/Models/Enums/StructureMemberPlacement.cs

@@ -0,0 +1,8 @@
+namespace PixiEditor.Models.Enums;
+internal enum StructureMemberPlacement
+{
+    Above,
+    Below,
+    Inside,
+    BelowOutsideFolder
+}

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

@@ -9,6 +9,7 @@ using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 using PixiEditor.Models.DocumentPassthroughActions;
+using PixiEditor.Models.Enums;
 using PixiEditor.Models.Position;
 
 namespace PixiEditor.ViewModels.SubViewModels.Document;
@@ -232,6 +233,13 @@ internal class DocumentViewModel : NotifyableObject
 
     public void UsePenTool() => Helpers.ChangeController.TryStartUpdateableChange<LineBasedPenExecutor>();
 
+    public void MoveStructureMember(Guid memberToMove, Guid memberToMoveIntoOrNextTo, StructureMemberPlacement placement)
+    {
+        if (Helpers.ChangeController.IsChangeActive || memberToMove == memberToMoveIntoOrNextTo)
+            return;
+        Helpers.StructureHelper.TryMoveStructureMember(memberToMove, memberToMoveIntoOrNextTo, placement);
+    }
+
 
     public void OnKeyDown(Key args) => Helpers.ChangeController.OnKeyDown(args);
     public void OnKeyUp(Key args) => Helpers.ChangeController.OnKeyUp(args);

+ 0 - 23
src/PixiEditor/ViewModels/SubViewModels/Document/StructureMemberViewModel.cs

@@ -3,7 +3,6 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Enums;
-using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Enums;
 
@@ -121,11 +120,6 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
     public WriteableBitmap? MaskPreviewBitmap { get; set; }
     public SKSurface? MaskPreviewSurface { get; set; }
 
-    public RelayCommand MoveUpCommand { get; }
-    public RelayCommand MoveDownCommand { get; }
-    public RelayCommand UpdateOpacityCommand { get; }
-    public RelayCommand EndOpacityUpdateCommand { get; }
-
     public void RaisePropertyChanged(string name)
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
@@ -145,26 +139,9 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
         Document = doc;
         Helpers = helpers;
 
-        MoveUpCommand = new(_ => Helpers.StructureHelper.MoveStructureMember(GuidValue, false));
-        MoveDownCommand = new(_ => Helpers.StructureHelper.MoveStructureMember(GuidValue, true));
-        UpdateOpacityCommand = new(UpdateOpacity);
-        EndOpacityUpdateCommand = new(EndOpacityUpdate);
-
         this.guidValue = guidValue;
         VecI previewSize = CalculatePreviewSize(doc.SizeBindable);
         PreviewBitmap = new WriteableBitmap(previewSize.X, previewSize.Y, 96, 96, PixelFormats.Pbgra32, null);
         PreviewSurface = SKSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
     }
-
-    private void EndOpacityUpdate(object? opacity)
-    {
-        Helpers.ActionAccumulator.AddFinishedActions(new EndStructureMemberOpacity_Action());
-    }
-
-    private void UpdateOpacity(object? opacity)
-    {
-        if (opacity is not double value)
-            throw new ArgumentException("The passed value isn't a double");
-        Helpers.ActionAccumulator.AddActions(new StructureMemberOpacity_Action(GuidValue, (float)value));
-    }
 }

+ 1 - 1
src/PixiEditor/Views/UserControls/Layers/FolderControl.xaml

@@ -48,7 +48,7 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <CheckBox Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
-                      IsThreeState="False" HorizontalAlignment="Center" Click="CheckBox_Checked"
+                      IsThreeState="False" HorizontalAlignment="Center"
                       IsChecked="{Binding Path=Folder.IsVisibleBindable, ElementName=folderControl}" Grid.Column="0" Height="16"/>
 
                 <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left">

+ 20 - 141
src/PixiEditor/Views/UserControls/Layers/FolderControl.xaml.cs

@@ -1,10 +1,12 @@
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using System.Windows.Media;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Views.UserControls.Layers;
-
+#nullable enable
 internal partial class FolderControl : UserControl
 {
     public static readonly DependencyProperty FolderProperty =
@@ -16,29 +18,31 @@ internal partial class FolderControl : UserControl
         set => SetValue(FolderProperty, value);
     }
 
-    public static string FolderControlDataName = typeof(FolderControl).FullName;
+    public static string? FolderControlDataName = typeof(FolderControl).FullName;
+    public static string? LayerControlDataName = typeof(LayerControl).FullName;
+
+    private readonly Brush? highlightColor;
 
     public FolderControl()
     {
         InitializeComponent();
+        highlightColor = (Brush?)App.Current.Resources["SoftSelectedLayerColor"];
     }
 
     private void Grid_DragEnter(object sender, DragEventArgs e)
     {
-        Grid item = sender as Grid;
-
-        item.Background = LayerControl.HighlightColor;
+        Grid item = (Grid)sender;
+        item.Background = highlightColor;
     }
 
     private void Grid_CenterEnter(object sender, DragEventArgs e)
     {
-        centerGrid.Background = LayerControl.HighlightColor;
+        centerGrid.Background = highlightColor;
     }
 
     private void Grid_DragLeave(object sender, DragEventArgs e)
     {
         Grid grid = (Grid)sender;
-
         LayerControl.RemoveDragEffect(grid);
     }
 
@@ -47,161 +51,36 @@ internal partial class FolderControl : UserControl
         LayerControl.RemoveDragEffect(centerGrid);
     }
 
-    /*
-    private void HandleDrop(IDataObject dataObj, Grid grid, bool above)
-    {
-        Guid referenceLayer = above ? GroupData.EndLayerGuid : GroupData.StartLayerGuid;
-        LayerItem.RemoveDragEffect(grid);
-
-        if (dataObj.GetDataPresent(LayerContainerDataName))
-        {
-            HandleLayerDrop(dataObj, above, referenceLayer, false);
-        }
-
-        if (dataObj.GetDataPresent(LayerGroupControlDataName))
-        {
-            HandleGroupControlDrop(dataObj, referenceLayer, above, false);
-        }
-    }
-
-    private void HandleLayerDrop(IDataObject dataObj, bool above, Guid referenceLayer, bool putItInside) // step brother
+    private void HandleDrop(IDataObject dataObj, StructureMemberPlacement placement)
     {
-        var data = (LayerStructureItemContainer)dataObj.GetData(LayerContainerDataName);
-        Guid group = data.Layer.GuidValue;
-
-        data.LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.MoveLayerInStructure(group, referenceLayer, above);
-
-        Guid? refGuid = putItInside ? GroupData?.GroupGuid : GroupData?.Parent?.GroupGuid;
-
-        data.LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure.AssignParent(group, refGuid);
-    }
-
-    private void HandleGroupControlDrop(IDataObject dataObj, Guid referenceLayer, bool above, bool putItInside) // daddy
-    {
-        var data = (LayerGroupControl)dataObj.GetData(LayerGroupControlDataName);
-        var document = data.LayersViewModel.Owner.BitmapManager.ActiveDocument;
-
-        Guid group = data.GroupGuid;
-
-        if (group == GroupGuid || document.LayerStructure.IsChildOf(GroupData, data.GroupData))
-        {
+        Guid? droppedMemberGuid = LayerControl.ExtractMemberGuid(dataObj);
+        if (droppedMemberGuid is null)
             return;
-        }
-
-        int modifier = above ? 1 : 0;
-
-        Layer layer = document.Layers.First(x => x.GuidValue == referenceLayer);
-        int indexOfReferenceLayer = Math.Clamp(document.Layers.IndexOf(layer) + modifier, 0, document.Layers.Count);
-        MoveGroupWithTempLayer(above, document, group, indexOfReferenceLayer, putItInside);
+        Folder.Document.MoveStructureMember((Guid)droppedMemberGuid, Folder.GuidValue, placement);
     }
 
-    private void MoveGroupWithTempLayer(bool above, Models.DataHolders.Document document, Guid group, int indexOfReferenceLayer, bool putItInside) // ¯\_(ツ)_/¯
-    {
-        // The trick here is to insert a temp layer, assign group to it, then delete it.
-        Layer tempLayer = new("_temp", document.Width, document.Height);
-        document.Layers.Insert(indexOfReferenceLayer, tempLayer);
-
-        Guid? refGuid = putItInside ? GroupData?.GroupGuid : GroupData?.Parent?.GroupGuid;
-
-        document.LayerStructure.AssignParent(tempLayer.GuidValue, refGuid);
-        document.MoveGroupInStructure(group, tempLayer.GuidValue, above);
-        document.LayerStructure.AssignParent(tempLayer.GuidValue, null);
-        document.RemoveLayer(tempLayer, false);
-    }
-
-    private void HandleDropInside(IDataObject dataObj, Grid grid)
-    {
-        Guid referenceLayer = GroupData.EndLayerGuid;
-        LayerItem.RemoveDragEffect(grid);
-
-        if (dataObj.GetDataPresent(LayerContainerDataName))
-        {
-            HandleLayerDrop(dataObj, true, referenceLayer, true);
-        }
-
-        if (dataObj.GetDataPresent(LayerGroupControlDataName))
-        {
-            HandleGroupControlDrop(dataObj, referenceLayer, true, true);
-        }
-    }*/
-
     private void Grid_Drop_Top(object sender, DragEventArgs e)
     {
-        //HandleDrop(e.Data, (Grid)sender, true);
+        LayerControl.RemoveDragEffect((Grid)sender);
+        HandleDrop(e.Data, StructureMemberPlacement.Above);
     }
 
     private void Grid_Drop_Center(object sender, DragEventArgs e)
     {
-        //HandleDropInside(e.Data, (Grid)sender);
         LayerControl.RemoveDragEffect(centerGrid);
+        HandleDrop(e.Data, StructureMemberPlacement.Inside);
     }
 
     private void Grid_Drop_Bottom(object sender, DragEventArgs e)
     {
-        //HandleDrop(e.Data, (Grid)sender, false);
+        LayerControl.RemoveDragEffect((Grid)sender);
+        HandleDrop(e.Data, StructureMemberPlacement.Below);
     }
 
     private void Border_MouseDown(object sender, MouseButtonEventArgs e)
     {
         Folder?.Document.SetSelectedMember(Folder.GuidValue);
-        /*
-            var doc = LayersViewModel.Owner.BitmapManager.ActiveDocument;
-            var layer = doc.Layers.First(x => x.GuidValue == GroupData.EndLayerGuid);
-            if (doc.ActiveLayerGuid != layer.GuidValue)
-            {
-                doc.SetMainActiveLayer(doc.Layers.IndexOf(layer));
-            }*/
-    }
-
-    private void CheckBox_Checked(object sender, RoutedEventArgs e)
-    {
-        //HandleCheckboxChange(((CheckBox)e.OriginalSource).IsChecked.Value);
     }
-    /*
-    private void HandleCheckboxChange(bool value)
-    {
-        if (LayersViewModel?.Owner?.BitmapManager?.ActiveDocument != null)
-        {
-            var doc = LayersViewModel.Owner.BitmapManager.ActiveDocument;
-
-            IsVisibleUndoTriggerable = value;
-
-            var processArgs = new object[] { GroupGuid, value };
-            var reverseProcessArgs = new object[] { GroupGuid, !value };
-
-            ChangeGroupVisibilityProcess(processArgs);
-
-            doc.UndoManager.AddUndoChange(
-                new Change(
-                    ChangeGroupVisibilityProcess,
-                    reverseProcessArgs,
-                    ChangeGroupVisibilityProcess,
-                    processArgs,
-                    $"Change {GroupName} visibility"), false);
-        }
-    }
-
-    private void ChangeGroupVisibilityProcess(object[] args)
-    {
-        var doc = LayersViewModel.Owner.BitmapManager.ActiveDocument;
-        if (args.Length == 2 &&
-            args[0] is Guid groupGuid &&
-            args[1] is bool value
-            && doc != null)
-        {
-            var group = doc.LayerStructure.GetGroupByGuid(groupGuid);
-
-            group.IsVisible = value;
-            var layers = doc.LayerStructure.GetGroupLayers(group);
-
-            foreach (var layer in layers)
-            {
-                layer.IsVisible = layer.IsVisible;
-            }
-
-            IsVisibleUndoTriggerable = value;
-        }
-    }*/
 
     private void FolderControl_DragEnter(object sender, DragEventArgs e)
     {

+ 36 - 49
src/PixiEditor/Views/UserControls/Layers/LayerControl.xaml.cs

@@ -3,17 +3,18 @@ using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
 using PixiEditor.Helpers;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Views.UserControls.Layers;
-
+#nullable enable
 internal partial class LayerControl : UserControl
 {
-    public static Brush HighlightColor = Brushes.Blue;
-
     public static readonly DependencyProperty LayerProperty =
         DependencyProperty.Register(nameof(Layer), typeof(LayerViewModel), typeof(LayerControl), new(null));
 
+    private readonly Brush? highlightColor;
+
     public LayerViewModel Layer
     {
         get => (LayerViewModel)GetValue(LayerProperty);
@@ -23,6 +24,7 @@ internal partial class LayerControl : UserControl
     public LayerControl()
     {
         InitializeComponent();
+        highlightColor = (Brush?)App.Current.Resources["SoftSelectedLayerColor"];
     }
 
     public static readonly DependencyProperty ControlButtonsVisibleProperty = DependencyProperty.Register(
@@ -77,72 +79,57 @@ internal partial class LayerControl : UserControl
 
     }
 
-    private void Grid_DragEnter(object sender, DragEventArgs e)
+    private void Grid_DragEnter(object? sender, DragEventArgs e)
     {
-        Grid item = sender as Grid;
-
-        item.Background = HighlightColor;
+        Grid? item = sender as Grid;
+        if (item is not null)
+            item.Background = highlightColor;
     }
 
-    private void Grid_DragLeave(object sender, DragEventArgs e)
+    private void Grid_DragLeave(object? sender, DragEventArgs e)
     {
-        Grid item = sender as Grid;
-
-        RemoveDragEffect(item);
+        Grid? item = sender as Grid;
+        if (item is not null)
+            RemoveDragEffect(item);
     }
 
-    private void HandleGridDrop(object sender, DragEventArgs e, bool above, bool dropInParentFolder = false)
+    public static Guid? ExtractMemberGuid(IDataObject droppedMemberDataObject)
     {
-        /*
-        Grid item = sender as Grid;
-        RemoveDragEffect(item);
-
-        if (e.Data.GetDataPresent(FolderControl.LayerContainerDataName))
-        {
-            var data = (LayerControlContainer)e.Data.GetData(FolderControl.LayerContainerDataName);
-            //Guid layer = data.Layer.GuidValue;
-            //var doc = data.LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
-
-            /*doc.MoveLayerInStructure(layer, LayerGuid, above);
-            if (dropInParentFolder)
-            {
-                Guid? groupGuid = doc.LayerStructure.GetGroupByLayer(layer)?.Parent?.GroupGuid;
-                doc.LayerStructure.AssignParent(layer, groupGuid);
-            }
-        }
-
-        if (e.Data.GetDataPresent(FolderControl.FolderControlDataName))
-        {
-            var data = (FolderControl)e.Data.GetData(FolderControl.FolderControlDataName);
-            //Guid folder = data.GroupGuid;
-
-            //var document = data.LayersViewModel.Owner.BitmapManager.ActiveDocument;
-
-            /*var parentGroup = document.LayerStructure.GetGroupByLayer(LayerGuid);
-
-            if (parentGroup == data.GroupData || document.LayerStructure.IsChildOf(parentGroup, data.GroupData))
-            {
-                return;
-            }
+        object droppedLayer = droppedMemberDataObject.GetData(FolderControl.LayerControlDataName);
+        object droppedFolder = droppedMemberDataObject.GetData(FolderControl.FolderControlDataName);
+        if (droppedLayer is LayerControl layer)
+            return layer.Layer.GuidValue;
+        else if (droppedFolder is FolderControl folder)
+            return folder.Folder.GuidValue;
+        return null;
+    }
 
-            document.MoveGroupInStructure(folder, LayerGuid, above);
-        }
-*/
+    private void HandleDrop(IDataObject dataObj, StructureMemberPlacement placement)
+    {
+        if (placement == StructureMemberPlacement.Inside)
+            return;
+        Guid? droppedMemberGuid = ExtractMemberGuid(dataObj);
+        if (droppedMemberGuid is null)
+            return;
+        Layer.Document.MoveStructureMember((Guid)droppedMemberGuid, Layer.GuidValue, placement);
     }
 
     private void Grid_Drop_Top(object sender, DragEventArgs e)
     {
-        HandleGridDrop(sender, e, true);
+        RemoveDragEffect((Grid)sender);
+        HandleDrop(e.Data, StructureMemberPlacement.Above);
     }
 
     private void Grid_Drop_Bottom(object sender, DragEventArgs e)
     {
-        HandleGridDrop(sender, e, false);
+        RemoveDragEffect((Grid)sender);
+        HandleDrop(e.Data, StructureMemberPlacement.Below);
     }
 
     private void Grid_Drop_Below(object sender, DragEventArgs e)
     {
-        HandleGridDrop(sender, e, false, true);
+        RemoveDragEffect((Grid)sender);
+        HandleDrop(e.Data, StructureMemberPlacement.BelowOutsideFolder);
     }
 
     private void Border_MouseDown(object sender, MouseButtonEventArgs e)

+ 13 - 0
src/PixiEditor/Views/UserControls/Layers/LayersManager.xaml

@@ -103,6 +103,19 @@
                         <ui:ReversedOrderStackPanel/>
                     </ItemsPanelTemplate>
                 </TreeView.ItemsPanel>
+                <TreeView.ItemContainerStyle>
+                    <Style
+                            TargetType="TreeViewItem">
+                        <Setter
+                                Property="ItemsPanel">
+                            <Setter.Value>
+                                <ItemsPanelTemplate>
+                                    <ui:ReversedOrderStackPanel />
+                                </ItemsPanelTemplate>
+                            </Setter.Value>
+                        </Setter>
+                    </Style>
+                </TreeView.ItemContainerStyle>
                 <TreeView.Resources>
                     <HierarchicalDataTemplate DataType="{x:Type docVm:FolderViewModel}" ItemsSource="{Binding Children}">
                         <layerUserControls:FolderControl

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

@@ -2,50 +2,53 @@
 using System.Windows.Controls;
 using System.Windows.Media;
 using PixiEditor.Models.Controllers;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Views.UserControls.Layers;
-
+#nullable enable
 internal partial class LayersManager : UserControl
 {
     public static readonly DependencyProperty ActiveDocumentProperty =
         DependencyProperty.Register(nameof(ActiveDocument), typeof(DocumentViewModel), typeof(LayersManager), new(null));
 
-    public DocumentViewModel ActiveDocument
+    public DocumentViewModel? ActiveDocument
     {
         get => (DocumentViewModel)GetValue(ActiveDocumentProperty);
         set => SetValue(ActiveDocumentProperty, value);
     }
 
+    private readonly Brush? highlightColor;
     public LayersManager()
     {
         InitializeComponent();
         numberInput.OnScrollAction = () => NumberInput_LostFocus(null, null);
+        highlightColor = (Brush?)App.Current.Resources["SoftSelectedLayerColor"];
     }
 
-    private void LayerStructureItemContainer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
+    private void LayerStructureItemContainer_MouseMove(object? sender, System.Windows.Input.MouseEventArgs? e)
     {
-        /*
-        if (sender is LayerStructureItemContainer container
-            && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed && !container.Layer.IsRenaming)
+        if (e is null)
+            return;
+        if (sender is LayerControl container
+            && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed /*&& !container.Layer.IsRenaming*/)
         {
             Dispatcher.InvokeAsync(() => DragDrop.DoDragDrop(container, container, DragDropEffects.Move));
         }
-        */
     }
 
-    private void LayerGroup_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
+    private void LayerGroup_MouseMove(object? sender, System.Windows.Input.MouseEventArgs? e)
     {
-        /*
-        if (sender is LayerGroupControl container && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed
-                                                  && !container.GroupData.IsRenaming)
+        if (e is null)
+            return;
+        if (sender is FolderControl container && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed
+                                                  /*&& !container.GroupData.IsRenaming*/)
         {
             Dispatcher.InvokeAsync(() => DragDrop.DoDragDrop(container, container, DragDropEffects.Move));
         }
-        */
     }
 
-    private void NumberInput_LostFocus(object sender, RoutedEventArgs e)
+    private void NumberInput_LostFocus(object? sender, RoutedEventArgs? e)
     {
         if (ActiveDocument?.SelectedStructureMember is null)
             return;
@@ -57,42 +60,16 @@ internal partial class LayersManager : UserControl
 
     private void Grid_Drop(object sender, DragEventArgs e)
     {
-        /*
         dropBorder.BorderBrush = Brushes.Transparent;
-
-        if (e.Data.GetDataPresent(LayerGroupControl.LayerContainerDataName))
-        {
-            HandleLayerDrop(e.Data);
-        }
-
-        if (e.Data.GetDataPresent(LayerGroupControl.LayerGroupControlDataName))
-        {
-            HandleGroupControlDrop(e.Data);
-        }
-        */
-    }
-    /*
-    private void HandleLayerDrop(IDataObject data)
-    {
-        var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
-        if (doc.Layers.Count == 0) return;
-
-        var layerContainer = (LayerStructureItemContainer)data.GetData(LayerGroupControl.LayerContainerDataName);
-        var refLayer = doc.Layers[0].GuidValue;
-        doc.MoveLayerInStructure(layerContainer.Layer.GuidValue, refLayer);
-        doc.LayerStructure.AssignParent(layerContainer.Layer.GuidValue, null);
+        Guid? droppedGuid = LayerControl.ExtractMemberGuid(e.Data);
+        if (droppedGuid is null || ActiveDocument is null)
+            return;
+        ActiveDocument.MoveStructureMember((Guid)droppedGuid, ActiveDocument.StructureRoot.Children[0].GuidValue, StructureMemberPlacement.Below);
     }
 
-    private void HandleGroupControlDrop(IDataObject data)
-    {
-        var doc = LayerCommandsViewModel.Owner.BitmapManager.ActiveDocument;
-        var groupContainer = (LayerGroupControl)data.GetData(LayerGroupControl.LayerGroupControlDataName);
-        doc.LayerStructure.MoveGroup(groupContainer.GroupGuid, 0);
-    }*/
-
     private void Grid_DragEnter(object sender, DragEventArgs e)
     {
-        ((Border)sender).BorderBrush = LayerControl.HighlightColor;
+        ((Border)sender).BorderBrush = highlightColor;
     }
 
     private void Grid_DragLeave(object sender, DragEventArgs e)