Переглянути джерело

Delete and comment out an inappropriate amount of code

Equbuxu 3 роки тому
батько
коміт
f22d060589
100 змінених файлів з 369 додано та 8798 видалено
  1. 6 15
      src/PixiEditor/App.xaml.cs
  2. 0 22
      src/PixiEditor/Helpers/Converters/IndexOfConverter.cs
  3. 0 52
      src/PixiEditor/Helpers/Converters/LayerStructureToGroupsConverter.cs
  4. 0 111
      src/PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs
  5. 4 7
      src/PixiEditor/Helpers/CoordinatesHelper.cs
  6. 0 167
      src/PixiEditor/Helpers/EllipseGenerator.cs
  7. 7 11
      src/PixiEditor/Helpers/Extensions/ParserHelpers.cs
  8. 2 5
      src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs
  9. 3 3
      src/PixiEditor/Helpers/ProcessHelper.cs
  10. 0 45
      src/PixiEditor/Helpers/SelectionHelpers.cs
  11. 7 6
      src/PixiEditor/Models/Commands/Search/ColorSearchResult.cs
  12. 11 76
      src/PixiEditor/Models/Controllers/BitmapManager.cs
  13. 0 102
      src/PixiEditor/Models/Controllers/BitmapOperationsUtility.cs
  14. 19 32
      src/PixiEditor/Models/Controllers/ClipboardController.cs
  15. 0 170
      src/PixiEditor/Models/Controllers/LayerStackRenderer.cs
  16. 4 5
      src/PixiEditor/Models/Controllers/MouseMovementEventArgs.cs
  17. 0 100
      src/PixiEditor/Models/Controllers/SingleLayerRenderer.cs
  18. 0 45
      src/PixiEditor/Models/Controllers/SurfaceRenderer.cs
  19. 6 8
      src/PixiEditor/Models/Controllers/ToolSession.cs
  20. 5 7
      src/PixiEditor/Models/Controllers/ToolSessionController.cs
  21. 0 218
      src/PixiEditor/Models/Controllers/UndoManager.cs
  22. 0 75
      src/PixiEditor/Models/DataHolders/BitmapPixelChanges.cs
  23. 8 9
      src/PixiEditor/Models/DataHolders/CrashReport.cs
  24. 3 3
      src/PixiEditor/Models/DataHolders/Document/Document.Commands.cs
  25. 0 64
      src/PixiEditor/Models/DataHolders/Document/Document.Constructors.cs
  26. 0 81
      src/PixiEditor/Models/DataHolders/Document/Document.IO.cs
  27. 0 873
      src/PixiEditor/Models/DataHolders/Document/Document.Layers.cs
  28. 0 341
      src/PixiEditor/Models/DataHolders/Document/Document.Operations.cs
  29. 0 48
      src/PixiEditor/Models/DataHolders/Document/Document.Preview.cs
  30. 0 341
      src/PixiEditor/Models/DataHolders/Document/Document.cs
  31. 0 19
      src/PixiEditor/Models/DataHolders/PixelSize.cs
  32. 7 9
      src/PixiEditor/Models/DataHolders/RecentlyOpenedDocument.cs
  33. 0 105
      src/PixiEditor/Models/DataHolders/Selection.cs
  34. 6 8
      src/PixiEditor/Models/DataHolders/Surface.cs
  35. 0 8
      src/PixiEditor/Models/Enums/SelectionType.cs
  36. 0 16
      src/PixiEditor/Models/Events/DocumentChangedEventArgs.cs
  37. 10 11
      src/PixiEditor/Models/IO/Exporter.cs
  38. 9 11
      src/PixiEditor/Models/IO/Importer.cs
  39. 0 185
      src/PixiEditor/Models/ImageManipulation/BitmapUtils.cs
  40. 0 256
      src/PixiEditor/Models/ImageManipulation/ToolCalculator.cs
  41. 0 34
      src/PixiEditor/Models/Layers/BasicLayer.cs
  42. 0 14
      src/PixiEditor/Models/Layers/GroupChangedEventArgs.cs
  43. 0 22
      src/PixiEditor/Models/Layers/GroupData.cs
  44. 0 178
      src/PixiEditor/Models/Layers/GuidStructureItem.cs
  45. 0 8
      src/PixiEditor/Models/Layers/IHasGuid.cs
  46. 0 740
      src/PixiEditor/Models/Layers/Layer.cs
  47. 0 127
      src/PixiEditor/Models/Layers/LayerGroup.cs
  48. 0 81
      src/PixiEditor/Models/Layers/LayerHelper.cs
  49. 0 722
      src/PixiEditor/Models/Layers/LayerStructure.cs
  50. 0 19
      src/PixiEditor/Models/Layers/LayerStructureChangedEventArgs.cs
  51. 0 200
      src/PixiEditor/Models/Layers/StructuredLayerTree.cs
  52. 0 60
      src/PixiEditor/Models/Layers/Utils/LayerStructureUtils.cs
  53. 0 94
      src/PixiEditor/Models/Position/Coordinates.cs
  54. 0 165
      src/PixiEditor/Models/Position/CoordinatesCalculator.cs
  55. 0 14
      src/PixiEditor/Models/Position/DoubleCoords.cs
  56. 0 69
      src/PixiEditor/Models/Services/DocumentProvider.cs
  57. 3 76
      src/PixiEditor/Models/Tools/BitmapOperationTool.cs
  58. 0 12
      src/PixiEditor/Models/Tools/Brushes/Brush.cs
  59. 0 21
      src/PixiEditor/Models/Tools/Brushes/CircleBrush.cs
  60. 0 13
      src/PixiEditor/Models/Tools/Brushes/CircleBrushOverrides/InterestingShapeBrush.cs
  61. 0 24
      src/PixiEditor/Models/Tools/FloodFillRange.cs
  62. 0 6
      src/PixiEditor/Models/Tools/ICachedDocumentTool.cs
  63. 0 93
      src/PixiEditor/Models/Tools/MatrixBrush.cs
  64. 3 4
      src/PixiEditor/Models/Tools/ReadonlyTool.cs
  65. 2 58
      src/PixiEditor/Models/Tools/ShapeTool.cs
  66. 4 3
      src/PixiEditor/Models/Tools/ToolSettings/Toolbars/SelectToolToolbar.cs
  67. 3 75
      src/PixiEditor/Models/Tools/Tools/BrightnessTool.cs
  68. 3 101
      src/PixiEditor/Models/Tools/Tools/CircleTool.cs
  69. 9 93
      src/PixiEditor/Models/Tools/Tools/ColorPickerTool.cs
  70. 4 14
      src/PixiEditor/Models/Tools/Tools/EraserTool.cs
  71. 5 116
      src/PixiEditor/Models/Tools/Tools/FloodFillTool.cs
  72. 4 248
      src/PixiEditor/Models/Tools/Tools/LineTool.cs
  73. 5 76
      src/PixiEditor/Models/Tools/Tools/MagicWandTool.cs
  74. 3 164
      src/PixiEditor/Models/Tools/Tools/MoveTool.cs
  75. 6 7
      src/PixiEditor/Models/Tools/Tools/MoveViewportTool.cs
  76. 4 173
      src/PixiEditor/Models/Tools/Tools/PenTool.cs
  77. 3 57
      src/PixiEditor/Models/Tools/Tools/RectangleTool.cs
  78. 6 97
      src/PixiEditor/Models/Tools/Tools/SelectTool.cs
  79. 5 7
      src/PixiEditor/Models/Tools/Tools/ZoomTool.cs
  80. 0 138
      src/PixiEditor/Models/Undo/Change.cs
  81. 0 17
      src/PixiEditor/Models/Undo/LayerChunk.cs
  82. 0 388
      src/PixiEditor/Models/Undo/StorageBasedChange.cs
  83. 0 59
      src/PixiEditor/Models/Undo/UndoLayer.cs
  84. 2 0
      src/PixiEditor/PixiEditor.csproj
  85. 10 6
      src/PixiEditor/ViewModels/SubViewModels/Main/ClipboardViewModel.cs
  86. 22 22
      src/PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs
  87. 6 5
      src/PixiEditor/ViewModels/SubViewModels/Main/DiscordViewModel.cs
  88. 15 10
      src/PixiEditor/ViewModels/SubViewModels/Main/DocumentViewModel.cs
  89. 22 12
      src/PixiEditor/ViewModels/SubViewModels/Main/FileViewModel.cs
  90. 9 6
      src/PixiEditor/ViewModels/SubViewModels/Main/IoViewModel.cs
  91. 38 219
      src/PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs
  92. 1 1
      src/PixiEditor/ViewModels/SubViewModels/Main/RegistryViewModel.cs
  93. 3 14
      src/PixiEditor/ViewModels/SubViewModels/Main/SelectionViewModel.cs
  94. 3 52
      src/PixiEditor/ViewModels/SubViewModels/Main/ToolsViewModel.cs
  95. 12 14
      src/PixiEditor/ViewModels/SubViewModels/Main/UndoViewModel.cs
  96. 0 1
      src/PixiEditor/ViewModels/SubViewModels/Main/UpdateViewModel.cs
  97. 5 3
      src/PixiEditor/ViewModels/SubViewModels/Main/ViewportViewModel.cs
  98. 12 27
      src/PixiEditor/ViewModels/ViewModelMain.cs
  99. 4 24
      src/PixiEditor/Views/MainWindow.xaml
  100. 16 25
      src/PixiEditor/Views/MainWindow.xaml.cs

+ 6 - 15
src/PixiEditor/App.xaml.cs

@@ -1,18 +1,9 @@
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Dialogs;
-using PixiEditor.Models.Enums;
-using PixiEditor.ViewModels;
-using PixiEditor.Views.Dialogs;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
+using System.IO;
 using System.Text.RegularExpressions;
-using System.Threading;
 using System.Windows;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.UserPreferences;
+using PixiEditor.Models.DataHolders;
+using PixiEditor.Views.Dialogs;
 
 namespace PixiEditor;
 
@@ -107,12 +98,12 @@ public partial class App : Application
     protected override void OnSessionEnding(SessionEndingCancelEventArgs e)
     {
         base.OnSessionEnding(e);
-
+        /*
         if (ViewModelMain.Current.BitmapManager.Documents.Any(x => !x.ChangesSaved))
         {
             ConfirmationType confirmation = ConfirmationDialog.Show($"{e.ReasonSessionEnding} with unsaved data. Are you sure?", $"{e.ReasonSessionEnding}");
             e.Cancel = confirmation != ConfirmationType.Yes;
-        }
+        }*/
     }
 
     private bool ParseArgument(string pattern, string args, out Group[] groups)
@@ -127,4 +118,4 @@ public partial class App : Application
 
         return match.Success;
     }
-}
+}

+ 0 - 22
src/PixiEditor/Helpers/Converters/IndexOfConverter.cs

@@ -1,22 +0,0 @@
-using PixiEditor.Models.Layers;
-using PixiEditor.ViewModels;
-using System;
-using System.Globalization;
-using System.Windows.Data;
-
-namespace PixiEditor.Helpers.Converters;
-
-public class IndexOfConverter
-    : SingleInstanceConverter<IndexOfConverter>
-{
-    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-    {
-        if (value is Layer layer && ViewModelMain.Current.BitmapManager.ActiveDocument != null)
-        {
-            int index = ViewModelMain.Current.BitmapManager.ActiveDocument.Layers.IndexOf(layer);
-            return index;
-        }
-
-        return Binding.DoNothing;
-    }
-}

+ 0 - 52
src/PixiEditor/Helpers/Converters/LayerStructureToGroupsConverter.cs

@@ -1,52 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Layers;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Globalization;
-using System.Linq;
-using System.Windows.Data;
-using PixiEditor.Models.DataHolders;
-
-namespace PixiEditor.Helpers.Converters;
-
-public class LayerStructureToGroupsConverter
-    : SingleInstanceMultiValueConverter<LayerStructureToGroupsConverter>
-{
-    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
-    {
-        if (values[0] is not LayerStructure structure)
-        {
-            return Binding.DoNothing;
-        }
-
-        return GetSubGroups(structure.Groups);
-    }
-
-    private System.Collections.ObjectModel.ObservableCollection<GuidStructureItem> GetSubGroups(IEnumerable<GuidStructureItem> groups)
-    {
-        WpfObservableRangeCollection<GuidStructureItem> finalGroups = new WpfObservableRangeCollection<GuidStructureItem>();
-        foreach (var group in groups)
-        {
-            finalGroups.AddRange(GetSubGroups(group));
-        }
-
-        return finalGroups;
-    }
-
-    private IEnumerable<GuidStructureItem> GetSubGroups(GuidStructureItem group)
-    {
-        List<GuidStructureItem> groups = new List<GuidStructureItem>() { group };
-
-        foreach (var subGroup in group.Subgroups)
-        {
-            groups.Add(subGroup);
-            if (subGroup.Subgroups.Count > 0)
-            {
-                groups.AddRange(GetSubGroups(subGroup));
-            }
-        }
-
-        return groups.Distinct();
-    }
-}

+ 0 - 111
src/PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs

@@ -1,111 +0,0 @@
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Windows;
-
-namespace PixiEditor.Helpers.Converters;
-
-// TODO: Implement rebuilding only changed items instead whole tree
-public class LayersToStructuredLayersConverter
-    : MultiValueMarkupConverter
-{
-    private static StructuredLayerTree cachedTree;
-    private List<Guid> lastLayerGuids = new List<Guid>();
-    private IList<Layer> lastLayers = new List<Layer>();
-    private WpfObservableRangeCollection<GuidStructureItem> lastStructure = new WpfObservableRangeCollection<GuidStructureItem>();
-
-    public override object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
-    {
-        if (values[0] is WpfObservableRangeCollection<Layer> layers && values[1] is LayerStructure structure)
-        {
-            if (cachedTree == null)
-            {
-                cachedTree = new StructuredLayerTree(layers, structure);
-            }
-
-            if (TryFindStructureDifferences(structure) ||
-                lastLayerGuids.Count != layers.Count ||
-                LayerOrderIsDifferent(layers) ||
-                LayersAreDifferentObjects(layers, lastLayers))
-            {
-                cachedTree = new StructuredLayerTree(layers, structure);
-                lastLayers = layers;
-                lastLayerGuids = layers.Select(x => x.GuidValue).ToList();
-                lastStructure = structure.CloneGroups();
-            }
-
-            return cachedTree.RootDirectoryItems;
-        }
-
-        return DependencyProperty.UnsetValue;
-    }
-
-    public override object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
-    {
-        throw new ArgumentException("Value is not a StructuredLayerTree");
-    }
-
-    private bool LayerOrderIsDifferent(IList<Layer> layers)
-    {
-        var guids = layers.Select(x => x.GuidValue).ToArray();
-        return !guids.SequenceEqual(lastLayerGuids);
-    }
-
-    /// <summary>
-    /// This should trigger if you open and close the same files twice.
-    /// Even though the layers are technically the same, having two different objects screws things up down the line.
-    /// </summary>
-    private bool LayersAreDifferentObjects(IList<Layer> layers, IList<Layer> lastLayers)
-    {
-        for (int i = 0; i < layers.Count; i++)
-        {
-            if (layers[i] != lastLayers[i])
-                return true;
-        }
-        return false;
-    }
-
-    private bool TryFindStructureDifferences(LayerStructure structure)
-    {
-        bool structureModified = false;
-
-        if (lastStructure.Count != structure.Groups.Count)
-        {
-            return true;
-        }
-
-
-        foreach (GuidStructureItem treeItem in lastStructure)
-        {
-            var matchingGroup = structure.Groups.FirstOrDefault(x => x.GroupGuid == treeItem.GroupGuid);
-            List<GuidStructureItem> changedGroups = new List<GuidStructureItem>();
-            if (matchingGroup == null || StructureMismatch(treeItem, matchingGroup))
-            {
-                structureModified = true;
-            }
-
-        }
-
-        return structureModified;
-    }
-
-    private bool StructureMismatch(GuidStructureItem first, GuidStructureItem second)
-    {
-        bool rootMismatch = first.EndLayerGuid != second.EndLayerGuid || first.StartLayerGuid != second.StartLayerGuid || first.IsVisible != second.IsVisible || first.IsExpanded != second.IsExpanded || first.Opacity != second.Opacity || first.Subgroups.Count != second.Subgroups.Count || second.Name != first.Name;
-
-        if (!rootMismatch && first.Subgroups.Count > 0)
-        {
-            for (int i = 0; i < first.Subgroups.Count; i++)
-            {
-                if (StructureMismatch(first.Subgroups[i], second.Subgroups[i]))
-                {
-                    return true;
-                }
-            }
-        }
-        return rootMismatch;
-    }
-}

+ 4 - 7
src/PixiEditor/Helpers/CoordinatesHelper.cs

@@ -1,11 +1,8 @@
-using PixiEditor.Models.Position;
-using System;
-using System.Collections.Generic;
-
-namespace PixiEditor.Helpers;
+namespace PixiEditor.Helpers;
 
 internal class CoordinatesHelper
 {
+    /*
     public static (Coordinates, Coordinates) GetSquareOrLineCoordinates(IReadOnlyList<Coordinates> coords)
     {
         if (DoCoordsFormLine(coords))
@@ -80,5 +77,5 @@ internal class CoordinatesHelper
         float y = -Math.Sign(start.Y - end.Y) * axisLength;
         end = new Coordinates((int)x + start.X, (int)y + start.Y);
         return (start, end);
-    }
-}
+    }*/
+}

+ 0 - 167
src/PixiEditor/Helpers/EllipseGenerator.cs

@@ -1,167 +0,0 @@
-using PixiEditor.Models.Position;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace PixiEditor.Helpers;
-
-internal static class EllipseGenerator
-{
-    public static List<DoubleCoords> SplitEllipseIntoLines(List<Coordinates> ellipse)
-    {
-        List<DoubleCoords> lines = new();
-        var sorted = ellipse.OrderBy(
-            a => a,
-            Comparer<Coordinates>.Create((a, b) => a.Y != b.Y ? a.Y - b.Y : a.X - b.X)
-        );
-
-        int minX = int.MaxValue;
-        int maxX = int.MinValue;
-        Coordinates? prev = null;
-        foreach (var point in sorted)
-        {
-            if (prev.HasValue && point.Y != prev.Value.Y)
-            {
-                int prevY = prev.Value.Y;
-                lines.Add(new DoubleCoords(new(minX, prevY), new(maxX, prevY)));
-                minX = int.MaxValue;
-                maxX = int.MinValue;
-            }
-            minX = Math.Min(point.X, minX);
-            maxX = Math.Max(point.X, maxX);
-            prev = point;
-        }
-        lines.Add(new DoubleCoords(new(minX, prev.Value.Y), new(maxX, prev.Value.Y)));
-        return lines;
-    }
-    public static List<Coordinates> GenerateEllipseFromRect(DoubleCoords rect, List<Coordinates> listToFill = null)
-    {
-        float radiusX = (rect.Coords2.X - rect.Coords1.X) / 2.0f;
-        float radiusY = (rect.Coords2.Y - rect.Coords1.Y) / 2.0f;
-        float centerX = (rect.Coords1.X + rect.Coords2.X + 1) / 2.0f;
-        float centerY = (rect.Coords1.Y + rect.Coords2.Y + 1) / 2.0f;
-        return GenerateMidpointEllipse(radiusX, radiusY, centerX, centerY, listToFill);
-    }
-
-    /// <summary>
-    /// Draws an ellipse using it's center and radii
-    ///
-    /// Here is a usage example:
-    /// Let's say you want an ellipse that's 3 pixels wide and 3 pixels tall located in the top right corner of the canvas
-    /// It's center is at (1.5; 1.5). That's in the middle of a pixel
-    /// The radii are both equal to 1. Notice that it's 1 and not 1.5, since we want the ellipse to land in the middle of the pixel, not outside of it.
-    /// See desmos (note the inverted y axis): https://www.desmos.com/calculator/tq9uqg0hcq
-    ///
-    /// Another example:
-    /// 4x4 ellipse in the top right corner of the canvas
-    /// Center is at (2; 2). It's a place where 4 pixels meet
-    /// Both radii are 1.5. Making them 2 would make the ellipse touch the edges of pixels, whereas we want it to stay in the middle
-    /// </summary>
-    public static List<Coordinates> GenerateMidpointEllipse(
-        double halfWidth,
-        double halfHeight,
-        double centerX,
-        double centerY,
-        List<Coordinates> listToFill = null)
-    {
-        listToFill ??= new List<Coordinates>();
-        if (halfWidth < 1 || halfHeight < 1)
-        {
-            AddFallbackRectangle(halfWidth, halfHeight, centerX, centerY, listToFill);
-            return listToFill;
-        }
-
-        // ellipse formula: halfHeight^2 * x^2 + halfWidth^2 * y^2 - halfHeight^2 * halfWidth^2 = 0
-
-        // Make sure we are always at the center of a pixel
-        double currentX = Math.Ceiling(centerX - 0.5) + 0.5;
-        double currentY = centerY + halfHeight;
-
-
-        double currentSlope;
-
-        // from PI/2 to PI/4
-        do
-        {
-            AddRegionPoints(listToFill, currentX, centerX, currentY, centerY);
-
-            // calculate next pixel coords
-            currentX++;
-
-            if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX, 2)) +
-                (Math.Pow(halfWidth, 2) * Math.Pow(currentY - centerY - 0.5, 2)) -
-                (Math.Pow(halfWidth, 2) * Math.Pow(halfHeight, 2)) >= 0)
-            {
-                currentY--;
-            }
-
-            // calculate how far we've advanced
-            double derivativeX = 2 * Math.Pow(halfHeight, 2) * (currentX - centerX);
-            double derivativeY = 2 * Math.Pow(halfWidth, 2) * (currentY - centerY);
-            currentSlope = -(derivativeX / derivativeY);
-        }
-        while (currentSlope > -1 && currentY - centerY > 0.5);
-
-        // from PI/4 to 0
-        while (currentY - centerY >= 0)
-        {
-            AddRegionPoints(listToFill, currentX, centerX, currentY, centerY);
-
-            currentY--;
-            if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX + 0.5, 2)) +
-                (Math.Pow(halfWidth, 2) * Math.Pow(currentY - centerY, 2)) -
-                (Math.Pow(halfWidth, 2) * Math.Pow(halfHeight, 2)) < 0)
-            {
-                currentX++;
-            }
-        }
-
-        return listToFill;
-    }
-
-    private static void AddFallbackRectangle(double halfWidth, double halfHeight, double centerX, double centerY, List<Coordinates> coordinates)
-    {
-        int left = (int)Math.Floor(centerX - halfWidth);
-        int top = (int)Math.Floor(centerY - halfHeight);
-        int right = (int)Math.Floor(centerX + halfWidth);
-        int bottom = (int)Math.Floor(centerY + halfHeight);
-
-        for (int x = left; x <= right; x++)
-        {
-            coordinates.Add(new Coordinates(x, top));
-            coordinates.Add(new Coordinates(x, bottom));
-        }
-
-        for (int y = top; y <= bottom; y++)
-        {
-            coordinates.Add(new Coordinates(left, y));
-            coordinates.Add(new Coordinates(right, y));
-        }
-    }
-
-    private static void AddRegionPoints(List<Coordinates> coordinates, double x, double xc, double y, double yc)
-    {
-        int xFloor = (int)Math.Floor(x);
-        int yFloor = (int)Math.Floor(y);
-        int xFloorInv = (int)Math.Floor(-x + 2 * xc);
-        int yFloorInv = (int)Math.Floor(-y + 2 * yc);
-
-        //top and bottom or left and right
-        if (xFloor == xFloorInv || yFloor == yFloorInv)
-        {
-            coordinates.Add(new Coordinates(xFloor, yFloor));
-            coordinates.Add(new Coordinates(xFloorInv, yFloorInv));
-        }
-        //part of the arc
-        else
-        {
-            coordinates.Add(new Coordinates(xFloor, yFloor));
-            coordinates.Add(new Coordinates(xFloorInv, yFloorInv));
-            coordinates.Add(new Coordinates(xFloorInv, yFloor));
-            coordinates.Add(new Coordinates(xFloor, yFloorInv));
-        }
-    }
-}

+ 7 - 11
src/PixiEditor/Helpers/Extensions/ParserHelpers.cs

@@ -1,11 +1,5 @@
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
 using PixiEditor.Parser;
-using PixiEditor.Parser.Skia;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
 
 namespace PixiEditor.Helpers.Extensions;
 
@@ -13,6 +7,7 @@ public static class ParserHelpers
 {
     public static Document ToDocument(this SerializableDocument serializableDocument)
     {
+        /*
         Document document = new Document(serializableDocument.Width, serializableDocument.Height)
         {
             Layers = serializableDocument.ToLayers(),
@@ -28,9 +23,10 @@ public static class ParserHelpers
         }
         document.Renderer.ForceRerender();
 
-        return document;
+        return document;*/
+        throw new NotImplementedException();
     }
-
+    /*
     public static WpfObservableRangeCollection<Layer> ToLayers(this SerializableDocument document)
     {
         WpfObservableRangeCollection<Layer> layers = new();
@@ -51,7 +47,7 @@ public static class ParserHelpers
             Offset = new(layer.OffsetX, layer.OffsetY, 0, 0),
         };
     }
-
+    
     public static WpfObservableRangeCollection<GuidStructureItem> ToGroups(this SerializableDocument sdocument, Document document)
     {
         WpfObservableRangeCollection<GuidStructureItem> groups = new();
@@ -162,5 +158,5 @@ public static class ParserHelpers
     {
         document.Palette.AddRange(palette);
         return document;
-    }
-}
+    }*/
+}

+ 2 - 5
src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs

@@ -5,7 +5,6 @@ using PixiEditor.Models.DataProviders;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.IO.ClsFile;
 using PixiEditor.Models.IO.JascPalFile;
-using PixiEditor.Models.Services;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
 using PixiEditor.Models.UserPreferences;
@@ -62,7 +61,5 @@ public static class ServiceCollectionHelpers
         .AddSingleton<PaletteFileParser, JascFileParser>()
         .AddSingleton<PaletteFileParser, ClsFileParser>()
         // Palette data sources
-        .AddSingleton<PaletteListDataSource, LocalPalettesFetcher>()
-        // Other
-        .AddSingleton<DocumentProvider>();
-}
+        .AddSingleton<PaletteListDataSource, LocalPalettesFetcher>();
+}

+ 3 - 3
src/PixiEditor/Models/Processes/ProcessHelper.cs → src/PixiEditor/Helpers/ProcessHelper.cs

@@ -2,13 +2,13 @@
 using System.Diagnostics;
 using System.Security.Principal;
 
-namespace PixiEditor.Models.Processes;
+namespace PixiEditor.Helpers;
 
 public static class ProcessHelper
 {
     public static Process RunAsAdmin(string path)
     {
-        Process proc = new Process();
+        var proc = new Process();
         try
         {
             proc.StartInfo.FileName = path;
@@ -28,4 +28,4 @@ public static class ProcessHelper
     {
         return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
     }
-}
+}

+ 0 - 45
src/PixiEditor/Helpers/SelectionHelpers.cs

@@ -1,45 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-
-namespace PixiEditor.Helpers;
-
-public static class SelectionHelpers
-{
-    public static void AddSelectionUndoStep(Document document, IEnumerable<Coordinates> oldPoints, SelectionType mode)
-    {
-        if (mode == SelectionType.New && document.ActiveSelection.SelectedPoints.Count != 0)
-        {
-            if (oldPoints.Any())
-            {
-                // Add empty selection as the old one get's fully deleted first
-                document.UndoManager.AddUndoChange(
-                    new Change(
-                        SetSelectionProcess, new object[] { document, new List<Coordinates>(oldPoints) },
-                        SetSelectionProcess, new object[] { document, new List<Coordinates>() }));
-            }
-
-            document.UndoManager.AddUndoChange(
-                new Change(
-                    SetSelectionProcess, new object[] { document, new List<Coordinates>() },
-                    SetSelectionProcess, new object[] { document, new List<Coordinates>(document.ActiveSelection.SelectedPoints) }));
-        }
-        else
-        {
-            document.UndoManager.AddUndoChange(
-                new Change(
-                    SetSelectionProcess, new object[] { document, oldPoints is null ? new List<Coordinates>() : new List<Coordinates>(oldPoints) },
-                    SetSelectionProcess, new object[] { document, new List<Coordinates>(document.ActiveSelection.SelectedPoints) }));
-        }
-    }
-
-    private static void SetSelectionProcess(object[] arguments)
-    {
-        Document document = (Document)arguments[0];
-
-        document.ActiveSelection.SetSelection((IEnumerable<Coordinates>)arguments[1], SelectionType.New);
-    }
-}

+ 7 - 6
src/PixiEditor/Models/Commands/Search/ColorSearchResult.cs

@@ -1,7 +1,7 @@
-using PixiEditor.Helpers.Extensions;
+using System.Windows.Media;
+using PixiEditor.Helpers.Extensions;
 using PixiEditor.ViewModels;
 using SkiaSharp;
-using System.Windows.Media;
 
 namespace PixiEditor.Models.Commands.Search;
 
@@ -29,7 +29,7 @@ public class ColorSearchResult : SearchResult
         icon = GetIcon(color);
         this.target = target;
     }
-        
+
     public ColorSearchResult(SKColor color) : this(color, x => ViewModelMain.Current.ColorsSubViewModel.PrimaryColor = x)
     {
         text = $"Set color to {color}";
@@ -37,13 +37,14 @@ public class ColorSearchResult : SearchResult
 
     public static ColorSearchResult PastePalette(SKColor color, string searchTerm = null)
     {
-        var result = new ColorSearchResult(color, x => ViewModelMain.Current.BitmapManager.ActiveDocument.Palette.Add(x))
+        //var result = new ColorSearchResult(color, x => ViewModelMain.Current.BitmapManager.ActiveDocument.Palette.Add(x))
+        var result = new ColorSearchResult(color, x => { })
         {
             SearchTerm = searchTerm
         };
         result.text = $"Add color {color} to palette";
         result.requiresDocument = true;
-            
+
         return result;
     }
 
@@ -54,4 +55,4 @@ public class ColorSearchResult : SearchResult
         drawing.Geometry = geometry;
         return new DrawingImage(drawing);
     }
-}
+}

+ 11 - 76
src/PixiEditor/Models/Controllers/BitmapManager.cs

@@ -1,17 +1,12 @@
-using PixiEditor.Helpers;
+using System.Diagnostics;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Events;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
 using PixiEditor.ViewModels.SubViewModels.Main;
 using SkiaSharp;
-using System;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Windows;
-using PixiEditor.Models.Commands.Attributes;
 
 namespace PixiEditor.Models.Controllers;
 
@@ -20,7 +15,6 @@ public class BitmapManager : NotifyableObject
 {
     private ToolSessionController ToolSessionController { get; set; }
     public ICanvasInputTarget InputTarget => ToolSessionController;
-    public BitmapOperationsUtility BitmapOperations { get; set; }
 
     public System.Collections.ObjectModel.ObservableCollection<Document> Documents { get; set; } = new System.Collections.ObjectModel.ObservableCollection<Document>();
 
@@ -32,13 +26,9 @@ public class BitmapManager : NotifyableObject
         {
             if (activeDocument == value)
                 return;
-            activeDocument?.UpdatePreviewImage();
-            Document oldDoc = activeDocument;
             activeDocument = value;
-            activeDocument?.UpdatePreviewImage();
             RaisePropertyChanged(nameof(ActiveDocument));
             ActiveWindow = value;
-            DocumentChanged?.Invoke(this, new DocumentChangedEventArgs(value, oldDoc));
         }
     }
 
@@ -57,11 +47,8 @@ public class BitmapManager : NotifyableObject
         }
     }
 
-    public event EventHandler<DocumentChangedEventArgs> DocumentChanged;
     public event EventHandler StopUsingTool;
 
-    public Layer ActiveLayer => ActiveDocument.ActiveLayer;
-
     public SKColor PrimaryColor { get; set; }
 
     private bool hideReferenceLayer;
@@ -98,17 +85,8 @@ public class BitmapManager : NotifyableObject
         ToolSessionController.PixelMousePositionChanged += OnPixelMousePositionChange;
         ToolSessionController.PreciseMousePositionChanged += OnPreciseMousePositionChange;
         ToolSessionController.KeyStateChanged += (_, _) => UpdateActionDisplay(_tools.ActiveTool);
-        BitmapOperations = new BitmapOperationsUtility(this, tools);
 
         undo.UndoRedoCalled += (_, _) => ToolSessionController.ForceStopActiveSessionIfAny();
-
-        DocumentChanged += BitmapManager_DocumentChanged;
-
-        _highlightPen = new PenTool(this)
-        {
-            AutomaticallyResizeCanvas = false
-        };
-        _highlightColor = new SKColor(0, 0, 0, 77);
     }
 
     [Evaluator.CanExecute("PixiEditor.HasDocument")]
@@ -125,7 +103,6 @@ public class BitmapManager : NotifyableObject
 
         Documents.Remove(document);
         ActiveDocument = nextIndex >= 0 ? Documents[nextIndex] : null;
-        document.Dispose();
     }
 
     public void UpdateActionDisplay(Tool tool)
@@ -137,7 +114,6 @@ public class BitmapManager : NotifyableObject
     {
         activeSession = e;
 
-        ActiveDocument.PreviewLayer.Reset();
         ExecuteTool();
     }
 
@@ -145,12 +121,6 @@ public class BitmapManager : NotifyableObject
     {
         activeSession = null;
 
-        if (e.Tool is BitmapOperationTool operationTool && operationTool.RequiresPreviewLayer)
-        {
-            BitmapOperations.ApplyPreviewLayer();
-        }
-
-        ActiveDocument.PreviewLayer.Reset();
         HighlightPixels(ToolSessionController.LastPixelPosition);
         StopUsingTool?.Invoke(this, EventArgs.Empty);
     }
@@ -184,11 +154,11 @@ public class BitmapManager : NotifyableObject
 
         if (activeSession.Tool is BitmapOperationTool operationTool)
         {
-            BitmapOperations.UseTool(activeSession.MouseMovement, operationTool, PrimaryColor);
+            //BitmapOperations.UseTool(activeSession.MouseMovement, operationTool, PrimaryColor);
         }
         else if (activeSession.Tool is ReadonlyTool readonlyTool)
         {
-            readonlyTool.Use(activeSession.MouseMovement);
+            //readonlyTool.Use(activeSession.MouseMovement);
         }
         else
         {
@@ -196,11 +166,12 @@ public class BitmapManager : NotifyableObject
         }
     }
 
-    private void BitmapManager_DocumentChanged(object sender, DocumentChangedEventArgs e)
+    private void BitmapManager_DocumentChanged(object sender)
     {
+        /*
         e.NewDocument?.GeneratePreviewLayer();
         if (e.OldDocument != e.NewDocument)
-            ToolSessionController.ForceStopActiveSessionIfAny();
+            ToolSessionController.ForceStopActiveSessionIfAny();*/
     }
 
     public void UpdateHighlightIfNecessary(bool forceHide = false)
@@ -211,44 +182,8 @@ public class BitmapManager : NotifyableObject
         HighlightPixels(forceHide ? new(-1, -1) : ToolSessionController.LastPixelPosition);
     }
 
-    private void HighlightPixels(Coordinates newPosition)
+    private void HighlightPixels(VecI position)
     {
-        if (ActiveDocument == null || ActiveDocument.Layers.Count == 0)
-        {
-            return;
-        }
-
-        var previewLayer = ActiveDocument.PreviewLayer;
 
-        if (newPosition.X > ActiveDocument.Width
-            || newPosition.Y > ActiveDocument.Height
-            || newPosition.X < 0 || newPosition.Y < 0
-            || _tools.ActiveTool.HideHighlight)
-        {
-            previewLayer.Reset();
-            previewLayerSize = -1;
-            return;
-        }
-
-        if (_tools.ToolSize != previewLayerSize || previewLayer.IsReset)
-        {
-            previewLayerSize = _tools.ToolSize;
-            halfSize = (int)Math.Floor(_tools.ToolSize / 2f);
-            previewLayer.CreateNewBitmap(_tools.ToolSize, _tools.ToolSize);
-
-            Coordinates cords = new Coordinates(halfSize, halfSize);
-
-            previewLayer.Offset = new Thickness(0, 0, 0, 0);
-            _highlightPen.Draw(previewLayer, cords, cords, _highlightColor, _tools.ToolSize);
-        }
-        AdjustOffset(newPosition, previewLayer);
-
-        previewLayer.InvokeLayerBitmapChange();
-    }
-
-    private void AdjustOffset(Coordinates newPosition, Layer previewLayer)
-    {
-        Coordinates start = newPosition - halfSize;
-        previewLayer.Offset = new Thickness(start.X, start.Y, 0, 0);
     }
-}
+}

+ 0 - 102
src/PixiEditor/Models/Controllers/BitmapOperationsUtility.cs

@@ -1,102 +0,0 @@
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools;
-using PixiEditor.Models.Undo;
-using PixiEditor.ViewModels.SubViewModels.Main;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Windows;
-
-namespace PixiEditor.Models.Controllers;
-
-public class BitmapOperationsUtility
-{
-    public event EventHandler BitmapChanged;
-
-    public BitmapManager Manager { get; set; }
-
-    public ToolsViewModel Tools { get; set; }
-
-    public BitmapOperationsUtility(BitmapManager manager, ToolsViewModel tools)
-    {
-        Manager = manager;
-        Tools = tools;
-    }
-
-    public void DeletePixels(Layer[] layers, Coordinates[] pixels)
-    {
-        if (Manager.ActiveDocument == null)
-        {
-            return;
-        }
-
-        StorageBasedChange change = new StorageBasedChange(Manager.ActiveDocument, layers, true);
-
-        BitmapPixelChanges changes = BitmapPixelChanges.FromSingleColoredArray(pixels, SKColors.Empty);
-        for (int i = 0; i < layers.Length; i++)
-        {
-            Guid guid = layers[i].GuidValue;
-            layers[i].SetPixels(changes);
-        }
-
-        var args = new object[] { change.Document };
-        Manager.ActiveDocument.UndoManager.AddUndoChange(change.ToChange(StorageBasedChange.BasicUndoProcess, args, "Delete selected pixels"));
-    }
-
-    public void UseTool(IReadOnlyList<Coordinates> recordedMouseMovement, BitmapOperationTool tool, SKColor color)
-    {
-        if (Manager.ActiveDocument.Layers.Count == 0)
-            return;
-
-        if (!tool.RequiresPreviewLayer)
-        {
-            tool.Use(Manager.ActiveLayer, null, Manager.ActiveDocument.Layers, recordedMouseMovement, color);
-            BitmapChanged?.Invoke(this, null);
-        }
-        else
-        {
-            UseToolOnPreviewLayer(recordedMouseMovement, tool.ClearPreviewLayerOnEachIteration);
-        }
-    }
-
-    private void UseToolOnPreviewLayer(IReadOnlyList<Coordinates> recordedMouseMovement, bool clearPreviewLayer)
-    {
-        if (recordedMouseMovement.Count > 0)
-        {
-            if (clearPreviewLayer)
-            {
-                Manager.ActiveDocument.PreviewLayer.ClearCanvas();
-            }
-
-            ((BitmapOperationTool)Tools.ActiveTool).Use(
-                Manager.ActiveLayer,
-                Manager.ActiveDocument.PreviewLayer,
-                Manager.ActiveDocument.Layers,
-                recordedMouseMovement,
-                Manager.PrimaryColor);
-        }
-    }
-
-    /// <summary>
-    ///     Applies pixels from preview layer to selected layer.
-    /// </summary>
-    public void ApplyPreviewLayer()
-    {
-        var previewLayer = Manager.ActiveDocument.PreviewLayer;
-        var activeLayer = Manager.ActiveLayer;
-
-        Int32Rect dirtyRect = new Int32Rect(previewLayer.OffsetX, previewLayer.OffsetY, previewLayer.Width, previewLayer.Height);
-        activeLayer.DynamicResizeAbsolute(dirtyRect);
-        previewLayer.LayerBitmap.SkiaSurface.Draw(
-            activeLayer.LayerBitmap.SkiaSurface.Canvas,
-            previewLayer.OffsetX - activeLayer.OffsetX,
-            previewLayer.OffsetY - activeLayer.OffsetY,
-            Surface.BlendingPaint
-        );
-
-        Manager.ActiveLayer.InvokeLayerBitmapChange(dirtyRect);
-        BitmapChanged?.Invoke(this, null);
-    }
-}

+ 19 - 32
src/PixiEditor/Models/Controllers/ClipboardController.cs

@@ -1,24 +1,9 @@
-using PixiEditor.Exceptions;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows;
 using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.ImageManipulation;
 using PixiEditor.Models.IO;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using PixiEditor.Parser;
-using PixiEditor.ViewModels;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
 
 namespace PixiEditor.Models.Controllers;
 
@@ -35,15 +20,15 @@ public static class ClipboardController
     /// </summary>
     public static void CopyToClipboard(Document document)
     {
-        CopyToClipboard(
+        /*CopyToClipboard(
             document.Layers.Where(x => document.GetFinalLayerIsVisible(x) && x.IsActive).ToArray(),
             document.ActiveSelection.SelectionLayer,
             document.LayerStructure,
             document.Width,
             document.Height,
-            null/*document.ToSerializable()*/);
+            null/*document.ToSerializable());*/
     }
-
+    /*
     private static Surface CreateMaskedCombinedSurface(Layer[] layers, LayerStructure structure, Layer selLayer)
     {
         if (layers.Length == 0)
@@ -55,7 +40,7 @@ public static class ClipboardController
         combined.SkiaSurface.Canvas.DrawImage(snapshot, 0, 0, Surface.MaskingPaint);
         return combined;
     }
-
+    
     /// <summary>
     ///     Copies the selection to clipboard in PNG, Bitmap and DIB formats.
     /// </summary>
@@ -104,16 +89,17 @@ public static class ClipboardController
             data.SetData("PIXI", memoryStream); // PIXI, supports transparency, layers, groups and swatches
             ClipboardHelper.TrySetDataObject(data, true);
         }
-        */
+        
 
         ClipboardHelper.TrySetDataObject(data, true);
     }
-
+*/
     /// <summary>
     ///     Pastes image from clipboard into new layer.
     /// </summary>
     public static void PasteFromClipboard(Document document)
     {
+        /*
         Layer[] layers;
         try
         {
@@ -145,11 +131,12 @@ public static class ClipboardController
 
         document.UndoManager.AddUndoChange(change.ToChange(RemoveLayersProcess, undoArgs,
             RestoreLayersProcess, new object[] { document }, "Paste from clipboard"));
+        */
     }
-
+    /*
     private static void RemoveLayersProcess(object[] parameters)
     {
-        if (parameters.Length > 2 && parameters[1] is Document document && parameters[2] is PixelSize size) 
+        if (parameters.Length > 2 && parameters[1] is Document document && parameters[2] is PixelSize size)
         {
             document.RemoveLayersProcess(parameters);
             document.ResizeCanvas(size.Width, size.Height, Enums.AnchorPoint.Left | Enums.AnchorPoint.Top, false);
@@ -202,7 +189,7 @@ public static class ClipboardController
                 yield return layer;
             }
         }
-        else */
+        else 
         if (TryFromSingleImage(data, out Surface singleImage))
         {
             yield return new Layer("Image", singleImage, document.Width, document.Height);
@@ -234,7 +221,7 @@ public static class ClipboardController
             yield break;
         }
     }
-
+    */
     public static bool IsImageInClipboard()
     {
         DataObject dao = ClipboardHelper.TryGetDataObject();
@@ -255,7 +242,7 @@ public static class ClipboardController
                 }
             }
         }
-        catch(COMException)
+        catch (COMException)
         {
             return false;
         }
@@ -264,7 +251,7 @@ public static class ClipboardController
                dao.GetDataPresent(DataFormats.Bitmap) || dao.GetDataPresent(DataFormats.FileDrop) ||
                dao.GetDataPresent("PIXI");
     }
-
+    /*
     private static BitmapSource BitmapSelectionToBmpSource(WriteableBitmap bitmap, Coordinates[] selection, out int offsetX, out int offsetY, out int width, out int height)
     {
         offsetX = selection.Min(min => min.X);
@@ -345,5 +332,5 @@ public static class ClipboardController
     private static void ResizeToLayer(Document document, Layer layer)
     {
         document.ResizeCanvas(Math.Max(document.Width, layer.Width), Math.Max(document.Height, layer.Height), Enums.AnchorPoint.Left | Enums.AnchorPoint.Top, false);
-    }
-}
+    }*/
+}

+ 0 - 170
src/PixiEditor/Models/Controllers/LayerStackRenderer.cs

@@ -1,170 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Layers.Utils;
-using SkiaSharp;
-using System;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-
-namespace PixiEditor.Models.Controllers;
-
-public class LayerStackRenderer : INotifyPropertyChanged, IDisposable
-{
-    private SKPaint BlendingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
-    private SKPaint ClearPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Src, Color = SKColors.Transparent };
-
-    private System.Collections.ObjectModel.ObservableCollection<Layer> layers;
-    private LayerStructure structure;
-
-    private Surface finalSurface;
-    private SKSurface backingSurface;
-    private WriteableBitmap finalBitmap;
-    public WriteableBitmap FinalBitmap
-    {
-        get => finalBitmap;
-        set
-        {
-            finalBitmap = value;
-            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FinalBitmap)));
-        }
-    }
-
-    public Surface FinalSurface { get => finalSurface; }
-
-    public event PropertyChangedEventHandler PropertyChanged;
-    public LayerStackRenderer(System.Collections.ObjectModel.ObservableCollection<Layer> layers, LayerStructure structure, int width, int height)
-    {
-        this.layers = layers;
-        this.structure = structure;
-        layers.CollectionChanged += OnLayersChanged;
-        SubscribeToAllLayers(layers);
-        Resize(width, height);
-    }
-
-    public void Resize(int newWidth, int newHeight)
-    {
-        finalSurface?.Dispose();
-        backingSurface?.Dispose();
-        finalSurface = new Surface(newWidth, newHeight);
-        FinalBitmap = new WriteableBitmap(newWidth, newHeight, 96, 96, PixelFormats.Pbgra32, null);
-        var imageInfo = new SKImageInfo(newWidth, newHeight, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb());
-        backingSurface = SKSurface.Create(imageInfo, finalBitmap.BackBuffer, finalBitmap.BackBufferStride);
-        Update(new Int32Rect(0, 0, newWidth, newHeight));
-    }
-
-    public void SetNewLayersCollection(System.Collections.ObjectModel.ObservableCollection<Layer> layers)
-    {
-        layers.CollectionChanged -= OnLayersChanged;
-        UnsubscribeFromAllLayers(this.layers);
-        this.layers = layers;
-        SubscribeToAllLayers(layers);
-        layers.CollectionChanged += OnLayersChanged;
-        Update(new Int32Rect(0, 0, finalSurface.Width, finalSurface.Height));
-    }
-
-    public void ForceRerender()
-    {
-        Update(new Int32Rect(0, 0, finalSurface.Width, finalSurface.Height));
-    }
-
-    public void Dispose()
-    {
-        finalSurface.Dispose();
-        backingSurface.Dispose();
-        BlendingPaint.Dispose();
-        ClearPaint.Dispose();
-        layers.CollectionChanged -= OnLayersChanged;
-    }
-
-    private void SubscribeToAllLayers(System.Collections.ObjectModel.ObservableCollection<Layer> layers)
-    {
-        foreach (var layer in layers)
-        {
-            layer.LayerBitmapChanged += OnLayerBitmapChanged;
-        }
-    }
-
-    private void UnsubscribeFromAllLayers(System.Collections.ObjectModel.ObservableCollection<Layer> layers)
-    {
-        foreach (var layer in layers)
-        {
-            layer.LayerBitmapChanged -= OnLayerBitmapChanged;
-        }
-    }
-
-    private void Update(Int32Rect dirtyRectangle)
-    {
-        dirtyRectangle = dirtyRectangle.Intersect(new Int32Rect(0, 0, finalBitmap.PixelWidth, finalBitmap.PixelHeight));
-        finalSurface.SkiaSurface.Canvas.DrawRect(
-            new SKRect(
-                dirtyRectangle.X, dirtyRectangle.Y,
-                dirtyRectangle.X + dirtyRectangle.Width,
-                dirtyRectangle.Y + dirtyRectangle.Height
-            ),
-            ClearPaint
-        );
-        foreach (var layer in layers)
-        {
-            if (!LayerStructureUtils.GetFinalLayerIsVisible(layer, structure))
-                continue;
-            BlendingPaint.Color = new SKColor(255, 255, 255, (byte)(LayerStructureUtils.GetFinalLayerOpacity(layer, structure) * 255));
-
-            Int32Rect layerRect = new Int32Rect(layer.OffsetX, layer.OffsetY, layer.Width, layer.Height);
-            Int32Rect layerPortion = layerRect.Intersect(dirtyRectangle);
-
-            using var snapshot = layer.LayerBitmap.SkiaSurface.Snapshot();
-            finalSurface.SkiaSurface.Canvas.DrawImage(
-                snapshot,
-                new SKRect(
-                    layerPortion.X - layer.OffsetX,
-                    layerPortion.Y - layer.OffsetY,
-                    layerPortion.X - layer.OffsetX + layerPortion.Width,
-                    layerPortion.Y - layer.OffsetY + layerPortion.Height),
-                new SKRect(
-                    layerPortion.X,
-                    layerPortion.Y,
-                    layerPortion.X + layerPortion.Width,
-                    layerPortion.Y + layerPortion.Height
-                ),
-                BlendingPaint);
-        }
-        finalBitmap.Lock();
-        using (var snapshot = finalSurface.SkiaSurface.Snapshot())
-        {
-            SKRect rect = new(dirtyRectangle.X, dirtyRectangle.Y, dirtyRectangle.X + dirtyRectangle.Width, dirtyRectangle.Y + dirtyRectangle.Height);
-            backingSurface.Canvas.DrawImage(snapshot, rect, rect, Surface.ReplacingPaint);
-        }
-
-        finalBitmap.AddDirtyRect(dirtyRectangle);
-        finalBitmap.Unlock();
-    }
-
-    private void OnLayersChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
-    {
-        if (e.NewItems != null)
-        {
-            foreach (var obj in e.NewItems)
-            {
-                Layer layer = (Layer)obj;
-                layer.LayerBitmapChanged += OnLayerBitmapChanged;
-            }
-        }
-        if (e.OldItems != null)
-        {
-            foreach (var obj in e.OldItems)
-            {
-                ((Layer)obj).LayerBitmapChanged -= OnLayerBitmapChanged;
-            }
-        }
-        Update(new Int32Rect(0, 0, finalSurface.Width, finalSurface.Height));
-    }
-
-    private void OnLayerBitmapChanged(object sender, Int32Rect e)
-    {
-        Update(e);
-    }
-}

+ 4 - 5
src/PixiEditor/Models/Controllers/MouseMovementEventArgs.cs

@@ -1,14 +1,13 @@
-using System;
-using PixiEditor.Models.Position;
+using ChunkyImageLib.DataHolders;
 
 namespace PixiEditor.Models.Controllers;
 
 public class MouseMovementEventArgs : EventArgs
 {
-    public MouseMovementEventArgs(Coordinates mousePosition)
+    public MouseMovementEventArgs(VecI mousePosition)
     {
         NewPosition = mousePosition;
     }
 
-    public Coordinates NewPosition { get; set; }
-}
+    public VecI NewPosition { get; set; }
+}

+ 0 - 100
src/PixiEditor/Models/Controllers/SingleLayerRenderer.cs

@@ -1,100 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Layers;
-using SkiaSharp;
-using System;
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-
-namespace PixiEditor.Models.Controllers;
-
-public class SingleLayerRenderer : INotifyPropertyChanged, IDisposable
-{
-    private SKPaint BlendingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
-    private SKPaint ClearPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Src, Color = SKColors.Transparent };
-    private Layer layer;
-
-    private SKSurface backingSurface;
-    private WriteableBitmap finalBitmap;
-    public WriteableBitmap FinalBitmap
-    {
-        get => finalBitmap;
-        set
-        {
-            finalBitmap = value;
-            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FinalBitmap)));
-        }
-    }
-
-    public event PropertyChangedEventHandler PropertyChanged;
-    public SingleLayerRenderer(Layer layer, int width, int height)
-    {
-        this.layer = layer;
-        layer.LayerBitmapChanged += OnLayerBitmapChanged;
-        Resize(width, height);
-    }
-
-    public void Resize(int newWidth, int newHeight)
-    {
-        backingSurface?.Dispose();
-
-        finalBitmap = new WriteableBitmap(newWidth, newHeight, 96, 96, PixelFormats.Pbgra32, null);
-        var imageInfo = new SKImageInfo(newWidth, newHeight, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb());
-        backingSurface = SKSurface.Create(imageInfo, finalBitmap.BackBuffer, finalBitmap.BackBufferStride);
-        Update(new Int32Rect(0, 0, newWidth, newHeight));
-    }
-
-    public void Dispose()
-    {
-        backingSurface.Dispose();
-        BlendingPaint.Dispose();
-        layer.LayerBitmapChanged -= OnLayerBitmapChanged;
-    }
-
-    private void Update(Int32Rect dirtyRectangle)
-    {
-        dirtyRectangle = dirtyRectangle.Intersect(new Int32Rect(0, 0, finalBitmap.PixelWidth, finalBitmap.PixelHeight));
-        if (!dirtyRectangle.HasArea)
-            return;
-        backingSurface.Canvas.DrawRect(
-            new SKRect(
-                dirtyRectangle.X, dirtyRectangle.Y,
-                dirtyRectangle.X + dirtyRectangle.Width,
-                dirtyRectangle.Y + dirtyRectangle.Height
-            ),
-            ClearPaint
-        );
-        finalBitmap.Lock();
-        if (layer.IsVisible)
-        {
-            BlendingPaint.Color = new SKColor(255, 255, 255, (byte)(layer.Opacity * 255));
-            var layerDirty = dirtyRectangle.Intersect(new Int32Rect(layer.OffsetX, layer.OffsetY, layer.Width, layer.Height));
-            using (var snapshot = layer.LayerBitmap.SkiaSurface.Snapshot())
-            {
-                backingSurface.Canvas.DrawImage(
-                    snapshot,
-                    new SKRect(
-                        layerDirty.X - layer.OffsetX,
-                        layerDirty.Y - layer.OffsetY,
-                        layerDirty.X - layer.OffsetX + layerDirty.Width,
-                        layerDirty.Y - layer.OffsetY + layerDirty.Height),
-                    new SKRect(
-                        layerDirty.X,
-                        layerDirty.Y,
-                        layerDirty.X + layerDirty.Width,
-                        layerDirty.Y + layerDirty.Height
-                    ),
-                    BlendingPaint);
-            }
-        }
-
-        finalBitmap.AddDirtyRect(dirtyRectangle);
-        finalBitmap.Unlock();
-    }
-
-    private void OnLayerBitmapChanged(object sender, Int32Rect e)
-    {
-        Update(e);
-    }
-}

+ 0 - 45
src/PixiEditor/Models/Controllers/SurfaceRenderer.cs

@@ -1,45 +0,0 @@
-using PixiEditor.Models.DataHolders;
-using SkiaSharp;
-using System;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-
-namespace PixiEditor.Models.Controllers;
-
-class SurfaceRenderer : IDisposable
-{
-    public SKSurface BackingSurface { get; private set; }
-    public WriteableBitmap FinalBitmap { get; private set; }
-    private SKPaint BlendingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
-    private SKPaint HighQualityResizePaint { get; } = new SKPaint() { FilterQuality = SKFilterQuality.High };
-    public SurfaceRenderer(int width, int height)
-    {
-        FinalBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Pbgra32, null);
-        var imageInfo = new SKImageInfo(width, height, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb());
-        BackingSurface = SKSurface.Create(imageInfo, FinalBitmap.BackBuffer, FinalBitmap.BackBufferStride);
-    }
-
-    public void Dispose()
-    {
-        BackingSurface.Dispose();
-        BlendingPaint.Dispose();
-        HighQualityResizePaint.Dispose();
-    }
-
-    public void Draw(Surface otherSurface, byte opacity)
-    {
-        Draw(otherSurface, opacity, new SKRectI(0, 0, otherSurface.Width, otherSurface.Height));
-    }
-
-    public void Draw(Surface otherSurface, byte opacity, SKRectI drawRect)
-    {
-        BackingSurface.Canvas.Clear();
-        FinalBitmap.Lock();
-        BlendingPaint.Color = new SKColor(255, 255, 255, opacity);
-        using (var snapshot = otherSurface.SkiaSurface.Snapshot(drawRect))
-            BackingSurface.Canvas.DrawImage(snapshot, new SKRect(0, 0, FinalBitmap.PixelWidth, FinalBitmap.PixelHeight), HighQualityResizePaint);
-        FinalBitmap.AddDirtyRect(new Int32Rect(0, 0, FinalBitmap.PixelWidth, FinalBitmap.PixelHeight));
-        FinalBitmap.Unlock();
-    }
-}

+ 6 - 8
src/PixiEditor/Models/Controllers/ToolSession.cs

@@ -1,18 +1,16 @@
-using PixiEditor.Models.Position;
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.Tools;
-using System;
-using System.Collections.Generic;
-using System.Windows.Input;
 using SkiaSharp;
 
 namespace PixiEditor.Models.Controllers;
 
 public class ToolSession
 {
-    private List<Coordinates> mouseMovement = new();
+    private List<VecI> mouseMovement = new();
     private bool ended = false;
 
-    public IReadOnlyList<Coordinates> MouseMovement => mouseMovement;
+    public IReadOnlyList<VecI> MouseMovement => mouseMovement;
     public Tool Tool { get; }
 
     public bool IsCtrlDown { get; private set; }
@@ -104,7 +102,7 @@ public class ToolSession
         Tool.OnKeyUp(key);
     }
 
-    public void OnPixelPositionChange(Coordinates pos)
+    public void OnPixelPositionChange(VecI pos)
     {
         UpdateMinMax(pos.X, pos.Y);
         mouseMovement.Add(pos);
@@ -117,4 +115,4 @@ public class ToolSession
         _biggestX = Math.Max(_biggestX, x);
         _biggestY = Math.Max(_biggestY, y);
     }
-}
+}

+ 5 - 7
src/PixiEditor/Models/Controllers/ToolSessionController.cs

@@ -1,8 +1,6 @@
-using PixiEditor.Models.Position;
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.Tools;
-using System;
-using System.Collections.Generic;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Controllers;
 
@@ -21,7 +19,7 @@ public class ToolSessionController : ICanvasInputTarget
     public bool IsCtrlDown => keyboardState.ContainsKey(Key.LeftCtrl) ? keyboardState[Key.LeftCtrl] == KeyStates.Down : false;
     public bool IsAltDown => keyboardState.ContainsKey(Key.LeftAlt) ? keyboardState[Key.LeftAlt] == KeyStates.Down : false;
 
-    public Coordinates LastPixelPosition => new(lastPixelX, lastPixelY);
+    public VecI LastPixelPosition => new(lastPixelX, lastPixelY);
 
     private int lastPixelX;
     private int lastPixelY;
@@ -113,7 +111,7 @@ public class ToolSessionController : ICanvasInputTarget
         //call internal events
         PreciseMousePositionChanged?.Invoke(this, (newCanvasX, newCanvasY));
         if (pixelPosChanged)
-            PixelMousePositionChanged?.Invoke(this, new MouseMovementEventArgs(new Coordinates(newX, newY)));
+            PixelMousePositionChanged?.Invoke(this, new MouseMovementEventArgs(new VecI(newX, newY)));
     }
 
     public void OnLeftMouseButtonDown(double canvasPosX, double canvasPosY)
@@ -136,4 +134,4 @@ public class ToolSessionController : ICanvasInputTarget
         //call session events
         TryStopToolSession();
     }
-}
+}

+ 0 - 218
src/PixiEditor/Models/Controllers/UndoManager.cs

@@ -1,218 +0,0 @@
-using PixiEditor.Models.Undo;
-using PixiEditor.ViewModels;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-
-namespace PixiEditor.Models.Controllers;
-
-[DebuggerDisplay("{UndoStack.Count} undo steps, {RedoStack.Count} redo step(s)")]
-public class UndoManager : IDisposable
-{
-    private bool lastChangeWasUndo;
-
-    private PropertyInfo newUndoChangeBlockedProperty;
-
-    public Stack<Change> UndoStack { get; set; } = new Stack<Change>();
-
-    public Stack<Change> RedoStack { get; set; } = new Stack<Change>();
-
-    public bool CanUndo => UndoStack.Count > 0;
-
-    public bool CanRedo => RedoStack.Count > 0;
-
-    public object MainRoot { get; set; }
-
-    public UndoManager()
-    {
-        if (ViewModelMain.Current != null && ViewModelMain.Current.UndoSubViewModel != null)
-        {
-            MainRoot = ViewModelMain.Current.UndoSubViewModel;
-        }
-    }
-
-    public UndoManager(object mainRoot)
-    {
-        MainRoot = mainRoot;
-    }
-
-    /// <summary>
-    ///     Adds property change to UndoStack.
-    /// </summary>
-    public void AddUndoChange(Change change, bool invokedInsideSetter = false)
-    {
-        if (change.Property != null && (ChangeIsBlockedProperty(change) && invokedInsideSetter == true))
-        {
-            newUndoChangeBlockedProperty = null;
-            return;
-        }
-
-        lastChangeWasUndo = false;
-
-        // Clears RedoStack if last move wasn't redo or undo and if redo stack is greater than 0.
-        if (lastChangeWasUndo == false && RedoStack.Count > 0)
-        {
-            foreach (var redo in RedoStack)
-            {
-                redo.Dispose();
-            }
-            RedoStack.Clear();
-        }
-
-        change.Root ??= MainRoot;
-        UndoStack.Push(change);
-    }
-
-    /// <summary>
-    ///     Sets top property in UndoStack to Old Value.
-    /// </summary>
-    public void Undo()
-    {
-        lastChangeWasUndo = true;
-        Change change = UndoStack.Pop();
-        if (change.ReverseProcess == null)
-        {
-            SetPropertyValue(GetChangeRoot(change), change.Property, change.OldValue);
-        }
-        else
-        {
-            change.ReverseProcess(change.ReverseProcessArguments);
-        }
-
-        RedoStack.Push(change);
-    }
-
-    /// <summary>
-    ///     Sets top property from RedoStack to old value.
-    /// </summary>
-    public void Redo()
-    {
-        lastChangeWasUndo = true;
-        Change change = RedoStack.Pop();
-        if (change.Process == null)
-        {
-            SetPropertyValue(GetChangeRoot(change), change.Property, change.NewValue);
-        }
-        else
-        {
-            change.Process(change.ProcessArguments);
-        }
-
-        UndoStack.Push(change);
-    }
-
-    /// <summary>
-    /// Merges multiple undo changes into one.
-    /// </summary>
-    /// <param name="amount">Amount of changes to squash.</param>
-    public void SquashUndoChanges(int amount)
-    {
-        string description = UndoStack.ElementAt(UndoStack.Count - amount).Description;
-        if (string.IsNullOrEmpty(description))
-        {
-            description = $"Squash {amount} undo changes.";
-        }
-
-        SquashUndoChanges(amount, description);
-    }
-
-    /// <summary>
-    /// Merges multiple undo changes into one.
-    /// </summary>
-    /// <param name="amount">Amount of changes to squash.</param>
-    /// <param name="description">Final change description.</param>
-    public void SquashUndoChanges(int amount, string description, bool reverseOrderOnRedo = true)
-    {
-        Change[] changes = new Change[amount];
-        for (int i = 0; i < amount; i++)
-        {
-            changes[i] = UndoStack.Pop();
-        }
-
-        Action<object[]> reverseProcess = (object[] props) =>
-        {
-            foreach (var prop in props)
-            {
-                Change change = (Change)prop;
-                if (change.ReverseProcess == null)
-                {
-                    SetPropertyValue(GetChangeRoot(change), change.Property, change.OldValue);
-                }
-                else
-                {
-                    change.ReverseProcess(change.ReverseProcessArguments);
-                }
-            }
-        };
-
-        Action<object[]> process = (object[] props) =>
-        {
-            var finalProps = reverseOrderOnRedo ? props.Reverse() : props;
-
-            foreach (var prop in finalProps)
-            {
-                Change change = (Change)prop;
-                if (change.Process == null)
-                {
-                    SetPropertyValue(GetChangeRoot(change), change.Property, change.NewValue);
-                }
-                else
-                {
-                    change.Process(change.ProcessArguments);
-                }
-            }
-        };
-
-        Change change = new(reverseProcess, changes, process, changes, description);
-        AddUndoChange(change);
-    }
-
-    public void Dispose()
-    {
-        foreach (Change change in UndoStack.Concat(RedoStack))
-        {
-            change.Dispose();
-        }
-
-        GC.SuppressFinalize(this);
-    }
-
-    private bool ChangeIsBlockedProperty(Change change)
-    {
-        return (change.Root != null || change.FindRootProcess != null)
-               && GetProperty(GetChangeRoot(change), change.Property).Item1 == newUndoChangeBlockedProperty;
-    }
-
-    private object GetChangeRoot(Change change)
-    {
-        return change.FindRootProcess != null ? change.FindRootProcess(change.FindRootProcessArgs) : change.Root;
-    }
-
-    private void SetPropertyValue(object target, string propName, object value)
-    {
-        var properties = GetProperty(target, propName);
-        PropertyInfo propertyToSet = properties.Item1;
-        newUndoChangeBlockedProperty = propertyToSet;
-        propertyToSet.SetValue(properties.Item2, value, null);
-    }
-
-    /// <summary>
-    /// Gets property info for propName from target. Supports '.' format.
-    /// </summary>
-    /// <param name="target">A object where target can be found.</param>
-    /// <param name="propName">Name of property to get, supports nested property.</param>
-    /// <returns>PropertyInfo about property and target object where property can be found.</returns>
-    private Tuple<PropertyInfo, object> GetProperty(object target, string propName)
-    {
-        string[] bits = propName.Split('.');
-        for (int i = 0; i < bits.Length - 1; i++)
-        {
-            PropertyInfo propertyToGet = target.GetType().GetProperty(bits[i]);
-            target = propertyToGet.GetValue(target, null);
-        }
-
-        return new Tuple<PropertyInfo, object>(target.GetType().GetProperty(bits.Last()), target);
-    }
-}

+ 0 - 75
src/PixiEditor/Models/DataHolders/BitmapPixelChanges.cs

@@ -1,75 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Position;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace PixiEditor.Models.DataHolders;
-
-public struct BitmapPixelChanges
-{
-    public BitmapPixelChanges(Dictionary<Coordinates, SKColor> changedPixels)
-    {
-        ChangedPixels = changedPixels;
-        WasBuiltAsSingleColored = false;
-    }
-
-    public static BitmapPixelChanges Empty => new BitmapPixelChanges(new Dictionary<Coordinates, SKColor>());
-
-    public bool WasBuiltAsSingleColored { get; private set; }
-
-    public Dictionary<Coordinates, SKColor> ChangedPixels { get; set; }
-
-    /// <summary>
-    ///     Builds BitmapPixelChanges with only one color for specified coordinates.
-    /// </summary>
-    /// <returns>Single-colored BitmapPixelChanges.</returns>
-    public static BitmapPixelChanges FromSingleColoredArray(IEnumerable<Coordinates> coordinates, SKColor color)
-    {
-        Dictionary<Coordinates, SKColor> dict = new Dictionary<Coordinates, SKColor>();
-        foreach (Coordinates coordinate in coordinates)
-        {
-            if (dict.ContainsKey(coordinate))
-            {
-                continue;
-            }
-
-            dict.Add(coordinate, color);
-        }
-
-        return new BitmapPixelChanges(dict) { WasBuiltAsSingleColored = true };
-    }
-
-    /// <summary>
-    ///     Combines pixel changes array with overriding values.
-    /// </summary>
-    /// <param name="changes">BitmapPixelChanges to combine.</param>
-    /// <returns>Combined BitmapPixelChanges.</returns>
-    public static BitmapPixelChanges CombineOverride(BitmapPixelChanges[] changes)
-    {
-        if (changes == null || changes.Length == 0)
-        {
-            throw new ArgumentException();
-        }
-
-        BitmapPixelChanges output = Empty;
-
-        for (int i = 0; i < changes.Length; i++)
-        {
-            output.ChangedPixels.AddRangeOverride(changes[i].ChangedPixels);
-        }
-
-        return output;
-    }
-
-    public static BitmapPixelChanges CombineOverride(BitmapPixelChanges changes1, BitmapPixelChanges changes2)
-    {
-        return CombineOverride(new[] { changes1, changes2 });
-    }
-
-    public BitmapPixelChanges WithoutTransparentPixels()
-    {
-        return new BitmapPixelChanges(ChangedPixels.Where(x => x.Value.Alpha > 0).ToDictionary(y => y.Key, y => y.Value));
-    }
-}

+ 8 - 9
src/PixiEditor/Models/DataHolders/CrashReport.cs

@@ -1,15 +1,9 @@
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Parser;
-using PixiEditor.ViewModels;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
+using System.Diagnostics;
 using System.IO;
 using System.IO.Compression;
-using System.Linq;
 using System.Reflection;
 using System.Text;
+using PixiEditor.Helpers;
 
 namespace PixiEditor.Models.DataHolders;
 
@@ -93,6 +87,8 @@ public class CrashReport : IDisposable
 
     public List<Document> RecoverDocuments()
     {
+        return new List<Document>();
+        /*
         List<Document> documents = new();
         foreach (ZipArchiveEntry entry in ZipFile.Entries.Where(x => x.FullName.EndsWith(".pixi")))
         {
@@ -114,6 +110,7 @@ public class CrashReport : IDisposable
         }
 
         return documents;
+        */
     }
 
     public void Dispose()
@@ -149,6 +146,7 @@ public class CrashReport : IDisposable
 
     public void Save()
     {
+        /*
         using FileStream zipStream = new(FilePath, FileMode.Create, FileAccess.Write);
         using ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create);
 
@@ -171,6 +169,7 @@ public class CrashReport : IDisposable
             }
             catch { }
         }
+        */
     }
 
     private void ExtractReport()
@@ -190,4 +189,4 @@ public class CrashReport : IDisposable
 
         public string Mail { get; set; }
     }
-}
+}

+ 3 - 3
src/PixiEditor/Models/DataHolders/Document/Document.Commands.cs

@@ -10,7 +10,7 @@ public partial class Document
 
     private void SetRelayCommands()
     {
-        RequestCloseDocumentCommand = new RelayCommand(RequestCloseDocument);
-        SetAsActiveOnClickCommand = new RelayCommand(SetAsActiveOnClick);
+        //RequestCloseDocumentCommand = new RelayCommand(RequestCloseDocument);
+        //SetAsActiveOnClickCommand = new RelayCommand(SetAsActiveOnClick);
     }
-}
+}

+ 0 - 64
src/PixiEditor/Models/DataHolders/Document/Document.Constructors.cs

@@ -1,64 +0,0 @@
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.ViewModels;
-using System;
-using System.Linq;
-
-namespace PixiEditor.Models.DataHolders;
-
-public partial class Document
-{
-    public Document(int width, int height)
-        : this()
-    {
-        if (width <= 0 || height <= 0)
-            throw new ArgumentException("Document dimensions must be greater than 0");
-        Width = width;
-        Height = height;
-        Renderer = new LayerStackRenderer(layers, layerStructure, Width, Height);
-        DocumentSizeChanged?.Invoke(this, new DocumentSizeChangedEventArgs(1, 1, width, height));
-    }
-
-    private Document()
-    {
-        SetRelayCommands();
-        UndoManager = new UndoManager();
-        LayerStructure = new LayerStructure(this);
-        XamlAccesibleViewModel = ViewModelMain.Current;
-        GeneratePreviewLayer();
-        Layers.CollectionChanged += Layers_CollectionChanged;
-        LayerStructure.Groups.CollectionChanged += Groups_CollectionChanged;
-        LayerStructure.LayerStructureChanged += LayerStructure_LayerStructureChanged;
-        DocumentSizeChanged += (sender, args) =>
-        {
-            ActiveSelection = new Selection(Array.Empty<Coordinates>(), new PixelSize(args.NewWidth, args.NewHeight));
-            Renderer.Resize(args.NewWidth, args.NewHeight);
-            GeneratePreviewLayer();
-        };
-    }
-
-    private void LayerStructure_LayerStructureChanged(object sender, LayerStructureChangedEventArgs e)
-    {
-        RaisePropertyChanged(nameof(LayerStructure));
-        foreach (var layerGuid in e.AffectedLayerGuids)
-        {
-            Layer layer = Layers.First(x => x.GuidValue == layerGuid);
-            layer.RaisePropertyChange(nameof(layer.IsVisible));
-            layer.RaisePropertyChange(nameof(layer.Opacity));
-        }
-    }
-
-    private void Groups_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
-    {
-        if (e.OldItems != e.NewItems)
-        {
-            RaisePropertyChanged(nameof(LayerStructure));
-        }
-    }
-
-    private void Layers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
-    {
-        RaisePropertyChanged(nameof(Layers));
-    }
-}

+ 0 - 81
src/PixiEditor/Models/DataHolders/Document/Document.IO.cs

@@ -1,81 +0,0 @@
-using System.Collections.ObjectModel;
-using System.Linq;
-using PixiEditor.Models.IO;
-using PixiEditor.Models.UserPreferences;
-
-namespace PixiEditor.Models.DataHolders;
-
-public partial class Document
-{
-    private string documentFilePath = string.Empty;
-
-    public string DocumentFilePath
-    {
-        get => documentFilePath;
-        set
-        {
-            documentFilePath = value;
-            RaisePropertyChanged(nameof(DocumentFilePath));
-            RaisePropertyChanged(nameof(Name));
-            UpdateRecentlyOpened(value);
-        }
-    }
-
-    private bool changesSaved = true;
-
-    public bool ChangesSaved
-    {
-        get => changesSaved;
-        set
-        {
-            changesSaved = value;
-            RaisePropertyChanged(nameof(ChangesSaved));
-            RaisePropertyChanged(nameof(Name)); // This updates name so it shows asterisk if unsaved
-        }
-    }
-
-    public void SaveWithDialog()
-    {
-        bool savedSuccessfully = Exporter.SaveAsEditableFileWithDialog(this, out string path);
-        DocumentFilePath = path;
-        ChangesSaved = savedSuccessfully;
-    }
-
-    public void Save()
-    {
-        Save(DocumentFilePath);
-    }
-
-    public void Save(string path)
-    {
-        DocumentFilePath = Exporter.SaveAsEditableFile(this, path);
-        ChangesSaved = true;
-    }
-
-    private void UpdateRecentlyOpened(string newPath)
-    {
-        RecentlyOpenedCollection recentlyOpened = XamlAccesibleViewModel.FileSubViewModel.RecentlyOpened;
-
-        if (!recentlyOpened.Contains(newPath))
-        {
-            recentlyOpened.Insert(0, newPath);
-        }
-        else
-        {
-            int index = recentlyOpened.IndexOf(newPath);
-            recentlyOpened.Move(index, 0);
-        }
-
-        if (recentlyOpened.Count > IPreferences.Current.GetPreference("MaxOpenedRecently", 8))
-        {
-            for (int i = 4; i < recentlyOpened.Count; i++)
-            {
-                recentlyOpened.RemoveAt(i);
-            }
-        }
-
-        IPreferences.Current.UpdateLocalPreference("RecentlyOpened", recentlyOpened.Select(x => x.FilePath));
-
-        XamlAccesibleViewModel.FileSubViewModel.HasRecent = true;
-    }
-}

+ 0 - 873
src/PixiEditor/Models/DataHolders/Document/Document.Layers.cs

@@ -1,873 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Layers.Utils;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using SkiaSharp;
-using System;
-using System.Buffers;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Windows;
-using Windows.Graphics;
-
-namespace PixiEditor.Models.DataHolders;
-
-public partial class Document
-{
-    public const string MainSelectedLayerColor = "#505056";
-    public const string SecondarySelectedLayerColor = "#7D505056";
-    private static readonly Regex reversedLayerSuffixRegex = new(@"(?:\)([0-9]+)*\()? *([\s\S]+)", RegexOptions.Compiled);
-    private Guid activeLayerGuid;
-    private LayerStructure layerStructure;
-
-    private WpfObservableRangeCollection<Layer> layers = new();
-
-    public WpfObservableRangeCollection<Layer> Layers
-    {
-        get => layers;
-        set
-        {
-            layers = value;
-            Layers.CollectionChanged += Layers_CollectionChanged;
-            Renderer.SetNewLayersCollection(value);
-        }
-    }
-
-    public LayerStructure LayerStructure
-    {
-        get => layerStructure;
-        private set
-        {
-            layerStructure = value;
-            RaisePropertyChanged(nameof(LayerStructure));
-        }
-    }
-
-    private LayerStackRenderer renderer;
-    public LayerStackRenderer Renderer
-    {
-        get => renderer;
-        private set
-        {
-            renderer = value;
-            RaisePropertyChanged(nameof(Renderer));
-        }
-    }
-
-    private Layer referenceLayer;
-    private SingleLayerRenderer referenceLayerRenderer;
-    public Layer ReferenceLayer
-    {
-        get => referenceLayer;
-        set
-        {
-            referenceLayer = value;
-            referenceLayerRenderer?.Dispose();
-            referenceLayerRenderer = referenceLayer == null ? null : new SingleLayerRenderer(referenceLayer, referenceLayer.Width, referenceLayer.Height);
-            RaisePropertyChanged(nameof(ReferenceLayer));
-            RaisePropertyChanged(nameof(ReferenceLayerRenderer));
-        }
-    }
-
-    public SingleLayerRenderer ReferenceLayerRenderer
-    {
-        get => referenceLayerRenderer;
-    }
-
-    public Layer ActiveLayer => Layers.Count > 0 ? Layers.FirstOrDefault(x => x.GuidValue == ActiveLayerGuid) : null;
-
-    public Guid ActiveLayerGuid
-    {
-        get => activeLayerGuid;
-        set
-        {
-            if (value != activeLayerGuid)
-            {
-                activeLayerGuid = value;
-                RaisePropertyChanged(nameof(ActiveLayerGuid));
-                RaisePropertyChanged(nameof(ActiveLayer));
-            }
-        }
-    }
-
-    public event EventHandler<LayersChangedEventArgs> LayersChanged;
-
-    public void SetMainActiveLayer(int index)
-    {
-        if (ActiveLayer != null && Layers.IndexOf(ActiveLayer) <= Layers.Count - 1)
-        {
-            ActiveLayer.IsActive = false;
-        }
-
-        foreach (var layer in Layers)
-        {
-            if (layer.IsActive)
-            {
-                layer.IsActive = false;
-            }
-        }
-
-        ActiveLayerGuid = Layers[index].GuidValue;
-        ActiveLayer.IsActive = true;
-        LayersChanged?.Invoke(this, new LayersChangedEventArgs(ActiveLayerGuid, LayerAction.SetActive));
-    }
-
-    /// <summary>
-    /// Gets final layer IsVisible taking into consideration group visibility.
-    /// </summary>
-    /// <param name="layer">Layer to check.</param>
-    /// <returns>True if is visible, false if at least parent is not visible or layer itself is invisible.</returns>
-    public bool GetFinalLayerIsVisible(Layer layer) => LayerStructureUtils.GetFinalLayerIsVisible(layer, LayerStructure);
-    public void UpdateLayersColor()
-    {
-        foreach (var layer in Layers)
-        {
-            if (layer.GuidValue == ActiveLayerGuid)
-            {
-                layer.LayerHighlightColor = MainSelectedLayerColor;
-            }
-            else
-            {
-                layer.LayerHighlightColor = SecondarySelectedLayerColor;
-            }
-        }
-    }
-
-    public void MoveLayerInStructure(Guid layerGuid, Guid referenceLayer, bool above = false, bool addToUndo = true)
-    {
-        var args = new object[] { layerGuid, referenceLayer, above };
-
-        Layer layer = Layers.First(x => x.GuidValue == layerGuid);
-
-        int oldIndex = Layers.IndexOf(layer);
-
-        var oldLayerStrcutureGroups = LayerStructure.CloneGroups();
-
-        MoveLayerInStructureProcess(args);
-
-        AddLayerStructureToUndo(oldLayerStrcutureGroups);
-
-        if (!addToUndo) return;
-
-        UndoManager.AddUndoChange(new Change(
-            ReverseMoveLayerInStructureProcess,
-            new object[] { oldIndex, layerGuid },
-            MoveLayerInStructureProcess,
-            args,
-            "Move layer"));
-
-        UndoManager.SquashUndoChanges(2, "Move layer");
-    }
-
-    public void MoveGroupInStructure(Guid groupGuid, Guid referenceLayer, bool above = false)
-    {
-        var args = new object[] { groupGuid, referenceLayer, above };
-
-        var topLayer = Layers.First(x => x.GuidValue == LayerStructure.GetGroupByGuid(groupGuid).EndLayerGuid);
-        var bottomLayer = Layers.First(x => x.GuidValue == LayerStructure.GetGroupByGuid(groupGuid).StartLayerGuid);
-
-        int indexOfTopLayer = Layers.IndexOf(topLayer);
-        Guid oldReferenceLayerGuid;
-        bool oldAbove = false;
-
-        if (indexOfTopLayer + 1 < Layers.Count)
-        {
-            oldReferenceLayerGuid = topLayer.GuidValue;
-        }
-        else
-        {
-            int indexOfBottomLayer = Layers.IndexOf(bottomLayer);
-            oldReferenceLayerGuid = Layers[indexOfBottomLayer - 1].GuidValue;
-            oldAbove = true;
-        }
-
-        var oldLayerStructure = LayerStructure.CloneGroups();
-
-        MoveGroupInStructureProcess(args);
-
-        AddLayerStructureToUndo(oldLayerStructure);
-
-        UndoManager.AddUndoChange(new Change(
-            MoveGroupInStructureProcess,
-            new object[] { groupGuid, oldReferenceLayerGuid, oldAbove },
-            MoveGroupInStructureProcess,
-            args));
-
-        UndoManager.SquashUndoChanges(2, "Move group");
-    }
-
-    public void AddNewLayer(string name, Surface bitmap, bool setAsActive = true)
-    {
-        AddNewLayer(name, bitmap.Width, bitmap.Height, setAsActive, bitmap);
-    }
-
-    public void AddNewLayer(string name, bool setAsActive = true)
-    {
-        AddNewLayer(name, 1, 1, setAsActive);
-    }
-
-    public void AddNewLayer(string name, int width, int height, bool setAsActive = true, Surface bitmap = null)
-    {
-        Layer layer;
-
-        if (bitmap != null)
-        {
-            if (width != bitmap.Width || height != bitmap.Height)
-                throw new ArgumentException("Inconsistent width and height");
-        }
-        if (width <= 0 || height <= 0)
-            throw new ArgumentException("Dimensions must be greater than 0");
-
-        layer = bitmap == null ? new Layer(name, width, height, Width, Height) : new Layer(name, bitmap, Width, Height);
-
-        Layers.Add(layer);
-
-        layer.Name = GetLayerSuffix(layer);
-
-        if (setAsActive)
-        {
-            SetMainActiveLayer(Layers.Count - 1);
-        }
-
-        if (Layers.Count > 1)
-        {
-            StorageBasedChange storageChange = new(this, new[] { Layers[^1] }, false);
-            UndoManager.AddUndoChange(
-                storageChange.ToChange(
-                    RemoveLayerProcess,
-                    new object[] { Layers[^1].GuidValue },
-                    RestoreLayersProcess,
-                    "Add layer"));
-        }
-
-        LayersChanged?.Invoke(this, new LayersChangedEventArgs(Layers[^1].GuidValue, LayerAction.Add));
-    }
-
-    /// <summary>
-    /// Duplicates the layer at the <paramref name="index"/>.
-    /// </summary>
-    /// <param name="index">The index of the layer to duplicate.</param>
-    /// <returns>The duplicate.</returns>
-    public Layer DuplicateLayer(int index)
-    {
-        Layer duplicate = Layers[index].Clone(true);
-
-        duplicate.Name = GetLayerSuffix(duplicate);
-
-        Layers.Insert(index + 1, duplicate);
-        SetMainActiveLayer(index + 1);
-
-        StorageBasedChange storageChange = new(this, new[] { duplicate }, false);
-        UndoManager.AddUndoChange(
-            storageChange.ToChange(
-                RemoveLayerProcess,
-                new object[] { duplicate.GuidValue },
-                RestoreLayersProcess,
-                "Duplicate Layer"));
-
-        return duplicate;
-    }
-
-    public void SetNextLayerAsActive(int lastLayerIndex)
-    {
-        if (Layers.Count > 0)
-        {
-            if (lastLayerIndex == 0)
-            {
-                SetMainActiveLayer(0);
-            }
-            else
-            {
-                SetMainActiveLayer(lastLayerIndex - 1);
-            }
-        }
-    }
-
-    public void SetNextSelectedLayerAsActive(Guid lastLayerGuid)
-    {
-        var selectedLayers = Layers.Where(x => x.IsActive);
-        foreach (var layer in selectedLayers)
-        {
-            if (layer.GuidValue != lastLayerGuid)
-            {
-                ActiveLayerGuid = layer.GuidValue;
-                LayersChanged?.Invoke(this, new LayersChangedEventArgs(ActiveLayerGuid, LayerAction.SetActive));
-                return;
-            }
-        }
-    }
-
-    public void ToggleLayer(int index)
-    {
-        if (index < Layers.Count && index >= 0)
-        {
-            Layer layer = Layers[index];
-            if (layer.IsActive && Layers.Count(x => x.IsActive) == 1)
-            {
-                return;
-            }
-
-            if (ActiveLayerGuid == layer.GuidValue)
-            {
-                SetNextSelectedLayerAsActive(layer.GuidValue);
-            }
-
-            layer.IsActive = !layer.IsActive;
-        }
-    }
-
-    /// <summary>
-    /// Selects all layers between active layer and layer at given index.
-    /// </summary>
-    /// <param name="index">End of range index.</param>
-    public void SelectLayersRange(int index)
-    {
-        DeselectAllExcept(ActiveLayer);
-        int firstIndex = Layers.IndexOf(ActiveLayer);
-
-        int startIndex = Math.Min(index, firstIndex);
-        for (int i = startIndex; i <= startIndex + Math.Abs(index - firstIndex); i++)
-        {
-            Layers[i].IsActive = true;
-        }
-    }
-
-    public void DeselectAllExcept(Layer exceptLayer)
-    {
-        foreach (var layer in Layers)
-        {
-            if (layer == exceptLayer)
-            {
-                continue;
-            }
-
-            layer.IsActive = false;
-        }
-    }
-
-    public void RemoveLayer(int layerIndex, bool addToUndo = true)
-    {
-        if (Layers.Count == 0)
-        {
-            return;
-        }
-
-        LayerStructure.AssignParent(Layers[layerIndex].GuidValue, null);
-
-        bool wasActive = Layers[layerIndex].IsActive;
-
-        if (addToUndo)
-        {
-            StorageBasedChange change = new(this, new[] { Layers[layerIndex] });
-            UndoManager.AddUndoChange(
-                change.ToChange(RestoreLayersProcess, RemoveLayerProcess, new object[] { Layers[layerIndex].GuidValue }));
-        }
-
-        Layers.RemoveAt(layerIndex);
-        if (wasActive)
-        {
-            SetNextLayerAsActive(layerIndex);
-        }
-    }
-
-    public void RemoveLayer(Layer layer, bool addToUndo)
-    {
-        RemoveLayer(Layers.IndexOf(layer), addToUndo);
-    }
-
-    public void RemoveActiveLayers()
-    {
-        if (Layers.Count == 0 || !Layers.Any(x => x.IsActive))
-        {
-            return;
-        }
-
-        var oldLayerStructure = LayerStructure.CloneGroups();
-
-        Layer[] layers = Layers.Where(x => x.IsActive).ToArray();
-        int firstIndex = Layers.IndexOf(layers[0]);
-
-        object[] guidArgs = new object[] { layers.Select(x => x.GuidValue).ToArray() };
-
-        StorageBasedChange change = new(this, layers);
-
-        RemoveLayersProcess(guidArgs);
-
-        AddLayerStructureToUndo(oldLayerStructure);
-
-        InjectRemoveActiveLayersUndo(guidArgs, change);
-
-        UndoManager.SquashUndoChanges(2, "Removed active layers");
-
-        SetNextLayerAsActive(firstIndex);
-
-    }
-
-    public void AddLayerStructureToUndo(WpfObservableRangeCollection<GuidStructureItem> oldLayerStructureGroups)
-    {
-        UndoManager.AddUndoChange(
-            new Change(
-                BuildLayerStructureProcess,
-                new object[] { oldLayerStructureGroups },
-                BuildLayerStructureProcess,
-                new object[] { LayerStructure.CloneGroups() }, "Reload LayerStructure"));
-    }
-
-    public Layer MergeLayers(Layer[] layersToMerge, bool nameOfLast, int index)
-    {
-        if (layersToMerge == null || layersToMerge.Length < 2)
-        {
-            throw new ArgumentException("Not enough layers were provided to merge. Minimum amount is 2");
-        }
-
-        string name;
-
-        // Which name should be used
-        if (nameOfLast)
-        {
-            name = layersToMerge[^1].Name;
-        }
-        else
-        {
-            name = layersToMerge[0].Name;
-        }
-
-        Layer mergedLayer = layersToMerge[0];
-
-        var groupParent = LayerStructure.GetGroupByLayer(layersToMerge[^1].GuidValue);
-
-        Layer placeholderLayer = new("_placeholder", Width, Height);
-        Layers.Insert(index, placeholderLayer);
-        LayerStructure.AssignParent(placeholderLayer.GuidValue, groupParent?.GroupGuid);
-
-        for (int i = 0; i < layersToMerge.Length - 1; i++)
-        {
-            Layer firstLayer = mergedLayer;
-            Layer secondLayer = layersToMerge[i + 1];
-            firstLayer.ClipCanvas();
-            secondLayer.ClipCanvas();
-            mergedLayer = firstLayer.MergeWith(secondLayer, name, Width, Height);
-            RemoveLayer(layersToMerge[i], false);
-        }
-
-        Layers.Insert(index, mergedLayer);
-        LayerStructure.AssignParent(mergedLayer.GuidValue, groupParent?.GroupGuid);
-
-        RemoveLayer(placeholderLayer, false);
-        RemoveLayer(layersToMerge[^1], false);
-
-        SetMainActiveLayer(Layers.IndexOf(mergedLayer));
-
-        return mergedLayer;
-    }
-
-    public Layer MergeLayers(Layer[] layersToMerge, bool nameIsLastLayers)
-    {
-        if (layersToMerge == null || layersToMerge.Length < 2)
-        {
-            throw new ArgumentException("Not enough layers were provided to merge. Minimum amount is 2");
-        }
-
-        Layer[] undoArgs = layersToMerge;
-
-        var oldLayerStructure = LayerStructure.CloneGroups();
-
-        StorageBasedChange undoChange = new(this, undoArgs);
-
-        int[] indexes = layersToMerge.Select(x => Layers.IndexOf(x)).ToArray();
-
-        var layer = MergeLayers(layersToMerge, nameIsLastLayers, Layers.IndexOf(layersToMerge[0]));
-
-        AddLayerStructureToUndo(oldLayerStructure);
-
-        UndoManager.AddUndoChange(undoChange.ToChange(
-            InsertLayersAtIndexesProcess,
-            new object[] { indexes[0] },
-            MergeLayersProcess,
-            new object[] { indexes, nameIsLastLayers, layer.GuidValue }));
-
-        UndoManager.SquashUndoChanges(2, "Undo merge layers", false);
-
-        LayersChanged?.Invoke(this, new LayersChangedEventArgs(layer.GuidValue, LayerAction.Add));
-
-        return layer;
-    }
-
-    public SKColor GetColorAtPoint(int x, int y)
-    {
-        return Renderer.FinalSurface.GetSRGBPixel(x, y);
-    }
-
-    private void DisposeLayerBitmaps()
-    {
-        foreach (var layer in layers)
-        {
-            layer.LayerBitmap.Dispose();
-        }
-
-        referenceLayer?.LayerBitmap.Dispose();
-        previewLayer?.LayerBitmap.Dispose();
-
-        previewLayerRenderer?.Dispose();
-        referenceLayerRenderer?.Dispose();
-        renderer?.Dispose();
-    }
-
-    public void BuildLayerStructureProcess(object[] parameters)
-    {
-        if (parameters.Length > 0 && parameters[0] is WpfObservableRangeCollection<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];
-        Guid layerGuid = (Guid)props[1];
-
-        Guid layerAtOldIndex = Layers[indexTo].GuidValue;
-
-        var startGroup = LayerStructure.GetGroupByLayer(layerGuid);
-
-        LayerStructure.Unassign(new GroupData(startGroup?.GroupGuid), layerGuid);
-
-        Layers.Move(Layers.IndexOf(Layers.First(x => x.GuidValue == layerGuid)), indexTo);
-
-        var newGroup = LayerStructure.GetGroupByLayer(layerAtOldIndex);
-
-        LayerStructure.Assign(new GroupData(newGroup?.GroupGuid), layerGuid);
-
-        RaisePropertyChanged(nameof(LayerStructure));
-    }
-
-    private void InjectRemoveActiveLayersUndo(object[] guidArgs, StorageBasedChange change)
-    {
-        Action<Layer[], UndoLayer[]> undoAction = RestoreLayersProcess;
-        Action<object[]> redoAction = RemoveLayersProcess;
-
-        if (Layers.Count == 0)
-        {
-            Layer layer = new("Base Layer", 1, 1) { MaxHeight = Height, MaxWidth = Width };
-            Layers.Add(layer);
-            undoAction = (Layer[] layers, UndoLayer[] undoData) =>
-            {
-                Layers.RemoveAt(0);
-                RestoreLayersProcess(layers, undoData);
-            };
-            redoAction = (object[] args) =>
-            {
-                RemoveLayersProcess(args);
-                Layers.Add(layer);
-            };
-        }
-
-        UndoManager.AddUndoChange(
-            change.ToChange(
-                undoAction,
-                redoAction,
-                guidArgs,
-                "Remove layers"));
-    }
-
-    private void MergeLayersProcess(object[] args)
-    {
-        if (args.Length > 0
-            && args[0] is int[] indexes
-            && args[1] is bool nameOfSecond
-            && args[2] is Guid mergedLayerGuid)
-        {
-            Layer[] layers = new Layer[indexes.Length];
-
-            for (int i = 0; i < layers.Length; i++)
-            {
-                layers[i] = Layers[indexes[i]];
-            }
-
-            Layer layer = MergeLayers(layers, nameOfSecond, indexes[0]);
-            layer.ChangeGuid(mergedLayerGuid);
-            SetMainActiveLayer(Layers.IndexOf(layer));
-        }
-    }
-
-    private void InsertLayersAtIndexesProcess(Layer[] layers, UndoLayer[] data, object[] args)
-    {
-        if (args.Length > 0 && args[0] is int layerIndex)
-        {
-            RemoveLayer(layerIndex, false);
-
-            for (int i = 0; i < layers.Length; i++)
-            {
-                Layer layer = layers[i];
-                layer.IsActive = data[i].IsActive;
-                Layers.Insert(data[i].LayerIndex, layer);
-            }
-
-            ActiveLayerGuid = layers.First(x => x.LayerHighlightColor == MainSelectedLayerColor).GuidValue;
-            // Identifying main layer by highlightColor is a bit hacky, but shhh
-        }
-    }
-
-    /// <summary>
-    ///     Moves offsets of layers by specified vector.
-    /// </summary>
-    private void MoveOffsets(IList<Layer> layers, IList<Int32Rect> bounds, Coordinates moveVector)
-    {
-        for (int i = 0; i < layers.Count; i++)
-        {
-            Layer layer = layers[i];
-            Int32Rect bound = bounds[i];
-            Thickness offset = layer.Offset;
-            layer.Offset = new Thickness(offset.Left + moveVector.X, offset.Top + moveVector.Y, 0, 0);
-            if (!bound.IsEmpty && layer.Bounds != bound)
-            {
-                layer.DynamicResizeAbsolute(bound);
-            }
-            else
-            {
-                layer.ClipCanvas();
-            }
-        }
-    }
-
-    private void MoveOffsetsProcess(object[] arguments)
-    {
-        if (arguments.Length > 0 && arguments[0] is List<Guid> guids && arguments[1] is List<Int32Rect> bounds && arguments[2] is Coordinates vector)
-        {
-            List<Layer> layers = new List<Layer>(guids.Count);
-            foreach (Guid guid in guids)
-            {
-                layers.Add(Layers.First(x => x.GuidValue == guid));
-            }
-
-            MoveOffsets(layers, bounds, vector);
-        }
-        else
-        {
-            throw new ArgumentException("Provided arguments were invalid. Expected IEnumerable<Layer> and Coordinates");
-        }
-    }
-
-    private void MoveGroupInStructureProcess(object[] parameter)
-    {
-        Guid groupGuid = (Guid)parameter[0];
-        Guid referenceLayerGuid = (Guid)parameter[1];
-        bool above = (bool)parameter[2];
-
-        GuidStructureItem group = LayerStructure.GetGroupByGuid(groupGuid);
-        GuidStructureItem referenceLayerGroup = LayerStructure.GetGroupByLayer(referenceLayerGuid);
-
-        Layer referenceLayer = Layers.First(x => x.GuidValue == referenceLayerGuid);
-
-        int layerIndex = Layers.IndexOf(referenceLayer);
-        int folderTopIndex = Layers.IndexOf(Layers.First(x => x.GuidValue == group?.EndLayerGuid));
-        int oldIndex = folderTopIndex;
-
-        if (layerIndex < folderTopIndex)
-        {
-            int folderBottomIndex = Layers.IndexOf(Layers.First(x => x.GuidValue == group.StartLayerGuid));
-            oldIndex = folderBottomIndex;
-        }
-
-        int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
-
-        LayerStructure.MoveGroup(groupGuid, newIndex);
-
-        LayerStructure.ReassignParent(group, referenceLayerGroup);
-
-        LayerStructure.Assign(new GroupData(group?.Parent?.GroupGuid), new GroupData(group?.GroupGuid));
-    }
-
-    private int CalculateNewIndex(int layerIndex, bool above, int oldIndex)
-    {
-        int newIndex = layerIndex;
-
-        int diff = newIndex - oldIndex;
-
-        if (TriesToMoveAboveBelow(above, diff) || TriesToMoveBelowAbove(above, diff) || (above && newIndex < oldIndex) || (!above && newIndex > oldIndex))
-        {
-            newIndex += above ? 1 : -1;
-        }
-
-        return Math.Clamp(newIndex, 0, Layers.Count - 1);
-    }
-
-    private bool TriesToMoveAboveBelow(bool above, int diff) => above && diff == -1;
-
-    private bool TriesToMoveBelowAbove(bool above, int diff) => !above && diff == 1;
-
-    private void MoveLayerInStructureProcess(object[] parameter)
-    {
-        Guid layer = (Guid)parameter[0];
-        Guid referenceLayer = (Guid)parameter[1];
-        bool above = (bool)parameter[2];
-
-        int layerIndex = Layers.IndexOf(Layers.First(x => x.GuidValue == referenceLayer));
-        int oldIndex = Layers.IndexOf(Layers.First(x => x.GuidValue == layer));
-        int newIndex = CalculateNewIndex(layerIndex, above, oldIndex);
-
-        var startGroup = LayerStructure.GetGroupByLayer(layer);
-
-        LayerStructure.Unassign(new GroupData(startGroup?.GroupGuid), layer);
-
-        Layers.Move(oldIndex, newIndex);
-
-        var newFolder = LayerStructure.GetGroupByLayer(referenceLayer);
-
-        LayerStructure.Assign(new GroupData(newFolder?.GroupGuid), layer);
-
-        if (Layers.IndexOf(ActiveLayer) == oldIndex)
-        {
-            SetMainActiveLayer(newIndex);
-        }
-
-        RaisePropertyChanged(nameof(LayerStructure));
-        Renderer.ForceRerender();
-    }
-
-    public void RestoreLayersProcess(Layer[] layers, UndoLayer[] layersData)
-    {
-        for (int i = 0; i < layers.Length; i++)
-        {
-            Layer layer = layers[i];
-
-            Layers.Insert(layersData[i].LayerIndex, layer);
-            if (layersData[i].IsActive)
-            {
-                SetMainActiveLayer(Layers.IndexOf(layer));
-            }
-        }
-    }
-
-    public void RemoveLayerProcess(object[] parameters)
-    {
-        if (parameters is { Length: > 0 } && parameters[0] is Guid layerGuid)
-        {
-            Layer layer = Layers.First(x => x.GuidValue == layerGuid);
-            int index = Layers.IndexOf(layer);
-            bool wasActive = layer.IsActive;
-
-            var layerGroup = LayerStructure.GetGroupByLayer(layer.GuidValue);
-
-            LayerStructure.ExpandParentGroups(layerGroup);
-
-            if (layerGroup?.Parent != null && LayerStructure.GroupContainsOnlyLayer(layer.GuidValue, layerGroup))
-            {
-                LayerStructure.Unassign(new GroupData(layerGroup.Parent.GroupGuid), new GroupData(layerGroup.GroupGuid));
-            }
-
-            LayerStructure.AssignParent(Layers[index].GuidValue, null);
-            RemoveGroupsIfEmpty(layer, layerGroup);
-
-            Layers.Remove(layer);
-
-            if (wasActive || Layers.IndexOf(ActiveLayer) >= index)
-            {
-                SetNextLayerAsActive(index);
-            }
-
-            LayersChanged?.Invoke(this, new LayersChangedEventArgs(layerGuid, LayerAction.Remove));
-        }
-    }
-
-    private void RemoveGroupsIfEmpty(Layer layer, GuidStructureItem layerGroup)
-    {
-        if (LayerStructure.GroupContainsOnlyLayer(layer.GuidValue, layerGroup))
-        {
-            if (layerGroup.Parent != null)
-            {
-                layerGroup.Parent.Subgroups.Remove(layerGroup);
-                RemoveGroupsIfEmpty(layer, layerGroup.Parent);
-            }
-            else
-            {
-                LayerStructure.Groups.Remove(layerGroup);
-            }
-        }
-    }
-
-    /// <summary>
-    /// Get's the layers suffix, e.g. "New Layer" becomes "New Layer (1)".
-    /// </summary>
-    /// <returns>Name of the layer with suffix.</returns>
-    private string GetLayerSuffix(Layer layer)
-    {
-        Match match = reversedLayerSuffixRegex.Match(layer.Name.Reverse());
-
-        int? highestValue = GetHighestSuffix(layer, match.Groups[2].Value, reversedLayerSuffixRegex);
-
-        string actualName = match.Groups[2].Value.Reverse();
-
-        if (highestValue == null)
-        {
-            return actualName;
-        }
-
-        return actualName + $" ({highestValue + 1})";
-    }
-
-    private int? GetHighestSuffix(Layer except, string layerName, Regex regex)
-    {
-        int? highestValue = null;
-
-        foreach (Layer otherLayer in Layers)
-        {
-            if (otherLayer == except)
-            {
-                continue;
-            }
-
-            Match otherMatch = regex.Match(otherLayer.Name.Reverse());
-
-            if (otherMatch.Groups[2].Value == layerName)
-            {
-                SetHighest(otherMatch.Groups[1].Value.Reverse(), ref highestValue);
-            }
-        }
-
-        return highestValue;
-    }
-
-    /// <returns>Was the parse a sucess.</returns>
-    private bool SetHighest(string number, ref int? highest, int? defaultValue = 0)
-    {
-        bool sucess = int.TryParse(number, out int parsedNumber);
-
-        if (sucess)
-        {
-            if (highest == null || highest < parsedNumber)
-            {
-                highest = parsedNumber;
-            }
-        }
-        else
-        {
-            if (highest == null)
-            {
-                highest = defaultValue;
-            }
-        }
-
-        return sucess;
-    }
-
-    public void RemoveLayersProcess(object[] parameters)
-    {
-        if (parameters != null && parameters.Length > 0 && parameters[0] is IEnumerable<Guid> layerGuids)
-        {
-            object[] args = new object[1];
-            foreach (var guid in layerGuids)
-            {
-                args[0] = guid;
-                RemoveLayerProcess(args);
-            }
-        }
-    }
-}

+ 0 - 341
src/PixiEditor/Models/DataHolders/Document/Document.Operations.cs

@@ -1,341 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using SkiaSharp;
-using System;
-using System.Linq;
-using System.Windows;
-
-namespace PixiEditor.Models.DataHolders;
-
-public partial class Document
-{
-    public event EventHandler<DocumentSizeChangedEventArgs> DocumentSizeChanged;
-
-    public void ReplaceColor(SKColor oldColor, SKColor newColor)
-    {
-        StorageBasedChange change = new(this, Layers);
-
-        var args = new object[] { oldColor, newColor };
-
-        ReplaceColorProcess(args);
-
-        ChangesSaved = false;
-
-        UndoManager.AddUndoChange(change.ToChange(
-            StorageBasedChange.BasicUndoProcess,
-            new object[] { this },
-            ReplaceColorProcess,
-            args,
-            "Resize canvas"));
-    }
-
-
-    /// <summary>
-    ///     Resizes canvas to specified width and height to selected anchor.
-    /// </summary>
-    /// <param name="width">New width of canvas.</param>
-    /// <param name="height">New height of canvas.</param>
-    /// <param name="anchor">
-    ///     Point that will act as "starting position" of resizing. Use pipe to connect horizontal and
-    ///     vertical.
-    /// </param>
-    public void ResizeCanvas(int width, int height, AnchorPoint anchor, bool addToUndo = true)
-    {
-        int oldWidth = Width;
-        int oldHeight = Height;
-
-        int offsetX = GetOffsetXForAnchor(Width, width, anchor);
-        int offsetY = GetOffsetYForAnchor(Height, height, anchor);
-
-        Thickness[] newOffsets = Layers.Select(x => new Thickness(offsetX + x.OffsetX, offsetY + x.OffsetY, 0, 0))
-            .ToArray();
-
-        object[] processArgs = { newOffsets, width, height };
-        object[] reverseProcessArgs = { Width, Height };
-
-        if (addToUndo) 
-        { 
-            StorageBasedChange change = new(this, Layers);
-            ResizeCanvas(newOffsets, width, height);
-
-            UndoManager.AddUndoChange(change.ToChange(
-                RestoreDocumentLayersProcess,
-                reverseProcessArgs,
-                ResizeCanvasProcess,
-                processArgs,
-                "Resize canvas"));
-        }
-        else
-        {
-            ResizeCanvas(newOffsets, width, height);
-        }
-
-        if (oldWidth == Width && Height == oldHeight) return;
-
-        DocumentSizeChanged?.Invoke(this, new DocumentSizeChangedEventArgs(oldWidth, oldHeight, width, height));
-    }
-
-    public void RotateActiveDocument(float degrees)
-    {
-        object[] processArgs = { degrees };
-        object[] reverseProcessArgs = { -degrees };
-
-        RotateDocumentProcess(processArgs);
-
-        UndoManager.AddUndoChange(new Change(
-            RotateDocumentProcess,
-            reverseProcessArgs,
-            RotateDocumentProcess,
-            processArgs,
-            "Rotate layer"));
-    }
-
-    public void FlipActiveDocument(FlipType flip)
-    {
-        object[] processArgs = { flip };
-
-        FlipDocumentProcess(processArgs);
-
-        UndoManager.AddUndoChange(new Change(
-            FlipDocumentProcess,
-            processArgs,
-            FlipDocumentProcess,
-            processArgs,
-            $"Flip layer: {flip}"));
-    }
-
-    /// <summary>
-    ///     Resizes all document layers using NearestNeighbor interpolation.
-    /// </summary>
-    /// <param name="newWidth">New document width.</param>
-    /// <param name="newHeight">New document height.</param>
-    public void Resize(int newWidth, int newHeight)
-    {
-        object[] reverseArgs = { Width, Height };
-        object[] args = { newWidth, newHeight };
-        StorageBasedChange change = new StorageBasedChange(this, Layers);
-
-        ResizeDocument(newWidth, newHeight);
-
-        UndoManager.AddUndoChange(
-            change.ToChange(
-                RestoreDocumentLayersProcess,
-                reverseArgs,
-                ResizeDocumentProcess,
-                args,
-                "Resize document"));
-    }
-
-    private void ReplaceColorProcess(object[] args)
-    {
-        SKColor oldColor = (SKColor)args[0];
-        SKColor newColor = (SKColor)args[1];
-
-        foreach (var layer in Layers)
-        {
-            layer.ReplaceColor(oldColor, newColor);
-        }
-    }
-
-    private void FlipDocumentProcess(object[] processArgs)
-    {
-        FlipType flip = (FlipType)processArgs[0];
-        foreach (var layer in Layers)
-        {
-            using (new SKAutoCanvasRestore(layer.LayerBitmap.SkiaSurface.Canvas, true))
-            {
-                var copy = layer.LayerBitmap.SkiaSurface.Snapshot();
-
-                var canvas = layer.LayerBitmap.SkiaSurface.Canvas;
-
-                layer.ClipCanvas();
-
-                if (flip == FlipType.Horizontal)
-                {
-                    canvas.Translate(layer.Width, 0);
-                    canvas.Scale(-1, 1, 0, 0);
-                }
-                else
-                {
-                    canvas.Translate(0, layer.Width);
-                    canvas.Scale(1, -1, 0, 0);
-                }
-
-                // Flip offset based on document and layer center point
-                var documentCenter = new Coordinates(Width / 2, Height / 2);
-                var layerCenter = new Coordinates(layer.Width / 2, layer.Height / 2);
-
-                int newOffsetX = layer.OffsetX;
-                int newOffsetY = layer.OffsetY;
-
-                if (flip == FlipType.Horizontal)
-                {
-                    newOffsetX += layerCenter.X;
-                    int diff = documentCenter.X - newOffsetX;
-                    newOffsetX = layer.OffsetX + (diff * 2);
-                }
-                else if (flip == FlipType.Vertical)
-                {
-                    newOffsetY += layerCenter.Y;
-                    int diff = documentCenter.Y - newOffsetY;
-                    newOffsetY = layer.OffsetY + (diff * 2);
-                }
-
-                layer.Offset = new Thickness(newOffsetX, newOffsetY, 0, 0);
-
-                canvas.DrawImage(copy, default(SKPoint));
-                copy.Dispose();
-            }
-
-            layer.InvokeLayerBitmapChange();
-        }
-    }
-
-    private void RotateDocumentProcess(object[] parameters)
-    {
-        float degrees = (float)parameters[0];
-
-        int oldWidth = Width;
-        int oldHeight = Height;
-
-        int biggerMaxSize = Math.Max(Width, Height);
-
-        // TODO: Fix v0.2
-        foreach (var layer in Layers)
-        {
-            using (new SKAutoCanvasRestore(layer.LayerBitmap.SkiaSurface.Canvas, true))
-            {
-                var copy = layer.LayerBitmap.SkiaSurface.Snapshot();
-
-                double radians = Math.PI * degrees / 180;
-                float sine = (float)Math.Abs(Math.Sin(radians));
-                float cosine = (float)Math.Abs(Math.Cos(radians));
-                int originalWidth = layer.Width;
-                int originalHeight = layer.Height;
-                int rotatedWidth = (int)(cosine * originalWidth + sine * originalHeight);
-                int rotatedHeight = (int)(cosine * originalHeight + sine * originalWidth);
-
-                layer.CreateNewBitmap(rotatedWidth, rotatedHeight);
-
-                var surface = layer.LayerBitmap.SkiaSurface.Canvas;
-
-                surface.Translate(rotatedWidth / 2, rotatedHeight / 2);
-                surface.RotateDegrees((float)degrees);
-                surface.Translate(-originalWidth / 2, -originalHeight / 2);
-                surface.DrawImage(copy, default(SKPoint));
-
-                layer.MaxHeight = oldWidth;
-                layer.MaxWidth = oldHeight;
-
-                copy.Dispose();
-            }
-
-            layer.InvokeLayerBitmapChange();
-        }
-
-        Height = oldWidth;
-        Width = oldHeight;
-        DocumentSizeChanged?.Invoke(
-            this,
-            new DocumentSizeChangedEventArgs(oldWidth, oldHeight, Width, Height));
-    }
-
-    private void RestoreDocumentLayersProcess(Layer[] layers, UndoLayer[] data, object[] args)
-    {
-        int oldWidth = Width;
-        int oldHeight = Height;
-        Width = (int)args[0];
-        Height = (int)args[1];
-        DocumentSizeChanged?.Invoke(
-            this,
-            new DocumentSizeChangedEventArgs(oldWidth, oldHeight, Width, Height));
-        Layers.Clear();
-        Layers.AddRange(layers);
-    }
-
-    /// <summary>
-    ///     Resizes canvas.
-    /// </summary>
-    /// <param name="offset">Offset of content in new canvas. It will move layer to that offset.</param>
-    /// <param name="newWidth">New canvas size.</param>
-    /// <param name="newHeight">New canvas height.</param>
-    private void ResizeCanvas(Thickness[] offset, int newWidth, int newHeight)
-    {
-        Int32Rect newCanvasRect = new(0, 0, newWidth, newHeight);
-        for (int i = 0; i < Layers.Count; i++)
-        {
-            Layer layer = Layers[i];
-            Layers[i].MaxWidth = newWidth;
-            Layers[i].MaxHeight = newHeight;
-            if (layer.IsReset)
-                continue;
-
-            Thickness newOffset = offset[i];
-            Int32Rect newRect = new((int)newOffset.Left, (int)newOffset.Top, layer.Width, layer.Height);
-            Int32Rect newLayerRect = newRect.Intersect(newCanvasRect);
-            if (!newLayerRect.HasArea)
-            {
-                layer.Reset();
-                continue;
-            }
-            Surface newBitmap = new(newLayerRect.Width, newLayerRect.Height);
-            var oldBitmap = layer.LayerBitmap;
-            using var snapshot = oldBitmap.SkiaSurface.Snapshot();
-            newBitmap.SkiaSurface.Canvas.DrawImage(snapshot, newRect.X - newLayerRect.X, newRect.Y - newLayerRect.Y, Surface.ReplacingPaint);
-
-            layer.LayerBitmap = newBitmap;
-            oldBitmap.Dispose();
-
-            Layers[i].Offset = new Thickness(newLayerRect.X, newLayerRect.Y, 0, 0);
-        }
-
-        Width = newWidth;
-        Height = newHeight;
-    }
-
-    private void ResizeDocumentProcess(object[] args)
-    {
-        if (args.Length > 1 && args[0] is int width && args[1] is int height)
-        {
-            ResizeDocument(width, height);
-        }
-    }
-
-    private void ResizeDocument(int newWidth, int newHeight)
-    {
-        int oldWidth = Width;
-        int oldHeight = Height;
-
-        for (int i = 0; i < Layers.Count; i++)
-        {
-            float widthRatio = (float)newWidth / Width;
-            float heightRatio = (float)newHeight / Height;
-            int layerWidth = Math.Max(1, (int)(Layers[i].Width * widthRatio));
-            int layerHeight = Math.Max(1, (int)(Layers[i].Height * heightRatio));
-
-            Layers[i].Resize(layerWidth, layerHeight, newWidth, newHeight);
-            Layers[i].Offset = new Thickness(Math.Floor(Layers[i].OffsetX * widthRatio), Math.Floor(Layers[i].OffsetY * heightRatio), 0, 0);
-        }
-
-        Height = newHeight;
-        Width = newWidth;
-        DocumentSizeChanged?.Invoke(
-            this,
-            new DocumentSizeChangedEventArgs(oldWidth, oldHeight, newWidth, newHeight));
-    }
-
-    private void ResizeCanvasProcess(object[] arguments)
-    {
-        int oldWidth = Width;
-        int oldHeight = Height;
-
-        Thickness[] offset = (Thickness[])arguments[0];
-        int width = (int)arguments[1];
-        int height = (int)arguments[2];
-        ResizeCanvas(offset, width, height);
-        DocumentSizeChanged?.Invoke(this, new DocumentSizeChangedEventArgs(oldWidth, oldHeight, width, height));
-    }
-}

+ 0 - 48
src/PixiEditor/Models/DataHolders/Document/Document.Preview.cs

@@ -1,48 +0,0 @@
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.ImageManipulation;
-using PixiEditor.Models.Layers;
-using System.Windows.Media.Imaging;
-
-namespace PixiEditor.Models.DataHolders;
-
-public partial class Document
-{
-    private WriteableBitmap previewImage;
-
-    public WriteableBitmap PreviewImage
-    {
-        get => previewImage;
-    }
-
-    private Layer previewLayer;
-    private SingleLayerRenderer previewLayerRenderer;
-
-    public Layer PreviewLayer
-    {
-        get => previewLayer;
-        set
-        {
-            previewLayer = value;
-            previewLayerRenderer?.Dispose();
-            previewLayerRenderer = previewLayer == null ? null : new SingleLayerRenderer(previewLayer, Width, Height);
-            RaisePropertyChanged(nameof(PreviewLayer));
-            RaisePropertyChanged(nameof(PreviewLayerRenderer));
-        }
-    }
-
-    public SingleLayerRenderer PreviewLayerRenderer
-    {
-        get => previewLayerRenderer;
-    }
-
-    public void UpdatePreviewImage()
-    {
-        previewImage = BitmapUtils.GeneratePreviewBitmap(this, 30, 20);
-        RaisePropertyChanged(nameof(PreviewImage));
-    }
-
-    public void GeneratePreviewLayer()
-    {
-        PreviewLayer = new Layer("_previewLayer", Width, Height);
-    }
-}

+ 0 - 341
src/PixiEditor/Models/DataHolders/Document/Document.cs

@@ -1,341 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Layers.Utils;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using PixiEditor.ViewModels;
-using SkiaSharp;
-using System;
-using System.Buffers;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Windows;
-
-namespace PixiEditor.Models.DataHolders;
-
-[DebuggerDisplay("'{Name, nq}' {width}x{height} {Layers.Count} Layer(s)")]
-public partial class Document : NotifyableObject, IDisposable
-{
-
-    private ViewModelMain xamlAccesibleViewModel = null;
-    public ViewModelMain XamlAccesibleViewModel // Used to access ViewModelMain, without changing DataContext in XAML
-    {
-        get => xamlAccesibleViewModel;
-        set
-        {
-            xamlAccesibleViewModel = value;
-            RaisePropertyChanged(nameof(XamlAccesibleViewModel));
-        }
-    }
-
-    public string Name
-    {
-        get => (string.IsNullOrEmpty(DocumentFilePath) ? "Untitled" : Path.GetFileName(DocumentFilePath))
-               + (!ChangesSaved ? " *" : string.Empty);
-    }
-
-    private int width = 1;
-    public int Width
-    {
-        get => width;
-        private set
-        {
-            width = value;
-            RaisePropertyChanged(nameof(Width));
-        }
-    }
-
-    private int height = 1;
-    public int Height
-    {
-        get => height;
-        private set
-        {
-            height = value;
-            RaisePropertyChanged("Height");
-        }
-    }
-
-    private Selection selection;
-
-    public Selection ActiveSelection
-    {
-        get => selection;
-        set
-        {
-            selection = value;
-            RaisePropertyChanged(nameof(ActiveSelection));
-        }
-    }
-
-    private double mouseXonCanvas;
-    public double MouseXOnCanvas // Mouse X coordinate relative to canvas
-    {
-        get => mouseXonCanvas;
-        set
-        {
-            mouseXonCanvas = value;
-            RaisePropertyChanged(nameof(MouseXOnCanvas));
-        }
-    }
-
-    private double mouseYonCanvas;
-    public double MouseYOnCanvas // Mouse Y coordinate relative to canvas
-    {
-        get => mouseYonCanvas;
-        set
-        {
-            mouseYonCanvas = value;
-            RaisePropertyChanged(nameof(MouseYOnCanvas));
-        }
-    }
-
-    public bool Disposed { get; private set; } = false;
-
-    public ExecutionTrigger<Size> CenterViewportTrigger { get; } = new();
-    public ExecutionTrigger<double> ZoomViewportTrigger { get; } = new();
-
-    public UndoManager UndoManager { get; set; }
-
-    public WpfObservableRangeCollection<SKColor> Swatches { get; set; } = new WpfObservableRangeCollection<SKColor>();
-    public WpfObservableRangeCollection<SKColor> Palette { get; set; } = new WpfObservableRangeCollection<SKColor>();
-
-    public void RaisePropertyChange(string name)
-    {
-        RaisePropertyChanged(name);
-    }
-
-    /// <summary>
-    ///     Resizes canvas, so it fits exactly the size of drawn content, without any transparent pixels outside.
-    /// </summary>
-    public void ClipCanvas()
-    {
-        DoubleCoords? maybePoints = GetEdgePoints(Layers);
-
-        if (maybePoints == null)
-        {
-            //all layers are empty
-            return;
-        }
-        DoubleCoords points = maybePoints.Value;
-
-        int smallestX = points.Coords1.X;
-        int smallestY = points.Coords1.Y;
-        int biggestX = points.Coords2.X;
-        int biggestY = points.Coords2.Y;
-
-        int width = biggestX - smallestX;
-        int height = biggestY - smallestY;
-        Coordinates moveVector = new Coordinates(-smallestX, -smallestY);
-
-        Thickness[] oldOffsets = Layers.Select(x => x.Offset).ToArray();
-        int oldWidth = Width;
-        int oldHeight = Height;
-
-        StorageBasedChange change = new StorageBasedChange(this, Layers);
-
-        object[] reverseArguments = { oldWidth, oldHeight };
-        object[] processArguments = { Layers.Select(x => new Thickness(x.OffsetX - smallestX, x.OffsetY - smallestY, 0, 0)).ToArray(), width, height };
-
-        ResizeCanvasProcess(processArguments);
-
-        UndoManager.AddUndoChange(change.ToChange(
-            RestoreDocumentLayersProcess,
-            reverseArguments,
-            ResizeCanvasProcess,
-            processArguments,
-            "Clip canvas"));
-    }
-
-    /// <summary>
-    /// Centers selected, visible layers inside document.
-    /// </summary>
-    public void CenterContent()
-    {
-        var layersToCenter = Layers.Where(x => x.IsActive && LayerStructureUtils.GetFinalLayerIsVisible(x, LayerStructure)).ToList();
-        if (layersToCenter.Count == 0)
-        {
-            return;
-        }
-
-        List<Int32Rect> oldBounds = layersToCenter.Select(x => x.Bounds).ToList();
-
-        DoubleCoords? maybePoints = ClipLayersAndGetEdgePoints(layersToCenter);
-        if (maybePoints == null)
-            return;
-        DoubleCoords points = maybePoints.Value;
-
-        int smallestX = points.Coords1.X;
-        int smallestY = points.Coords1.Y;
-        int biggestX = points.Coords2.X;
-        int biggestY = points.Coords2.Y;
-
-        Coordinates contentCenter = CoordinatesCalculator.GetCenterPoint(points.Coords1, points.Coords2);
-        Coordinates documentCenter = CoordinatesCalculator.GetCenterPoint(
-            new Coordinates(0, 0),
-            new Coordinates(Width, Height));
-        Coordinates moveVector = new Coordinates(documentCenter.X - contentCenter.X, documentCenter.Y - contentCenter.Y);
-
-        List<Int32Rect> emptyBounds = Enumerable.Repeat(Int32Rect.Empty, layersToCenter.Count).ToList();
-
-        MoveOffsets(layersToCenter, emptyBounds, moveVector);
-
-        List<Guid> guids = layersToCenter.Select(x => x.GuidValue).ToList();
-        UndoManager.AddUndoChange(
-            new Change(
-                MoveOffsetsProcess,
-                new object[] { guids, oldBounds, new Coordinates(-moveVector.X, -moveVector.Y) },
-                MoveOffsetsProcess,
-                new object[] { guids, emptyBounds, moveVector },
-                "Center content"));
-    }
-
-    public void Dispose()
-    {
-        if (Disposed)
-            return;
-        Disposed = true;
-        DisposeLayerBitmaps();
-        UndoManager.Dispose();
-
-        GC.SuppressFinalize(this);
-    }
-
-    private void SetAsActiveOnClick(object obj)
-    {
-        if (XamlAccesibleViewModel?.BitmapManager?.ActiveDocument != this)
-        {
-            XamlAccesibleViewModel.BitmapManager.ActiveDocument = this;
-        }
-    }
-
-    private void RequestCloseDocument(object parameter)
-    {
-        ViewModelMain.Current.DocumentSubViewModel.RequestCloseDocument(this);
-    }
-
-    private int GetOffsetXForAnchor(int srcWidth, int destWidth, AnchorPoint anchor)
-    {
-        if (anchor.HasFlag(AnchorPoint.Center))
-        {
-            return (destWidth / 2) - (srcWidth / 2);
-        }
-
-        if (anchor.HasFlag(AnchorPoint.Right))
-        {
-            return destWidth - srcWidth;
-        }
-
-        return 0;
-    }
-
-    private int GetOffsetYForAnchor(int srcHeight, int destHeight, AnchorPoint anchor)
-    {
-        if (anchor.HasFlag(AnchorPoint.Middle))
-        {
-            return (destHeight / 2) - (srcHeight / 2);
-        }
-
-        if (anchor.HasFlag(AnchorPoint.Bottom))
-        {
-            return destHeight - srcHeight;
-        }
-
-        return 0;
-    }
-
-    private DoubleCoords? GetEdgePoints(IEnumerable<Layer> layers)
-    {
-        if (Layers.Count == 0)
-            throw new ArgumentException("Not enough layers");
-
-        int smallestX = int.MaxValue;
-        int smallestY = int.MaxValue;
-        int biggestX = int.MinValue;
-        int biggestY = int.MinValue;
-
-        bool allLayersSkipped = true;
-
-        foreach (Layer layer in layers)
-        {
-            Int32Rect bounds = layer.TightBounds;
-            if (layer.IsReset || !bounds.HasArea)
-                continue;
-            allLayersSkipped = false;
-
-            if (layer.OffsetX + bounds.X < smallestX)
-                smallestX = layer.OffsetX + bounds.X;
-
-            if (layer.OffsetX + bounds.X + bounds.Width > biggestX)
-                biggestX = layer.OffsetX + bounds.X + bounds.Width;
-
-            if (layer.OffsetY + bounds.Y < smallestY)
-                smallestY = layer.OffsetY + bounds.Y;
-
-            if (layer.OffsetY + bounds.Y + bounds.Height > biggestY)
-                biggestY = layer.OffsetY + bounds.Y + bounds.Height;
-        }
-
-        if (allLayersSkipped)
-            return null;
-
-        return new DoubleCoords(
-            new Coordinates(smallestX, smallestY),
-            new Coordinates(biggestX, biggestY));
-    }
-
-    private DoubleCoords? ClipLayersAndGetEdgePoints(IEnumerable<Layer> layers)
-    {
-        if (Layers.Count == 0)
-        {
-            throw new ArgumentException("Not enough layers");
-        }
-
-        int smallestX = int.MaxValue;
-        int smallestY = int.MaxValue;
-        int biggestX = int.MinValue;
-        int biggestY = int.MinValue;
-
-        bool allLayersSkipped = true;
-
-        foreach (Layer layer in layers)
-        {
-            layer.ClipCanvas();
-            if (layer.IsReset)
-                continue;
-            allLayersSkipped = false;
-
-            if (layer.OffsetX < smallestX)
-            {
-                smallestX = layer.OffsetX;
-            }
-
-            if (layer.OffsetX + layer.Width > biggestX)
-            {
-                biggestX = layer.OffsetX + layer.Width;
-            }
-
-            if (layer.OffsetY < smallestY)
-            {
-                smallestY = layer.OffsetY;
-            }
-
-            if (layer.OffsetY + layer.Height > biggestY)
-            {
-                biggestY = layer.OffsetY + layer.Height;
-            }
-        }
-
-        if (allLayersSkipped)
-            return null;
-
-        return new DoubleCoords(
-            new Coordinates(smallestX, smallestY),
-            new Coordinates(biggestX, biggestY));
-    }
-}

+ 0 - 19
src/PixiEditor/Models/DataHolders/PixelSize.cs

@@ -1,19 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace PixiEditor.Models.DataHolders;
-
-public struct PixelSize
-{
-    public int Width { get; set; }
-    public int Height { get; set; }
-
-    public PixelSize(int width, int height)
-    {
-        Width = width;
-        Height = height;
-    }
-}

+ 7 - 9
src/PixiEditor/Models/DataHolders/RecentlyOpenedDocument.cs

@@ -1,13 +1,11 @@
-using PixiEditor.Helpers;
+using System.Diagnostics;
+using System.IO;
+using System.Windows.Media.Imaging;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.Helpers;
 using PixiEditor.Models.IO;
-using PixiEditor.Models.Position;
 using PixiEditor.Parser;
 using PixiEditor.Parser.Skia;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Windows.Media.Imaging;
 
 namespace PixiEditor.Models.DataHolders;
 
@@ -87,7 +85,7 @@ public class RecentlyOpenedDocument : NotifyableObject
             using Surface surface = Surface.Combine(serializableDocument.Width, serializableDocument.Height,
                 serializableDocument.Layers
                     .Where(x => x.Opacity > 0.8)
-                    .Select(x => (x.ToSKImage(), new Coordinates(x.OffsetX, x.OffsetY))));
+                    .Select(x => (x.ToSKImage(), new VecI(x.OffsetX, x.OffsetY))));
 
             return DownscaleToMaxSize(surface.ToWriteableBitmap());
         }
@@ -123,4 +121,4 @@ public class RecentlyOpenedDocument : NotifyableObject
         }
         return bitmap;
     }
-}
+}

+ 0 - 105
src/PixiEditor/Models/DataHolders/Selection.cs

@@ -1,105 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using SkiaSharp;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Linq;
-using System.Windows;
-
-namespace PixiEditor.Models.DataHolders;
-
-[DebuggerDisplay("{SelectedPoints.Count} selected Pixels")]
-public class Selection : NotifyableObject
-{
-    private readonly SKColor selectionBlue;
-    private Layer selectionLayer;
-
-    public Selection(Coordinates[] selectedPoints, PixelSize maxSize)
-    {
-        SelectedPoints = new ObservableCollection<Coordinates>(selectedPoints);
-        SelectionLayer = new Layer("_selectionLayer", maxSize.Width, maxSize.Height);
-        selectionBlue = new SKColor(142, 202, 255, 255);
-    }
-
-    public System.Collections.ObjectModel.ObservableCollection<Coordinates> SelectedPoints { get; private set; }
-
-    public Layer SelectionLayer
-    {
-        get => selectionLayer;
-        set
-        {
-            selectionLayer = value;
-            RaisePropertyChanged(nameof(SelectionLayer));
-        }
-    }
-
-    public void SetSelection(IEnumerable<Coordinates> selection, SelectionType mode)
-    {
-        SKColor selectionColor = selectionBlue;
-        switch (mode)
-        {
-            case SelectionType.New:
-                SelectedPoints = new System.Collections.ObjectModel.ObservableCollection<Coordinates>(selection);
-                SelectionLayer.Reset();
-                break;
-            case SelectionType.Add:
-                SelectedPoints = new System.Collections.ObjectModel.ObservableCollection<Coordinates>(SelectedPoints.Concat(selection).Distinct());
-                break;
-            case SelectionType.Subtract:
-                SelectedPoints = new System.Collections.ObjectModel.ObservableCollection<Coordinates>(SelectedPoints.Except(selection));
-                selectionColor = SKColors.Transparent;
-                break;
-        }
-
-        SelectionLayer.SetPixels(BitmapPixelChanges.FromSingleColoredArray(selection, selectionColor));
-    }
-
-    public void TranslateSelection(int dX, int dY)
-    {
-        selectionLayer.Offset = new Thickness(selectionLayer.OffsetX + dX, selectionLayer.OffsetY + dY, 0, 0);
-        for (int i = 0; i < SelectedPoints.Count; i++)
-        {
-            SelectedPoints[i] = new Coordinates(SelectedPoints[i].X + dX, SelectedPoints[i].Y + dY);
-        }
-    }
-
-    public void SetSelection(Int32Rect rect, bool isCirclular, SelectionType mode)
-    {
-        using SKPaint paint = new()
-        {
-            Color = selectionBlue,
-            BlendMode = SKBlendMode.Src,
-            Style = SKPaintStyle.StrokeAndFill,
-        };
-        switch (mode)
-        {
-            case SelectionType.New:
-                SelectionLayer.Reset();
-                break;
-            case SelectionType.Subtract:
-                paint.Color = SKColors.Transparent;
-                break;
-        }
-
-        SelectionLayer.DynamicResizeAbsolute(new Int32Rect(rect.X, rect.Y, rect.Width, rect.Height));
-        if (isCirclular)
-        {
-            float cx = rect.X + rect.Width / 2f;
-            float cy = rect.Y + rect.Height / 2f;
-            SelectionLayer.LayerBitmap.SkiaSurface.Canvas.DrawOval(cx, cy, rect.Width / 2f, rect.Height / 2f, paint);
-        }
-        else
-        {
-            SelectionLayer.LayerBitmap.SkiaSurface.Canvas.DrawRect(rect.X, rect.Y, rect.Width, rect.Height, paint);
-        }
-    }
-
-    public void Clear()
-    {
-        SelectionLayer.Reset();
-        SelectedPoints.Clear();
-    }
-}

+ 6 - 8
src/PixiEditor/Models/DataHolders/Surface.cs

@@ -1,15 +1,13 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Position;
-using SkiaSharp;
-using System;
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.Helpers.Extensions;
+using SkiaSharp;
 
 namespace PixiEditor.Models.DataHolders;
 
@@ -88,7 +86,7 @@ public class Surface : IDisposable
     /// <param name="width">The width of the <see cref="Surface"/></param>
     /// <param name="height">The height of the <see cref="Surface"/></param>
     /// <returns>A surface that has the <paramref name="images"/> drawn on it</returns>
-    public static Surface Combine(int width, int height, IEnumerable<(SKImage image, Coordinates offset)> images)
+    public static Surface Combine(int width, int height, IEnumerable<(SKImage image, VecI offset)> images)
     {
         Surface surface = new Surface(width, height);
 
@@ -296,4 +294,4 @@ public class Surface : IDisposable
         }
     }
 #endif
-}
+}

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

@@ -1,8 +0,0 @@
-namespace PixiEditor.Models.Enums;
-
-public enum SelectionType
-{
-    New,
-    Add,
-    Subtract
-}

+ 0 - 16
src/PixiEditor/Models/Events/DocumentChangedEventArgs.cs

@@ -1,16 +0,0 @@
-using PixiEditor.Models.DataHolders;
-
-namespace PixiEditor.Models.Events;
-
-public class DocumentChangedEventArgs
-{
-    public DocumentChangedEventArgs(Document newDocument, Document oldDocument)
-    {
-        NewDocument = newDocument;
-        OldDocument = oldDocument;
-    }
-
-    public Document OldDocument { get; set; }
-
-    public Document NewDocument { get; set; }
-}

+ 10 - 11
src/PixiEditor/Models/IO/Exporter.cs

@@ -1,18 +1,14 @@
-using Microsoft.Win32;
+using System.IO;
+using System.IO.Compression;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Media.Imaging;
+using Microsoft.Win32;
 using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
 using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Windows;
-using System.Windows.Media.Imaging;
 
 namespace PixiEditor.Models.IO;
 
@@ -51,6 +47,8 @@ public class Exporter
     /// <returns>Path.</returns>
     public static string SaveAsEditableFile(Document document, string path, FileType requestedType = FileType.Unset)
     {
+        return path;
+        /*
         var typeFromPath = ParseImageFormat(Path.GetExtension(path));
         FileType finalType = (typeFromPath, requestedType) switch
         {
@@ -80,6 +78,7 @@ public class Exporter
         }
 
         return path;
+        */
     }
 
     private static string AppendExtension(string path, FileTypeDialogData data)
@@ -174,4 +173,4 @@ public class Exporter
             NoticeDialog.Show(err.ToString(), "Error");
         }
     }
-}
+}

+ 9 - 11
src/PixiEditor/Models/IO/Importer.cs

@@ -1,15 +1,11 @@
-using PixiEditor.Exceptions;
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Parser;
-using SkiaSharp;
-using System;
-using System.IO;
+using System.IO;
 using System.IO.Compression;
-using System.Linq;
 using System.Runtime.InteropServices;
 using System.Windows.Media.Imaging;
+using PixiEditor.Exceptions;
+using PixiEditor.Helpers;
+using PixiEditor.Models.DataHolders;
+using SkiaSharp;
 
 namespace PixiEditor.Models.IO;
 
@@ -74,6 +70,7 @@ public class Importer : NotifyableObject
 
     public static Document ImportDocument(string path)
     {
+        /*
         try
         {
             Document doc = PixiEditor.Parser.PixiParser.Deserialize(path).ToDocument();
@@ -83,7 +80,8 @@ public class Importer : NotifyableObject
         catch (InvalidFileException)
         {
             throw new CorruptedFileException();
-        }
+        }*/
+        return null;
     }
 
     public static bool IsSupportedFile(string path)
@@ -118,4 +116,4 @@ public class Importer : NotifyableObject
             Marshal.FreeHGlobal(ptr);
         }
     }
-}
+}

+ 0 - 185
src/PixiEditor/Models/ImageManipulation/BitmapUtils.cs

@@ -1,185 +0,0 @@
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Layers.Utils;
-using PixiEditor.Parser;
-using PixiEditor.Parser.Skia;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows;
-using System.Windows.Media.Imaging;
-
-namespace PixiEditor.Models.ImageManipulation;
-
-public static class BitmapUtils
-{
-    public static Surface CombineLayers(Int32Rect portion, IEnumerable<Layer> layers, LayerStructure structure = null)
-    {
-        Surface finalSurface = new(portion.Width, portion.Height);
-        using SKPaint paint = new();
-
-        for (int i = 0; i < layers.Count(); i++)
-        {
-            Layer layer = layers.ElementAt(i);
-            if (structure != null && !LayerStructureUtils.GetFinalLayerIsVisible(layer, structure))
-                continue;
-            float layerOpacity = structure == null ? layer.Opacity : LayerStructureUtils.GetFinalLayerOpacity(layer, structure);
-            paint.Color = new(255, 255, 255, (byte)(layerOpacity * 255));
-
-            if (layer.OffsetX < 0 || layer.OffsetY < 0 ||
-                layer.Width + layer.OffsetX > layer.MaxWidth ||
-                layer.Height + layer.OffsetY > layer.MaxHeight)
-            {
-                throw new InvalidOperationException("Layers must not extend beyond canvas borders");
-            }
-
-            using SKImage snapshot = layer.LayerBitmap.SkiaSurface.Snapshot();
-            int x = portion.X - layer.OffsetX;
-            int y = portion.Y - layer.OffsetY;
-            finalSurface.SkiaSurface.Canvas.DrawImage(
-                snapshot,
-                new SKRect(x, y, portion.Width + x, portion.Height + y),
-                new SKRect(0, 0, portion.Width, portion.Height),
-                paint);
-        }
-
-        return finalSurface;
-    }
-
-    public static Surface[] ExtractSelectedPortions(Layer selLayer, Layer[] extractFrom, bool eraceFromLayers)
-    {
-        using var selSnap = selLayer.LayerBitmap.SkiaSurface.Snapshot();
-        Surface[] output = new Surface[extractFrom.Length];
-
-        int count = 0;
-        foreach (Layer layer in extractFrom)
-        {
-            Surface portion = new Surface(selLayer.Width, selLayer.Height);
-            SKRect selLayerRect = new SKRect(0, 0, selLayer.Width, selLayer.Height);
-
-            int x = selLayer.OffsetX - layer.OffsetX;
-            int y = selLayer.OffsetY - layer.OffsetY;
-
-            using (var layerSnap = layer.LayerBitmap.SkiaSurface.Snapshot())
-                portion.SkiaSurface.Canvas.DrawImage(layerSnap, new SKRect(x, y, x + selLayer.Width, y + selLayer.Height), selLayerRect, Surface.ReplacingPaint);
-            portion.SkiaSurface.Canvas.DrawImage(selSnap, 0, 0, Surface.MaskingPaint);
-            output[count] = portion;
-            count++;
-
-            if (eraceFromLayers)
-            {
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawImage(selSnap, new SKRect(0, 0, selLayer.Width, selLayer.Height),
-                    new SKRect(selLayer.OffsetX - layer.OffsetX, selLayer.OffsetY - layer.OffsetY, selLayer.OffsetX - layer.OffsetX + selLayer.Width, selLayer.OffsetY - layer.OffsetY + selLayer.Height),
-                    Surface.InverseMaskingPaint);
-                layer.InvokeLayerBitmapChange(new Int32Rect(selLayer.OffsetX, selLayer.OffsetY, selLayer.Width, selLayer.Height));
-            }
-        }
-        return output;
-    }
-
-    /// <summary>
-    /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
-    /// </summary>
-    /// <param name="document">Document which be used to generate preview.</param>
-    /// <param name="maxPreviewWidth">Max width of preview.</param>
-    /// <param name="maxPreviewHeight">Max height of preview.</param>
-    /// <returns>WriteableBitmap image.</returns>
-    public static WriteableBitmap GeneratePreviewBitmap(Document document, int maxPreviewWidth, int maxPreviewHeight)
-    {
-        var opacityLayers = document.Layers.Where(x => x.IsVisible && x.Opacity > 0.8f);
-
-        return GeneratePreviewBitmap(
-            opacityLayers.Select(x => x.LayerBitmap),
-            opacityLayers.Select(x => x.OffsetX),
-            opacityLayers.Select(x => x.OffsetY),
-            document.Width,
-            document.Height,
-            maxPreviewWidth,
-            maxPreviewHeight);
-    }
-
-    public static WriteableBitmap GeneratePreviewBitmap(IEnumerable<Layer> layers, int width, int height, int maxPreviewWidth, int maxPreviewHeight)
-    {
-        var opacityLayers = layers.Where(x => x.IsVisible && x.Opacity > 0.8f);
-
-        return GeneratePreviewBitmap(
-            opacityLayers.Select(x => x.LayerBitmap),
-            opacityLayers.Select(x => x.OffsetX),
-            opacityLayers.Select(x => x.OffsetY),
-            width,
-            height,
-            maxPreviewWidth,
-            maxPreviewHeight);
-    }
-
-    public static WriteableBitmap GeneratePreviewBitmap(IEnumerable<SerializableLayer> layers, int width, int height, int maxPreviewWidth, int maxPreviewHeight)
-    {
-        var opacityLayers = layers.Where(x => x.IsVisible && x.Opacity > 0.8f
-                                                          && x.Height > 0 && x.Width > 0);
-
-        return GeneratePreviewBitmap(
-            opacityLayers.Select(x => new Surface(x.ToSKImage())),
-            opacityLayers.Select(x => x.OffsetX),
-            opacityLayers.Select(x => x.OffsetY),
-            width,
-            height,
-            maxPreviewWidth,
-            maxPreviewHeight);
-    }
-
-    public static SKColor BlendColors(SKColor bottomColor, SKColor topColor)
-    {
-        if ((topColor.Alpha < 255 && topColor.Alpha > 0))
-        {
-            byte r = (byte)((topColor.Red * topColor.Alpha / 255) + (bottomColor.Red * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
-            byte g = (byte)((topColor.Green * topColor.Alpha / 255) + (bottomColor.Green * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
-            byte b = (byte)((topColor.Blue * topColor.Alpha / 255) + (bottomColor.Blue * bottomColor.Alpha * (255 - topColor.Alpha) / (255 * 255)));
-            byte a = (byte)(topColor.Alpha + (bottomColor.Alpha * (255 - topColor.Alpha) / 255));
-            return new SKColor(r, g, b, a);
-        }
-
-        return topColor.Alpha == 255 ? topColor : bottomColor;
-    }
-
-    private static WriteableBitmap GeneratePreviewBitmap(
-        IEnumerable<Surface> layerBitmaps,
-        IEnumerable<int> offsetsX,
-        IEnumerable<int> offsetsY,
-        int width,
-        int height,
-        int maxPreviewWidth,
-        int maxPreviewHeight)
-    {
-        int count = layerBitmaps.Count();
-
-        if (count != offsetsX.Count() || count != offsetsY.Count())
-        {
-            throw new ArgumentException("There were not the same amount of bitmaps and offsets", nameof(layerBitmaps));
-        }
-
-        using Surface previewSurface = new Surface(width, height);
-
-        var layerBitmapsEnumerator = layerBitmaps.GetEnumerator();
-        var offsetsXEnumerator = offsetsX.GetEnumerator();
-        var offsetsYEnumerator = offsetsY.GetEnumerator();
-
-        while (layerBitmapsEnumerator.MoveNext())
-        {
-            offsetsXEnumerator.MoveNext();
-            offsetsYEnumerator.MoveNext();
-
-            var bitmap = layerBitmapsEnumerator.Current.SkiaSurface.Snapshot();
-            var offsetX = offsetsXEnumerator.Current;
-            var offsetY = offsetsYEnumerator.Current;
-
-            previewSurface.SkiaSurface.Canvas.DrawImage(
-                bitmap,
-                offsetX, offsetY, Surface.BlendingPaint);
-        }
-
-        int newWidth = width >= height ? maxPreviewWidth : (int)Math.Ceiling(width / ((float)height / maxPreviewHeight));
-        int newHeight = height > width ? maxPreviewHeight : (int)Math.Ceiling(height / ((float)width / maxPreviewWidth));
-        return previewSurface.ResizeNearestNeighbor(newWidth, newHeight).ToWriteableBitmap();
-    }
-}

+ 0 - 256
src/PixiEditor/Models/ImageManipulation/ToolCalculator.cs

@@ -1,256 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools;
-using PixiEditor.Models.Tools.Tools;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Windows;
-using System.Windows.Input;
-
-namespace PixiEditor.Models.ImageManipulation;
-
-public static class ToolCalculator
-{
-    /// <summary>
-    /// This function calculates fill and outputs it into Coordinates list.
-    /// </summary>
-    /// <remarks>All coordinates are calculated without layer offset.
-    /// If you want to take consideration offset, just do it in CalculateBresenhamLine in PerformLinearFill function.</remarks>
-    /// <param name="layer">Layer to calculate fill from.</param>
-    /// <param name="startingCoords">Starting fill coordinates</param>
-    /// <param name="maxWidth">Maximum fill width</param>
-    /// <param name="maxHeight">Maximum fill height</param>
-    /// <param name="newColor">Replacement color to stop on</param>
-    /// <param name="output">List with output coordinates.</param>
-    public static void GetLinearFillAbsolute(Layer layer, Coordinates startingCoords, int maxWidth, int maxHeight, SKColor newColor, List<Coordinates> output)
-    {
-        Queue<FloodFillRange> floodFillQueue = new Queue<FloodFillRange>();
-        SKColor colorToReplace = layer.GetPixelWithOffset(startingCoords.X, startingCoords.Y);
-        if ((colorToReplace.Alpha == 0 && newColor.Alpha == 0) ||
-            colorToReplace == newColor)
-            return;
-
-        int width = maxWidth;
-        int height = maxHeight;
-        if (startingCoords.X < 0 || startingCoords.Y < 0 || startingCoords.X >= width || startingCoords.Y >= height)
-            return;
-        var visited = new bool[width * height];
-
-        Int32Rect dirtyRect = new Int32Rect(startingCoords.X, startingCoords.Y, 1, 1);
-
-        PerformLinearFill(layer, floodFillQueue, startingCoords, width, colorToReplace, ref dirtyRect, visited, output);
-        PerformFloodFIll(layer, floodFillQueue, colorToReplace, ref dirtyRect, width, height, visited, output);
-    }
-
-    public static void GenerateEllipseNonAlloc(Coordinates start, Coordinates end, bool fill,
-        List<Coordinates> output)
-    {
-        DoubleCoords fixedCoordinates = CalculateCoordinatesForShapeRotation(start, end);
-            
-        EllipseGenerator.GenerateEllipseFromRect(fixedCoordinates, output);
-        if (fill)
-        {
-            CalculateFillForEllipse(output);
-        }
-    }
-
-    public static void GenerateRectangleNonAlloc(
-        Coordinates start,
-        Coordinates end, bool fill, int thickness, List<Coordinates> output)
-    {
-        DoubleCoords fixedCoordinates = CalculateCoordinatesForShapeRotation(start, end);
-        CalculateRectanglePoints(fixedCoordinates, output);
-
-        for (int i = 1; i < (int)Math.Floor(thickness / 2f) + 1; i++)
-        {
-            CalculateRectanglePoints(
-                new DoubleCoords(
-                    new Coordinates(fixedCoordinates.Coords1.X - i, fixedCoordinates.Coords1.Y - i),
-                    new Coordinates(fixedCoordinates.Coords2.X + i, fixedCoordinates.Coords2.Y + i)), output);
-        }
-
-        for (int i = 1; i < (int)Math.Ceiling(thickness / 2f); i++)
-        {
-            CalculateRectanglePoints(
-                new DoubleCoords(
-                    new Coordinates(fixedCoordinates.Coords1.X + i, fixedCoordinates.Coords1.Y + i),
-                    new Coordinates(fixedCoordinates.Coords2.X - i, fixedCoordinates.Coords2.Y - i)), output);
-        }
-
-        if (fill)
-        {
-            CalculateRectangleFillNonAlloc(start, end, thickness, output);
-        }
-    }
-
-    public static DoubleCoords CalculateCoordinatesForShapeRotation(
-        Coordinates startingCords,
-        Coordinates secondCoordinates)
-    {
-        Coordinates currentCoordinates = secondCoordinates;
-
-        if (startingCords.X > currentCoordinates.X && startingCords.Y > currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(currentCoordinates.X, currentCoordinates.Y),
-                new Coordinates(startingCords.X, startingCords.Y));
-        }
-
-        if (startingCords.X < currentCoordinates.X && startingCords.Y < currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(startingCords.X, startingCords.Y),
-                new Coordinates(currentCoordinates.X, currentCoordinates.Y));
-        }
-
-        if (startingCords.Y > currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(startingCords.X, currentCoordinates.Y),
-                new Coordinates(currentCoordinates.X, startingCords.Y));
-        }
-
-        if (startingCords.X > currentCoordinates.X && startingCords.Y <= currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(currentCoordinates.X, startingCords.Y),
-                new Coordinates(startingCords.X, currentCoordinates.Y));
-        }
-
-        return new DoubleCoords(startingCords, secondCoordinates);
-    }
-
-    private static void PerformLinearFill(
-        Layer layer, Queue<FloodFillRange> floodFillQueue,
-        Coordinates coords, int width, SKColor colorToReplace, ref Int32Rect dirtyRect, bool[] visited, List<Coordinates> output)
-    {
-        // Find the Left Edge of the Color Area
-        int fillXLeft = coords.X;
-        while (true)
-        {
-            // Indicate that this pixel has been checked
-            int pixelIndex = (coords.Y * width) + fillXLeft;
-            visited[pixelIndex] = true;
-
-            // Move one pixel to the left
-            fillXLeft--;
-            // Exit the loop if we're at edge of the bitmap or the color area
-            if (fillXLeft < 0 || visited[pixelIndex - 1] || layer.GetPixelWithOffset(fillXLeft, coords.Y) != colorToReplace)
-                break;
-        }
-        int lastCheckedPixelLeft = fillXLeft + 1;
-
-        // Find the Right Edge of the Color Area
-        int fillXRight = coords.X;
-        while (true)
-        {
-            int pixelIndex = (coords.Y * width) + fillXRight;
-            visited[pixelIndex] = true;
-
-            fillXRight++;
-            if (fillXRight >= width || visited[pixelIndex + 1] || layer.GetPixelWithOffset(fillXRight, coords.Y) != colorToReplace)
-                break;
-        }
-        int lastCheckedPixelRight = fillXRight - 1;
-
-        int relativeY = coords.Y;
-        LineTool.CalculateBresenhamLine(new Coordinates(lastCheckedPixelLeft, relativeY), new Coordinates(lastCheckedPixelRight, relativeY), output);
-        dirtyRect = dirtyRect.Expand(new Int32Rect(lastCheckedPixelLeft, coords.Y, lastCheckedPixelRight - lastCheckedPixelLeft + 1, 1));
-
-        FloodFillRange range = new FloodFillRange(lastCheckedPixelLeft, lastCheckedPixelRight, coords.Y);
-        floodFillQueue.Enqueue(range);
-    }
-
-    private static void PerformFloodFIll(
-        Layer layer, Queue<FloodFillRange> floodFillQueue,
-        SKColor colorToReplace, ref Int32Rect dirtyRect, int width, int height, bool[] pixelsVisited, List<Coordinates> output)
-    {
-        while (floodFillQueue.Count > 0)
-        {
-            FloodFillRange range = floodFillQueue.Dequeue();
-
-            //START THE LOOP UPWARDS AND DOWNWARDS
-            int upY = range.Y - 1; //so we can pass the y coord by ref
-            int downY = range.Y + 1;
-            int downPixelxIndex = (width * (range.Y + 1)) + range.StartX;
-            int upPixelIndex = (width * (range.Y - 1)) + range.StartX;
-            for (int i = range.StartX; i <= range.EndX; i++)
-            {
-                //START LOOP UPWARDS
-                //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
-                if (range.Y > 0 && (!pixelsVisited[upPixelIndex]) && layer.GetPixelWithOffset(i, upY) == colorToReplace)
-                    PerformLinearFill(layer, floodFillQueue, new Coordinates(i, upY), width, colorToReplace, ref dirtyRect, pixelsVisited, output);
-                //START LOOP DOWNWARDS
-                if (range.Y < (height - 1) && (!pixelsVisited[downPixelxIndex]) && layer.GetPixelWithOffset(i, downY) == colorToReplace)
-                    PerformLinearFill(layer, floodFillQueue, new Coordinates(i, downY), width, colorToReplace, ref dirtyRect, pixelsVisited, output);
-                downPixelxIndex++;
-                upPixelIndex++;
-            }
-        }
-    }
-
-    private static void CalculateFillForEllipse(List<Coordinates> outlineCoordinates)
-    {
-        if (!outlineCoordinates.Any())
-            return;
-
-        var lines = EllipseGenerator.SplitEllipseIntoLines(outlineCoordinates);
-        foreach (var line in lines)
-        {
-            for (int i = line.Coords1.X; i <= line.Coords2.X; i++)
-            {
-                outlineCoordinates.Add(new Coordinates(i, line.Coords1.Y));
-            }
-        }
-    }
-
-    private static void CalculateRectangleFillNonAlloc(Coordinates start, Coordinates end, int thickness, List<Coordinates> output)
-    {
-        int offset = (int)Math.Ceiling(thickness / 2f);
-        DoubleCoords fixedCords = CalculateCoordinatesForShapeRotation(start, end);
-
-        DoubleCoords innerCords = new DoubleCoords
-        {
-            Coords1 = new Coordinates(fixedCords.Coords1.X + offset, fixedCords.Coords1.Y + offset),
-            Coords2 = new Coordinates(fixedCords.Coords2.X - (offset - 1), fixedCords.Coords2.Y - (offset - 1))
-        };
-
-        int height = innerCords.Coords2.Y - innerCords.Coords1.Y;
-        int width = innerCords.Coords2.X - innerCords.Coords1.X;
-
-        if (height < 1 || width < 1)
-        {
-            return;
-        }
-
-        int i = 0;
-        for (int y = 0; y < height; y++)
-        {
-            for (int x = 0; x < width; x++)
-            {
-                output.Add(new Coordinates(innerCords.Coords1.X + x, innerCords.Coords1.Y + y));
-                i++;
-            }
-        }
-    }
-
-    private static void CalculateRectanglePoints(DoubleCoords coordinates, List<Coordinates> output)
-    {
-        for (int i = coordinates.Coords1.X; i < coordinates.Coords2.X + 1; i++)
-        {
-            output.Add(new Coordinates(i, coordinates.Coords1.Y));
-            output.Add(new Coordinates(i, coordinates.Coords2.Y));
-        }
-
-        for (int i = coordinates.Coords1.Y + 1; i <= coordinates.Coords2.Y - 1; i++)
-        {
-            output.Add(new Coordinates(coordinates.Coords1.X, i));
-            output.Add(new Coordinates(coordinates.Coords2.X, i));
-        }
-    }
-}

+ 0 - 34
src/PixiEditor/Models/Layers/BasicLayer.cs

@@ -1,34 +0,0 @@
-using PixiEditor.Helpers;
-using System;
-
-namespace PixiEditor.Models.Layers;
-
-[Serializable]
-public class BasicLayer : NotifyableObject, IHasGuid
-{
-    private int height;
-
-    private int width;
-
-    public int Width
-    {
-        get => width;
-        set
-        {
-            width = value;
-            RaisePropertyChanged("Width");
-        }
-    }
-
-    public int Height
-    {
-        get => height;
-        set
-        {
-            height = value;
-            RaisePropertyChanged("Height");
-        }
-    }
-
-    public Guid GuidValue { get; protected set; }
-}

+ 0 - 14
src/PixiEditor/Models/Layers/GroupChangedEventArgs.cs

@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.Layers;
-
-public class GroupChangedEventArgs : EventArgs
-{
-    public List<GuidStructureItem> GroupsAffected { get; set; }
-
-    public GroupChangedEventArgs(List<GuidStructureItem> groupsAffected)
-    {
-        GroupsAffected = groupsAffected;
-    }
-}

+ 0 - 22
src/PixiEditor/Models/Layers/GroupData.cs

@@ -1,22 +0,0 @@
-using PixiEditor.Views.UserControls;
-using System;
-
-namespace PixiEditor.Models.Layers;
-
-public record GroupData
-{
-    public int TopIndex { get; set; }
-    public int BottomIndex { get; set; }
-    public Guid? GroupGuid { get; set; }
-
-    public GroupData(Guid? groupGuid)
-    {
-        GroupGuid = groupGuid;
-    }
-
-    public GroupData(int topIndex, int bottomIndex)
-    {
-        TopIndex = topIndex;
-        BottomIndex = bottomIndex;
-    }
-}

+ 0 - 178
src/PixiEditor/Models/Layers/GuidStructureItem.cs

@@ -1,178 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Linq;
-using PixiEditor.Helpers;
-using PixiEditor.ViewModels;
-
-namespace PixiEditor.Models.Layers;
-
-[DebuggerDisplay("{Name} - {GroupGuid}")]
-public class GuidStructureItem : NotifyableObject, ICloneable
-{
-    public event EventHandler<GroupChangedEventArgs> GroupsChanged;
-
-    public Guid GroupGuid { get; init; }
-
-    private string name;
-
-    public string Name
-    {
-        get => name;
-        set
-        {
-            name = value;
-            RaisePropertyChanged(nameof(Name));
-        }
-    }
-
-    private Guid startLayerGuid;
-
-    public Guid StartLayerGuid
-    {
-        get => startLayerGuid;
-        set
-        {
-            startLayerGuid = value;
-            RaisePropertyChanged(nameof(StartLayerGuid));
-        }
-    }
-
-    private Guid endLayerGuid;
-
-    public Guid EndLayerGuid
-    {
-        get => endLayerGuid;
-        set
-        {
-            endLayerGuid = value;
-            RaisePropertyChanged(nameof(EndLayerGuid));
-        }
-    }
-
-    public ObservableCollection<GuidStructureItem> Subgroups { get; set; } = new ObservableCollection<GuidStructureItem>();
-
-    public GuidStructureItem Parent { get; set; }
-
-    private bool isExpanded;
-
-    public bool IsExpanded
-    {
-        get => isExpanded;
-        set => SetProperty(ref isExpanded, value);
-    }
-
-    private bool isRenaming = false;
-
-    public bool IsRenaming
-    {
-        get => isRenaming;
-        set => SetProperty(ref isRenaming, value);
-    }
-
-    private bool isVisible = true;
-
-    public bool IsVisible
-    {
-        get => isVisible;
-        set
-        {
-            if (SetProperty(ref isVisible, value))
-            {
-                ViewModelMain.Current.ToolsSubViewModel.TriggerCacheOutdated();
-            }
-        }
-    }
-
-    private float opacity = 1;
-
-    public float Opacity
-    {
-        get => opacity;
-        set
-        {
-            if (SetProperty(ref opacity, value))
-            {
-                ViewModelMain.Current.ToolsSubViewModel.TriggerCacheOutdated();
-            }
-        }
-    }
-
-    public GuidStructureItem(
-        string name,
-        Guid startLayerGuid,
-        Guid endLayerGuid,
-        IEnumerable<GuidStructureItem> subgroups,
-        GuidStructureItem parent)
-    {
-        Name = name;
-        Subgroups = new ObservableCollection<GuidStructureItem>(subgroups);
-        GroupGuid = Guid.NewGuid();
-        Parent = parent;
-        StartLayerGuid = startLayerGuid;
-        EndLayerGuid = endLayerGuid;
-        Subgroups.CollectionChanged += Subgroups_CollectionChanged;
-    }
-
-    public GuidStructureItem(string name, Guid layer)
-    {
-        Name = name;
-        GroupGuid = Guid.NewGuid();
-        Parent = null;
-        StartLayerGuid = layer;
-        EndLayerGuid = layer;
-        Subgroups.CollectionChanged += Subgroups_CollectionChanged;
-    }
-
-    public override int GetHashCode()
-    {
-        HashCode hc = default;
-        hc.Add(GroupGuid);
-        hc.Add(EndLayerGuid);
-        hc.Add(StartLayerGuid);
-        hc.Add(Opacity);
-        hc.Add(IsVisible);
-        hc.Add(IsExpanded);
-        hc.Add(IsRenaming);
-        hc.Add(Parent);
-        hc.Add(Subgroups);
-        return hc.ToHashCode();
-    }
-
-    public GuidStructureItem CloneGroup()
-    {
-        GuidStructureItem item = new(Name, StartLayerGuid, EndLayerGuid, Array.Empty<GuidStructureItem>(), null)
-        {
-            GroupGuid = GroupGuid,
-            IsExpanded = isExpanded,
-            IsRenaming = isRenaming,
-            IsVisible = isVisible,
-            Opacity = opacity
-        };
-
-        if(Subgroups.Count > 0)
-        {
-            item.Subgroups = new ObservableCollection<GuidStructureItem>();
-            for (int i = 0; i < Subgroups.Count; i++)
-            {
-                item.Subgroups.Add(Subgroups[i].CloneGroup());
-                item.Subgroups[^1].Parent = item;
-            }
-        }
-
-        return item;
-    }
-
-    public object Clone()
-    {
-        return CloneGroup();
-    }
-
-    private void Subgroups_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
-    {
-        var args = new GroupChangedEventArgs(e.NewItems != null ? e.NewItems.Cast<GuidStructureItem>().ToList() : new List<GuidStructureItem>());
-        GroupsChanged?.Invoke(this, args);
-        Parent?.GroupsChanged?.Invoke(this, args);
-    }
-}

+ 0 - 8
src/PixiEditor/Models/Layers/IHasGuid.cs

@@ -1,8 +0,0 @@
-using System;
-
-namespace PixiEditor.Models.Layers;
-
-public interface IHasGuid
-{
-    Guid GuidValue { get; }
-}

+ 0 - 740
src/PixiEditor/Models/Layers/Layer.cs

@@ -1,740 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using PixiEditor.ViewModels;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Media;
-using PixiEditor.Models.Dialogs;
-
-namespace PixiEditor.Models.Layers;
-
-[DebuggerDisplay("'{name,nq}' {width}x{height}")]
-public class Layer : BasicLayer
-{
-    private bool clipRequested;
-
-    private bool isActive;
-
-    private bool isRenaming;
-    private bool isVisible = true;
-    private Surface layerBitmap;
-
-    private string name;
-
-    private Thickness offset;
-
-    private float opacity = 1f;
-
-    private string layerHighlightColor = "#666666";
-
-
-    public Layer(string name, int maxWidth, int maxHeight)
-    {
-        Name = name;
-        LayerBitmap = new Surface(1, 1);
-        IsReset = true;
-        Width = 1;
-        Height = 1;
-        MaxWidth = maxWidth;
-        MaxHeight = maxHeight;
-        GuidValue = Guid.NewGuid();
-    }
-
-    public Layer(string name, int width, int height, int maxWidth, int maxHeight)
-    {
-        Name = name;
-        LayerBitmap = new Surface(width, height);
-        IsReset = true;
-        Width = width;
-        Height = height;
-        MaxWidth = maxWidth;
-        MaxHeight = maxHeight;
-        GuidValue = Guid.NewGuid();
-    }
-
-    public Layer(string name, Surface layerBitmap, int maxWidth, int maxHeight)
-    {
-        Name = name;
-        LayerBitmap = layerBitmap;
-        Width = layerBitmap.Width;
-        Height = layerBitmap.Height;
-        MaxWidth = maxWidth;
-        MaxHeight = maxHeight;
-        GuidValue = Guid.NewGuid();
-    }
-
-    public Dictionary<Coordinates, SKColor> LastRelativeCoordinates { get; set; }
-
-    public string LayerHighlightColor
-    {
-        get => IsActive ? layerHighlightColor : "#00000000";
-        set
-        {
-            SetProperty(ref layerHighlightColor, value);
-        }
-    }
-
-    public string Name
-    {
-        get => name;
-        set
-        {
-            name = value;
-            RaisePropertyChanged(nameof(Name));
-        }
-    }
-
-    public bool IsActive
-    {
-        get => isActive;
-        set
-        {
-            isActive = value;
-            RaisePropertyChanged(nameof(IsActive));
-            RaisePropertyChanged(nameof(LayerHighlightColor));
-        }
-    }
-
-    public bool IsVisible
-    {
-        get => isVisible;
-        set
-        {
-            isVisible = value;
-            RaisePropertyChanged(nameof(IsVisibleUndoTriggerable));
-            RaisePropertyChanged(nameof(IsVisible));
-            ViewModelMain.Current?.ToolsSubViewModel?.TriggerCacheOutdated();
-            InvokeLayerBitmapChange();
-        }
-    }
-
-    public bool IsVisibleUndoTriggerable
-    {
-        get => IsVisible;
-        set
-        {
-            if (value != IsVisible)
-            {
-                ViewModelMain.Current?.BitmapManager?.ActiveDocument?.UndoManager
-                    .AddUndoChange(
-                        new Change(
-                            nameof(IsVisible),
-                            isVisible,
-                            value,
-                            LayerHelper.FindLayerByGuidProcess,
-                            new object[] { GuidValue },
-                            "Change layer visibility"));
-                IsVisible = value;
-                InvokeLayerBitmapChange();
-            }
-        }
-    }
-
-    public bool IsRenaming
-    {
-        get => isRenaming;
-        set
-        {
-            isRenaming = value;
-            RaisePropertyChanged("IsRenaming");
-        }
-    }
-
-    public Surface LayerBitmap
-    {
-        get => layerBitmap;
-        set
-        {
-            Int32Rect prevRect = new Int32Rect(OffsetX, OffsetY, Width, Height);
-            layerBitmap = value;
-            Width = layerBitmap.Width;
-            Height = layerBitmap.Height;
-            Int32Rect curRect = new Int32Rect(OffsetX, OffsetY, Width, Height);
-            RaisePropertyChanged(nameof(LayerBitmap));
-            InvokeLayerBitmapChange(prevRect.Expand(curRect));
-        }
-    }
-
-    public float Opacity
-    {
-        get => opacity;
-        set
-        {
-            opacity = value;
-            RaisePropertyChanged(nameof(OpacityUndoTriggerable));
-            ViewModelMain.Current?.ToolsSubViewModel?.TriggerCacheOutdated();
-            InvokeLayerBitmapChange();
-        }
-    }
-
-    public float OpacityUndoTriggerable
-    {
-        get => Opacity;
-        set
-        {
-            if (value != Opacity)
-            {
-                ViewModelMain.Current?.BitmapManager?.ActiveDocument?.UndoManager
-                    .AddUndoChange(
-                        new Change(
-                            nameof(Opacity),
-                            opacity,
-                            value,
-                            LayerHelper.FindLayerByGuidProcess,
-                            new object[] { GuidValue },
-                            "Change layer opacity"));
-                Opacity = value;
-            }
-        }
-    }
-
-    public int OffsetX => (int)Offset.Left;
-
-    public int OffsetY => (int)Offset.Top;
-
-    public Thickness Offset
-    {
-        get => offset;
-        set
-        {
-            Int32Rect prevRect = new Int32Rect(OffsetX, OffsetY, Width, Height);
-            offset = value;
-            Int32Rect curRect = new Int32Rect(OffsetX, OffsetY, Width, Height);
-            RaisePropertyChanged(nameof(Offset));
-            InvokeLayerBitmapChange(prevRect.Expand(curRect));
-        }
-    }
-
-    public int MaxWidth { get; set; } = int.MaxValue;
-
-    public int MaxHeight { get; set; } = int.MaxValue;
-
-    public bool IsReset { get; private set; }
-
-    public Int32Rect TightBounds => GetContentDimensions();
-    public Int32Rect Bounds => new Int32Rect(OffsetX, OffsetY, Width, Height);
-
-    public event EventHandler<Int32Rect> LayerBitmapChanged;
-
-    public void InvokeLayerBitmapChange()
-    {
-        IsReset = false;
-        LayerBitmapChanged?.Invoke(this, new Int32Rect(OffsetX, OffsetY, Width, Height));
-    }
-
-    public void InvokeLayerBitmapChange(Int32Rect dirtyArea)
-    {
-        IsReset = false;
-        LayerBitmapChanged?.Invoke(this, dirtyArea);
-    }
-
-
-    /// <summary>
-    /// Changes Guid of layer.
-    /// </summary>
-    /// <param name="newGuid">Guid to set.</param>
-    /// <remarks>This is potentially destructive operation, use when absolutelly necessary.</remarks>
-    public void ChangeGuid(Guid newGuid)
-    {
-        GuidValue = newGuid;
-    }
-
-    public IEnumerable<Layer> GetLayers()
-    {
-        return new Layer[] { this };
-    }
-
-    /// <summary>
-    ///     Returns clone of layer.
-    /// </summary>
-    public Layer Clone(bool generateNewGuid = false)
-    {
-        return new Layer(Name, new Surface(LayerBitmap), MaxWidth, MaxHeight)
-        {
-            IsVisible = IsVisible,
-            Offset = Offset,
-            Opacity = Opacity,
-            IsActive = IsActive,
-            IsRenaming = IsRenaming,
-            GuidValue = generateNewGuid ? Guid.NewGuid() : GuidValue
-        };
-    }
-
-    public void RaisePropertyChange(string property)
-    {
-        RaisePropertyChanged(property);
-    }
-
-    /// <summary>
-    ///     Resizes bitmap with it's content using NearestNeighbor interpolation.
-    /// </summary>
-    /// <param name="width">New width.</param>
-    /// <param name="height">New height.</param>
-    /// <param name="newMaxWidth">New layer maximum width, this should be document width.</param>
-    /// <param name="newMaxHeight">New layer maximum height, this should be document height.</param>
-    public void Resize(int width, int height, int newMaxWidth, int newMaxHeight)
-    {
-        LayerBitmap = LayerBitmap.ResizeNearestNeighbor(width, height);
-        Width = width;
-        Height = height;
-        MaxWidth = newMaxWidth;
-        MaxHeight = newMaxHeight;
-    }
-
-    /// <summary>
-    ///     Converts coordinates relative to viewport to relative to layer.
-    /// </summary>
-    public Coordinates GetRelativePosition(Coordinates cords)
-    {
-        return new Coordinates(cords.X - OffsetX, cords.Y - OffsetY);
-    }
-
-    /// <summary>
-    ///     Returns pixel color of x and y coordinates relative to document using (x - OffsetX) formula.
-    /// </summary>
-    /// <param name="x">Viewport relative X.</param>
-    /// <param name="y">Viewport relative Y.</param>
-    /// <returns>Color of a pixel.</returns>
-    public SKColor GetPixelWithOffset(int x, int y)
-    {
-        //This does not use GetRelativePosition for better performance
-        return GetPixel(x - OffsetX, y - OffsetY);
-    }
-
-    /// <summary>
-    ///     Returns pixel color on x and y.
-    /// </summary>
-    /// <param name="x">X coordinate.</param>
-    /// <param name="y">Y Coordinate.</param>
-    /// <returns>Color of pixel, if out of bounds, returns transparent pixel.</returns>
-    public SKColor GetPixel(int x, int y)
-    {
-        if (x > Width - 1 || x < 0 || y > Height - 1 || y < 0)
-        {
-            return SKColors.Empty;
-        }
-
-        return LayerBitmap.GetSRGBPixel(x, y);
-    }
-
-    public void SetPixelWithOffset(Coordinates coordinates, SKColor color)
-    {
-        LayerBitmap.SetSRGBPixel(coordinates.X - OffsetX, coordinates.Y - OffsetY, color);
-    }
-
-    public void SetPixelWithOffset(int x, int y, SKColor color)
-    {
-        LayerBitmap.SetSRGBPixel(x - OffsetX, y - OffsetY, color);
-    }
-
-    /// <summary>
-    ///     Applies pixels to layer.
-    /// </summary>
-    /// <param name="pixels">Pixels to apply.</param>
-    /// <param name="dynamicResize">Resizes bitmap to fit content.</param>
-    /// <param name="applyOffset">Converts pixels coordinates to relative to bitmap.</param>
-    public void SetPixels(BitmapPixelChanges pixels, bool dynamicResize = true, bool applyOffset = true)
-    {
-        if (pixels.ChangedPixels == null || pixels.ChangedPixels.Count == 0)
-        {
-            return;
-        }
-
-        if (applyOffset)
-        {
-            pixels.ChangedPixels = GetRelativePosition(pixels.ChangedPixels);
-        }
-
-        if (dynamicResize)
-        {
-            DynamicResize(pixels);
-        }
-
-        LastRelativeCoordinates = pixels.ChangedPixels;
-
-        int minX = int.MaxValue;
-        int maxX = int.MinValue;
-        int minY = int.MaxValue;
-        int maxY = int.MinValue;
-
-        foreach (KeyValuePair<Coordinates, SKColor> coords in pixels.ChangedPixels)
-        {
-            if (OutOfBounds(coords.Key))
-            {
-                continue;
-            }
-
-            LayerBitmap.SetSRGBPixel(coords.Key.X, coords.Key.Y, coords.Value);
-            minX = Math.Min(minX, coords.Key.X);
-            minY = Math.Min(minY, coords.Key.Y);
-            maxX = Math.Max(maxX, coords.Key.X);
-            maxY = Math.Max(maxY, coords.Key.Y);
-        }
-
-        ClipIfNecessary();
-        if (minX != int.MaxValue)
-            InvokeLayerBitmapChange(new Int32Rect(minX + OffsetX, minY + OffsetY, maxX - minX + 1, maxY - minY + 1));
-    }
-
-    /// <summary>
-    ///     Converts absolute coordinates array to relative to this layer coordinates array.
-    /// </summary>
-    /// <param name="nonRelativeCords">absolute coordinates array.</param>
-    public Coordinates[] ConvertToRelativeCoordinates(Coordinates[] nonRelativeCords)
-    {
-        Coordinates[] result = new Coordinates[nonRelativeCords.Length];
-        for (int i = 0; i < nonRelativeCords.Length; i++)
-        {
-            result[i] = new Coordinates(nonRelativeCords[i].X - OffsetX, nonRelativeCords[i].Y - OffsetY);
-        }
-
-        return result;
-    }
-
-    public void CreateNewBitmap(int width, int height)
-    {
-        LayerBitmap = new Surface(width, height);
-
-        Width = width;
-        Height = height;
-    }
-
-
-    /// <summary>
-    ///     Resizes canvas to fit pixels outside current bounds. Clamped to MaxHeight and MaxWidth.
-    /// </summary>
-    public void DynamicResize(BitmapPixelChanges pixels)
-    {
-        if (pixels.ChangedPixels.Count == 0)
-        {
-            return;
-        }
-
-        ResetOffset(pixels);
-        Tuple<DoubleCoords, bool> borderData = ExtractBorderData(pixels);
-        DoubleCoords minMaxCords = borderData.Item1;
-        int newMaxX = minMaxCords.Coords2.X;
-        int newMaxY = minMaxCords.Coords2.Y;
-        int newMinX = minMaxCords.Coords1.X;
-        int newMinY = minMaxCords.Coords1.Y;
-
-        if (!(pixels.WasBuiltAsSingleColored && pixels.ChangedPixels.First().Value.Alpha == 0))
-        {
-            DynamicResizeRelative(newMaxX, newMaxY, newMinX, newMinY);
-        }
-
-        // if clip is requested
-        if (borderData.Item2)
-        {
-            clipRequested = true;
-        }
-    }
-
-    public void DynamicResizeAbsolute(Int32Rect newSize)
-    {
-        newSize = newSize.Intersect(new Int32Rect(0, 0, MaxWidth, MaxHeight));
-        if (newSize.IsEmpty)
-            return;
-        if (IsReset)
-        {
-            Offset = new Thickness(newSize.X, newSize.Y, 0, 0);
-        }
-
-        int relX = newSize.X - OffsetX;
-        int relY = newSize.Y - OffsetY;
-        int maxX = relX + newSize.Width - 1;
-        int maxY = relY + newSize.Height - 1;
-
-        DynamicResizeRelative(maxX, maxY, relX, relY);
-    }
-
-    /// <summary>
-    ///     Resizes canvas to fit pixels outside current bounds. Clamped to MaxHeight and MaxWidth.
-    /// </summary>
-    public void DynamicResizeRelative(int newMaxX, int newMaxY, int newMinX, int newMinY)
-    {
-        if ((newMaxX + 1 > Width && Width < MaxWidth) || (newMaxY + 1 > Height && Height < MaxHeight))
-        {
-            newMaxX = Math.Max(newMaxX, (int)(Width * 1.5f));
-            newMaxY = Math.Max(newMaxY, (int)(Height * 1.5f));
-            IncreaseSizeToBottomAndRight(newMaxX, newMaxY);
-        }
-
-        if ((newMinX < 0 && Width < MaxWidth) || (newMinY < 0 && Height < MaxHeight))
-        {
-            newMinX = Math.Min(newMinX, Width - (int)(Width * 1.5f));
-            newMinY = Math.Min(newMinY, Height - (int)(Height * 1.5f));
-            IncreaseSizeToTopAndLeft(newMinX, newMinY);
-        }
-    }
-
-    public Int32Rect GetContentDimensions()
-    {
-        DoubleCoords points = GetEdgePoints();
-        int smallestX = points.Coords1.X;
-        int smallestY = points.Coords1.Y;
-        int biggestX = points.Coords2.X;
-        int biggestY = points.Coords2.Y;
-
-        if (smallestX < 0 && smallestY < 0 && biggestX < 0 && biggestY < 0)
-        {
-            return Int32Rect.Empty;
-        }
-
-        int width = biggestX - smallestX + 1;
-        int height = biggestY - smallestY + 1;
-        return new Int32Rect(smallestX, smallestY, width, height);
-    }
-
-    /// <summary>
-    ///     Changes size of bitmap to fit content.
-    /// </summary>
-    public void ClipCanvas()
-    {
-        var dimensions = GetContentDimensions();
-        if (dimensions == Int32Rect.Empty)
-        {
-            Reset();
-            return;
-        }
-
-        ResizeCanvas(0, 0, dimensions.X, dimensions.Y, dimensions.Width, dimensions.Height);
-        Offset = new Thickness(OffsetX + dimensions.X, OffsetY + dimensions.Y, 0, 0);
-    }
-
-    public void Reset()
-    {
-        if (IsReset)
-            return;
-        var dirtyRect = new Int32Rect(OffsetX, OffsetY, Width, Height);
-        LayerBitmap?.Dispose();
-        LayerBitmap = new Surface(1, 1);
-        Width = 1;
-        Height = 1;
-        Offset = new Thickness(0, 0, 0, 0);
-        IsReset = true;
-        LayerBitmapChanged?.Invoke(this, dirtyRect);
-    }
-
-    public void ClearCanvas()
-    {
-        if (IsReset)
-            return;
-        LayerBitmap.SkiaSurface.Canvas.Clear();
-        InvokeLayerBitmapChange();
-    }
-
-    /// <summary>
-    ///     Converts layer WriteableBitmap to byte array.
-    /// </summary>
-    public byte[] ConvertBitmapToBytes()
-    {
-        return LayerBitmap.ToByteArray();
-    }
-
-    public SKRectI GetRect() => SKRectI.Create(OffsetX, OffsetY, Width, Height);
-
-    public void CropIntersect(SKRectI rect)
-    {
-        SKRectI layerRect = GetRect();
-        SKRectI intersect = SKRectI.Intersect(layerRect, rect);
-
-        Crop(intersect);
-    }
-
-    public void Crop(SKRectI intersect)
-    {
-        if (intersect == SKRectI.Empty)
-        {
-            return;
-        }
-
-        using var oldSurface = LayerBitmap;
-
-        int offsetX = (int)(Offset.Left - intersect.Left);
-        int offsetY = (int)(Offset.Top - intersect.Top);
-
-        Width = intersect.Width;
-        Height = intersect.Height;
-        LayerBitmap = LayerBitmap.Crop(offsetX, offsetY, Width, Height);
-
-        Offset = new(intersect.Left, intersect.Top, 0, 0);
-    }
-
-    private Dictionary<Coordinates, SKColor> GetRelativePosition(Dictionary<Coordinates, SKColor> changedPixels)
-    {
-        return changedPixels.ToDictionary(
-            d => new Coordinates(d.Key.X - OffsetX, d.Key.Y - OffsetY),
-            d => d.Value);
-    }
-
-    private Tuple<DoubleCoords, bool> ExtractBorderData(BitmapPixelChanges pixels)
-    {
-        Coordinates firstCords = pixels.ChangedPixels.First().Key;
-        int minX = firstCords.X;
-        int minY = firstCords.Y;
-        int maxX = minX;
-        int maxY = minY;
-        bool clipRequested = false;
-
-        foreach (KeyValuePair<Coordinates, SKColor> pixel in pixels.ChangedPixels)
-        {
-            if (pixel.Key.X < minX)
-            {
-                minX = pixel.Key.X;
-            }
-            else if (pixel.Key.X > maxX)
-            {
-                maxX = pixel.Key.X;
-            }
-
-            if (pixel.Key.Y < minY)
-            {
-                minY = pixel.Key.Y;
-            }
-            else if (pixel.Key.Y > maxY)
-            {
-                maxY = pixel.Key.Y;
-            }
-
-            if (clipRequested == false && IsBorderPixel(pixel.Key) && pixel.Value.Alpha == 0)
-            {
-                clipRequested = true;
-            }
-        }
-
-        return new Tuple<DoubleCoords, bool>(
-            new DoubleCoords(new Coordinates(minX, minY), new Coordinates(maxX, maxY)), clipRequested);
-    }
-
-    private bool IsBorderPixel(Coordinates cords)
-    {
-        return cords.X - OffsetX == 0 || cords.Y - OffsetY == 0 || cords.X - OffsetX == Width - 1 ||
-               cords.Y - OffsetY == Height - 1;
-    }
-
-    private bool OutOfBounds(Coordinates cords)
-    {
-        return cords.X < 0 || cords.X > Width - 1 || cords.Y < 0 || cords.Y > Height - 1;
-    }
-
-    private void ClipIfNecessary()
-    {
-        if (clipRequested)
-        {
-            ClipCanvas();
-            clipRequested = false;
-        }
-    }
-
-    private void IncreaseSizeToBottomAndRight(int newMaxX, int newMaxY)
-    {
-        if (MaxWidth - OffsetX < 0 || MaxHeight - OffsetY < 0)
-        {
-            return;
-        }
-
-        newMaxX = Math.Clamp(Math.Max(newMaxX + 1, Width), 1, MaxWidth - OffsetX);
-        newMaxY = Math.Clamp(Math.Max(newMaxY + 1, Height), 1, MaxHeight - OffsetY);
-
-        ResizeCanvas(0, 0, 0, 0, newMaxX, newMaxY);
-    }
-
-    private void IncreaseSizeToTopAndLeft(int newMinX, int newMinY)
-    {
-        newMinX = Math.Clamp(Math.Min(newMinX, Width), Math.Min(-OffsetX, OffsetX), 0);
-        newMinY = Math.Clamp(Math.Min(newMinY, Height), Math.Min(-OffsetY, OffsetY), 0);
-
-        Offset = new Thickness(
-            Math.Clamp(OffsetX + newMinX, 0, MaxWidth),
-            Math.Clamp(OffsetY + newMinY, 0, MaxHeight),
-            0,
-            0);
-
-        int newWidth = Math.Clamp(Width - newMinX, 0, MaxWidth);
-        int newHeight = Math.Clamp(Height - newMinY, 0, MaxHeight);
-
-        int offsetX = Math.Abs(newWidth - Width);
-        int offsetY = Math.Abs(newHeight - Height);
-
-        ResizeCanvas(offsetX, offsetY, 0, 0, newWidth, newHeight);
-    }
-
-    private DoubleCoords GetEdgePoints()
-    {
-        Coordinates smallestPixel = CoordinatesCalculator.FindMinEdgeNonTransparentPixel(LayerBitmap);
-        Coordinates biggestPixel = CoordinatesCalculator.FindMostEdgeNonTransparentPixel(LayerBitmap);
-
-        return new DoubleCoords(smallestPixel, biggestPixel);
-    }
-
-    private void ResetOffset(BitmapPixelChanges pixels)
-    {
-        if (Width == 0 || Height == 0)
-        {
-            int offsetX = Math.Max(pixels.ChangedPixels.Min(x => x.Key.X), 0);
-            int offsetY = Math.Max(pixels.ChangedPixels.Min(x => x.Key.Y), 0);
-            Offset = new Thickness(offsetX, offsetY, 0, 0);
-        }
-    }
-
-    /// <summary>
-    ///     Resizes canvas to new size with specified offset.
-    /// </summary>
-    private void ResizeCanvas(int offsetX, int offsetY, int offsetXSrc, int offsetYSrc, int newWidth, int newHeight)
-    {
-        Surface result = new Surface(newWidth, newHeight);
-        LayerBitmap.SkiaSurface.Draw(result.SkiaSurface.Canvas, offsetX - offsetXSrc, offsetY - offsetYSrc, Surface.ReplacingPaint);
-        LayerBitmap?.Dispose();
-        LayerBitmap = result;
-        Width = newWidth;
-        Height = newHeight;
-    }
-
-
-    public void ReplaceColor(SKColor oldColor, SKColor newColor)
-    {
-        if (LayerBitmap == null)
-        {
-            return;
-        }
-
-        int maxThreads = Environment.ProcessorCount;
-        int rowsPerThread = Height / maxThreads;
-
-        Parallel.For(0, maxThreads, i =>
-        {
-            int startRow = i * rowsPerThread;
-            int endRow = (i + 1) * rowsPerThread;
-            if (i == maxThreads - 1)
-            {
-                endRow = Height;
-            }
-
-            for (int y = startRow; y < endRow; y++)
-            {
-                for (int x = 0; x < Width; x++)
-                {
-                    if (LayerBitmap.GetSRGBPixel(x, y) == oldColor)
-                    {
-                        LayerBitmap.SetSRGBPixelUnmanaged(x, y, newColor);
-                    }
-                }
-            }
-        });
-
-        layerBitmap.SkiaSurface.Canvas.DrawPaint(new SKPaint { BlendMode = SKBlendMode.Dst });
-
-        InvokeLayerBitmapChange();
-    }
-}

+ 0 - 127
src/PixiEditor/Models/Layers/LayerGroup.cs

@@ -1,127 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.ViewModels;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-
-namespace PixiEditor.Models.Layers;
-
-public class LayerGroup : NotifyableObject, IHasGuid
-{
-    public Guid GuidValue { get; init; }
-
-    private GuidStructureItem structureData;
-    public GuidStructureItem StructureData
-    {
-        get => structureData;
-        set => SetProperty(ref structureData, value);
-    }
-
-    private ObservableCollection<Layer> Layers { get; set; } = new ObservableCollection<Layer>();
-
-    private ObservableCollection<LayerGroup> Subfolders { get; set; } = new ObservableCollection<LayerGroup>();
-
-    private ObservableCollection<IHasGuid> items = null;
-    public ObservableCollection<IHasGuid> Items => items ??= BuildItems();
-
-    private ObservableCollection<IHasGuid> BuildItems()
-    {
-        List<IHasGuid> obj = new(Layers.Reverse());
-        foreach (var subfolder in Subfolders)
-        {
-            obj.Insert(Math.Clamp(subfolder.DisplayIndex - DisplayIndex, 0, obj.Count), subfolder);
-        }
-
-        obj.Reverse();
-
-        return new ObservableCollection<IHasGuid>(obj);
-    }
-
-    private string name;
-
-    public string Name
-    {
-        get => name;
-        set
-        {
-            name = value;
-            RaisePropertyChanged(nameof(Name));
-        }
-    }
-
-    private bool isExpanded = false;
-
-    public bool IsExpanded
-    {
-        get => isExpanded;
-        set
-        {
-            isExpanded = value;
-            UpdateIsExpandedInDocument(value);
-            RaisePropertyChanged(nameof(IsExpanded));
-        }
-    }
-
-    private int displayIndex;
-
-    public int DisplayIndex
-    {
-        get => displayIndex;
-        set
-        {
-            displayIndex = value;
-            RaisePropertyChanged(nameof(DisplayIndex));
-        }
-    }
-
-    private int topIndex;
-
-    public int TopIndex
-    {
-        get => topIndex;
-        set
-        {
-            topIndex = value;
-            RaisePropertyChanged(nameof(TopIndex));
-        }
-    }
-
-    private bool isRenaming;
-
-    public bool IsRenaming
-    {
-        get => isRenaming;
-        set
-        {
-            SetProperty(ref isRenaming, value);
-        }
-    }
-
-    private void UpdateIsExpandedInDocument(bool value)
-    {
-        var folder = ViewModelMain.Current.BitmapManager.ActiveDocument.LayerStructure.GetGroupByGuid(GuidValue);
-        if (folder != null)
-        {
-            folder.IsExpanded = value;
-        }
-    }
-
-    public LayerGroup(IEnumerable<Layer> layers, IEnumerable<LayerGroup> subfolders, string name,
-        int displayIndex, int topIndex, GuidStructureItem structureData)
-        : this(layers, subfolders, name, Guid.NewGuid(), displayIndex, topIndex, structureData)
-    {
-    }
-
-    public LayerGroup(IEnumerable<Layer> layers, IEnumerable<LayerGroup> subfolders, string name,
-        Guid guid, int displayIndex, int topIndex, GuidStructureItem structureData)
-    {
-        Layers = new ObservableCollection<Layer>(layers);
-        Subfolders = new ObservableCollection<LayerGroup>(subfolders);
-        Name = name;
-        GuidValue = guid;
-        DisplayIndex = displayIndex;
-        TopIndex = topIndex;
-        StructureData = structureData;
-    }
-}

+ 0 - 81
src/PixiEditor/Models/Layers/LayerHelper.cs

@@ -1,81 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.ImageManipulation;
-using PixiEditor.ViewModels;
-using System;
-using System.Linq;
-using System.Windows;
-
-namespace PixiEditor.Models.Layers;
-
-public static class LayerHelper
-{
-    public static Layer FindLayerByGuid(Document document, Guid guid)
-    {
-        return document.Layers.FirstOrDefault(x => x.GuidValue == guid);
-    }
-
-    public static object FindLayerByGuidProcess(object[] parameters)
-    {
-        if (parameters != null && parameters.Length > 0 && parameters[0] is Guid guid)
-        {
-            return FindLayerByGuid(ViewModelMain.Current.BitmapManager.ActiveDocument, guid);
-        }
-
-        return null;
-    }
-
-    /// <summary>
-    /// Gets the closer layers to the axises.
-    /// </summary>
-    /// <param name="xCloser">The layer closer to the x Axis.</param>
-    /// <param name="yCloser">The layer closer to the y Axis.</param>
-    /// <param name="xOther">The other layer that is not closer to the x axis.</param>
-    /// <param name="yOther">The other layer that is not closer to the y axis.</param>
-    public static void GetCloser(this Layer layer1, Layer layer2, out Layer xCloser, out Layer yCloser, out Layer xOther, out Layer yOther)
-    {
-        if (layer2.OffsetX > layer1.OffsetX)
-        {
-            xCloser = layer1;
-            xOther = layer2;
-        }
-        else
-        {
-            xCloser = layer2;
-            xOther = layer1;
-        }
-
-        if (layer2.OffsetY > layer1.OffsetY)
-        {
-            yCloser = layer1;
-            yOther = layer2;
-        }
-        else
-        {
-            yCloser = layer2;
-            yOther = layer1;
-        }
-    }
-
-    public static Layer MergeWith(this Layer thisLayer, Layer otherLayer, string newName, PixelSize documentSize)
-    {
-        Int32Rect thisRect = new(thisLayer.OffsetX, thisLayer.OffsetY, thisLayer.Width, thisLayer.Height);
-        Int32Rect otherRect = new(otherLayer.OffsetX, otherLayer.OffsetY, otherLayer.Width, otherLayer.Height);
-
-        Int32Rect combined = thisRect.Expand(otherRect);
-
-        Surface mergedBitmap = BitmapUtils.CombineLayers(combined, new Layer[] { thisLayer, otherLayer });
-
-        Layer mergedLayer = new Layer(newName, mergedBitmap, documentSize.Width, documentSize.Height)
-        {
-            Offset = new Thickness(combined.X, combined.Y, 0, 0),
-        };
-
-        return mergedLayer;
-    }
-
-    public static Layer MergeWith(this Layer thisLayer, Layer otherLayer, string newName, int documentWidth, int documentHeight)
-    {
-        return MergeWith(thisLayer, otherLayer, newName, new PixelSize(documentWidth, documentHeight));
-    }
-}

+ 0 - 722
src/PixiEditor/Models/Layers/LayerStructure.cs

@@ -1,722 +0,0 @@
-using PixiEditor.Models.DataHolders;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-
-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<LayerStructureChangedEventArgs> LayerStructureChanged;
-
-    public WpfObservableRangeCollection<GuidStructureItem> Groups { get; set; }
-
-    private Document Owner { get; }
-
-    /// <summary>
-    /// Checks whenever group contains only single layer and none subgroups.
-    /// </summary>
-    /// <param name="layerGuid">Guid of layer to check.</param>
-    /// <param name="layerGroup">Group to check.</param>
-    /// <returns>True if group contains single layer (EndLayerGuid and StartLayerGuid == layerGuid) and none subgroups.</returns>
-    public static bool GroupContainsOnlyLayer(Guid layerGuid, GuidStructureItem layerGroup)
-    {
-        return layerGroup != null && layerGroup.Subgroups.Count == 0 && layerGroup.StartLayerGuid == layerGuid && layerGroup.EndLayerGuid == layerGuid;
-    }
-
-    /// <summary>
-    /// Deep clones groups.
-    /// </summary>
-    /// <param name="groups">Groups to clone.</param>
-    /// <returns>ObservableCollection with cloned groups.</returns>
-    public static WpfObservableRangeCollection<GuidStructureItem> CloneGroups(WpfObservableRangeCollection<GuidStructureItem> groups)
-    {
-        WpfObservableRangeCollection<GuidStructureItem> outputGroups = new();
-        foreach (var group in groups.ToArray())
-        {
-            outputGroups.Add(group.CloneGroup());
-        }
-
-        return outputGroups;
-    }
-
-    /// <summary>
-    ///  Finds parent group by layer guid.
-    /// </summary>
-    /// <param name="layerGuid">Guid of group to check.</param>
-    /// <returns><see cref="GuidStructureItem"/>if parent group was found or null if not.</returns>
-    public GuidStructureItem GetGroupByLayer(Guid layerGuid)
-    {
-        return GetGroupByLayer(layerGuid, Groups);
-    }
-
-    /// <summary>
-    /// Finds <see cref="GuidStructureItem"/> (Group) by it's guid.
-    /// </summary>
-    /// <param name="groupGuid">Guid of group.</param>
-    /// <returns><see cref="GuidStructureItem"/> if group was found or null if not.</returns>
-    public GuidStructureItem GetGroupByGuid(Guid? groupGuid)
-    {
-        return GetGroupByGuid(groupGuid, Groups);
-    }
-
-    public WpfObservableRangeCollection<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)
-    {
-        var activeLayerParent = GetGroupByLayer(activeLayer);
-
-        List<GuidStructureItem> sameLevelGroups = new List<GuidStructureItem>();
-
-        var group = AddNewGroup(groupName, activeLayer);
-
-        if (activeLayerParent == null)
-        {
-            sameLevelGroups.AddRange(Groups);
-        }
-        else
-        {
-            sameLevelGroups.AddRange(activeLayerParent.Subgroups);
-        }
-
-        sameLevelGroups.Remove(group);
-        group.Subgroups = new ObservableCollection<GuidStructureItem>(sameLevelGroups);
-
-        sameLevelGroups = new(sameLevelGroups.Where(x => IsChildOf(activeLayer, x)));
-
-        Guid lastLayer = activeLayer;
-
-        foreach (var layer in layers)
-        {
-            if (layer.LayerGuid == activeLayer)
-            {
-                continue;
-            }
-
-            Owner.MoveLayerInStructure(layer.LayerGuid, lastLayer, false);
-            lastLayer = layer.LayerGuid;
-        }
-
-        return group;
-    }*/
-
-    /// <summary>
-    /// Adds a new group to layer structure taking into consideration nesting. Invokes LayerStructureChanged event.
-    /// </summary>
-    /// <param name="groupName">Name of a group.</param>
-    /// <param name="childLayer">Child layer of a new group.</param>
-    /// <returns>Newly created group (<see cref="GuidStructureItem"/>).</returns>
-    public GuidStructureItem AddNewGroup(string groupName, Guid childLayer)
-    {
-        var parent = GetGroupByLayer(childLayer);
-        GuidStructureItem group = new(groupName, childLayer) { IsExpanded = true };
-        if (parent == null)
-        {
-            Groups.Add(group);
-        }
-        else
-        {
-            group.Parent = parent;
-            parent.Subgroups.Add(group);
-        }
-
-        group.GroupsChanged += Group_GroupsChanged;
-
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(childLayer));
-        return group;
-    }
-
-    public GuidStructureItem AddNewGroup(string groupName, GuidStructureItem childGroup)
-    {
-        if (childGroup == null)
-        {
-            throw new ArgumentException("Child group can't be null.");
-        }
-        GuidStructureItem group = new(groupName, childGroup.StartLayerGuid, childGroup.EndLayerGuid, new[] { childGroup }, childGroup.Parent) { IsExpanded = true };
-        if (childGroup.Parent == null)
-        {
-            Groups.Add(group);
-            Groups.Remove(childGroup);
-        }
-        else
-        {
-            childGroup.Parent.Subgroups.Add(group);
-            childGroup.Parent.Subgroups.Remove(childGroup);
-        }
-
-        childGroup.Parent = group;
-
-        group.GroupsChanged += Group_GroupsChanged;
-
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(GetGroupLayerGuids(group)));
-        return group;
-    }
-
-    /// <summary>
-    /// Moves group and it's children from one index to another. This method makes changes in <see cref="Document"/> Layers.
-    /// </summary>
-    /// <param name="groupGuid">Group guid to move.</param>
-    /// <param name="newIndex">New group index, relative to <see cref="Document"/> Layers.</param>
-    public void MoveGroup(Guid groupGuid, int newIndex)
-    {
-        var group = GetGroupByGuid(groupGuid);
-        var parentGroup = group.Parent;
-        bool reverseOrder = true;
-        int groupTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == group.EndLayerGuid));
-        int groupBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == group.StartLayerGuid));
-
-        int difference = newIndex - groupTopIndex;
-
-        if (newIndex < groupTopIndex)
-        {
-            reverseOrder = false;
-            difference = newIndex - groupBottomIndex;
-        }
-
-        if (difference == 0)
-        {
-            return;
-        }
-
-        Unassign(parentGroup, group);
-
-        List<Guid> layersInOrder = GetLayersInOrder(new GroupData(groupTopIndex, groupBottomIndex));
-
-        MoveLayersInGroup(layersInOrder, difference, reverseOrder);
-
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(layersInOrder));
-    }
-
-    /// <summary>
-    /// Checks if group is nested inside parent group.
-    /// </summary>
-    /// <param name="group">Group to check.</param>
-    /// <param name="parent">Parent of that group.</param>
-    /// <returns>True if group is nested inside parent, false if not.</returns>
-    public bool IsChildOf(GuidStructureItem group, GuidStructureItem parent)
-    {
-        if (group == null)
-        {
-            return false;
-        }
-
-        foreach (var subgroup in parent.Subgroups)
-        {
-            if (subgroup == group)
-            {
-                return true;
-            }
-
-            if (subgroup.Subgroups.Count > 0)
-            {
-                if (IsChildOf(group, subgroup))
-                {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /// <summary>
-    /// Checks if layer is nested inside parent group.
-    /// </summary>
-    /// <param name="layerGuid">Layer GUID to check.</param>
-    /// <param name="parent">Parent of that group.</param>
-    /// <returns>True if layer is nested inside parent, false if not.</returns>
-    public bool IsChildOf(Guid layerGuid, GuidStructureItem parent)
-    {
-        var layerParent = GetGroupByLayer(layerGuid);
-
-        return layerParent == parent ? true : IsChildOf(layerParent, parent);
-    }
-
-    /// <summary>
-    /// Reassigns (removes) group data from parent group.
-    /// </summary>
-    /// <param name="parentGroup">Parent group to reassign data in.</param>
-    /// <param name="group">Group which data should be reassigned.</param>
-    public void Unassign(GroupData parentGroup, GroupData group)
-    {
-        Unassign(GetGroupByGuid(parentGroup.GroupGuid), GetGroupByGuid(group.GroupGuid));
-    }
-
-    /// <summary>
-    /// Reassigns (removes) layer data from parent group.
-    /// </summary>
-    /// <param name="parentGroup">Parent group to reassign data in.</param>
-    /// <param name="layer">Layer which data should be reassigned.</param>
-    public void Unassign(GroupData parentGroup, Guid layer)
-    {
-        PreMoveReassignBounds(GetGroupByGuid(parentGroup.GroupGuid), layer);
-    }
-
-    /// <summary>
-    /// Reassigns (adds) layer data to parent group.
-    /// </summary>
-    /// <param name="parentGroup">Parent group to reassign data in.</param>
-    /// <param name="layerGuid">Group which data should be reassigned.</param>
-    public void Assign(GroupData parentGroup, Guid layerGuid)
-    {
-        Assign(GetGroupByGuid(parentGroup.GroupGuid), layerGuid);
-    }
-
-    /// <summary>
-    /// Reassigns (adds) group data to parent group.
-    /// </summary>
-    /// <param name="parentGroup">Parent group to reassign data in.</param>
-    /// <param name="group">Group which data should be reassigned.</param>
-    public void Assign(GroupData parentGroup, GroupData group)
-    {
-        Assign(GetGroupByGuid(parentGroup?.GroupGuid), GetGroupByGuid(group.GroupGuid));
-    }
-
-    /// <summary>
-    /// Assigns parent to a layer.
-    /// </summary>
-    /// <param name="layer">Layer to assign parent to.</param>
-    /// <param name="parent">Parent which should be assigned. Null indicates no parent.</param>
-    public void AssignParent(Guid layer, Guid? parent)
-    {
-        AssignParent(layer, parent.HasValue ? GetGroupByGuid(parent) : null);
-    }
-
-    /// <summary>
-    /// Assigns group new parent.
-    /// </summary>
-    /// <param name="group">Group to assign parent</param>
-    /// <param name="referenceLayerGroup">Parent of group.</param>
-    public void ReassignParent(GuidStructureItem group, GuidStructureItem referenceLayerGroup)
-    {
-        group.Parent?.Subgroups.Remove(group);
-        if (Groups.Contains(group))
-        {
-            Groups.Remove(group);
-        }
-
-        if (referenceLayerGroup == null)
-        {
-            if (!Groups.Contains(group))
-            {
-                Groups.Add(group);
-                group.Parent = null;
-            }
-        }
-        else
-        {
-            referenceLayerGroup.Subgroups.Add(group);
-            group.Parent = referenceLayerGroup;
-        }
-
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(GetGroupLayerGuids(group)));
-    }
-
-    /// <summary>
-    /// Gets all layers inside group, including nested groups.
-    /// </summary>
-    /// <param name="group">Group to get layers from.</param>
-    /// <returns>List of layers.</returns>
-    public List<Layer> GetGroupLayers(GuidStructureItem group)
-    {
-        List<Layer> layers = new();
-        var layerGuids = GetGroupLayerGuids(group);
-        foreach (var layerGuid in layerGuids)
-        {
-            layers.Add(Owner.Layers.First(x => x.GuidValue == layerGuid));
-        }
-
-        return layers;
-    }
-
-    /// <summary>
-    /// Sets parent groups IsExpanded to true.
-    /// </summary>
-    /// <param name="layerGuid">Guid of layer which parents will be affected.</param>
-    public void ExpandParentGroups(Guid layerGuid)
-    {
-        var group = GetGroupByLayer(layerGuid);
-
-        while (group != null)
-        {
-            group.IsExpanded = true;
-            group = group.Parent;
-        }
-    }
-
-    /// <summary>
-    /// Sets parent groups IsExpanded to true.
-    /// </summary>
-    /// <param name="group">Group which parents will be affected.</param>
-    public void ExpandParentGroups(GuidStructureItem group)
-    {
-        GuidStructureItem currentGroup = group;
-
-        while (currentGroup != null)
-        {
-            currentGroup.IsExpanded = true;
-            currentGroup = currentGroup.Parent;
-        }
-    }
-
-    private static Guid GetNextLayerGuid(Guid layer, List<Guid> allLayers, bool above)
-    {
-        int indexOfLayer = allLayers.IndexOf(layer);
-
-        int modifier = above ? 1 : -1;
-
-        int newIndex = Math.Clamp(indexOfLayer + modifier, 0, allLayers.Count - 1);
-
-        return allLayers[newIndex];
-    }
-
-    /// <summary>
-    /// Gets all layers inside group, including nested groups.
-    /// </summary>
-    /// <param name="group">Group to get layers from.</param>
-    /// <returns>List of layer guids.</returns>
-    private List<Guid> GetGroupLayerGuids(GuidStructureItem group)
-    {
-        Layer layerTop = Owner.Layers.FirstOrDefault(x => x.GuidValue == group.EndLayerGuid);
-        Layer layerBottom = Owner.Layers.FirstOrDefault(x => x.GuidValue == group.StartLayerGuid);
-
-        if (layerTop == null || layerBottom == null)
-        {
-            return new List<Guid>();
-        }
-
-        int indexTop = Owner.Layers.IndexOf(layerTop);
-        int indexBottom = Owner.Layers.IndexOf(layerBottom);
-
-        return GetLayersInOrder(new GroupData(indexTop, indexBottom));
-    }
-
-    private List<Guid> GetLayersInOrder(GroupData group)
-    {
-        List<Guid> layerGuids = new();
-        int minIndex = group.BottomIndex;
-        int maxIndex = group.TopIndex;
-
-        for (int i = minIndex; i <= maxIndex; i++)
-        {
-            layerGuids.Add(Owner.Layers[i].GuidValue);
-        }
-
-        return layerGuids;
-    }
-
-    private void PreMoveReassignBounds(GuidStructureItem parentGroup, Guid layer)
-    {
-        if (parentGroup != null)
-        {
-            Guid oldStart = parentGroup.StartLayerGuid;
-            Guid oldEnd = parentGroup.EndLayerGuid;
-            GuidStructureItem parentOfParent = parentGroup.Parent;
-            if (parentGroup.Subgroups.Count == 0 && parentGroup.StartLayerGuid == layer && parentGroup.EndLayerGuid == layer)
-            {
-                RemoveGroup(parentGroup);
-            }
-            else
-            {
-                if (parentGroup.EndLayerGuid == layer)
-                {
-                    parentGroup.EndLayerGuid = FindBoundLayer(parentGroup, layer, false);
-                }
-
-                if (parentGroup.StartLayerGuid == layer)
-                {
-                    parentGroup.StartLayerGuid = FindBoundLayer(parentGroup, layer, true);
-                }
-            }
-
-            if (parentOfParent != null)
-            {
-                ApplyBoundsToParents(parentOfParent, parentGroup, oldStart, oldEnd);
-            }
-            LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(layer));
-        }
-    }
-
-    private void Unassign(GuidStructureItem parentGroup, GuidStructureItem group)
-    {
-        if (parentGroup != null)
-        {
-            Guid oldStart = parentGroup.StartLayerGuid;
-            Guid oldEnd = parentGroup.EndLayerGuid;
-
-            if (parentGroup.Subgroups.Count == 1 && parentGroup.StartLayerGuid == group.StartLayerGuid && parentGroup.EndLayerGuid == group.EndLayerGuid)
-            {
-                RemoveGroup(parentGroup);
-            }
-            else
-            {
-                if (group.EndLayerGuid == parentGroup.EndLayerGuid)
-                {
-                    parentGroup.EndLayerGuid = FindBoundLayer(parentGroup, group.StartLayerGuid, false);
-                }
-
-                if (group.StartLayerGuid == parentGroup.StartLayerGuid)
-                {
-                    parentGroup.StartLayerGuid = FindBoundLayer(parentGroup, group.EndLayerGuid, true);
-                }
-            }
-
-            if (parentGroup.Parent != null)
-            {
-                ApplyBoundsToParents(parentGroup.Parent, parentGroup, oldStart, oldEnd);
-            }
-        }
-    }
-
-    private void Assign(GuidStructureItem parentGroup, Guid layerGuid)
-    {
-        if (parentGroup != null)
-        {
-            Guid? oldStart = parentGroup.StartLayerGuid;
-            Guid? oldEnd = parentGroup.EndLayerGuid;
-
-            int layerIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == layerGuid));
-
-            int folderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == parentGroup.EndLayerGuid));
-            int folderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == parentGroup.StartLayerGuid));
-
-            int finalTopIndex = Math.Max(folderTopIndex, layerIndex);
-            int finalBottomIndex = Math.Min(folderBottomIndex, layerIndex);
-
-            Guid? topBoundLayer = FindBoundLayer(layerGuid, finalTopIndex, finalBottomIndex, false);
-            Guid? bottomBoundLayer = FindBoundLayer(layerGuid, finalTopIndex, finalBottomIndex, true);
-
-            if (topBoundLayer == parentGroup.EndLayerGuid)
-            {
-                parentGroup.EndLayerGuid = layerGuid;
-            }
-
-            if (bottomBoundLayer == parentGroup.StartLayerGuid)
-            {
-                parentGroup.StartLayerGuid = layerGuid;
-            }
-
-            if (parentGroup.Parent != null)
-            {
-                ApplyBoundsToParents(parentGroup.Parent, parentGroup, oldStart, oldEnd);
-            }
-
-            var args = new LayerStructureChangedEventArgs(layerGuid);
-
-            if (topBoundLayer.HasValue)
-            {
-                args.AffectedLayerGuids.Add(topBoundLayer.Value);
-            }
-            if (bottomBoundLayer.HasValue)
-            {
-                args.AffectedLayerGuids.Add(bottomBoundLayer.Value);
-            }
-
-            LayerStructureChanged?.Invoke(this, args);
-        }
-    }
-
-    private void Assign(GuidStructureItem parentGroup, GuidStructureItem group)
-    {
-        if (parentGroup != null)
-        {
-            Guid oldStart = parentGroup.StartLayerGuid;
-            Guid oldEnd = parentGroup.EndLayerGuid;
-            int folderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == group.EndLayerGuid));
-            int folderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == group.StartLayerGuid));
-
-            int parentFolderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == parentGroup.EndLayerGuid));
-            int parentFolderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == parentGroup.StartLayerGuid));
-
-            int finalTopIndex = Math.Max(folderTopIndex, parentFolderTopIndex);
-            int finalBottomIndex = Math.Min(folderBottomIndex, parentFolderBottomIndex);
-
-            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 (bottomBoundLayer == parentGroup.StartLayerGuid)
-            {
-                parentGroup.StartLayerGuid = group.StartLayerGuid;
-            }
-
-            if (parentGroup.Parent != null)
-            {
-                ApplyBoundsToParents(parentGroup.Parent, parentGroup, oldStart, oldEnd);
-            }
-        }
-    }
-
-    private void AssignParent(Guid layer, GuidStructureItem parent)
-    {
-        var currentParent = GetGroupByLayer(layer);
-        if (currentParent != null)
-        {
-            PreMoveReassignBounds(currentParent, layer);
-        }
-
-        Assign(parent, layer);
-
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(layer));
-    }
-
-    private void Group_GroupsChanged(object sender, GroupChangedEventArgs e)
-    {
-        List<Guid> layersAffected = new List<Guid>();
-        e.GroupsAffected.ForEach(x => layersAffected.AddRange(GetGroupLayerGuids(x)));
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(layersAffected));
-    }
-
-    private void RemoveGroup(GuidStructureItem parentFolder)
-    {
-        parentFolder.GroupsChanged -= Group_GroupsChanged;
-
-        var layerGuids = GetGroupLayerGuids(parentFolder);
-
-        if (parentFolder.Parent == null)
-        {
-            Groups.Remove(parentFolder);
-        }
-        else
-        {
-            parentFolder.Parent.Subgroups.Remove(parentFolder);
-        }
-
-        LayerStructureChanged?.Invoke(this, new LayerStructureChangedEventArgs(layerGuids));
-
-    }
-
-    private void ApplyBoundsToParents(GuidStructureItem parent, GuidStructureItem group, Guid? oldStart, Guid? oldEnd)
-    {
-        Guid parentOldStart = parent.StartLayerGuid;
-        Guid parentOldEnd = parent.EndLayerGuid;
-
-        if (parent.Subgroups.Count == 0)
-        {
-            RemoveGroup(parent);
-        }
-
-        if (parent.StartLayerGuid == oldStart)
-        {
-            parent.StartLayerGuid = group.StartLayerGuid;
-        }
-
-        if (parent.EndLayerGuid == oldEnd)
-        {
-            parent.EndLayerGuid = group.EndLayerGuid;
-        }
-
-        if (parent.Parent != null)
-        {
-            ApplyBoundsToParents(parent.Parent, parent, parentOldStart, parentOldEnd);
-        }
-    }
-
-    private Guid FindBoundLayer(Guid layerGuid, int parentFolderTopIndex, int parentFolderBottomIndex, bool above)
-    {
-        return GetNextLayerGuid(
-            layerGuid,
-            GetLayersInOrder(new GroupData(parentFolderTopIndex, parentFolderBottomIndex)),
-            above);
-    }
-
-    private Guid FindBoundLayer(GuidStructureItem parentFolder, Guid layerGuid, bool above)
-    {
-        int parentFolderTopIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == parentFolder.EndLayerGuid));
-        int parentFolderBottomIndex = Owner.Layers.IndexOf(Owner.Layers.First(x => x.GuidValue == parentFolder.StartLayerGuid));
-
-        return FindBoundLayer(layerGuid, parentFolderTopIndex, parentFolderBottomIndex, above);
-    }
-
-    private void MoveLayersInGroup(List<Guid> layers, int moveBy, bool reverseOrder)
-    {
-        List<Guid> layerGuids = reverseOrder ? layers.Reverse<Guid>().ToList() : layers;
-
-        for (int i = 0; i < layers.Count; i++)
-        {
-            Guid layerGuid = layerGuids[i];
-            var layer = Owner.Layers.First(x => x.GuidValue == layerGuid);
-            int layerIndex = Owner.Layers.IndexOf(layer);
-            Owner.Layers.Move(layerIndex, layerIndex + moveBy);
-        }
-    }
-
-    private GuidStructureItem GetGroupByLayer(Guid layerGuid, IEnumerable<GuidStructureItem> groups)
-    {
-        foreach (var currentGroup in groups)
-        {
-            var endLayer = Owner.Layers.First(x => x.GuidValue == currentGroup.EndLayerGuid);
-            var startLayer = Owner.Layers.First(x => x.GuidValue == currentGroup.StartLayerGuid);
-
-            int topIndex = Owner.Layers.IndexOf(endLayer);
-            int bottomIndex = Owner.Layers.IndexOf(startLayer);
-            var layers = GetLayersInOrder(new GroupData(topIndex, bottomIndex));
-
-            if (currentGroup.Subgroups.Count > 0)
-            {
-                var group = GetGroupByLayer(layerGuid, currentGroup.Subgroups);
-                if (group != null)
-                {
-                    return group;
-                }
-            }
-
-            if (layers.Contains(layerGuid))
-            {
-                return currentGroup;
-            }
-        }
-
-        return null;
-    }
-
-    private GuidStructureItem GetGroupByGuid(Guid? groupGuid, IEnumerable<GuidStructureItem> groups)
-    {
-        foreach (var group in groups)
-        {
-            if (group.GroupGuid == groupGuid)
-            {
-                return group;
-            }
-
-            if (group.Subgroups.Count > 0)
-            {
-                var guid = GetGroupByGuid(groupGuid, group.Subgroups);
-                if (guid != null)
-                {
-                    return guid;
-                }
-            }
-        }
-
-        return null;
-    }
-
-    public LayerStructure(WpfObservableRangeCollection<GuidStructureItem> items, Document owner)
-    {
-        Groups = items;
-        Owner = owner;
-    }
-
-    public LayerStructure(Document owner)
-    {
-        Groups = new WpfObservableRangeCollection<GuidStructureItem>();
-        Owner = owner;
-    }
-}

+ 0 - 19
src/PixiEditor/Models/Layers/LayerStructureChangedEventArgs.cs

@@ -1,19 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.Layers;
-
-public class LayerStructureChangedEventArgs : EventArgs
-{
-    public List<Guid> AffectedLayerGuids { get; set; }
-
-    public LayerStructureChangedEventArgs(List<Guid> affectedLayerGuids)
-    {
-        AffectedLayerGuids = affectedLayerGuids;
-    }
-
-    public LayerStructureChangedEventArgs(Guid affectedLayerGuid)
-    {
-        AffectedLayerGuids = new List<Guid>() { affectedLayerGuid };
-    }
-}

+ 0 - 200
src/PixiEditor/Models/Layers/StructuredLayerTree.cs

@@ -1,200 +0,0 @@
-using PixiEditor.Helpers;
-using PixiEditor.Models.DataHolders;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-
-namespace PixiEditor.Models.Layers;
-
-public class StructuredLayerTree : NotifyableObject
-{
-    private List<Guid> layersInStructure = new();
-
-    public WpfObservableRangeCollection<IHasGuid> RootDirectoryItems { get; } = new WpfObservableRangeCollection<IHasGuid>();
-
-    private static void Swap(ref int startIndex, ref int endIndex)
-    {
-        (startIndex, endIndex) = (endIndex, startIndex);
-    }
-
-    public StructuredLayerTree(WpfObservableRangeCollection<Layer> layers, LayerStructure structure)
-    {
-        if (layers == null || structure == null)
-        {
-            return;
-        }
-
-        if (structure.Groups == null || structure.Groups.Count == 0)
-        {
-            RootDirectoryItems.AddRange(layers);
-            return;
-        }
-
-        var parsedFolders = ParseFolders(structure.Groups, layers);
-
-        parsedFolders = parsedFolders.OrderBy(x => x.DisplayIndex).ToList();
-
-        PlaceItems(parsedFolders, layers);
-
-        layersInStructure.Clear();
-    }
-
-    private void PlaceItems(List<LayerGroup> parsedFolders, ObservableCollection<Layer> layers)
-    {
-        LayerGroup currentFolder = null;
-        List<LayerGroup> groupsAtIndex = new();
-        Stack<LayerGroup> unfinishedFolders = new();
-
-        for (int i = 0; i < layers.Count; i++)
-        {
-            if (currentFolder != null && layers[i].GuidValue == currentFolder.StructureData.EndLayerGuid)
-            {
-                if (unfinishedFolders.Count > 0)
-                {
-                    currentFolder = unfinishedFolders.Pop();
-                }
-                else
-                {
-                    currentFolder = null;
-                }
-
-                continue;
-            }
-
-            AssignGroup(parsedFolders, layers, ref currentFolder, ref groupsAtIndex, unfinishedFolders, i);
-
-            if (currentFolder == null && !layersInStructure.Contains(layers[i].GuidValue))
-            {
-                RootDirectoryItems.Add(layers[i]);
-            }
-            else if (!RootDirectoryItems.Contains(currentFolder))
-            {
-                RootDirectoryItems.AddRange(groupsAtIndex.Where(x => !RootDirectoryItems.Contains(x)));
-            }
-        }
-    }
-
-    private void AssignGroup(List<LayerGroup> parsedFolders, ObservableCollection<Layer> layers, ref LayerGroup currentFolder, ref List<LayerGroup> groupsAtIndex, Stack<LayerGroup> unfinishedFolders, int i)
-    {
-        if (parsedFolders.Any(x => x.StructureData.StartLayerGuid == layers[i].GuidValue))
-        {
-            groupsAtIndex = parsedFolders.Where(x => x.StructureData.StartLayerGuid == layers[i].GuidValue).ToList();
-            for (int j = 0; j < groupsAtIndex.Count; j++)
-            {
-                LayerGroup group = groupsAtIndex[j];
-
-                if (currentFolder != null)
-                {
-                    unfinishedFolders.Push(currentFolder);
-                }
-
-                groupsAtIndex[j] = parsedFolders.First(x => x.StructureData.StartLayerGuid == layers[i].GuidValue);
-                groupsAtIndex[j].DisplayIndex = RootDirectoryItems.Count;
-                groupsAtIndex[j].TopIndex = CalculateTopIndex(group.DisplayIndex, group.StructureData, layers);
-                if (groupsAtIndex[j].StructureData.EndLayerGuid != layers[i].GuidValue)
-                {
-                    currentFolder = groupsAtIndex[j];
-                }
-            }
-        }
-    }
-
-    private int CalculateTopIndex(int displayIndex, GuidStructureItem structureData, ObservableCollection<Layer> layers)
-    {
-        var endLayer = layers.FirstOrDefault(x => x.GuidValue == structureData.EndLayerGuid);
-        var bottomLayer = layers.FirstOrDefault(x => x.GuidValue == structureData.StartLayerGuid);
-        int originalTopIndex = 0;
-        int originalBottomIndex = 0;
-        if (endLayer != null)
-        {
-            originalTopIndex = layers.IndexOf(endLayer);
-        }
-        if (bottomLayer != null)
-        {
-            originalBottomIndex = layers.IndexOf(bottomLayer);
-        }
-
-        return displayIndex + (originalTopIndex - originalBottomIndex);
-    }
-
-    private List<LayerGroup> ParseFolders(IEnumerable<GuidStructureItem> folders, ObservableCollection<Layer> layers)
-    {
-        List<LayerGroup> parsedFolders = new();
-        foreach (var structureItem in folders)
-        {
-            parsedFolders.Add(ParseFolder(structureItem, layers));
-        }
-
-        return parsedFolders;
-    }
-
-    private LayerGroup ParseFolder(GuidStructureItem structureItem, ObservableCollection<Layer> layers)
-    {
-        List<Layer> structureItemLayers = new();
-
-        Guid[] layersInFolder = GetLayersInGroup(layers, structureItem);
-
-        var subFolders = new List<LayerGroup>();
-
-        if (structureItem.Subgroups.Count > 0)
-        {
-            subFolders = ParseFolders(structureItem.Subgroups, layers);
-        }
-
-        foreach (var guid in layersInFolder)
-        {
-            var layer = layers.FirstOrDefault(x => x.GuidValue == guid);
-            if (layer != null)
-            {
-                if (!layersInStructure.Contains(layer.GuidValue))
-                {
-                    layersInStructure.Add(layer.GuidValue);
-                    structureItemLayers.Add(layer);
-                }
-            }
-        }
-
-        int displayIndex = layersInFolder.Length > 0 ? layers.IndexOf(layers.First(x => x.GuidValue == structureItem.StartLayerGuid)) : 0;
-
-        structureItemLayers.Reverse();
-
-        LayerGroup folder = new(structureItemLayers, subFolders, structureItem.Name,
-            structureItem.GroupGuid, displayIndex, displayIndex + structureItemLayers.Count - 1, structureItem)
-        {
-            IsExpanded = structureItem.IsExpanded,
-            IsRenaming = structureItem.IsRenaming
-        };
-        return folder;
-    }
-
-    private Guid[] GetLayersInGroup(ObservableCollection<Layer> layers, GuidStructureItem structureItem)
-    {
-        var startLayer = layers.FirstOrDefault(x => x.GuidValue == structureItem.StartLayerGuid);
-        var endLayer = layers.FirstOrDefault(x => x.GuidValue == structureItem.EndLayerGuid);
-
-        if (startLayer == null || endLayer == null)
-        {
-            return Array.Empty<Guid>();
-        }
-
-        int startIndex = layers.IndexOf(startLayer);
-        int endIndex = layers.IndexOf(endLayer);
-
-        if (startIndex > endIndex)
-        {
-            Swap(ref startIndex, ref endIndex);
-        }
-
-        int len = endIndex - startIndex + 1;
-
-        Guid[] guids = new Guid[len];
-
-        for (int i = 0; i < len; i++)
-        {
-            guids[i] = layers[i + startIndex].GuidValue;
-        }
-
-        return guids;
-    }
-}

+ 0 - 60
src/PixiEditor/Models/Layers/Utils/LayerStructureUtils.cs

@@ -1,60 +0,0 @@
-using System;
-
-namespace PixiEditor.Models.Layers.Utils;
-
-public static class LayerStructureUtils
-{
-    /// <summary>
-    /// Gets final layer opacity taking into consideration parent groups.
-    /// </summary>
-    /// <param name="layer">Layer to check.</param>
-    /// <returns>Float from range 0-1.</returns>
-    public static float GetFinalLayerOpacity(Layer layer, LayerStructure structure)
-    {
-        if (layer.Opacity == 0)
-        {
-            return 0f;
-        }
-
-        var group = structure.GetGroupByLayer(layer.GuidValue);
-        GuidStructureItem groupToCheck = group;
-        float finalOpacity = layer.Opacity;
-
-        while (groupToCheck != null)
-        {
-            finalOpacity *= groupToCheck.Opacity;
-            groupToCheck = groupToCheck.Parent;
-        }
-
-        return Math.Clamp(finalOpacity, 0f, 1f);
-    }
-
-    /// <summary>
-    /// Gets final layer IsVisible taking into consideration group visibility.
-    /// </summary>
-    /// <param name="layer">Layer to check.</param>
-    /// <returns>True if is visible, false if at least parent is not visible or layer itself is invisible.</returns>
-    public static bool GetFinalLayerIsVisible(Layer layer, LayerStructure structure)
-    {
-        if (!layer.IsVisible)
-        {
-            return false;
-        }
-
-        var group = structure.GetGroupByLayer(layer.GuidValue);
-        bool atLeastOneParentIsInvisible = false;
-        GuidStructureItem groupToCheck = group;
-        while (groupToCheck != null)
-        {
-            if (!groupToCheck.IsVisible)
-            {
-                atLeastOneParentIsInvisible = true;
-                break;
-            }
-
-            groupToCheck = groupToCheck.Parent;
-        }
-
-        return !atLeastOneParentIsInvisible;
-    }
-}

+ 0 - 94
src/PixiEditor/Models/Position/Coordinates.cs

@@ -1,94 +0,0 @@
-using SkiaSharp;
-using System;
-using System.Diagnostics;
-using System.Windows;
-
-namespace PixiEditor.Models.Position;
-
-[DebuggerDisplay("({DebuggerDisplay,nq})")]
-public struct Coordinates
-{
-    public static Coordinates Zero => new Coordinates(0, 0);
-
-    private string DebuggerDisplay => ToString();
-
-    public Coordinates(int x, int y)
-    {
-        X = x;
-        Y = y;
-    }
-
-    public int X { get; set; }
-
-    public int Y { get; set; }
-
-    public static implicit operator Coordinates((int width, int height) tuple)
-    {
-        return new Coordinates(tuple.width, tuple.height);
-    }
-
-    public static Coordinates operator -(Coordinates coordiantes, Thickness thickness)
-    {
-        return new Coordinates(coordiantes.X - (int)thickness.Left, coordiantes.Y - (int)thickness.Top);
-    }
-
-    public static Coordinates operator -(Coordinates coordiantes, int size)
-    {
-        return new Coordinates(coordiantes.X - size, coordiantes.Y - size);
-    }
-
-    public static Coordinates operator +(Coordinates coordiantes, int size)
-    {
-        return new Coordinates(coordiantes.X + size, coordiantes.Y + size);
-    }
-
-    public static Coordinates operator -(Coordinates coordiantes1, Coordinates coordinates2)
-    {
-        return new Coordinates(coordiantes1.X - coordinates2.X, coordiantes1.Y - coordinates2.Y);
-    }
-
-    public static bool operator ==(Coordinates c1, Coordinates c2)
-    {
-        return c2.X == c1.X && c2.Y == c1.Y;
-    }
-
-    public static bool operator !=(Coordinates c1, Coordinates c2)
-    {
-        return !(c1 == c2);
-    }
-
-    public override string ToString()
-    {
-        return $"{X}, {Y}";
-    }
-
-    public string ToString(IFormatProvider provider)
-    {
-        return $"{X.ToString(provider)}, {Y.ToString(provider)}";
-    }
-
-    public static explicit operator SKPoint(Coordinates coordinates)
-    {
-        return new SKPoint(coordinates.X, coordinates.Y);
-    }
-
-    public static explicit operator SKPointI(Coordinates coordinates)
-    {
-        return new SKPointI(coordinates.X, coordinates.Y);
-    }
-
-    public override bool Equals(object obj)
-    {
-        return obj is Coordinates coords && this == coords;
-    }
-
-    public override int GetHashCode()
-    {
-        return HashCode.Combine(X, Y);
-    }
-
-    public SKPoint ToSKPoint()
-    {
-        return new SKPoint(X, Y);
-    }
-}

+ 0 - 165
src/PixiEditor/Models/Position/CoordinatesCalculator.cs

@@ -1,165 +0,0 @@
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.Position;
-
-public static class CoordinatesCalculator
-{
-    /// <summary>
-    ///     Calculates center of thickness * thickness rectangle.
-    /// </summary>
-    /// <param name="startPosition">Top left position of rectangle.</param>
-    /// <param name="thickness">Thickness of rectangle.</param>
-    public static DoubleCoords CalculateThicknessCenter(Coordinates startPosition, int thickness)
-    {
-        int x1, x2, y1, y2;
-        if (thickness % 2 == 0)
-        {
-            x2 = startPosition.X + (thickness / 2);
-            y2 = startPosition.Y + (thickness / 2);
-            x1 = x2 - thickness;
-            y1 = y2 - thickness;
-        }
-        else
-        {
-            x2 = startPosition.X + ((thickness - 1) / 2) + 1;
-            y2 = startPosition.Y + ((thickness - 1) / 2) + 1;
-            x1 = x2 - thickness;
-            y1 = y2 - thickness;
-        }
-
-        return new DoubleCoords(new Coordinates(x1, y1), new Coordinates(x2 - 1, y2 - 1));
-    }
-
-    public static Coordinates GetCenterPoint(Coordinates startingPoint, Coordinates endPoint)
-    {
-        int x = (int)Math.Floor((startingPoint.X + endPoint.X) / 2f);
-        int y = (int)Math.Floor((startingPoint.Y + endPoint.Y) / 2f);
-        return new Coordinates(x, y);
-    }
-
-    /// <summary>
-    ///     Calculates coordinates of rectangle by edge points x1, y1, x2, y2.
-    /// </summary>
-    /// <param name="x1">Top left x point.</param>
-    /// <param name="y1">Top left y position.</param>
-    /// <param name="x2">Bottom right x position.</param>
-    /// <param name="y2">Bottom right Y position.</param>
-    public static IEnumerable<Coordinates> RectangleToCoordinates(int x1, int y1, int x2, int y2)
-    {
-        x2++;
-        y2++;
-        List<Coordinates> coordinates = new List<Coordinates>();
-        for (int y = y1; y < y1 + (y2 - y1); y++)
-        {
-            for (int x = x1; x < x1 + (x2 - x1); x++)
-            {
-                coordinates.Add(new Coordinates(x, y));
-            }
-        }
-
-        return coordinates;
-    }
-
-    public static void DrawRectangle(Layer layer, SKColor color, int x1, int y1, int x2, int y2)
-    {
-        //TODO: use some kind of context
-        x2++;
-        y2++;
-        for (int y = y1; y < y1 + (y2 - y1); y++)
-        {
-            for (int x = x1; x < x1 + (x2 - x1); x++)
-            {
-                layer.SetPixelWithOffset(x, y, color);
-            }
-        }
-    }
-
-    public static IEnumerable<Coordinates> RectangleToCoordinates(DoubleCoords coordinates)
-    {
-        return RectangleToCoordinates(coordinates.Coords1.X, coordinates.Coords1.Y, coordinates.Coords2.X, coordinates.Coords2.Y);
-    }
-
-    /// <summary>
-    ///     Returns first pixel coordinates in bitmap that is most top left on canvas.
-    /// </summary>
-    public static Coordinates FindMinEdgeNonTransparentPixel(Surface bitmap)
-    {
-        return new Coordinates(FindMinXNonTransparent(bitmap), FindMinYNonTransparent(bitmap));
-    }
-
-    /// <summary>
-    ///     Returns last pixel coordinates that is most bottom right.
-    /// </summary>
-    public static Coordinates FindMostEdgeNonTransparentPixel(Surface bitmap)
-    {
-        return new Coordinates(FindMaxXNonTransparent(bitmap), FindMaxYNonTransparent(bitmap));
-    }
-
-    public static int FindMinYNonTransparent(Surface bitmap)
-    {
-        for (int y = 0; y < bitmap.Height; y++)
-        {
-            for (int x = 0; x < bitmap.Width; x++)
-            {
-                if (bitmap.GetSRGBPixel(x, y).Alpha != 0)
-                {
-                    return y;
-                }
-            }
-        }
-
-        return -1;
-    }
-
-    public static int FindMinXNonTransparent(Surface bitmap)
-    {
-        for (int x = 0; x < bitmap.Width; x++)
-        {
-            for (int y = 0; y < bitmap.Height; y++)
-            {
-                if (bitmap.GetSRGBPixel(x, y).Alpha != 0)
-                {
-                    return x;
-                }
-            }
-        }
-
-        return -1;
-    }
-
-    public static int FindMaxYNonTransparent(Surface bitmap)
-    {
-        for (int y = bitmap.Height - 1; y >= 0; y--)
-        {
-            for (int x = bitmap.Width - 1; x >= 0; x--)
-            {
-                if (bitmap.GetSRGBPixel(x, y).Alpha != 0)
-                {
-                    return y;
-                }
-            }
-        }
-
-        return -1;
-    }
-
-    public static int FindMaxXNonTransparent(Surface bitmap)
-    {
-        for (int x = bitmap.Width - 1; x >= 0; x--)
-        {
-            for (int y = bitmap.Height - 1; y >= 0; y--)
-            {
-                if (bitmap.GetSRGBPixel(x, y).Alpha != 0)
-                {
-                    return x;
-                }
-            }
-        }
-
-        return -1;
-    }
-}

+ 0 - 14
src/PixiEditor/Models/Position/DoubleCoords.cs

@@ -1,14 +0,0 @@
-namespace PixiEditor.Models.Position;
-
-public struct DoubleCoords
-{
-    public DoubleCoords(Coordinates cords1, Coordinates cords2)
-    {
-        Coords1 = cords1;
-        Coords2 = cords2;
-    }
-
-    public Coordinates Coords1 { get; set; }
-
-    public Coordinates Coords2 { get; set; }
-}

+ 0 - 69
src/PixiEditor/Models/Services/DocumentProvider.cs

@@ -1,69 +0,0 @@
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.Services;
-
-/// <summary>
-/// Provides the active document and it's values like active layer and reference layer
-/// </summary>
-public class DocumentProvider
-{
-    private readonly BitmapManager _bitmapManager;
-
-    public DocumentProvider(BitmapManager bitmapManager)
-    {
-        _bitmapManager = bitmapManager;
-    }
-
-    /// <summary>
-    /// Gets all opened documents
-    /// </summary>
-    public IEnumerable<Document> GetDocuments() => _bitmapManager.Documents;
-
-    /// <summary>
-    /// Gets the active document
-    /// </summary>
-    public Document GetDocument() => _bitmapManager.ActiveDocument;
-
-    /// <summary>
-    /// Get the layers of the opened document
-    /// </summary>
-    public IEnumerable<Layer> GetLayers() => _bitmapManager.ActiveDocument?.Layers;
-
-    /// <summary>
-    /// Gets the layer structure of the opened document
-    /// </summary>
-    public LayerStructure GetStructure() => _bitmapManager.ActiveDocument?.LayerStructure;
-
-    /// <summary>
-    /// Gets the active layer
-    /// </summary>
-    public Layer GetLayer() => _bitmapManager.ActiveLayer;
-
-    /// <summary>
-    /// Gets the surface of the active layer
-    /// </summary>
-    public Surface GetSurface() => _bitmapManager.ActiveLayer?.LayerBitmap;
-
-    /// <summary>
-    /// Gets the reference layer of the active document
-    /// </summary>
-    public Layer GetReferenceLayer() => _bitmapManager.ActiveDocument?.ReferenceLayer;
-
-    /// <summary>
-    /// Gets the reference layer surface of the active document
-    /// </summary>
-    public Surface GetReferenceSurface() => _bitmapManager.ActiveDocument?.ReferenceLayer?.LayerBitmap;
-
-    /// <summary>
-    /// Gets the renderer for the active document
-    /// </summary>
-    public LayerStackRenderer GetRenderer() => _bitmapManager.ActiveDocument?.Renderer;
-
-    /// <summary>
-    /// Gets the renderer for the reference layer of the active document
-    /// </summary>
-    public SingleLayerRenderer GetReferenceRenderer() => _bitmapManager.ActiveDocument?.ReferenceLayerRenderer;
-}

+ 3 - 76
src/PixiEditor/Models/Tools/BitmapOperationTool.cs

@@ -1,37 +1,13 @@
-using System;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using SkiaSharp;
-using System.Collections.Generic;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
+using SkiaSharp;
 
 namespace PixiEditor.Models.Tools;
 
 public abstract class BitmapOperationTool : Tool
 {
-    public bool RequiresPreviewLayer { get; set; }
-
-    public bool ClearPreviewLayerOnEachIteration { get; set; } = true;
-
-    public bool UseDefaultUndoMethod { get; set; } = true;
-
-    public bool UseDocumentRectForUndo { get; set; } = false;
-
-    private SKRectI _rectReportedByTool;
-    private bool _customRectReported = false;
-
-    private StorageBasedChange _change;
-
-    public abstract void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color);
+    public abstract void Use();
 
     public override void BeforeUse()
     {
-        if (UseDefaultUndoMethod && !RequiresPreviewLayer)
-        {
-            InitializeStorageBasedChange(SKRectI.Empty);
-        }
     }
 
     /// <summary>
@@ -40,54 +16,5 @@ public abstract class BitmapOperationTool : Tool
     /// <remarks>When overriding, set UseDefaultUndoMethod to false.</remarks>
     public override void AfterUse(SKRectI sessionRect)
     {
-        if (!UseDefaultUndoMethod)
-            return;
-
-        if (RequiresPreviewLayer)
-        {
-            InitializeStorageBasedChange(sessionRect);
-        }
-
-        var document = ViewModels.ViewModelMain.Current.BitmapManager.ActiveDocument;
-        var args = new object[] { _change.Document };
-        document.UndoManager.AddUndoChange(_change.ToChange(StorageBasedChange.BasicUndoProcess, args));
-        _change = null;
-    }
-
-    protected void ReportCustomSessionRect(SKRectI rect)
-    {
-        _rectReportedByTool = rect;
-        _customRectReported = true;
-    }
-
-    private void InitializeStorageBasedChange(SKRectI toolSessionRect)
-    {
-        Document doc = ViewModels.ViewModelMain.Current.BitmapManager.ActiveDocument;
-        var toolSize = Toolbar.GetSetting<SizeSetting>("ToolSize");
-        SKRectI finalRect = toolSessionRect;
-        if (toolSize != null && toolSize.Value > 1)
-        {
-            int halfSize = (int)Math.Ceiling(toolSize.Value / 2f);
-            finalRect.Inflate(halfSize, halfSize);
-        }
-
-        if (toolSessionRect.IsEmpty)
-        {
-            finalRect = SKRectI.Create(doc.ActiveLayer.OffsetX, doc.ActiveLayer.OffsetY, doc.ActiveLayer.Width, doc.ActiveLayer.Height);
-        }
-
-        if (UseDocumentRectForUndo)
-        {
-            finalRect = SKRectI.Create(0, 0, doc.Width, doc.Height);
-        }
-
-        if (_customRectReported)
-        {
-            _customRectReported = false;
-            finalRect = _rectReportedByTool;
-            _rectReportedByTool = SKRectI.Empty;
-        }
-
-        _change = new StorageBasedChange(doc, new[] { new LayerChunk(doc.ActiveLayer, finalRect) });
     }
-}
+}

+ 0 - 12
src/PixiEditor/Models/Tools/Brushes/Brush.cs

@@ -1,12 +0,0 @@
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.Tools.Brushes;
-
-public abstract class Brush
-{
-    public abstract void Draw(Layer layer, int toolSize, Coordinates coordinates, SKPaint paint);
-}

+ 0 - 21
src/PixiEditor/Models/Tools/Brushes/CircleBrush.cs

@@ -1,21 +0,0 @@
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.Tools;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
-using SkiaSharp;
-using System;
-
-namespace PixiEditor.Models.Tools.Brushes;
-
-public class CircleBrush : Brush
-{
-    public override void Draw(Layer layer, int toolSize, Coordinates coordinates, SKPaint paint)
-    {
-        int halfSize = (int)Math.Ceiling(toolSize / 2f);
-        int modifier = toolSize % 2 != 0 ? 1 : 0;
-        Coordinates topLeft = new Coordinates(coordinates.X - halfSize + modifier, coordinates.Y - halfSize + modifier);
-        Coordinates bottomRight = new Coordinates(coordinates.X + halfSize - 1, coordinates.Y + halfSize - 1);
-
-        CircleTool.DrawEllipseFromCoordinates(layer, topLeft, bottomRight, paint.Color, paint.Color, 1, true);
-    }
-}

+ 0 - 13
src/PixiEditor/Models/Tools/Brushes/CircleBrushOverrides/InterestingShapeBrush.cs

@@ -1,13 +0,0 @@
-namespace PixiEditor.Models.Tools.Brushes;
-
-public class InterestingShapeBrush : MatrixBrush
-{
-    public static readonly int[,] InterestingShapeMatrix = new int[,]
-    {
-        { 1, 1, 1 },
-        { 0, 1, 0 },
-        { 0, 1, 0 }
-    };
-
-    public override int[,] BrushMatrix => InterestingShapeMatrix;
-}

+ 0 - 24
src/PixiEditor/Models/Tools/FloodFillRange.cs

@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace PixiEditor.Models.Tools;
-
-/// <summary>
-/// Represents a linear range to be filled and branched from.
-/// </summary>
-public struct FloodFillRange
-{
-    public int StartX;
-    public int EndX;
-    public int Y;
-
-    public FloodFillRange(int startX, int endX, int y)
-    {
-        StartX = startX;
-        EndX = endX;
-        Y = y;
-    }
-}

+ 0 - 6
src/PixiEditor/Models/Tools/ICachedDocumentTool.cs

@@ -1,6 +0,0 @@
-namespace PixiEditor.Models.Tools;
-
-public interface ICachedDocumentTool
-{
-    public void DocumentChanged();
-}

+ 0 - 93
src/PixiEditor/Models/Tools/MatrixBrush.cs

@@ -1,93 +0,0 @@
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.Brushes;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-
-namespace PixiEditor.Models.Tools;
-
-public abstract class MatrixBrush : Brush
-{
-    public abstract int[,] BrushMatrix { get; }
-
-    public SKPoint[] BakedMatrix => _cachedBakedMatrix;
-
-
-    private SKPoint[] _cachedBakedMatrix;
-    private SKPoint[] _cachedGetAtPointBakedMatrix;
-
-    public MatrixBrush()
-    {
-        InitMatrix();
-    }
-
-    public override void Draw(Layer layer, int toolSize, Coordinates coordinates, SKPaint paint)
-    {
-        layer.LayerBitmap.SkiaSurface.Canvas.DrawPoints(SKPointMode.Points, GetAtPoint(coordinates, layer.OffsetX, layer.OffsetY), paint);
-    }
-
-    //We can easily handle .pixi to brush parsing
-
-    /// <summary>
-    ///     Creates an SKPoint[] array from BrushMatrix. All values grater than 0 will be placed in final array.
-    /// </summary>
-    /// <returns>Points array, ready to be drawn on Skia canvas.</returns>
-    public virtual SKPoint[] BakeMatrix()
-    {
-        List<SKPoint> result = new List<SKPoint>();
-
-        int brushHeight = BrushMatrix.GetLength(0);
-        int brushWidth = BrushMatrix.GetLength(1);
-
-        int centerX = (int)Math.Floor(brushWidth / 2f);
-        int centerY = (int)Math.Floor(brushHeight / 2f);
-
-        for (int i = 0; i < brushHeight; i++)
-        {
-            for (int j = 0; j < brushWidth; j++)
-            {
-                if (BrushMatrix[i, j] > 0)
-                {
-                    result.Add(new SKPoint(centerX - j, centerY - i));
-                }
-            }
-        }
-
-        return result.ToArray();
-    }
-
-    /// <summary>
-    ///     Calculates BrushMatrix for given point.
-    /// </summary>
-    /// <param name="point">Point to calculate BrushMatrix for.</param>
-    /// <returns>SKPoints for given coordinate.</returns>
-    public SKPoint[] GetAtPoint(Coordinates point, int offsetX, int offsetY)
-    {
-        if (_cachedGetAtPointBakedMatrix == null)
-        {
-            InitMatrix();
-        }
-
-        for (int i = 0; i < _cachedGetAtPointBakedMatrix.Length; i++)
-        {
-            _cachedGetAtPointBakedMatrix[i] = new SKPoint(
-                _cachedBakedMatrix[i].X + point.X - offsetX,
-                _cachedBakedMatrix[i].Y + point.Y - offsetY);
-
-        }
-
-        return _cachedGetAtPointBakedMatrix;
-    }
-
-    private void InitMatrix()
-    {
-        if (_cachedBakedMatrix == null)
-        {
-            _cachedBakedMatrix = BakeMatrix();
-            _cachedGetAtPointBakedMatrix = new SKPoint[_cachedBakedMatrix.Length];
-            Array.Copy(_cachedBakedMatrix, _cachedGetAtPointBakedMatrix, BakedMatrix.Length);
-        }
-    }
-
-}

+ 3 - 4
src/PixiEditor/Models/Tools/ReadonlyTool.cs

@@ -1,9 +1,8 @@
-using PixiEditor.Models.Position;
-using System.Collections.Generic;
+using ChunkyImageLib.DataHolders;
 
 namespace PixiEditor.Models.Tools;
 
 public abstract class ReadonlyTool : Tool
 {
-    public abstract void Use(IReadOnlyList<Coordinates> pixels);
-}
+    public abstract void Use(VecD position);
+}

+ 2 - 58
src/PixiEditor/Models/Tools/ShapeTool.cs

@@ -1,69 +1,13 @@
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
+using System.Windows.Input;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using SkiaSharp;
-using System.Collections.Generic;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools;
 
 public abstract class ShapeTool : BitmapOperationTool
 {
-    public static DoubleCoords CalculateCoordinatesForShapeRotation(
-        Coordinates startingCords,
-        Coordinates secondCoordinates)
-    {
-        Coordinates currentCoordinates = secondCoordinates;
-
-        if (startingCords.X > currentCoordinates.X && startingCords.Y > currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(currentCoordinates.X, currentCoordinates.Y),
-                new Coordinates(startingCords.X, startingCords.Y));
-        }
-
-        if (startingCords.X < currentCoordinates.X && startingCords.Y < currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(startingCords.X, startingCords.Y),
-                new Coordinates(currentCoordinates.X, currentCoordinates.Y));
-        }
-
-        if (startingCords.Y > currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(startingCords.X, currentCoordinates.Y),
-                new Coordinates(currentCoordinates.X, startingCords.Y));
-        }
-
-        if (startingCords.X > currentCoordinates.X && startingCords.Y <= currentCoordinates.Y)
-        {
-            return new DoubleCoords(
-                new Coordinates(currentCoordinates.X, startingCords.Y),
-                new Coordinates(startingCords.X, currentCoordinates.Y));
-        }
-
-        return new DoubleCoords(startingCords, secondCoordinates);
-    }
-
     public ShapeTool()
     {
-        RequiresPreviewLayer = true;
         Cursor = Cursors.Cross;
         Toolbar = new BasicShapeToolbar();
     }
-
-    public static void ThickenShape(Layer layer, SKColor color, IEnumerable<Coordinates> shape, int thickness)
-    {
-        foreach (Coordinates item in shape)
-        {
-            ThickenShape(layer, color, item, thickness);
-        }
-    }
-
-    protected static void ThickenShape(Layer layer, SKColor color, Coordinates coords, int thickness)
-    {
-        var dcords = CoordinatesCalculator.CalculateThicknessCenter(coords, thickness);
-        CoordinatesCalculator.DrawRectangle(layer, color, dcords.Coords1.X, dcords.Coords1.Y, dcords.Coords2.X, dcords.Coords2.Y);
-    }
-}
+}

+ 4 - 3
src/PixiEditor/Models/Tools/ToolSettings/Toolbars/SelectToolToolbar.cs

@@ -1,4 +1,5 @@
-using PixiEditor.Models.Enums;
+using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.Models.Enums;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 
 namespace PixiEditor.Models.Tools.ToolSettings.Toolbars;
@@ -7,11 +8,11 @@ public class SelectToolToolbar : Toolbar
 {
     public SelectToolToolbar(bool includeSelectionShape = true)
     {
-        Settings.Add(new EnumSetting<SelectionType>("SelectMode", "Selection type"));
+        Settings.Add(new EnumSetting<SelectionMode>("SelectMode", "Selection type"));
 
         if (includeSelectionShape)
         {
             Settings.Add(new EnumSetting<SelectionShape>("SelectShape", "Selection shape"));
         }
     }
-}
+}

+ 3 - 75
src/PixiEditor/Models/Tools/Tools/BrightnessTool.cs

@@ -1,15 +1,7 @@
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.Colors;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Enums;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using SkiaSharp;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
@@ -19,9 +11,6 @@ public class BrightnessTool : BitmapOperationTool
     private const float CorrectionFactor = 5f; // Initial correction factor
 
     private readonly string defaultActionDisplay = "Draw on pixels to make them brighter. Hold Ctrl to darken.";
-    private readonly List<Coordinates> pixelsVisited = new List<Coordinates>();
-    private List<DoubleCoords> circleCache = new List<DoubleCoords>();
-    private int cachedCircleSize = -1;
 
     public BrightnessTool()
     {
@@ -41,69 +30,8 @@ public class BrightnessTool : BitmapOperationTool
             ActionDisplay = "Draw on pixels to make them darker. Release Ctrl to brighten.";
     }
 
-    public override void BeforeUse()
+    public override void Use()
     {
-        base.BeforeUse();
-        pixelsVisited.Clear();
-    }
-
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
-    {
-        int toolSize = Toolbar.GetSetting<SizeSetting>("ToolSize").Value;
-        float correctionFactor = Toolbar.GetSetting<FloatSetting>("CorrectionFactor").Value;
-        Mode = Toolbar.GetEnumSetting<BrightnessMode>("BrightnessMode").Value;
-
-        if (Session.IsCtrlDown)
-        {
-            ChangeBrightness(activeLayer, recordedMouseMovement[^1], toolSize, -correctionFactor);
-        }
-        else
-        {
-            ChangeBrightness(activeLayer, recordedMouseMovement[^1], toolSize, correctionFactor);
-        }
-    }
-
-    private void ChangeBrightness(Layer layer, Coordinates coordinates, int toolSize, float correctionFactor)
-    {
-        if (cachedCircleSize != toolSize)
-            UpdateCircleCache(toolSize);
 
-        int radius = (int)Math.Ceiling(toolSize / 2f);
-        Int32Rect dirtyRect = new(coordinates.X - radius, coordinates.Y - radius, radius * 2, radius * 2);
-        layer.DynamicResizeAbsolute(dirtyRect);
-
-        foreach (var pair in circleCache)
-        {
-            Coordinates left = pair.Coords1;
-            Coordinates right = pair.Coords2;
-            int y = left.Y + coordinates.Y;
-
-            for (int x = left.X + coordinates.X; x <= right.X + coordinates.X; x++)
-            {
-                if (Mode == BrightnessMode.Default)
-                {
-                    Coordinates here = new(x, y);
-                    if (pixelsVisited.Contains(here))
-                        continue;
-
-                    pixelsVisited.Add(here);
-                }
-
-                SKColor pixel = layer.GetPixelWithOffset(x, y);
-                SKColor newColor = ExColor.ChangeColorBrightness(
-                    pixel,
-                    correctionFactor);
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(x - layer.OffsetX, y - layer.OffsetY, newColor);
-            }
-        }
-        layer.InvokeLayerBitmapChange(dirtyRect);
-    }
-
-    private void UpdateCircleCache(int newCircleSize)
-    {
-        cachedCircleSize = newCircleSize;
-        DoubleCoords rect = CoordinatesCalculator.CalculateThicknessCenter(new Coordinates(0, 0), newCircleSize);
-        List<Coordinates> circle = EllipseGenerator.GenerateEllipseFromRect(rect);
-        circleCache = EllipseGenerator.SplitEllipseIntoLines(circle);
     }
-}
+}

+ 3 - 101
src/PixiEditor/Models/Tools/Tools/CircleTool.cs

@@ -1,15 +1,5 @@
-using PixiEditor.Helpers;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows;
-using System.Windows.Input;
-using System.Windows.Media;
 
 namespace PixiEditor.Models.Tools.Tools;
 
@@ -33,96 +23,8 @@ public class CircleTool : ShapeTool
             ActionDisplay = defaultActionDisplay;
     }
 
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
+    public override void Use()
     {
-        int thickness = Toolbar.GetSetting<SizeSetting>("ToolSize").Value;
-        var hasFillColor = Toolbar.GetSetting<BoolSetting>("Fill").Value;
-        Color temp = Toolbar.GetSetting<ColorSetting>("FillColor").Value;
-        SKColor fill = new SKColor(temp.R, temp.G, temp.B, temp.A);
 
-        var (start, end) = Session.IsShiftDown ?
-            CoordinatesHelper.GetSquareCoordiantes(recordedMouseMovement) :
-            (recordedMouseMovement[0], recordedMouseMovement[^1]);
-
-        var dirtyRect = DrawEllipseFromCoordinates(previewLayer, start, end, color, fill, thickness, hasFillColor);
-        ReportCustomSessionRect(SKRectI.Create(dirtyRect.X, dirtyRect.Y, dirtyRect.Width, dirtyRect.Height));
-    }
-
-    public static Int32Rect DrawEllipseFromCoordinates(Layer layer, Coordinates first, Coordinates second,
-        SKColor color, SKColor fillColor, int thickness, bool hasFillColor)
-    {
-        DoubleCoords corners = CalculateCoordinatesForShapeRotation(first, second);
-        corners.Coords2 = new(corners.Coords2.X, corners.Coords2.Y);
-
-        int halfThickness = (int)Math.Ceiling(thickness / 2.0);
-        Int32Rect dirtyRect = new Int32Rect(
-            corners.Coords1.X - halfThickness,
-            corners.Coords1.Y - halfThickness,
-            corners.Coords2.X + halfThickness * 2 - corners.Coords1.X,
-            corners.Coords2.Y + halfThickness * 2 - corners.Coords1.Y);
-        layer.DynamicResizeAbsolute(dirtyRect);
-
-        using (SKPaint paint = new SKPaint())
-        {
-            List<Coordinates> outline = EllipseGenerator.GenerateEllipseFromRect(corners);
-            if (hasFillColor)
-            {
-                DrawEllipseFill(layer, fillColor, outline);
-            }
-            DrawEllipseOutline(layer, color, outline, thickness);
-
-            // An Idea, use Skia DrawOval for bigger sizes.
-        }
-
-        layer.InvokeLayerBitmapChange(dirtyRect);
-        return dirtyRect;
-    }
-
-    public static void DrawEllipseFill(Layer layer, SKColor color, List<Coordinates> outlineCoordinates)
-    {
-        if (!outlineCoordinates.Any())
-            return;
-
-        int bottom = outlineCoordinates.Max(x => x.Y);
-        int top = outlineCoordinates.Min(x => x.Y);
-
-        using SKPaint fillPaint = new();
-        fillPaint.Color = color;
-        fillPaint.BlendMode = SKBlendMode.Src;
-
-        for (int i = top + 1; i < bottom; i++)
-        {
-            IEnumerable<Coordinates> rowCords = outlineCoordinates.Where(x => x.Y == i);
-            int right = rowCords.Max(x => x.X);
-            int left = rowCords.Min(x => x.X);
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawLine(left - layer.OffsetX, i - layer.OffsetY, right - layer.OffsetX, i - layer.OffsetY, fillPaint);
-        }
-    }
-
-    /// <summary>
-    ///     Calculates ellipse points for specified coordinates and thickness.
-    /// </summary>
-    /// <param name="thickness">Thickness of ellipse.</param>
-    public static void DrawEllipseOutline(Layer layer, SKColor color, List<Coordinates> ellipse, int thickness)
-    {
-        if (thickness == 1)
-        {
-            foreach (var coords in ellipse)
-            {
-                layer.LayerBitmap.SetSRGBPixel(coords.X - layer.OffsetX, coords.Y - layer.OffsetY, color);
-            }
-        }
-        else
-        {
-            using SKPaint paint = new();
-            paint.Color = color;
-            paint.BlendMode = SKBlendMode.Src;
-            float offsetX = thickness % 2 == 1 ? layer.OffsetX - 0.5f : layer.OffsetX;
-            float offsetY = thickness % 2 == 1 ? layer.OffsetY - 0.5f : layer.OffsetY;
-            foreach (var coords in ellipse)
-            {
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawCircle(coords.X - offsetX, coords.Y - offsetY, thickness / 2f, paint);
-            }
-        }
     }
-}
+}

+ 9 - 93
src/PixiEditor/Models/Tools/Tools/ColorPickerTool.cs

@@ -1,27 +1,19 @@
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.ImageManipulation;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Services;
-using PixiEditor.ViewModels;
-using SkiaSharp;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.O, Transient = Key.LeftAlt)]
 internal class ColorPickerTool : ReadonlyTool
 {
-    private readonly DocumentProvider _docProvider;
     private readonly BitmapManager _bitmapManager;
     private readonly string defaultActionDisplay = "Click to pick colors. Hold Ctrl to hide the canvas. Hold Shift to hide the reference layer";
 
-    public ColorPickerTool(DocumentProvider documentProvider, BitmapManager bitmapManager)
+    public ColorPickerTool(BitmapManager bitmapManager)
     {
         ActionDisplay = defaultActionDisplay;
-        _docProvider = documentProvider;
         _bitmapManager = bitmapManager;
     }
 
@@ -31,87 +23,6 @@ internal class ColorPickerTool : ReadonlyTool
 
     public override string Tooltip => $"Picks the primary color from the canvas. ({Shortcut})";
 
-    public override void Use(IReadOnlyList<Coordinates> recordedMouseMovement)
-    {
-        var coords = recordedMouseMovement[^1];
-        var doc = _docProvider.GetDocument();
-        if (coords.X < 0 || coords.Y < 0 || coords.X >= doc.Width || coords.Y >= doc.Height)
-            return;
-
-        ViewModelMain.Current.ColorsSubViewModel.PrimaryColor = GetColorAt(coords.X, coords.Y);
-    }
-
-    public SKColor GetColorAt(int x, int y)
-    {
-        Layer referenceLayer = _docProvider.GetReferenceLayer();
-
-        if (referenceLayer != null && referenceLayer.IsVisible)
-        {
-            double preciseX = _docProvider.GetDocument().MouseXOnCanvas;
-            double preciseY = _docProvider.GetDocument().MouseYOnCanvas;
-
-            if (Session.IsCtrlDown)
-                return GetReferenceColor(preciseX, preciseY);
-            if (Session.IsShiftDown)
-                return GetCanvasColor(x, y);
-            return GetCombinedColor(x, y, preciseX, preciseY);
-        }
-
-        return GetCanvasColor(x, y);
-    }
-
-    private SKColor GetCombinedColor(int x, int y, double preciseX, double preciseY)
-    {
-        SKColor top = GetCanvasColor(x, y);
-        SKColor bottom = GetReferenceColor(preciseX, preciseY);
-        return BitmapUtils.BlendColors(bottom, top);
-    }
-
-    private SKColor GetCanvasColor(int x, int y)
-    {
-        return _docProvider.GetRenderer()?.FinalSurface.GetSRGBPixel(x, y) ?? SKColors.Transparent;
-    }
-
-    private SKColor GetReferenceColor(double x, double y)
-    {
-        Document activeDocument = _docProvider.GetDocument();
-        Layer referenceLayer = _docProvider.GetReferenceLayer();
-        Coordinates refPos = CanvasSpaceToReferenceSpace(
-            x, y,
-            activeDocument.Width, activeDocument.Height,
-            referenceLayer.Width, referenceLayer.Height);
-
-        if (refPos.X >= 0 && refPos.Y >= 0 && refPos.X < referenceLayer.Width && refPos.Y < referenceLayer.Height)
-            return referenceLayer.LayerBitmap.GetSRGBPixel(refPos.X, refPos.Y);
-        return SKColors.Transparent;
-    }
-
-    private Coordinates CanvasSpaceToReferenceSpace(double canvasX, double canvasY, int canvasW, int canvasH, int referenceW, int referenceH)
-    {
-        double canvasRatio = canvasW / (double)canvasH;
-        double referenceRatio = referenceW / (double)referenceH;
-        bool blackBarsAreOnTopAndBottom = referenceRatio > canvasRatio;
-        if (blackBarsAreOnTopAndBottom)
-        {
-            double combinedBlackBarsHeight = (1 - canvasRatio / referenceRatio) * canvasH;
-            double refScale = referenceH / ((double)canvasH - combinedBlackBarsHeight);
-
-            int outX = (int)Math.Floor(canvasX * referenceW / canvasW);
-            int outY = (int)Math.Floor((canvasY - combinedBlackBarsHeight / 2) * refScale);
-
-            return new Coordinates(outX, outY);
-        }
-        else
-        {
-            double combinedBlackBarsWidth = (1 - referenceRatio / canvasRatio) * canvasW;
-            double refScale = referenceW / ((double)canvasW - combinedBlackBarsWidth);
-
-            int outX = (int)Math.Floor((canvasX - combinedBlackBarsWidth / 2) * refScale);
-            int outY = (int)Math.Floor(canvasY * referenceH / canvasH);
-            return new Coordinates(outX, outY);
-        }
-    }
-
     public override void UpdateActionDisplay(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     {
         if (!IsActive)
@@ -141,4 +52,9 @@ internal class ColorPickerTool : ReadonlyTool
             ActionDisplay = defaultActionDisplay;
         }
     }
-}
+
+    public override void Use(VecD position)
+    {
+
+    }
+}

+ 4 - 14
src/PixiEditor/Models/Tools/Tools/EraserTool.cs

@@ -1,11 +1,7 @@
-using PixiEditor.Models.Commands.Attributes;
+using System.Windows.Input;
+using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using SkiaSharp;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
@@ -23,14 +19,8 @@ internal class EraserTool : BitmapOperationTool
 
     public override string Tooltip => $"Erasers color from pixel. ({Shortcut})";
 
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
+    public override void Use()
     {
-        Erase(activeLayer, recordedMouseMovement, Toolbar.GetSetting<SizeSetting>("ToolSize").Value);
-    }
 
-    public void Erase(Layer layer, IReadOnlyList<Coordinates> coordinates, int toolSize)
-    {
-        Coordinates startingCords = coordinates.Count > 1 ? coordinates[^2] : coordinates[0];
-        pen.Draw(layer, startingCords, coordinates[^1], SKColors.Transparent, toolSize, false, null, SKBlendMode.Src);
     }
-}
+}

+ 5 - 116
src/PixiEditor/Models/Tools/Tools/FloodFillTool.cs

@@ -1,134 +1,23 @@
-using PixiEditor.Helpers.Extensions;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
 using SkiaSharp;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.G)]
 internal class FloodFillTool : BitmapOperationTool
 {
-    private BitmapManager BitmapManager { get; }
     private SKPaint fillPaint = new SKPaint() { BlendMode = SKBlendMode.Src };
 
-    public FloodFillTool(BitmapManager bitmapManager)
+    public FloodFillTool()
     {
         ActionDisplay = "Press on an area to fill it.";
-        BitmapManager = bitmapManager;
-        UseDocumentRectForUndo = true;
     }
 
     public override string Tooltip => $"Fills area with color. ({Shortcut})";
 
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
+    public override void Use()
     {
-        if (activeLayer.IsReset)
-        {
-            activeLayer.DynamicResizeAbsolute(new(0, 0, BitmapManager.ActiveDocument.Width, BitmapManager.ActiveDocument.Height));
-            activeLayer.LayerBitmap.SkiaSurface.Canvas.Clear(color);
-            activeLayer.InvokeLayerBitmapChange();
-        }
-        else
-        {
-            LinearFill(activeLayer, recordedMouseMovement[^1], color);
-        }
+        throw new NotImplementedException();
     }
-
-    public void LinearFill(Layer layer, Coordinates startingCoords, SKColor newColor)
-    {
-        Queue<FloodFillRange> floodFillQueue = new Queue<FloodFillRange>();
-        SKColor colorToReplace = layer.GetPixelWithOffset(startingCoords.X, startingCoords.Y);
-        if ((colorToReplace.Alpha == 0 && newColor.Alpha == 0) ||
-            colorToReplace == newColor)
-            return;
-
-        int width = BitmapManager.ActiveDocument.Width;
-        int height = BitmapManager.ActiveDocument.Height;
-        if (startingCoords.X < 0 || startingCoords.Y < 0 || startingCoords.X >= width || startingCoords.Y >= height)
-            return;
-        var visited = new bool[width * height];
-
-        fillPaint.Color = newColor;
-
-        Int32Rect dirtyRect = new Int32Rect(startingCoords.X, startingCoords.Y, 1, 1);
-
-        PerformLinearFill(layer, floodFillQueue, startingCoords, width, colorToReplace, ref dirtyRect, visited);
-        PerformFloodFIll(layer, floodFillQueue, colorToReplace, ref dirtyRect, width, height, visited);
-
-        layer.InvokeLayerBitmapChange(dirtyRect);
-    }
-
-    private void PerformLinearFill(
-        Layer layer, Queue<FloodFillRange> floodFillQueue,
-        Coordinates coords, int width, SKColor colorToReplace, ref Int32Rect dirtyRect, bool[] visited)
-    {
-        // Find the Left Edge of the Color Area
-        int fillXLeft = coords.X;
-        while (true)
-        {
-            // Indicate that this pixel has been checked
-            int pixelIndex = (coords.Y * width) + fillXLeft;
-            visited[pixelIndex] = true;
-
-            // Move one pixel to the left
-            fillXLeft--;
-            // Exit the loop if we're at edge of the bitmap or the color area
-            if (fillXLeft < 0 || visited[pixelIndex - 1] || layer.GetPixelWithOffset(fillXLeft, coords.Y) != colorToReplace)
-                break;
-        }
-        int lastCheckedPixelLeft = fillXLeft + 1;
-
-        // Find the Right Edge of the Color Area
-        int fillXRight = coords.X;
-        while (true)
-        {
-            int pixelIndex = (coords.Y * width) + fillXRight;
-            visited[pixelIndex] = true;
-
-            fillXRight++;
-            if (fillXRight >= width || visited[pixelIndex + 1] || layer.GetPixelWithOffset(fillXRight, coords.Y) != colorToReplace)
-                break;
-        }
-        int lastCheckedPixelRight = fillXRight - 1;
-
-        layer.DynamicResizeAbsolute(new(lastCheckedPixelLeft, coords.Y, lastCheckedPixelRight - lastCheckedPixelLeft + 1, 1));
-        int relativeY = coords.Y - layer.OffsetY;
-        layer.LayerBitmap.SkiaSurface.Canvas.DrawLine(lastCheckedPixelLeft - layer.OffsetX, relativeY, lastCheckedPixelRight - layer.OffsetX + 1, relativeY, fillPaint);
-        dirtyRect = dirtyRect.Expand(new Int32Rect(lastCheckedPixelLeft, coords.Y, lastCheckedPixelRight - lastCheckedPixelLeft + 1, 1));
-
-        FloodFillRange range = new FloodFillRange(lastCheckedPixelLeft, lastCheckedPixelRight, coords.Y);
-        floodFillQueue.Enqueue(range);
-    }
-
-    private void PerformFloodFIll(
-        Layer layer, Queue<FloodFillRange> floodFillQueue,
-        SKColor colorToReplace, ref Int32Rect dirtyRect, int width, int height, bool[] pixelsVisited)
-    {
-        while (floodFillQueue.Count > 0)
-        {
-            FloodFillRange range = floodFillQueue.Dequeue();
-
-            //START THE LOOP UPWARDS AND DOWNWARDS
-            int upY = range.Y - 1; //so we can pass the y coord by ref
-            int downY = range.Y + 1;
-            int downPixelxIndex = (width * (range.Y + 1)) + range.StartX;
-            int upPixelIndex = (width * (range.Y - 1)) + range.StartX;
-            for (int i = range.StartX; i <= range.EndX; i++)
-            {
-                //START LOOP UPWARDS
-                //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
-                if (range.Y > 0 && (!pixelsVisited[upPixelIndex]) && layer.GetPixelWithOffset(i, upY) == colorToReplace)
-                    PerformLinearFill(layer, floodFillQueue, new Coordinates(i, upY), width, colorToReplace, ref dirtyRect, pixelsVisited);
-                //START LOOP DOWNWARDS
-                if (range.Y < (height - 1) && (!pixelsVisited[downPixelxIndex]) && layer.GetPixelWithOffset(i, downY) == colorToReplace)
-                    PerformLinearFill(layer, floodFillQueue, new Coordinates(i, downY), width, colorToReplace, ref dirtyRect, pixelsVisited);
-                downPixelxIndex++;
-                upPixelIndex++;
-            }
-        }
-    }
-}
+}

+ 4 - 248
src/PixiEditor/Models/Tools/Tools/LineTool.cs

@@ -1,23 +1,12 @@
-using PixiEditor.Helpers;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using SkiaSharp;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.L)]
 public class LineTool : ShapeTool
 {
-    private List<Coordinates> linePoints = new List<Coordinates>();
-    private SKPaint paint = new SKPaint() { Style = SKPaintStyle.Stroke };
-
-    public bool AutomaticallyResizeCanvas { get; set; } = true;
-
     private string defaltActionDisplay = "Click and move to draw a line. Hold Shift to draw an even one.";
 
     public LineTool()
@@ -36,241 +25,8 @@ public class LineTool : ShapeTool
             ActionDisplay = defaltActionDisplay;
     }
 
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
-    {
-        int thickness = Toolbar.GetSetting<SizeSetting>("ToolSize").Value;
-
-        Coordinates start = recordedMouseMovement[0];
-        Coordinates end = recordedMouseMovement[^1];
-
-        if (Session.IsShiftDown)
-            (start, end) = CoordinatesHelper.GetSquareOrLineCoordinates(recordedMouseMovement);
-
-        var dirtyRect = DrawLine(previewLayer, start, end, color, thickness, SKBlendMode.Src);
-        ReportCustomSessionRect(SKRectI.Create(dirtyRect.X, dirtyRect.Y, dirtyRect.Width, dirtyRect.Height));
-    }
-
-    public Int32Rect DrawLine(
-        Layer layer, Coordinates start, Coordinates end, SKColor color, int thickness, SKBlendMode blendMode,
-        SKStrokeCap strokeCap = SKStrokeCap.Butt)
-    {
-        int x = start.X;
-        int y = start.Y;
-        int x1 = end.X;
-        int y1 = end.Y;
-
-        int dirtyX = Math.Min(x, x1) - thickness;
-        int dirtyY = Math.Min(y, y1) - thickness;
-
-        Int32Rect dirtyRect = new Int32Rect(
-            dirtyX,
-            dirtyY,
-            Math.Max(x1, x) + thickness - dirtyX,
-            Math.Max(y1, y) + thickness - dirtyY);
-        if (AutomaticallyResizeCanvas)
-        {
-            layer.DynamicResizeAbsolute(dirtyRect);
-        }
-
-        x -= layer.OffsetX;
-        y -= layer.OffsetY;
-        x1 -= layer.OffsetX;
-        y1 -= layer.OffsetY;
-
-        paint.StrokeWidth = thickness;
-        paint.Color = color;
-        paint.BlendMode = blendMode;
-        paint.StrokeCap = strokeCap;
-
-        if (thickness == 1)
-        {
-            DrawBresenhamLine(layer, x, y, x1, y1, paint);
-        }
-        else
-        {
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawLine(x, y, x1, y1, paint);
-        }
-
-        layer.InvokeLayerBitmapChange(dirtyRect);
-        return dirtyRect;
-    }
-
-    private void DrawBresenhamLine(Layer layer, int x1, int y1, int x2, int y2, SKPaint paint)
-    {
-        if (x1 == x2 && y1 == y2)
-        {
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(x1, y1, paint);
-            return;
-        }
-
-        int d, dx, dy, ai, bi, xi, yi;
-        int x = x1, y = y1;
-
-        if (x1 < x2)
-        {
-            xi = 1;
-            dx = x2 - x1;
-        }
-        else
-        {
-            xi = -1;
-            dx = x1 - x2;
-        }
-
-        if (y1 < y2)
-        {
-            yi = 1;
-            dy = y2 - y1;
-        }
-        else
-        {
-            yi = -1;
-            dy = y1 - y2;
-        }
-
-        layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(x, y, paint);
-
-        if (dx > dy)
-        {
-            ai = (dy - dx) * 2;
-            bi = dy * 2;
-            d = bi - dx;
-
-            while (x != x2)
-            {
-                if (d >= 0)
-                {
-                    x += xi;
-                    y += yi;
-                    d += ai;
-                }
-                else
-                {
-                    d += bi;
-                    x += xi;
-                }
-
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(x, y, paint);
-            }
-        }
-        else
-        {
-            ai = (dx - dy) * 2;
-            bi = dx * 2;
-            d = bi - dy;
-
-            while (y != y2)
-            {
-                if (d >= 0)
-                {
-                    x += xi;
-                    y += yi;
-                    d += ai;
-                }
-                else
-                {
-                    d += bi;
-                    y += yi;
-                }
-
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(x, y, paint);
-            }
-        }
-    }
-
-
-    public static List<Coordinates> GetBresenhamLine(Coordinates start, Coordinates end)
-    {
-        List<Coordinates> output = new List<Coordinates>();
-        CalculateBresenhamLine(start, end, output);
-        return output;
-    }
-
-    public static void CalculateBresenhamLine(Coordinates start, Coordinates end, List<Coordinates> output)
+    public override void Use()
     {
-        int x1 = start.X;
-        int x2 = end.X;
-        int y1 = start.Y;
-        int y2 = end.Y;
-
-        if (x1 == x2 && y1 == y2)
-        {
-            output.Add(start);
-            return;
-        }
-
-        int d, dx, dy, ai, bi, xi, yi;
-        int x = x1, y = y1;
-
-        if (x1 < x2)
-        {
-            xi = 1;
-            dx = x2 - x1;
-        }
-        else
-        {
-            xi = -1;
-            dx = x1 - x2;
-        }
-
-        if (y1 < y2)
-        {
-            yi = 1;
-            dy = y2 - y1;
-        }
-        else
-        {
-            yi = -1;
-            dy = y1 - y2;
-        }
-
-        output.Add(new Coordinates(x, y));
-
-        if (dx > dy)
-        {
-            ai = (dy - dx) * 2;
-            bi = dy * 2;
-            d = bi - dx;
-
-            while (x != x2)
-            {
-                if (d >= 0)
-                {
-                    x += xi;
-                    y += yi;
-                    d += ai;
-                }
-                else
-                {
-                    d += bi;
-                    x += xi;
-                }
-
-                output.Add(new Coordinates(x, y));
-            }
-        }
-        else
-        {
-            ai = (dx - dy) * 2;
-            bi = dx * 2;
-            d = bi - dy;
-
-            while (y != y2)
-            {
-                if (d >= 0)
-                {
-                    x += xi;
-                    y += yi;
-                    d += ai;
-                }
-                else
-                {
-                    d += bi;
-                    y += yi;
-                }
-
-                output.Add(new Coordinates(x, y));
-            }
-        }
+        throw new NotImplementedException();
     }
-}
+}

+ 5 - 76
src/PixiEditor/Models/Tools/Tools/MagicWandTool.cs

@@ -1,95 +1,24 @@
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.ImageManipulation;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using PixiEditor.ViewModels;
-using SkiaSharp;
-using System.Collections.ObjectModel;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.W)]
-internal class MagicWandTool : ReadonlyTool, ICachedDocumentTool
+internal class MagicWandTool : ReadonlyTool
 {
-    private static Selection ActiveSelection { get => ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection; }
-
-    private BitmapManager BitmapManager { get; }
-
-    private IEnumerable<Coordinates> oldSelection;
-    private List<Coordinates> newSelection = new List<Coordinates>();
-
     public override string Tooltip => $"Magic Wand ({Shortcut}). Flood's the selection";
 
-    private Layer cachedDocument;
-
     public MagicWandTool(BitmapManager manager)
     {
-        BitmapManager = manager;
-
         Toolbar = new MagicWandToolbar();
-
         ActionDisplay = "Click to flood the selection.";
     }
 
-    public override void Use(IReadOnlyList<Coordinates> pixels)
+    public override void Use(VecD position)
     {
-        if (pixels.Count > 1)
-            return;
-
-        oldSelection = new ReadOnlyCollection<Coordinates>(ActiveSelection.SelectedPoints);
-
-        SelectionType selectionType = Toolbar.GetEnumSetting<SelectionType>("SelectMode").Value;
-        DocumentScope documentScope = Toolbar.GetEnumSetting<DocumentScope>(nameof(DocumentScope)).Value;
-
-        Document document = BitmapManager.ActiveDocument;
-        Layer layer;
-
-        if (documentScope == DocumentScope.SingleLayer)
-        {
-            layer = BitmapManager.ActiveLayer;
-        }
-        else
-        {
-            ValidateCache(document);
-            layer = cachedDocument;
-        }
-
-        Selection selection = BitmapManager.ActiveDocument.ActiveSelection;
 
-
-        newSelection.Clear();
-
-        ToolCalculator.GetLinearFillAbsolute(
-            layer,
-            pixels[0],
-            BitmapManager.ActiveDocument.Width,
-            BitmapManager.ActiveDocument.Height,
-            SKColors.White,
-            newSelection);
-
-        selection.SetSelection(newSelection, selectionType);
-
-        SelectionHelpers.AddSelectionUndoStep(ViewModelMain.Current.BitmapManager.ActiveDocument, oldSelection, selectionType);
-    }
-
-    public void DocumentChanged()
-    {
-        cachedDocument = null;
-    }
-
-    private void ValidateCache(Document document)
-    {
-        cachedDocument ??= new Layer("_CombinedLayers", BitmapUtils.CombineLayers(
-            new Int32Rect(0, 0, document.Width, document.Height),
-            document.Layers,
-            document.LayerStructure), document.Width, document.Height);
     }
-}
+}

+ 3 - 164
src/PixiEditor/Models/Tools/Tools/MoveTool.cs

@@ -1,51 +1,24 @@
-using PixiEditor.Helpers;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.ImageManipulation;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Undo;
-using SkiaSharp;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.V)]
 internal class MoveTool : BitmapOperationTool
 {
-    private Layer[] affectedLayers;
-    private Surface[] currentlyDragged;
-    private Coordinates[] currentlyDraggedPositions;
-    private Surface previewLayerData;
-
-    private List<Coordinates> moveStartSelectedPoints = null;
-    private Int32Rect moveStartRect;
-
-    private Coordinates lastDragDelta;
-
-    private StorageBasedChange change;
-
     private string defaultActionDisplay = "Hold mouse to move selected pixels. Hold Ctrl to move all layers.";
 
     public MoveTool(BitmapManager bitmapManager)
     {
         ActionDisplay = defaultActionDisplay;
         Cursor = Cursors.Arrow;
-        RequiresPreviewLayer = true;
-        UseDefaultUndoMethod = false;
-
-        BitmapManager = bitmapManager;
     }
 
     public override string Tooltip => $"Moves selected pixels ({Shortcut}). Hold Ctrl to move all layers.";
 
     public override bool HideHighlight => true;
 
-    private BitmapManager BitmapManager { get; }
-
     public override void UpdateActionDisplay(bool ctrlIsDown, bool shiftIsDown, bool altIsDown)
     {
         if (ctrlIsDown)
@@ -54,142 +27,8 @@ internal class MoveTool : BitmapOperationTool
             ActionDisplay = defaultActionDisplay;
     }
 
-    public override void BeforeUse()
-    {
-        Document doc = BitmapManager.ActiveDocument;
-        Selection selection = doc.ActiveSelection;
-        bool anySelection = selection.SelectedPoints.Any();
-
-        if (Session.IsCtrlDown)
-        {
-            affectedLayers = doc.Layers.Where(x => x.IsVisible).ToArray();
-        }
-        else
-        {
-            affectedLayers = doc.Layers.Where(x => x.IsActive && doc.GetFinalLayerIsVisible(x)).ToArray();
-        }
-
-        change = new StorageBasedChange(doc, affectedLayers, true, true);
-
-        Layer selLayer = selection.SelectionLayer;
-        moveStartRect = anySelection ?
-            new(selLayer.OffsetX, selLayer.OffsetY, selLayer.Width, selLayer.Height) :
-            new(0, 0, doc.Width, doc.Height);
-        lastDragDelta = new Coordinates(0, 0);
-
-        previewLayerData?.Dispose();
-        previewLayerData = CreateCombinedPreview(anySelection ? selLayer : null, affectedLayers);
-
-        if (currentlyDragged != null)
-        {
-            foreach (var surface in currentlyDragged)
-                surface.Dispose();
-        }
-
-        if (anySelection)
-        {
-            currentlyDragged = BitmapUtils.ExtractSelectedPortions(selLayer, affectedLayers, true);
-            currentlyDraggedPositions = Enumerable.Repeat(new Coordinates(selLayer.OffsetX, selLayer.OffsetY), affectedLayers.Length).ToArray();
-        }
-        else
-        {
-            (currentlyDraggedPositions, currentlyDragged) = CutDraggedLayers(affectedLayers);
-        }
-
-        if (anySelection)
-            moveStartSelectedPoints = selection.SelectedPoints.ToList();
-    }
-
-    private Surface CreateCombinedPreview(Layer selLayer, Layer[] layersToCombine)
-    {
-        var combined = BitmapUtils.CombineLayers(moveStartRect, layersToCombine, BitmapManager.ActiveDocument.LayerStructure);
-        if (selLayer != null)
-        {
-            using var selSnap = selLayer.LayerBitmap.SkiaSurface.Snapshot();
-            combined.SkiaSurface.Canvas.DrawImage(selSnap, 0, 0, Surface.MaskingPaint);
-        }
-        return combined;
-    }
-
-    private static (Coordinates[], Surface[]) CutDraggedLayers(Layer[] draggedLayers)
-    {
-        Surface[] outSurfaces = new Surface[draggedLayers.Length];
-        Coordinates[] outCoords = new Coordinates[draggedLayers.Length];
-
-        int count = 0;
-        foreach (var layer in draggedLayers)
-        {
-            outCoords[count] = new Coordinates(layer.OffsetX, layer.OffsetY);
-            Surface copy = new(layer.Width, layer.Height);
-            layer.LayerBitmap.SkiaSurface.Draw(copy.SkiaSurface.Canvas, 0, 0, Surface.ReplacingPaint);
-            layer.LayerBitmap.SkiaSurface.Canvas.Clear();
-            layer.InvokeLayerBitmapChange();
-            outSurfaces[count] = copy;
-            count++;
-        }
-
-        return (outCoords, outSurfaces);
-    }
-
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
-    {
-        Coordinates newPos = recordedMouseMovement[^1];
-        Coordinates moveStartPos = recordedMouseMovement[0];
-        int dX = newPos.X - moveStartPos.X;
-        int dY = newPos.Y - moveStartPos.Y;
-        BitmapManager.ActiveDocument.ActiveSelection.TranslateSelection(dX - lastDragDelta.X, dY - lastDragDelta.Y);
-        lastDragDelta = new Coordinates(dX, dY);
-
-
-        int newX = moveStartRect.X + dX;
-        int newY = moveStartRect.Y + dY;
-
-        Int32Rect dirtyRect = new Int32Rect(newX, newY, moveStartRect.Width, moveStartRect.Height);
-        previewLayer.DynamicResizeAbsolute(dirtyRect);
-        previewLayerData.SkiaSurface.Draw(previewLayer.LayerBitmap.SkiaSurface.Canvas, newX - previewLayer.OffsetX, newY - previewLayer.OffsetY, Surface.ReplacingPaint);
-        previewLayer.InvokeLayerBitmapChange(dirtyRect);
-    }
-
-    public override void AfterUse(SKRectI sessionRect)
-    {
-        base.AfterUse(sessionRect);
-        BitmapManager.ActiveDocument.PreviewLayer.ClearCanvas();
-
-        ApplySurfacesToLayers(currentlyDragged, currentlyDraggedPositions, affectedLayers, new Coordinates(lastDragDelta.X, lastDragDelta.Y));
-        foreach (var surface in currentlyDragged)
-            surface.Dispose();
-        currentlyDragged = null;
-
-        SaveUndo(BitmapManager.ActiveDocument);
-    }
-
-    private static void ApplySurfacesToLayers(Surface[] surfaces, Coordinates[] startPositions, Layer[] layers, Coordinates delta)
+    public override void Use()
     {
-        int count = 0;
-        foreach (Surface surface in surfaces)
-        {
-            var layer = layers[count];
-            using SKImage snapshot = surface.SkiaSurface.Snapshot();
-            Coordinates position = new Coordinates(startPositions[count].X + delta.X, startPositions[count].Y + delta.Y);
-            Int32Rect dirtyRect = new Int32Rect(position.X, position.Y, surface.Width, surface.Height);
-            layer.DynamicResizeAbsolute(dirtyRect);
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawImage(snapshot, position.X - layer.OffsetX, position.Y - layer.OffsetY);
-            layer.InvokeLayerBitmapChange(dirtyRect);
 
-            count++;
-        }
-    }
-
-    private void SaveUndo(Document document)
-    {
-        var args = new object[] { change.Document };
-        document.UndoManager.AddUndoChange(change.ToChange(StorageBasedChange.BasicUndoProcess, args));
-        if (moveStartSelectedPoints != null)
-        {
-            SelectionHelpers.AddSelectionUndoStep(document, moveStartSelectedPoints, SelectionType.New);
-            document.UndoManager.SquashUndoChanges(3, "Move selected area");
-            moveStartSelectedPoints = null;
-        }
-        change = null;
     }
-}
+}

+ 6 - 7
src/PixiEditor/Models/Tools/Tools/MoveViewportTool.cs

@@ -1,7 +1,6 @@
-using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Position;
-using System.Collections.Generic;
-using System.Windows.Input;
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.Models.Commands.Attributes;
 
 namespace PixiEditor.Models.Tools.Tools;
 
@@ -15,10 +14,10 @@ public class MoveViewportTool : ReadonlyTool
     }
 
     public override bool HideHighlight => true;
-    public override string Tooltip => $"Move viewport. ({Shortcut})"; 
+    public override string Tooltip => $"Move viewport. ({Shortcut})";
 
-    public override void Use(IReadOnlyList<Coordinates> pixels)
+    public override void Use(VecD pos)
     {
         // Implemented inside Zoombox.xaml.cs
     }
-}
+}

+ 4 - 173
src/PixiEditor/Models/Tools/Tools/PenTool.cs

@@ -1,34 +1,16 @@
-using PixiEditor.Models.Commands.Attributes;
+using System.Windows.Input;
+using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.Brushes;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using SkiaSharp;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.B)]
 internal class PenTool : ShapeTool
 {
-    public Brush Brush { get; set; }
-    public List<Brush> Brushes { get; } = new List<Brush>();
-
-
     private readonly SizeSetting toolSizeSetting;
     private readonly BoolSetting pixelPerfectSetting;
-    private readonly List<Coordinates> confirmedPixels = new List<Coordinates>();
-    private readonly LineTool lineTool;
-    private SKPaint paint = new SKPaint() { Style = SKPaintStyle.Stroke };
-    private Coordinates[] lastChangedPixels = new Coordinates[3];
-    private byte changedPixelsindex;
-    private Coordinates lastChangedPixel = new Coordinates(-1, -1);
-
-    private BitmapManager BitmapManager { get; }
-
 
     public PenTool(BitmapManager bitmapManager)
     {
@@ -37,162 +19,11 @@ internal class PenTool : ShapeTool
         Toolbar = new PenToolbar();
         toolSizeSetting = Toolbar.GetSetting<SizeSetting>("ToolSize");
         pixelPerfectSetting = Toolbar.GetSetting<BoolSetting>("PixelPerfectEnabled");
-        ClearPreviewLayerOnEachIteration = false;
-        BitmapManager = bitmapManager;
-        paint.BlendMode = SKBlendMode.Src;
-        Brushes.Add(new CircleBrush());
-        Brush = Brushes[0];
-        lineTool = new LineTool
-        {
-            AutomaticallyResizeCanvas = AutomaticallyResizeCanvas
-        };
     }
 
     public override string Tooltip => $"Standard brush. ({Shortcut})";
 
-    public bool AutomaticallyResizeCanvas { get; set; } = true;
-
-    public override void BeforeUse()
-    {
-        base.BeforeUse();
-        changedPixelsindex = 0;
-        lastChangedPixels = new Coordinates[] { new(-1, -1), new(-1, -1), new(-1, -1) };
-        lastChangedPixel = new(-1, -1);
-        confirmedPixels.Clear();
-    }
-
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
-    {
-        Coordinates startingCords = recordedMouseMovement.Count > 1 ? recordedMouseMovement[^2] : recordedMouseMovement[0];
-        paint.Color = color;
-        if (AutomaticallyResizeCanvas)
-        {
-            int maxX = recordedMouseMovement.Max(x => x.X);
-            int maxY = recordedMouseMovement.Max(x => x.Y);
-            int minX = recordedMouseMovement.Min(x => x.X);
-            int minY = recordedMouseMovement.Min(x => x.Y);
-            previewLayer.DynamicResizeAbsolute(new(minX, minY, maxX - minX + 1, maxX - minX + 1));
-        }
-        Draw(
-            previewLayer,
-            startingCords,
-            recordedMouseMovement[^1],
-            color,
-            toolSizeSetting.Value,
-            pixelPerfectSetting.Value,
-            BitmapManager.ActiveDocument.PreviewLayer);
-    }
-
-    public void Draw(
-        Layer layer, Coordinates startingCoords, Coordinates latestCords, SKColor color, int toolSize,
-        bool pixelPerfect = false,
-        Layer previewLayer = null,
-        SKBlendMode blendMode = SKBlendMode.Src)
-    {
-
-        SKStrokeCap cap = SKStrokeCap.Butt;
-        paint.Color = color;
-
-        if (!pixelPerfect)
-        {
-            Brush.Draw(layer, toolSize, latestCords, paint);
-            lineTool.DrawLine(layer, startingCoords, latestCords, color, toolSize, blendMode, cap);
-            return;
-        }
-
-        if (latestCords != lastChangedPixel)
-        {
-            if (previewLayer != null && previewLayer.GetPixelWithOffset(latestCords.X, latestCords.Y).Alpha > 0)
-            {
-                confirmedPixels.Add(latestCords);
-            }
-
-            Brush.Draw(layer, toolSize, latestCords, paint);
-
-            lineTool.DrawLine(layer, startingCoords, latestCords, color, toolSize, blendMode, cap);
-            SetPixelToCheck(LineTool.GetBresenhamLine(startingCoords, latestCords));
-
-            if (changedPixelsindex == 2)
-            {
-                byte alpha = ApplyPixelPerfectToPixels(
-                    layer,
-                    lastChangedPixels[0],
-                    lastChangedPixels[1],
-                    lastChangedPixels[2],
-                    color,
-                    toolSize,
-                    paint);
-
-                MovePixelsToCheck(alpha);
-
-                lastChangedPixel = latestCords;
-                return;
-            }
-
-            changedPixelsindex += changedPixelsindex >= 2 ? (byte)0 : (byte)1;
-        }
-
-        lastChangedPixel = latestCords;
-    }
-
-    private void MovePixelsToCheck(byte alpha)
+    public override void Use()
     {
-        if (alpha != 0)
-        {
-            lastChangedPixels[0] = lastChangedPixels[1];
-            lastChangedPixels[1] = lastChangedPixels[2];
-            changedPixelsindex = 2;
-        }
-        else
-        {
-            lastChangedPixels[0] = lastChangedPixels[2];
-            changedPixelsindex = 1;
-        }
-    }
-
-    private void SetPixelToCheck(IEnumerable<Coordinates> latestPixels)
-    {
-        if (latestPixels.Count() == 1)
-        {
-            lastChangedPixels[changedPixelsindex] = latestPixels.First();
-        }
-        else
-        {
-            lastChangedPixels[changedPixelsindex] = latestPixels.ElementAt(1);
-        }
-    }
-
-    private byte ApplyPixelPerfectToPixels(Layer layer, Coordinates p1, Coordinates p2, Coordinates p3, SKColor color, int toolSize, SKPaint paint)
-    {
-        byte alpha = color.Alpha;
-        paint.StrokeWidth = toolSize;
-
-        if (Math.Abs(p3.X - p1.X) == 1 && Math.Abs(p3.Y - p1.Y) == 1 && !confirmedPixels.Contains(p2))
-        {
-            paint.Color = SKColors.Transparent;
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(p2.X - layer.OffsetX, p2.Y - layer.OffsetY, paint);
-            paint.Color = color;
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(p1.X - layer.OffsetX, p1.Y - layer.OffsetY, paint);
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(p3.X - layer.OffsetX, p3.Y - layer.OffsetY, paint);
-
-            if (lastChangedPixels.Length > 1 && p2 == lastChangedPixels[1] /*Here might be a bug, I don't remember if it should be p2*/)
-            {
-                alpha = 0;
-            }
-        }
-        else
-        {
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(p2.X - layer.OffsetX, p2.Y - layer.OffsetY, paint);
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(p3.X - layer.OffsetX, p3.Y - layer.OffsetY, paint);
-        }
-
-        Int32Rect dirtyRect = new Int32Rect(
-            p2.X,
-            p2.Y,
-            2,
-            2);
-
-        layer.InvokeLayerBitmapChange(dirtyRect);
-        return alpha;
     }
-}
+}

+ 3 - 57
src/PixiEditor/Models/Tools/Tools/RectangleTool.cs

@@ -1,11 +1,5 @@
-using PixiEditor.Helpers;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools.ToolSettings.Settings;
-using SkiaSharp;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
@@ -30,55 +24,7 @@ public class RectangleTool : ShapeTool
             ActionDisplay = defaultActionDisplay;
     }
 
-    public override void Use(Layer activeLayer, Layer previewLayer, IEnumerable<Layer> allLayers, IReadOnlyList<Coordinates> recordedMouseMovement, SKColor color)
+    public override void Use()
     {
-        int thickness = Toolbar.GetSetting<SizeSetting>("ToolSize").Value;
-        SKColor? fillColor = null;
-        if (Toolbar.GetSetting<BoolSetting>("Fill").Value)
-        {
-            var temp = Toolbar.GetSetting<ColorSetting>("FillColor").Value;
-            fillColor = new SKColor(temp.R, temp.G, temp.B, temp.A);
-        }
-        var dirtyRect = CreateRectangle(previewLayer, color, fillColor, recordedMouseMovement, thickness);
-        ReportCustomSessionRect(SKRectI.Create(dirtyRect.X, dirtyRect.Y, dirtyRect.Width, dirtyRect.Height));
     }
-
-    private Int32Rect CreateRectangle(Layer layer, SKColor color, SKColor? fillColor, IReadOnlyList<Coordinates> coordinates, int thickness)
-    {
-        var (start, end) = Session.IsShiftDown ? CoordinatesHelper.GetSquareCoordiantes(coordinates) : (coordinates[0], coordinates[^1]);
-
-        DoubleCoords fixedCoordinates = CalculateCoordinatesForShapeRotation(start, end);
-
-        int halfThickness = (int)Math.Ceiling(thickness / 2.0);
-        Int32Rect dirtyRect = new Int32Rect(
-            fixedCoordinates.Coords1.X - halfThickness,
-            fixedCoordinates.Coords1.Y - halfThickness,
-            fixedCoordinates.Coords2.X + halfThickness * 2 - fixedCoordinates.Coords1.X,
-            fixedCoordinates.Coords2.Y + halfThickness * 2 - fixedCoordinates.Coords1.Y);
-        layer.DynamicResizeAbsolute(dirtyRect);
-
-        using (SKPaint paint = new SKPaint())
-        {
-            int x = fixedCoordinates.Coords1.X - layer.OffsetX;
-            int y = fixedCoordinates.Coords1.Y - layer.OffsetY;
-            int w = fixedCoordinates.Coords2.X - fixedCoordinates.Coords1.X;
-            int h = fixedCoordinates.Coords2.Y - fixedCoordinates.Coords1.Y;
-            paint.BlendMode = SKBlendMode.Src;
-
-            if (fillColor.HasValue)
-            {
-                paint.Color = fillColor.Value;
-                paint.Style = SKPaintStyle.StrokeAndFill;
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawRect(x, y, w, h, paint);
-            }
-
-            paint.StrokeWidth = thickness;
-            paint.Style = SKPaintStyle.Stroke;
-            paint.Color = color;
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawRect(x, y, w, h, paint);
-        }
-
-        layer.InvokeLayerBitmapChange(dirtyRect);
-        return dirtyRect;
-    }
-}
+}

+ 6 - 97
src/PixiEditor/Models/Tools/Tools/SelectTool.cs

@@ -1,126 +1,35 @@
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.ImageManipulation;
-using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
-using PixiEditor.ViewModels;
 using SkiaSharp;
-using System.Collections.ObjectModel;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.M)]
 internal class SelectTool : ReadonlyTool
 {
-    private readonly RectangleTool rectangleTool;
-    private readonly CircleTool circleTool;
-    private IEnumerable<Coordinates> oldSelectedPoints;
-
-    private static Selection ActiveSelection { get => ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection; }
-
-    private BitmapManager BitmapManager { get; }
-
     public SelectTool(BitmapManager bitmapManager)
     {
         ActionDisplay = "Click and move to select an area.";
         Toolbar = new SelectToolToolbar();
-        BitmapManager = bitmapManager;
-
-        rectangleTool = new RectangleTool();
-        circleTool = new CircleTool();
     }
 
-    public SelectionType SelectionType { get; set; } = SelectionType.Add;
+    public SelectionMode SelectionType { get; set; } = SelectionMode.Add;
 
     public override string Tooltip => $"Selects area. ({Shortcut})";
 
     public override void BeforeUse()
     {
-        base.BeforeUse();
-        SelectionType = Toolbar.GetEnumSetting<SelectionType>("SelectMode").Value;
-
-        oldSelectedPoints = new ReadOnlyCollection<Coordinates>(ActiveSelection.SelectedPoints);
     }
 
     public override void AfterUse(SKRectI sessionRect)
     {
-        base.AfterUse(sessionRect);
-        if (ActiveSelection.SelectedPoints.Count <= 1)
-        {
-            // If we have not selected multiple points, clear the selection
-            ActiveSelection.Clear();
-        }
-
-        SelectionHelpers.AddSelectionUndoStep(ViewModelMain.Current.BitmapManager.ActiveDocument, oldSelectedPoints, SelectionType);
-    }
-
-    public override void Use(IReadOnlyList<Coordinates> pixels)
-    {
-        Select(pixels, Toolbar.GetEnumSetting<SelectionShape>("SelectShape").Value);
-    }
-
-    public IEnumerable<Coordinates> GetRectangleSelectionForPoints(Coordinates start, Coordinates end)
-    {
-        List<Coordinates> result = new List<Coordinates>();
-        ToolCalculator.GenerateRectangleNonAlloc(
-            start, end, true, 1, result);
-        return result;
     }
 
-    public IEnumerable<Coordinates> GetCircleSelectionForPoints(Coordinates start, Coordinates end)
+    public override void Use(VecD pos)
     {
-        List<Coordinates> result = new List<Coordinates>();
-        ToolCalculator.GenerateEllipseNonAlloc(
-            start, end, true, result);
-        return result;
-    }
-
-    /// <summary>
-    ///     Gets coordinates of every pixel in root layer.
-    /// </summary>
-    /// <returns>Coordinates array of pixels.</returns>
-    public IEnumerable<Coordinates> GetAllSelection()
-    {
-        return GetAllSelection(ViewModelMain.Current.BitmapManager.ActiveDocument);
-    }
-
-    /// <summary>
-    ///     Gets coordinates of every pixel in chosen document.
-    /// </summary>
-    /// <returns>Coordinates array of pixels.</returns>
-    public IEnumerable<Coordinates> GetAllSelection(Document document)
-    {
-        return GetRectangleSelectionForPoints(new Coordinates(0, 0), new Coordinates(document.Width - 1, document.Height - 1));
-    }
-
-    private void Select(IReadOnlyList<Coordinates> pixels, SelectionShape shape)
-    {
-        IEnumerable<Coordinates> selection;
-
-        BitmapManager.ActiveDocument.ActiveSelection.SetSelection(oldSelectedPoints, SelectionType.New);
-
-        if (pixels.Count < 2)
-        {
-            selection = new List<Coordinates>();
-        }
-        else if (shape == SelectionShape.Circle)
-        {
-            selection = GetCircleSelectionForPoints(pixels[^1], pixels[0]);
-        }
-        else if (shape == SelectionShape.Rectangle)
-        {
-            selection = GetRectangleSelectionForPoints(pixels[^1], pixels[0]);
-        }
-        else
-        {
-            throw new NotImplementedException($"Selection shape '{shape}' has not been implemented");
-        }
-
-        BitmapManager.ActiveDocument.ActiveSelection.SetSelection(selection, SelectionType);
     }
-}
+}

+ 5 - 7
src/PixiEditor/Models/Tools/Tools/ZoomTool.cs

@@ -1,20 +1,18 @@
-using PixiEditor.Models.Commands.Attributes;
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Position;
-using System.Windows.Input;
 
 namespace PixiEditor.Models.Tools.Tools;
 
 [Command.Tool(Key = Key.Z)]
 internal class ZoomTool : ReadonlyTool
 {
-    private BitmapManager BitmapManager { get; }
     private string defaultActionDisplay = "Click and move to zoom. Click to zoom in, hold ctrl and click to zoom out.";
 
     public ZoomTool(BitmapManager bitmapManager)
     {
         ActionDisplay = defaultActionDisplay;
-        BitmapManager = bitmapManager;
     }
 
     public override bool HideHighlight => true;
@@ -37,8 +35,8 @@ internal class ZoomTool : ReadonlyTool
         }
     }
 
-    public override void Use(IReadOnlyList<Coordinates> pixels)
+    public override void Use(VecD pos)
     {
         // Implemented inside Zoombox.xaml.cs
     }
-}
+}

+ 0 - 138
src/PixiEditor/Models/Undo/Change.cs

@@ -1,138 +0,0 @@
-using System;
-using System.Linq;
-
-namespace PixiEditor.Models.Undo;
-
-[Serializable]
-public class Change : IDisposable
-{
-    /// <summary>
-    /// Initializes a new instance of the <see cref="Change"/> class.
-    ///     Creates new change for property based undo system.
-    /// </summary>
-    /// <param name="property">Name of property.</param>
-    /// <param name="oldValue">Old value of property.</param>
-    /// <param name="newValue">New value of property.</param>
-    /// <param name="description">Description of change.</param>
-    /// <param name="root">Custom root for finding property.</param>
-    public Change(
-        string property,
-        object oldValue,
-        object newValue,
-        string description = "",
-        object root = null)
-    {
-        Property = property;
-        OldValue = oldValue;
-        Description = description;
-        NewValue = newValue;
-        Root = root;
-    }
-
-    /// <summary>
-    /// Initializes a new instance of the <see cref="Change"/> class.
-    ///     Creates new change for property based undo system.
-    /// </summary>
-    /// <param name="property">Name of property.</param>
-    /// <param name="oldValue">Old value of property.</param>
-    /// <param name="newValue">New value of property.</param>
-    /// <param name="description">Description of change.</param>
-    /// <param name="root">Custom root for finding property.</param>
-    public Change(
-        string property,
-        object oldValue,
-        object newValue,
-        Func<object[], object> findRootProcess,
-        object[] findRootProcessArgs = null,
-        string description = "")
-    {
-        Property = property;
-        OldValue = oldValue;
-        Description = description;
-        NewValue = newValue;
-        FindRootProcess = findRootProcess;
-        FindRootProcessArgs = findRootProcessArgs;
-    }
-
-    /// <summary>
-    /// Initializes a new instance of the <see cref="Change"/> class.
-    ///     Creates new change for mixed reverse process based system with new value property based system.
-    /// </summary>
-    /// <param name="property">Name of property, which new value will be applied to.</param>
-    /// <param name="reverseProcess">Method with reversing value process.</param>
-    /// <param name="reverseArguments">Arguments for reverse method.</param>
-    /// <param name="newValue">New value of property.</param>
-    /// <param name="description">Description of change.</param>
-    /// <param name="root">Custom root for finding property.</param>
-    public Change(
-        string property,
-        Action<object[]> reverseProcess,
-        object[] reverseArguments,
-        object newValue,
-        string description = "",
-        object root = null)
-    {
-        Property = property;
-        ReverseProcess = reverseProcess;
-        ReverseProcessArguments = reverseArguments;
-        NewValue = newValue;
-        Description = description;
-        Root = root;
-    }
-
-    /// <summary>
-    /// Initializes a new instance of the <see cref="Change"/> class.
-    ///     Creates new change for reverse process based system.
-    /// </summary>
-    /// <param name="reverseProcess">Method with reversing value process.</param>
-    /// <param name="reverseArguments">Arguments for reverse method.</param>
-    /// <param name="process">Method with reversing the reversed value.</param>
-    /// <param name="processArguments">Arguments for process method.</param>
-    /// <param name="description">Description of change.</param>
-    public Change(
-        Action<object[]> reverseProcess,
-        object[] reverseArguments,
-        Action<object[]> process,
-        object[] processArguments,
-        string description = "")
-    {
-        ReverseProcess = reverseProcess;
-        ReverseProcessArguments = reverseArguments;
-        Process = process;
-        ProcessArguments = processArguments;
-        Description = description;
-    }
-
-    public object[] ProcessArguments { get; set; }
-
-    public object[] ReverseProcessArguments { get; set; }
-
-    public object OldValue { get; set; }
-
-    public object NewValue { get; set; }
-
-    public string Description { get; set; }
-
-    public string Property { get; set; }
-
-    public Action<object[]> ReverseProcess { get; set; }
-
-    public Action<object[]> Process { get; set; }
-
-    public object Root { get; set; }
-
-    public Func<object[], object> FindRootProcess { get; set; }
-
-    public object[] FindRootProcessArgs { get; set; }
-
-    public Action<object[], object[]> DisposeProcess { get; set; }
-
-    public void Dispose()
-    {
-        DisposeProcess?.Invoke(
-            ReverseProcessArguments ?? Array.Empty<object>(),
-            ProcessArguments ?? Array.Empty<object>());
-
-        GC.SuppressFinalize(this);
-    }
-}

+ 0 - 17
src/PixiEditor/Models/Undo/LayerChunk.cs

@@ -1,17 +0,0 @@
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using SkiaSharp;
-
-namespace PixiEditor.Models.Undo;
-
-public class LayerChunk
-{
-    public Layer Layer { get; set; }
-    public SKRectI AbsoluteChunkRect { get; set; }
-
-    public LayerChunk(Layer layer, SKRectI absoluteChunkRect)
-    {
-        Layer = layer;
-        AbsoluteChunkRect = absoluteChunkRect;
-    }
-}

+ 0 - 388
src/PixiEditor/Models/Undo/StorageBasedChange.cs

@@ -1,388 +0,0 @@
-using PixiEditor.Helpers.Extensions;
-using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.IO;
-using PixiEditor.Models.Layers;
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Windows;
-
-namespace PixiEditor.Models.Undo;
-
-/// <summary>
-///     A class that allows to save layers on disk and load them on Undo/Redo.
-/// </summary>
-public class StorageBasedChange : IDisposable
-{
-    public static string DefaultUndoChangeLocation { get; } = Path.Join(Path.GetTempPath(), "PixiEditor", Guid.NewGuid().ToString(), "UndoStack");
-
-    public string UndoChangeLocation { get; set; }
-
-    public UndoLayer[] StoredLayers { get; set; }
-
-    private List<Guid> layersToStore = new List<Guid>();
-    public Document Document { get; }
-
-    public StorageBasedChange(Document doc, IEnumerable<Layer> layers, bool saveOnStartup = true)
-    {
-        Document = doc;
-        Initialize(layers, DefaultUndoChangeLocation, saveOnStartup);
-    }
-
-    public StorageBasedChange(Document doc, IEnumerable<Layer> layers, bool useDocumentSize, bool saveOnStartup)
-    {
-        Document = doc;
-        Initialize(layers, DefaultUndoChangeLocation, saveOnStartup, useDocumentSize);
-    }
-
-    public StorageBasedChange(Document doc, IEnumerable<Layer> layers, string undoChangeLocation, bool saveOnStartup = true)
-    {
-        Document = doc;
-        Initialize(layers, undoChangeLocation, saveOnStartup);
-    }
-
-    public StorageBasedChange(Document doc, IEnumerable<LayerChunk> chunks, bool saveOnStartup = true)
-    {
-        Document = doc;
-        var chunkData = chunks as LayerChunk[] ?? chunks.ToArray();
-        LayerChunk[] layerChunks = new LayerChunk[chunkData.Length];
-        for (var i = 0; i < chunkData.Length; i++)
-        {
-            var chunk = chunkData[i];
-            layerChunks[i] = chunk;
-            layersToStore.Add(chunk.Layer.GuidValue);
-        }
-
-        UndoChangeLocation = DefaultUndoChangeLocation;
-        GenerateUndoLayers(layerChunks);
-        if (saveOnStartup)
-        {
-            SaveLayersOnDevice();
-        }
-    }
-
-    private void Initialize(IEnumerable<Layer> layers, string undoChangeLocation, bool saveOnStartup, bool useDocumentSize = false)
-    {
-        var layersArray = layers as Layer[] ?? layers.ToArray();
-        LayerChunk[] layerChunks = new LayerChunk[layersArray.Length];
-        for (var i = 0; i < layersArray.Length; i++)
-        {
-            var layer = layersArray[i];
-            int width = layer.Width;
-            int height = layer.Height;
-            int offsetX = layer.OffsetX;
-            int offsetY = layer.OffsetY;
-
-            if (useDocumentSize)
-            {
-                width = layer.MaxWidth;
-                height = layer.MaxHeight;
-                offsetX = 0;
-                offsetY = 0;
-            }
-
-            layerChunks[i] = new LayerChunk(layer, SKRectI.Create(offsetX, offsetY, width, height));
-            layersToStore.Add(layer.GuidValue);
-        }
-
-        UndoChangeLocation = undoChangeLocation;
-        GenerateUndoLayers(layerChunks);
-        if (saveOnStartup)
-        {
-            SaveLayersOnDevice();
-        }
-    }
-
-    public void SaveLayersOnDevice()
-    {
-        int i = 0;
-        foreach (var layerGuid in layersToStore)
-        {
-            Layer layer = Document.Layers.First(x => x.GuidValue == layerGuid);
-            UndoLayer storedLayer = StoredLayers[i];
-            if (Directory.Exists(Path.GetDirectoryName(storedLayer.StoredPngLayerName)))
-            {
-                // Calculate absolute rect to relative rect
-                SKRectI finalRect = SKRectI.Create(
-                    storedLayer.SerializedRect.Left - layer.OffsetX,
-                    storedLayer.SerializedRect.Top - layer.OffsetY,
-                    storedLayer.SerializedRect.Width,
-                    storedLayer.SerializedRect.Height);
-
-                using var image = layer.LayerBitmap.SkiaSurface.Snapshot();
-                using Surface targetSizeSurface = new Surface(finalRect.Width, finalRect.Height);
-
-                targetSizeSurface.SkiaSurface.Canvas.DrawImage(image, finalRect, SKRect.Create(0, 0, finalRect.Width, finalRect.Height), Surface.ReplacingPaint);
-
-                //DebugSavePng(targetSizeSurface, storedLayer);
-
-                Exporter.SaveAsGZippedBytes(storedLayer.StoredPngLayerName, targetSizeSurface);
-            }
-
-            i++;
-        }
-
-        layersToStore = new List<Guid>();
-    }
-
-    [Conditional("DEBUG")]
-    private static void DebugSavePng(Surface surface, UndoLayer storedLayer)
-    {
-        //Debug png visualization
-        using var targetSizeImage = surface.SkiaSurface.Snapshot();
-        using (var data = targetSizeImage.Encode(SKEncodedImageFormat.Png, 100))
-        using (var stream = File.OpenWrite(storedLayer.StoredPngLayerName + ".png"))
-        {
-            // save the data to a stream
-            data.SaveTo(stream);
-        }
-    }
-
-    /// <summary>
-    /// Loads saved layers from disk.
-    /// </summary>
-    /// <returns>Array of saved layers.</returns>
-    public Layer[] LoadLayersFromDevice()
-    {
-        Layer[] layers = new Layer[StoredLayers.Length];
-        for (int i = 0; i < StoredLayers.Length; i++)
-        {
-            UndoLayer storedLayer = StoredLayers[i];
-            var bitmap = Importer.LoadFromGZippedBytes(storedLayer.StoredPngLayerName);
-            layers[i] = new Layer(storedLayer.Name, bitmap, storedLayer.MaxWidth, storedLayer.MaxHeight)
-            {
-                Width = storedLayer.Width,
-                Height = storedLayer.Height,
-                Offset = new Thickness(storedLayer.OffsetX, storedLayer.OffsetY, 0, 0),
-                Opacity = storedLayer.Opacity,
-                IsVisible = storedLayer.IsVisible,
-                IsActive = storedLayer.IsActive,
-                LayerHighlightColor = storedLayer.LayerHighlightColor
-            };
-
-            layers[i].ChangeGuid(storedLayer.LayerGuid);
-
-            File.Delete(StoredLayers[i].StoredPngLayerName);
-        }
-
-        layersToStore = layers.Select(x => x.GuidValue).ToList();
-        return layers;
-    }
-
-    /// <summary>
-    ///     Creates UndoManager ready Change instance, where undo process loads layers from device, and redo saves them.
-    /// </summary>
-    /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-    /// <param name="processArgs">Custom parameters for undo process.</param>
-    /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-    /// <param name="redoProcessParameters">Parameters for redo process.</param>
-    /// <param name="description">Undo change description.</param>
-    /// <returns>UndoManager ready Change instance.</returns>
-    public Change ToChange(Action<Layer[], UndoLayer[], object[]> undoProcess, object[] processArgs, Action<object[]> redoProcess, object[] redoProcessParameters, string description = "")
-    {
-        Action<object[]> finalUndoProcess = processParameters =>
-        {
-            Layer[] layers = LoadLayersFromDevice();
-            undoProcess(layers, StoredLayers, processParameters);
-        };
-
-        Action<object[]> finalRedoProcess = parameters =>
-        {
-            SaveLayersOnDevice();
-            redoProcess(parameters);
-        };
-
-        var change = new Change(finalUndoProcess, processArgs, finalRedoProcess, redoProcessParameters, description);
-        change.DisposeProcess = (_, _) => Dispose();
-        return change;
-    }
-
-    /// <summary>
-    ///     Creates UndoManager ready Change instance, where undo and redo is the same, before process images are loaded from disk and current ones are saved.
-    /// </summary>
-    /// <param name="undoRedoProcess">Process that is invoked on redo and undo.</param>
-    /// <param name="processArgs">Custom parameters for undo and redo process.</param>
-    /// <param name="description">Undo change description.</param>
-    /// <returns>UndoManager ready 'Change' instance.</returns>
-    public Change ToChange(Action<Layer[], UndoLayer[], object[]> undoRedoProcess, object[] processArgs, string description = "")
-    {
-        Action<object[]> finalProcess = processParameters =>
-        {
-            Layer[] layers = LoadLayersFromDevice();
-            LayerChunk[] chunks = new LayerChunk[layers.Length];
-            for (int i = 0; i < layers.Length; i++)
-            {
-                chunks[i] = new LayerChunk(layers[i], StoredLayers[i].SerializedRect);
-            }
-
-            GenerateUndoLayers(chunks);
-
-            SaveLayersOnDevice();
-
-            undoRedoProcess(layers, StoredLayers, processParameters);
-        };
-
-        var change = new Change(finalProcess, processArgs, finalProcess, processArgs, description);
-        change.DisposeProcess = (_, _) => Dispose();
-        return change;
-    }
-
-    /// <summary>
-    ///     Creates UndoManager ready Change instance, where undo process loads layers from device, and redo saves them.
-    /// </summary>
-    /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-    /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-    /// <param name="redoProcessParameters">Parameters for redo process.</param>
-    /// <param name="description">Undo change description.</param>
-    /// <returns>UndoManager ready Change instance.</returns>
-    public Change ToChange(Action<Layer[], UndoLayer[]> undoProcess, Action<object[]> redoProcess, object[] redoProcessParameters, string description = "")
-    {
-        Action<object[]> finalUndoProcess = _ =>
-        {
-            Layer[] layers = LoadLayersFromDevice();
-            undoProcess(layers, StoredLayers);
-        };
-
-        Action<object[]> finalRedoProcess = parameters =>
-        {
-            SaveLayersOnDevice();
-            redoProcess(parameters);
-        };
-
-        var change = new Change(finalUndoProcess, null, finalRedoProcess, redoProcessParameters, description);
-        change.DisposeProcess = (_, _) => Dispose();
-        return change;
-    }
-
-    /// <summary>
-    ///     Creates UndoManager ready Change instance, where undo process saves layers on device, and redo loads them.
-    /// </summary>
-    /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-    /// <param name="undoProcessParameters">Parameters for undo process.</param>
-    /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-    /// <param name="description">Undo change description.</param>
-    /// <returns>UndoManager ready Change instance.</returns>
-    public Change ToChange(Action<object[]> undoProcess, object[] undoProcessParameters, Action<Layer[], UndoLayer[]> redoProcess, string description = "")
-    {
-        Action<object[]> finalUndoProcess = parameters =>
-        {
-            SaveLayersOnDevice();
-            undoProcess(parameters);
-        };
-
-        Action<object[]> finalRedoProcess = parameters =>
-        {
-            Layer[] layers = LoadLayersFromDevice();
-            redoProcess(layers, StoredLayers);
-        };
-
-        var change = new Change(finalUndoProcess, undoProcessParameters, finalRedoProcess, null, description);
-        change.DisposeProcess = (_, _) => Dispose();
-        return change;
-    }
-
-    /// <summary>
-    ///     Creates UndoManager ready Change instance, where undo process saves layers on device, and redo loads them.
-    /// </summary>
-    /// <param name="undoProcess">Method that is invoked on undo, with loaded layers parameter and UndoLayer array data.</param>
-    /// <param name="undoProcessParameters">Parameters for undo process.</param>
-    /// <param name="redoProcess">Method that is invoked on redo with custom object array parameters.</param>
-    /// <param name="redoProcessArgs">Parameters for redo process.</param>
-    /// <param name="description">Undo change description.</param>
-    /// <returns>UndoManager ready Change instance.</returns>
-    public Change ToChange(Action<object[]> undoProcess, object[] undoProcessParameters, Action<Layer[], UndoLayer[], object[]> redoProcess, object[] redoProcessArgs, string description = "")
-    {
-        Action<object[]> finalUndoProcess = parameters =>
-        {
-            SaveLayersOnDevice();
-            undoProcess(parameters);
-        };
-
-        Action<object[]> finalRedoProcess = parameters =>
-        {
-            Layer[] layers = LoadLayersFromDevice();
-            redoProcess(layers, StoredLayers, parameters);
-        };
-
-        var change = new Change(finalUndoProcess, undoProcessParameters, finalRedoProcess, redoProcessArgs, description);
-        change.DisposeProcess = (_, _) => Dispose();
-        return change;
-    }
-
-    /// <summary>
-    /// Generates UndoLayer[] StoredLayers data.
-    /// </summary>
-    private void GenerateUndoLayers(LayerChunk[] chunks)
-    {
-        StoredLayers = new UndoLayer[layersToStore.Count];
-        int i = 0;
-        foreach (var layerGuid in layersToStore)
-        {
-            Layer layer = Document.Layers.First(x => x.GuidValue == layerGuid);
-            if (!Document.Layers.Contains(layer))
-            {
-                throw new ArgumentException("Provided document doesn't contain selected layer");
-            }
-
-            int index = Document.Layers.IndexOf(layer);
-            string fileName = layer.Name + Guid.NewGuid();
-            StoredLayers[i] = new UndoLayer(
-                Path.Join(
-                    UndoChangeLocation,
-                    Convert.ToBase64String(Encoding.UTF8.GetBytes(fileName)) + ".undoimg"),
-                layer,
-                index,
-                chunks[i].AbsoluteChunkRect);
-            i++;
-        }
-    }
-
-    public static void BasicUndoProcess(Layer[] layers, UndoLayer[] data, object[] args)
-    {
-        if (args.Length > 0 && args[0] is Document document)
-        {
-            for (int i = 0; i < layers.Length; i++)
-            {
-                Layer layer = layers[i];
-                UndoLayer layerData = data[i];
-                var foundLayer = document.Layers.FirstOrDefault(x => x.GuidValue == layerData.LayerGuid);
-
-                if (foundLayer != null)
-                {
-                    ApplyChunkToLayer(foundLayer, layerData.SerializedRect, layer.LayerBitmap);
-                }
-                else
-                {
-                    document.RemoveLayer(layerData.LayerIndex, false);
-                    document.Layers.Insert(layerData.LayerIndex, layer);
-                }
-
-                if (layerData.IsActive)
-                {
-                    document.SetMainActiveLayer(layerData.LayerIndex);
-                }
-            }
-        }
-    }
-
-    private static void ApplyChunkToLayer(Layer layer, SKRectI rect, Surface chunk)
-    {
-        layer.DynamicResizeAbsolute(rect.ToInt32Rect());
-        using var snapshot = chunk.SkiaSurface.Snapshot();
-        layer.LayerBitmap.SkiaSurface.Canvas.DrawImage(snapshot, new SKPoint(rect.Left - layer.OffsetX, rect.Top - layer.OffsetY), Surface.ReplacingPaint);
-        layer.InvokeLayerBitmapChange(rect.ToInt32Rect());
-    }
-
-    public void Dispose()
-    {
-        for (int i = 0; i < StoredLayers.Length; i++)
-        {
-            if (File.Exists(StoredLayers[i].StoredPngLayerName))
-                File.Delete(StoredLayers[i].StoredPngLayerName);
-        }
-    }
-}

+ 0 - 59
src/PixiEditor/Models/Undo/UndoLayer.cs

@@ -1,59 +0,0 @@
-using System;
-using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
-using SkiaSharp;
-
-namespace PixiEditor.Models.Undo;
-
-[Serializable]
-public record UndoLayer
-{
-    public string StoredPngLayerName { get; set; }
-
-    public Guid LayerGuid { get; init; }
-
-    public string LayerHighlightColor { get; set; }
-
-    public string Name { get; set; }
-
-    public int LayerIndex { get; set; }
-
-    public int Width { get; set; }
-
-    public int Height { get; set; }
-
-    public int MaxWidth { get; set; }
-
-    public int MaxHeight { get; set; }
-
-    public bool IsVisible { get; set; }
-
-    public bool IsActive { get; set; }
-
-    public int OffsetX { get; set; }
-
-    public int OffsetY { get; set; }
-
-    public float Opacity { get; set; }
-
-    public SKRectI SerializedRect { get; set; }
-
-    public UndoLayer(string storedPngLayerName, Layer layer, int layerIndex, SKRectI serializedRect)
-    {
-        StoredPngLayerName = storedPngLayerName;
-        LayerIndex = layerIndex;
-        Name = layer.Name;
-        Width = layer.Width;
-        Height = layer.Height;
-        MaxWidth = layer.MaxWidth;
-        MaxHeight = layer.MaxHeight;
-        IsVisible = layer.IsVisible;
-        OffsetX = layer.OffsetX;
-        OffsetY = layer.OffsetY;
-        Opacity = layer.Opacity;
-        IsActive = layer.IsActive;
-        LayerGuid = layer.GuidValue;
-        LayerHighlightColor = layer.LayerHighlightColor;
-        SerializedRect = serializedRect;
-    }
-}

+ 2 - 0
src/PixiEditor/PixiEditor.csproj

@@ -334,7 +334,9 @@
 		</None>
 	</ItemGroup>
 	<ItemGroup>
+		<ProjectReference Include="..\PixiEditor.ChangeableDocument\PixiEditor.ChangeableDocument.csproj" />
 		<ProjectReference Include="..\PixiEditor.UpdateModule\PixiEditor.UpdateModule.csproj" />
+		<ProjectReference Include="..\PixiEditor.Zoombox\PixiEditor.Zoombox.csproj" />
 	</ItemGroup>
 	<ItemGroup>
 		<Reference Include="PixiParser">

+ 10 - 6
src/PixiEditor/ViewModels/SubViewModels/Main/ClipboardViewModel.cs

@@ -1,12 +1,12 @@
-using PixiEditor.Helpers.Extensions;
+using System.Text.RegularExpressions;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Commands.Search;
 using PixiEditor.Models.Controllers;
 using SkiaSharp;
-using System.Text.RegularExpressions;
-using System.Windows;
-using System.Windows.Input;
-using System.Windows.Media;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -21,17 +21,21 @@ public class ClipboardViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Clipboard.Duplicate", "Duplicate", "Duplicate selected area/layer", CanExecute = "PixiEditor.HasDocument", Key = Key.J, Modifiers = ModifierKeys.Control)]
     public void Duplicate()
     {
+        /*
         Copy();
         Paste();
+        */
     }
 
     [Command.Basic("PixiEditor.Clipboard.Cut", "Cut", "Cut selected area/layer", CanExecute = "PixiEditor.HasDocument", Key = Key.X, Modifiers = ModifierKeys.Control)]
     public void Cut()
     {
+        /*
         Copy();
         Owner.BitmapManager.BitmapOperations.DeletePixels(
             new[] { Owner.BitmapManager.ActiveDocument.ActiveLayer },
             Owner.BitmapManager.ActiveDocument.ActiveSelection.SelectedPoints.ToArray());
+        */
     }
 
     [Command.Basic("PixiEditor.Clipboard.Paste", "Paste", "Paste from clipboard", CanExecute = "PixiEditor.Clipboard.CanPaste", Key = Key.V, Modifiers = ModifierKeys.Control)]
@@ -78,4 +82,4 @@ public class ClipboardViewModel : SubViewModel<ViewModelMain>
 
         return ColorSearchResult.GetIcon(color.ToOpaqueSKColor());
     }
-}
+}

+ 22 - 22
src/PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs

@@ -1,4 +1,6 @@
-using Microsoft.Extensions.DependencyInjection;
+using System.Windows.Input;
+using System.Windows.Media;
+using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Commands.Search;
@@ -10,11 +12,8 @@ using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.ExternalServices;
 using PixiEditor.Models.IO;
-using PixiEditor.Models.Undo;
 using PixiEditor.Views.Dialogs;
 using SkiaSharp;
-using System.Windows.Input;
-using System.Windows.Media;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -77,18 +76,6 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
     [Command.Internal("PixiEditor.Colors.ReplaceColors")]
     public void ReplaceColors((SKColor oldColor, SKColor newColor) colors)
     {
-        Document activeDocument = Owner.BitmapManager?.ActiveDocument;
-        if (activeDocument != null)
-        {
-            activeDocument.ReplaceColor(colors.oldColor, colors.newColor);
-            ReplacePaletteColor(colors, activeDocument);
-            activeDocument.UndoManager.AddUndoChange(new Change(
-                ReplacePaletteColorProcess,
-                new object[] { (colors.newColor, colors.oldColor), activeDocument },
-                ReplacePaletteColorProcess,
-                new object[] { colors, activeDocument }));
-            activeDocument.UndoManager.SquashUndoChanges(2, $"Replace color {colors.oldColor} with {colors.newColor}");
-        }
 
     }
 
@@ -102,11 +89,11 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
 
     private static void ReplacePaletteColor((SKColor oldColor, SKColor newColor) colors, Document activeDocument)
     {
-        int oldIndex = activeDocument.Palette.IndexOf(colors.oldColor);
+        /*int oldIndex = activeDocument.Palette.IndexOf(colors.oldColor);
         if (oldIndex != -1)
         {
             activeDocument.Palette[oldIndex] = colors.newColor;
-        }
+        }*/
     }
 
     private async void OwnerOnStartupEvent(object sender, EventArgs e)
@@ -115,8 +102,8 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
     }
 
     [Command.Basic("PixiEditor.Colors.OpenPaletteBrowser", "Open Palette Browser", "Open Palette Browser", CanExecute = "PixiEditor.HasDocument", IconPath = "Globe.png")]
-    public void OpenPalettesBrowser() => PalettesBrowser.Open(PaletteDataSources, ImportPaletteCommand, Owner.BitmapManager.ActiveDocument.Palette);
-        
+    public void OpenPalettesBrowser() { } // PalettesBrowser.Open(PaletteDataSources, ImportPaletteCommand, Owner.BitmapManager.ActiveDocument.Palette);
+
     private async Task ImportLospecPalette()
     {
         var args = StartupArgs.Args;
@@ -185,6 +172,7 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
     [Command.Internal("PixiEditor.Colors.ImportPalette", CanExecute = "PixiEditor.Colors.CanImportPalette")]
     public void ImportPalette(List<string> palette)
     {
+        /*
         var doc = Owner.BitmapManager.ActiveDocument;
         if (doc is null)
             return;
@@ -198,13 +186,17 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
 
             doc.Palette.ReplaceRange(palette.Select(x => SKColor.Parse(x)));
         }
+        */
     }
 
     [Evaluator.CanExecute("PixiEditor.Colors.CanSelectPaletteColor")]
     public bool CanSelectPaletteColor(int index)
     {
+        /*
         var document = Owner.BitmapManager.ActiveDocument;
         return document?.Palette is not null && document.Palette.Count > index;
+        */
+        return false;
     }
 
     [Evaluator.Icon("PixiEditor.Colors.FirstPaletteColorIcon")]
@@ -231,6 +223,7 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
 
     private ImageSource GetPaletteColorIcon(int index)
     {
+        /*
         var document = Owner.BitmapManager.ActiveDocument;
 
         SKColor color;
@@ -239,7 +232,8 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
         else
             color = document.Palette[index];
 
-        return ColorSearchResult.GetIcon(color);
+        return ColorSearchResult.GetIcon(color);*/
+        return ColorSearchResult.GetIcon(SKColors.Transparent);
     }
 
     [Command.Basic("PixiEditor.Colors.SelectFirstPaletteColor", "Select color 1", "Select the first color in the palette", Key = Key.D1, Parameter = 0, CanExecute = "PixiEditor.Colors.CanSelectPaletteColor", IconEvaluator = "PixiEditor.Colors.FirstPaletteColorIcon")]
@@ -254,11 +248,13 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Colors.SelectTenthPaletteColor", "Select color 10", "Select the tenth color in the palette", Key = Key.D0, Parameter = 9, CanExecute = "PixiEditor.Colors.CanSelectPaletteColor", IconEvaluator = "PixiEditor.Colors.TenthPaletteColorIcon")]
     public void SelectPaletteColor(int index)
     {
+        /*
         var document = Owner.BitmapManager.ActiveDocument;
         if (document.Palette != null && document.Palette.Count > index)
         {
             PrimaryColor = document.Palette[index];
         }
+        */
     }
 
     [Command.Basic("PixiEditor.Colors.Swap", "Swap colors", "Swap primary and secondary colors", Key = Key.X)]
@@ -269,19 +265,23 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
 
     public void AddSwatch(SKColor color)
     {
+        /*
         if (!Owner.BitmapManager.ActiveDocument.Swatches.Contains(color))
         {
             Owner.BitmapManager.ActiveDocument.Swatches.Add(color);
         }
+        */
     }
 
     [Command.Internal("PixiEditor.Colors.RemoveSwatch")]
     public void RemoveSwatch(SKColor color)
     {
+        /*
         if (Owner.BitmapManager.ActiveDocument.Swatches.Contains(color))
         {
             Owner.BitmapManager.ActiveDocument.Swatches.Remove(color);
         }
+        */
     }
 
     [Command.Internal("PixiEditor.Colors.SelectColor")]
@@ -302,4 +302,4 @@ public class ColorsViewModel : SubViewModel<ViewModelMain>
             dataSource.Initialize();
         }
     }
-}
+}

+ 6 - 5
src/PixiEditor/ViewModels/SubViewModels/Main/DiscordViewModel.cs

@@ -1,8 +1,6 @@
 using DiscordRPC;
-using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.UserPreferences;
-using System;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -79,7 +77,7 @@ public class DiscordViewModel : SubViewModel<ViewModelMain>, IDisposable
     public DiscordViewModel(ViewModelMain owner, string clientId)
         : base(owner)
     {
-        Owner.BitmapManager.DocumentChanged += DocumentChanged;
+        //Owner.BitmapManager.DocumentChanged += DocumentChanged;
         this.clientId = clientId;
 
         Enabled = IPreferences.Current.GetPreference("EnableRichPresence", true);
@@ -106,6 +104,7 @@ public class DiscordViewModel : SubViewModel<ViewModelMain>, IDisposable
 
     public void UpdatePresence(Document document)
     {
+        /*
         if (client == null)
         {
             return;
@@ -140,6 +139,7 @@ public class DiscordViewModel : SubViewModel<ViewModelMain>, IDisposable
         }
 
         client.SetPresence(richPresence);
+        */
     }
 
     public void Dispose()
@@ -168,7 +168,7 @@ public class DiscordViewModel : SubViewModel<ViewModelMain>, IDisposable
             }
         };
     }
-
+    /*
     private void DocumentChanged(object sender, Models.Events.DocumentChangedEventArgs e)
     {
         if (currentDocument != null)
@@ -186,6 +186,7 @@ public class DiscordViewModel : SubViewModel<ViewModelMain>, IDisposable
             currentDocument.LayersChanged += DocumentLayerChanged;
         }
     }
+    */
 
     private void DocumentLayerChanged(object sender, Models.Controllers.LayersChangedEventArgs e)
     {
@@ -209,4 +210,4 @@ public class DiscordViewModel : SubViewModel<ViewModelMain>, IDisposable
     {
         Enabled = false;
     }
-}
+}

+ 15 - 10
src/PixiEditor/ViewModels/SubViewModels/Main/DocumentViewModel.cs

@@ -1,11 +1,6 @@
-using PixiEditor.Models.Commands.Attributes;
+using System.Windows.Input;
+using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Dialogs;
-using PixiEditor.Models.Enums;
-using System.Windows.Input;
-using SkiaSharp;
-using System;
-using System.Linq;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -22,6 +17,7 @@ public class DocumentViewModel : SubViewModel<ViewModelMain>
 
     public void FlipDocument(object parameter)
     {
+        /*
         if (parameter is "Horizontal")
         {
             Owner.BitmapManager.ActiveDocument?.FlipActiveDocument(FlipType.Horizontal);
@@ -30,24 +26,28 @@ public class DocumentViewModel : SubViewModel<ViewModelMain>
         {
             Owner.BitmapManager.ActiveDocument?.FlipActiveDocument(FlipType.Vertical);
         }
+        */
     }
 
     public void RotateDocument(object parameter)
     {
+        /*
         if (parameter is double angle)
         {
             Owner.BitmapManager.ActiveDocument?.RotateActiveDocument((float)angle);
         }
+        */
     }
 
     [Command.Basic("PixiEditor.Document.ClipCanvas", "Clip Canvas", "Clip Canvas", CanExecute = "PixiEditor.HasDocument")]
     public void ClipCanvas()
     {
-        Owner.BitmapManager.ActiveDocument?.ClipCanvas();
+        //Owner.BitmapManager.ActiveDocument?.ClipCanvas();
     }
 
     public void RequestCloseDocument(Document document)
     {
+        /*
         if (!document.ChangesSaved)
         {
             ConfirmationType result = ConfirmationDialog.Show(ConfirmationDialogMessage, ConfirmationDialogTitle);
@@ -64,21 +64,25 @@ public class DocumentViewModel : SubViewModel<ViewModelMain>
         }
 
         Owner.BitmapManager.CloseDocument(document);
+        */
     }
 
     [Command.Basic("PixiEditor.Document.DeletePixels", "Delete pixels", "Delete selected pixels", CanExecute = "PixiEditor.Selection.IsNotEmpty", Key = Key.Delete, IconPath = "Tools/EraserImage.png")]
     public void DeletePixels()
     {
+        /*
         var doc = Owner.BitmapManager.ActiveDocument;
         Owner.BitmapManager.BitmapOperations.DeletePixels(
             doc.Layers.Where(x => x.IsActive && doc.GetFinalLayerIsVisible(x)).ToArray(),
             doc.ActiveSelection.SelectedPoints.ToArray());
+        */
     }
 
     [Command.Basic("PixiEditor.Document.ResizeDocument", false, "Resize Document", "Resize Document", CanExecute = "PixiEditor.HasDocument", Key = Key.I, Modifiers = ModifierKeys.Control | ModifierKeys.Shift)]
     [Command.Basic("PixiEditor.Document.ResizeCanvas", true, "Resize Canvas", "Resize Canvas", CanExecute = "PixiEditor.HasDocument", Key = Key.C, Modifiers = ModifierKeys.Control | ModifierKeys.Shift)]
     public void OpenResizePopup(bool canvas)
     {
+        /*
         ResizeDocumentDialog dialog = new ResizeDocumentDialog(
             Owner.BitmapManager.ActiveDocument.Width,
             Owner.BitmapManager.ActiveDocument.Height,
@@ -94,11 +98,12 @@ public class DocumentViewModel : SubViewModel<ViewModelMain>
                 Owner.BitmapManager.ActiveDocument.Resize(dialog.Width, dialog.Height);
             }
         }
+        */
     }
 
     [Command.Basic("PixiEditor.Document.CenterContent", "Center Content", "Center Content", CanExecute = "PixiEditor.HasDocument")]
     public void CenterContent()
     {
-        Owner.BitmapManager.ActiveDocument.CenterContent();
+        //Owner.BitmapManager.ActiveDocument.CenterContent();
     }
-}
+}

+ 22 - 12
src/PixiEditor/ViewModels/SubViewModels/Main/FileViewModel.cs

@@ -1,19 +1,15 @@
-using Microsoft.Win32;
+using System.IO;
+using System.Windows.Input;
+using Microsoft.Win32;
 using Newtonsoft.Json.Linq;
-using PixiEditor.Exceptions;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.Attributes;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.UserPreferences;
-using PixiEditor.Parser;
 using PixiEditor.Views.Dialogs;
-using System.IO;
-using System.Windows;
-using System.Windows.Input;
-using System.Windows.Media.Imaging;
-using PixiEditor.Models.Controllers;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -77,6 +73,7 @@ public class FileViewModel : SubViewModel<ViewModelMain>
 
     public void NewDocument(int width, int height, bool addBaseLayer = true)
     {
+        /*
         Owner.BitmapManager.Documents.Add(new Document(width, height));
         Owner.BitmapManager.ActiveDocument = Owner.BitmapManager.Documents[^1];
         if (addBaseLayer)
@@ -85,6 +82,7 @@ public class FileViewModel : SubViewModel<ViewModelMain>
         }
 
         Owner.ResetProgramStateValues();
+        */
     }
 
     /// <summary>
@@ -93,6 +91,7 @@ public class FileViewModel : SubViewModel<ViewModelMain>
     /// <param name="path">Path to file.</param>
     public void OpenFile(string path)
     {
+        /*
         ImportFileDialog dialog = new ImportFileDialog();
 
         if (path != null && File.Exists(path))
@@ -109,11 +108,13 @@ public class FileViewModel : SubViewModel<ViewModelMain>
                 Importer.ImportImage(dialog.FilePath, dialog.FileWidth, dialog.FileHeight));
             Owner.BitmapManager.ActiveDocument.UpdatePreviewImage();
         }
+        */
     }
 
     [Command.Basic("PixiEditor.File.Open", "Open", "Open file", Key = Key.O, Modifiers = ModifierKeys.Control)]
     public void Open(string path)
     {
+        /*
         if (path == null)
         {
             Open();
@@ -141,6 +142,7 @@ public class FileViewModel : SubViewModel<ViewModelMain>
         {
             NoticeDialog.Show("This .pixi file uses the old format,\n which is no longer supported and can't be opened.", "Old file format");
         }
+        */
     }
 
     private void Owner_OnStartupEvent(object sender, System.EventArgs e)
@@ -165,6 +167,7 @@ public class FileViewModel : SubViewModel<ViewModelMain>
 
     public void OpenRecent(object parameter)
     {
+        /*
         string path = (string)parameter;
 
         foreach (Document document in Owner.BitmapManager.Documents)
@@ -185,8 +188,9 @@ public class FileViewModel : SubViewModel<ViewModelMain>
         }
 
         Open((string)parameter);
+        */
     }
-        
+
     public void Open()
     {
         var filter = SupportedFilesHelper.BuildOpenFilter();
@@ -213,24 +217,27 @@ public class FileViewModel : SubViewModel<ViewModelMain>
 
     private void OpenDocument(string path)
     {
+        /*
         Document document = Importer.ImportDocument(path);
 
         if (Owner.BitmapManager.Documents.Select(x => x.DocumentFilePath).All(y => y != path))
         {
-            Owner.BitmapManager.Documents.Add(document);
+          j  Owner.BitmapManager.Documents.Add(document);
             Owner.BitmapManager.ActiveDocument = Owner.BitmapManager.Documents.Last();
         }
         else
         {
             Owner.BitmapManager.ActiveDocument = Owner.BitmapManager.Documents.First(y => y.DocumentFilePath == path);
         }
+        */
     }
 
     [Command.Basic("PixiEditor.File.Save", false, "Save", "Save image", CanExecute = "PixiEditor.HasDocument", Key = Key.S, Modifiers = ModifierKeys.Control)]
     [Command.Basic("PixiEditor.File.SaveAsNew", true, "Save as...", "Save image as new", CanExecute = "PixiEditor.HasDocument", Key = Key.S, Modifiers = ModifierKeys.Control | ModifierKeys.Shift)]
     public void SaveDocument(bool asNew)
     {
-        if (asNew || string.IsNullOrEmpty(Owner.BitmapManager.ActiveDocument.DocumentFilePath)) 
+        /*
+        if (asNew || string.IsNullOrEmpty(Owner.BitmapManager.ActiveDocument.DocumentFilePath))
         {
             Owner.BitmapManager.ActiveDocument.SaveWithDialog();
         }
@@ -238,6 +245,7 @@ public class FileViewModel : SubViewModel<ViewModelMain>
         {
             Owner.BitmapManager.ActiveDocument.Save();
         }
+        */
     }
 
     /// <summary>
@@ -247,9 +255,11 @@ public class FileViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.File.Export", "Export", "Export image", CanExecute = "PixiEditor.HasDocument", Key = Key.S, Modifiers = ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)]
     public void ExportFile()
     {
+        /*
         ViewModelMain.Current.ActionDisplay = "";
         WriteableBitmap bitmap = Owner.BitmapManager.ActiveDocument.Renderer.FinalBitmap;
         Exporter.Export(bitmap, new Size(bitmap.PixelWidth, bitmap.PixelHeight));
+        */
     }
 
     private void UpdateMaxRecentlyOpened(object parameter)
@@ -285,4 +295,4 @@ public class FileViewModel : SubViewModel<ViewModelMain>
 
         return documents;
     }
-}
+}

+ 9 - 6
src/PixiEditor/ViewModels/SubViewModels/Main/IoViewModel.cs

@@ -1,11 +1,11 @@
-using PixiEditor.Helpers;
+using System.Windows;
+using System.Windows.Input;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Commands;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
-using System.Windows;
-using System.Windows.Input;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -22,7 +22,7 @@ public class IoViewModel : SubViewModel<ViewModelMain>
     private bool restoreToolOnKeyUp = false;
 
     private MouseInputFilter filter = new();
-    
+
     public IoViewModel(ViewModelMain owner)
         : base(owner)
     {
@@ -168,6 +168,7 @@ public class IoViewModel : SubViewModel<ViewModelMain>
 
     private void OnMouseDown(object sender, MouseButton button)
     {
+        /*
         if (button == MouseButton.Left)
         {
             BitmapManager bitmapManager = Owner.BitmapManager;
@@ -177,6 +178,7 @@ public class IoViewModel : SubViewModel<ViewModelMain>
 
             bitmapManager.InputTarget.OnLeftMouseButtonDown(activeDocument.MouseXOnCanvas, activeDocument.MouseYOnCanvas);
         }
+        */
     }
 
     private void OnPreviewMiddleMouseButton(object sender)
@@ -211,10 +213,11 @@ public class IoViewModel : SubViewModel<ViewModelMain>
 
     private void OnMouseMove(object sender, EventArgs args)
     {
+        /*
         var activeDocument = Owner.BitmapManager.ActiveDocument;
         if (activeDocument == null)
             return;
-        Owner.BitmapManager.InputTarget.OnMouseMove(activeDocument.MouseXOnCanvas, activeDocument.MouseYOnCanvas);
+        Owner.BitmapManager.InputTarget.OnMouseMove(activeDocument.MouseXOnCanvas, activeDocument.MouseYOnCanvas);*/
     }
 
     private void OnMouseUp(object sender, MouseButton button)
@@ -230,4 +233,4 @@ public class IoViewModel : SubViewModel<ViewModelMain>
             ChangeToolState<MoveViewportTool>(false);
         }
     }
-}
+}

+ 38 - 219
src/PixiEditor/ViewModels/SubViewModels/Main/LayersViewModel.cs

@@ -1,11 +1,6 @@
-using PixiEditor.Helpers;
+using System.Windows.Input;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.Layers;
-using PixiEditor.Views.UserControls.Layers;
-using System;
-using System.Linq;
-using System.Windows.Input;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -60,20 +55,16 @@ public class LayersViewModel : SubViewModel<ViewModelMain>
         RenameGroupCommand = new RelayCommand(RenameGroup);
         DeleteGroupCommand = new RelayCommand(DeleteGroup, CanDeleteGroup);
         DeleteSelectedCommand = new RelayCommand(DeleteSelected, CanDeleteSelected);
-        Owner.BitmapManager.DocumentChanged += BitmapManager_DocumentChanged;
     }
 
     public void CreateGroupFromActiveLayers(object parameter)
     {
-        // var doc = Owner.BitmapManager.ActiveDocument;
-        // if (doc != null)
-        // {
-        //    doc.LayerStructure.AddNewGroup($"{Owner.BitmapManager.ActiveLayer.Name} Group", doc.Layers.Where(x => x.IsActive).Reverse(), Owner.BitmapManager.ActiveDocument.ActiveLayerGuid);
-        // }
+
     }
 
     public bool CanDeleteSelected(object parameter)
     {
+        /*
         bool paramIsLayerOrGroup = parameter is not null and (Layer or LayerGroup);
         bool activeLayerExists = Owner.BitmapManager?.ActiveDocument?.ActiveLayer != null;
         bool activeDocumentExists = Owner.BitmapManager.ActiveDocument != null;
@@ -96,12 +87,13 @@ public class LayersViewModel : SubViewModel<ViewModelMain>
         else if (Owner.BitmapManager.ActiveDocument.ActiveLayer != null)
         {
             return CanDeleteActiveLayers(null);
-        }
+        }*/
         return false;
     }
 
     public void DeleteSelected(object parameter)
     {
+        /*
         if (parameter is Layer or LayerStructureItemContainer)
         {
             DeleteActiveLayers(null);
@@ -117,324 +109,151 @@ public class LayersViewModel : SubViewModel<ViewModelMain>
         else if (Owner.BitmapManager.ActiveDocument.ActiveLayer != null)
         {
             DeleteActiveLayers(null);
-        }
+        }*/
     }
 
     public bool CanDeleteGroup(object parameter)
     {
-        if (parameter is not Guid guid)
-            return false;
-
-        var document = Owner.BitmapManager.ActiveDocument;
-        if (document == null)
-            return false;
-
-        var group = document.LayerStructure.GetGroupByGuid(guid);
-        if (group == null)
-            return false;
-
-        return document.LayerStructure.GetGroupLayers(group).Count < document.Layers.Count;
+        return false;
     }
 
     public void DeleteGroup(object parameter)
     {
-        if (parameter is Guid guid)
-        {
-            foreach (var layer in Owner.BitmapManager.ActiveDocument?.Layers)
-            {
-                layer.IsActive = false;
-            }
-
-            var group = Owner.BitmapManager.ActiveDocument?.LayerStructure.GetGroupByGuid(guid);
-            var layers = Owner.BitmapManager.ActiveDocument?.LayerStructure.GetGroupLayers(group);
-            foreach (var layer in layers)
-            {
-                layer.IsActive = true;
-            }
-
-            Owner.BitmapManager.ActiveDocument?.RemoveActiveLayers();
-        }
+
     }
 
     public void RenameGroup(object parameter)
     {
-        if (parameter is Guid guid)
-        {
-            var group = Owner.BitmapManager.ActiveDocument?.LayerStructure.GetGroupByGuid(guid);
-            group.IsRenaming = true;
-        }
     }
 
     public void NewGroup(object parameter)
     {
-        GuidStructureItem control = GetGroupFromParameter(parameter);
-        var doc = Owner.BitmapManager.ActiveDocument;
-        if (doc != null)
-        {
-            var lastGroups = doc.LayerStructure.CloneGroups();
-            if (parameter is Layer or LayerStructureItemContainer)
-            {
-                GuidStructureItem group = doc.LayerStructure.AddNewGroup($"{doc.ActiveLayer.Name} Group", doc.ActiveLayer.GuidValue);
-
-                Owner.BitmapManager.ActiveDocument.LayerStructure.ExpandParentGroups(group);
-            }
-            else if (control != null)
-            {
-                doc.LayerStructure.AddNewGroup($"{control.Name} Group", control);
-            }
-
-            doc.AddLayerStructureToUndo(lastGroups);
-            doc.RaisePropertyChange(nameof(doc.LayerStructure));
-        }
+
     }
 
     public bool CanAddNewGroup(object property)
     {
-        return CanCreateNewLayer(property) && Owner.BitmapManager.ActiveLayer != null;
+        return CanCreateNewLayer(property) && false;
     }
 
     public bool CanMergeSelected(object obj)
     {
-        return Owner.BitmapManager.ActiveDocument?.Layers.Count(x => x.IsActive) > 1;
+        return false;
     }
 
     public bool CanCreateGroupFromSelected(object obj)
     {
-        return Owner.BitmapManager.ActiveDocument?.Layers.Count(x => x.IsActive) > 0;
+        return false;
     }
 
     [Command.Basic("PixiEditor.Layer.New", "New Layer", "Create new layer", CanExecute = "PixiEditor.HasDocument", Key = Key.N, Modifiers = ModifierKeys.Control | ModifierKeys.Shift, IconPath = "Layer-add.png")]
     public void NewLayer(object parameter)
     {
-        GuidStructureItem control = GetGroupFromParameter(parameter);
-        var doc = Owner.BitmapManager.ActiveDocument;
-        var activeLayerParent = doc.LayerStructure.GetGroupByLayer(doc.ActiveLayerGuid);
-
-        Guid lastActiveLayerGuid = doc.ActiveLayerGuid;
-
 
-        doc.AddNewLayer($"New Layer {Owner.BitmapManager.ActiveDocument.Layers.Count}");
-
-        var oldGroups = doc.LayerStructure.CloneGroups();
-
-        if (doc.Layers.Count > 1)
-        {
-            doc.MoveLayerInStructure(doc.Layers[^1].GuidValue, lastActiveLayerGuid, true);
-            Guid? parent = null;
-            if (activeLayerParent != null)
-            {
-                parent = parameter is Layer or LayerStructureItemContainer ? activeLayerParent?.GroupGuid : activeLayerParent.Parent?.GroupGuid;
-            }
-            doc.LayerStructure.AssignParent(doc.ActiveLayerGuid, parent);
-            doc.AddLayerStructureToUndo(oldGroups);
-            doc.UndoManager.SquashUndoChanges(3, "Add New Layer");
-        }
-        if (control != null)
-        {
-            control.IsExpanded = true;
-            doc.RaisePropertyChange(nameof(doc.LayerStructure));
-        }
     }
 
     public bool CanCreateNewLayer(object parameter)
     {
-        return Owner.BitmapManager.ActiveDocument != null;
+        return false;
     }
 
     public void SetActiveLayer(object parameter)
     {
-        int index = (int)parameter;
+        //int index = (int)parameter;
 
-        var doc = Owner.BitmapManager.ActiveDocument;
+        //var doc = Owner.BitmapManager.ActiveDocument;
 
-        if (doc.Layers[index].IsActive && Mouse.RightButton == MouseButtonState.Pressed)
+        /*if (doc.Layers[index].IsActive && Mouse.RightButton == MouseButtonState.Pressed)
         {
             return;
-        }
+        }*/
 
         if (Keyboard.IsKeyDown(Key.LeftCtrl))
         {
-            doc.ToggleLayer(index);
+            //doc.ToggleLayer(index);
         }
-        else if (Keyboard.IsKeyDown(Key.LeftShift) && Owner.BitmapManager.ActiveDocument.Layers.Any(x => x.IsActive))
+        //else if (Keyboard.IsKeyDown(Key.LeftShift) && Owner.BitmapManager.ActiveDocument.Layers.Any(x => x.IsActive))
         {
-            doc.SelectLayersRange(index);
+            //doc.SelectLayersRange(index);
         }
-        else
+        //else
         {
-            doc.SetMainActiveLayer(index);
+            //doc.SetMainActiveLayer(index);
         }
     }
 
     public void DeleteActiveLayers(object unusedParameter)
     {
-        var doc = Owner.BitmapManager.ActiveDocument;
-        doc.RemoveActiveLayers();
+
     }
 
     public bool CanDeleteActiveLayers(object unusedParam)
     {
-        if (Owner.BitmapManager.ActiveDocument == null)
-            return false;
-        int activeLayerCount = Owner.BitmapManager.ActiveDocument.Layers.Where(layer => layer.IsActive).Count();
-        return Owner.BitmapManager.ActiveDocument.Layers.Count > activeLayerCount;
+        return false;
     }
 
     public void DuplicateLayer(object parameter)
     {
-        Owner.BitmapManager.ActiveDocument.DuplicateLayer((int)parameter);
+
     }
 
     public bool CanDuplicateLayer(object property)
     {
-        return Owner.BitmapManager.ActiveDocument != null;
+        return false;
     }
 
     public void RenameLayer(object parameter)
     {
-        if (Owner.BitmapManager.ActiveDocument == null)
-            return;
 
-        int? index = (int?)parameter;
-
-        if (index == null)
-        {
-            index = Owner.BitmapManager.ActiveDocument.Layers.IndexOf(Owner.BitmapManager.ActiveDocument.ActiveLayer);
-        }
-
-        Owner.BitmapManager.ActiveDocument.Layers[(int)index].IsRenaming = true;
     }
 
     public bool CanRenameLayer(object parameter)
     {
-        return Owner.BitmapManager.ActiveDocument != null;
+        return false;
     }
 
     public void MoveLayerToFront(object parameter)
     {
-        int oldIndex = (int)parameter;
-        Guid layerToMove = Owner.BitmapManager.ActiveDocument.Layers[oldIndex].GuidValue;
-        Guid referenceLayer = Owner.BitmapManager.ActiveDocument.Layers[oldIndex + 1].GuidValue;
-        Owner.BitmapManager.ActiveDocument.MoveLayerInStructure(layerToMove, referenceLayer, true);
+
     }
 
     public void MoveLayerToBack(object parameter)
     {
-        int oldIndex = (int)parameter;
-        Guid layerToMove = Owner.BitmapManager.ActiveDocument.Layers[oldIndex].GuidValue;
-        Guid referenceLayer = Owner.BitmapManager.ActiveDocument.Layers[oldIndex - 1].GuidValue;
-        Owner.BitmapManager.ActiveDocument.MoveLayerInStructure(layerToMove, referenceLayer, false);
+
     }
 
     public bool CanMoveToFront(object property)
     {
-        if (property == null)
-        {
-            return false;
-        }
-
-        return Owner.DocumentIsNotNull(null) && Owner.BitmapManager.ActiveDocument.Layers.Count - 1 > (int)property;
+        return false;
     }
 
     public bool CanMoveToBack(object property)
     {
-        if (property == null)
-        {
-            return false;
-        }
-
-        return (int)property > 0;
+        return false;
     }
 
     public void MergeSelected(object parameter)
     {
-        Owner.BitmapManager.ActiveDocument.MergeLayers(Owner.BitmapManager.ActiveDocument.Layers.Where(x => x.IsActive).ToArray(), false);
+
     }
 
     public void MergeWithAbove(object parameter)
     {
-        int index = (int)parameter;
-        Layer layer1 = Owner.BitmapManager.ActiveDocument.Layers[index];
-        Layer layer2 = Owner.BitmapManager.ActiveDocument.Layers[index + 1];
-        Owner.BitmapManager.ActiveDocument.MergeLayers(new Layer[] { layer1, layer2 }, false);
+
     }
 
     public void MergeWithBelow(object parameter)
     {
-        int index = (int)parameter;
-        Layer layer1 = Owner.BitmapManager.ActiveDocument.Layers[index - 1];
-        Layer layer2 = Owner.BitmapManager.ActiveDocument.Layers[index];
-        Owner.BitmapManager.ActiveDocument.MergeLayers(new Layer[] { layer1, layer2 }, true);
+
     }
 
     public bool CanMergeWithAbove(object property)
     {
-        if (property == null)
-        {
-            return false;
-        }
-        int index = (int)property;
-        return Owner.DocumentIsNotNull(null) && index != Owner.BitmapManager.ActiveDocument.Layers.Count - 1
-                                             && Owner.BitmapManager.ActiveDocument.Layers.Count(x => x.IsActive) == 1;
+        return false;
     }
 
     public bool CanMergeWithBelow(object property)
     {
-        if (property == null)
-        {
-            return false;
-        }
-
-        int index = (int)property;
-        return Owner.DocumentIsNotNull(null) && index != 0 && Owner.BitmapManager.ActiveDocument.Layers.Count(x => x.IsActive) == 1;
-    }
-
-    private GuidStructureItem GetGroupFromParameter(object parameter)
-    {
-        if (parameter is LayerGroupControl)
-        {
-            return ((LayerGroupControl)parameter).GroupData;
-        }
-        else if (parameter is Layer || parameter is LayerStructureItemContainer)
-        {
-            Guid layerGuid = parameter is Layer layer ? layer.GuidValue : ((LayerStructureItemContainer)parameter).Layer.GuidValue;
-            var group = Owner.BitmapManager.ActiveDocument.LayerStructure.GetGroupByLayer(layerGuid);
-            if (group != null)
-            {
-                while (group.IsExpanded && group.Parent != null)
-                {
-                    group = group.Parent;
-                }
-            }
-            return group;
-        }
-
-        return null;
-    }
-
-    private void BitmapManager_DocumentChanged(object sender, Models.Events.DocumentChangedEventArgs e)
-    {
-        if (e.OldDocument != null)
-        {
-            e.OldDocument.LayersChanged -= Document_LayersChanged;
-        }
-
-        if (e.NewDocument != null)
-        {
-            e.NewDocument.LayersChanged += Document_LayersChanged;
-        }
-    }
-
-    private void Document_LayersChanged(object sender, LayersChangedEventArgs e)
-    {
-        if (e.LayerChangeType == Models.Enums.LayerAction.SetActive)
-        {
-            Owner.BitmapManager.ActiveDocument.UpdateLayersColor();
-            Owner.BitmapManager.ActiveDocument.LayerStructure.ExpandParentGroups(e.LayerAffectedGuid);
-        }
-        else
-        {
-            Owner.BitmapManager.ActiveDocument.ChangesSaved = false;
-        }
+        return false;
     }
-}
+}

+ 1 - 1
src/PixiEditor/ViewModels/SubViewModels/Main/RegistryViewModel.cs

@@ -3,8 +3,8 @@ using System.Diagnostics;
 using System.Security.AccessControl;
 using System.Windows;
 using Microsoft.Win32;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Dialogs;
-using PixiEditor.Models.Processes;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 

+ 3 - 14
src/PixiEditor/ViewModels/SubViewModels/Main/SelectionViewModel.cs

@@ -1,9 +1,6 @@
-using PixiEditor.Helpers;
+using System.Windows.Input;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Enums;
-using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools.Tools;
-using System.Windows.Input;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -21,26 +18,18 @@ public class SelectionViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Selection.SelectAll", "Select all", "Select everything", CanExecute = "PixiEditor.HasDocument", Key = Key.A, Modifiers = ModifierKeys.Control)]
     public void SelectAll()
     {
-        var oldSelection = new List<Coordinates>(Owner.BitmapManager.ActiveDocument.ActiveSelection.SelectedPoints);
 
-        Owner.BitmapManager.ActiveDocument.ActiveSelection.SetSelection(selectTool.GetAllSelection(), SelectionType.New);
-        SelectionHelpers.AddSelectionUndoStep(Owner.BitmapManager.ActiveDocument, oldSelection, SelectionType.New);
     }
 
     [Command.Basic("PixiEditor.Selection.Clear", "Clear selection", "Clear selection", CanExecute = "PixiEditor.Selection.IsNotEmpty", Key = Key.D, Modifiers = ModifierKeys.Control)]
     public void Deselect()
     {
-        var oldSelection = new List<Coordinates>(Owner.BitmapManager.ActiveDocument.ActiveSelection.SelectedPoints);
 
-        Owner.BitmapManager.ActiveDocument.ActiveSelection?.Clear();
-
-        SelectionHelpers.AddSelectionUndoStep(Owner.BitmapManager.ActiveDocument, oldSelection, SelectionType.New);
     }
 
     [Evaluator.CanExecute("PixiEditor.Selection.IsNotEmpty")]
     public bool SelectionIsNotEmpty()
     {
-        var selectedPoints = Owner.BitmapManager.ActiveDocument?.ActiveSelection.SelectedPoints;
-        return selectedPoints != null && selectedPoints.Count > 0;
+        return false;
     }
-}
+}

+ 3 - 52
src/PixiEditor/ViewModels/SubViewModels/Main/ToolsViewModel.cs

@@ -1,16 +1,11 @@
-using Microsoft.Extensions.DependencyInjection;
-using PixiEditor.Helpers;
+using System.Windows.Input;
+using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Enums;
 using PixiEditor.Models.Events;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.UserPreferences;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Windows.Input;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -63,9 +58,6 @@ public class ToolsViewModel : SubViewModel<ViewModelMain>
     {
         ToolSet = services.GetServices<Tool>().ToList();
         SetActiveTool<PenTool>();
-
-        Owner.BitmapManager.BitmapOperations.BitmapChanged += (_, _) => TriggerCacheOutdated();
-        Owner.BitmapManager.DocumentChanged += BitmapManager_DocumentChanged;
     }
 
     public void SetupToolsTooltipShortcuts(IServiceProvider services)
@@ -143,47 +135,6 @@ public class ToolsViewModel : SubViewModel<ViewModelMain>
         SetActiveTool(tool.GetType());
     }
 
-    public void TriggerCacheOutdated()
-    {
-        foreach (Tool tool in ToolSet)
-        {
-            if (tool is ICachedDocumentTool cachedTool)
-            {
-                cachedTool.DocumentChanged();
-            }
-        }
-    }
-
-    private void BitmapManager_DocumentChanged(object sender, Models.Events.DocumentChangedEventArgs e)
-    {
-        if (e.OldDocument != null)
-        {
-            e.OldDocument.DocumentSizeChanged -= Document_DocumentSizeChanged;
-            e.OldDocument.LayersChanged -= Document_LayersChanged;
-        }
-
-        if (e.NewDocument != null)
-        {
-            e.NewDocument.DocumentSizeChanged += Document_DocumentSizeChanged;
-            e.NewDocument.LayersChanged += Document_LayersChanged;
-        }
-
-        TriggerCacheOutdated();
-
-        void Document_DocumentSizeChanged(object sender, Models.DataHolders.DocumentSizeChangedEventArgs e)
-        {
-            TriggerCacheOutdated();
-        }
-
-        void Document_LayersChanged(object sender, Models.Controllers.LayersChangedEventArgs e)
-        {
-            if (e.LayerChangeType is LayerAction.Add or LayerAction.Remove or LayerAction.Move)
-            {
-                TriggerCacheOutdated();
-            }
-        }
-    }
-
     [Command.Basic("PixiEditor.Tools.IncreaseSize", 1, "Increase Tool Size", "Increase Tool Size", Key = Key.OemCloseBrackets)]
     [Command.Basic("PixiEditor.Tools.DecreaseSize", -1, "Decrease Tool Size", "Decrease Tool Size", Key = Key.OemOpenBrackets)]
     public void ChangeToolSize(int increment)
@@ -213,4 +164,4 @@ public class ToolsViewModel : SubViewModel<ViewModelMain>
             ToolCursor = Cursors.Arrow;
         }
     }
-}
+}

+ 12 - 14
src/PixiEditor/ViewModels/SubViewModels/Main/UndoViewModel.cs

@@ -1,7 +1,5 @@
-using PixiEditor.Models.Commands.Attributes;
-using PixiEditor.Models.Undo;
-using System.IO;
-using System.Windows.Input;
+using System.Windows.Input;
+using PixiEditor.Models.Commands.Attributes;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -13,7 +11,7 @@ public class UndoViewModel : SubViewModel<ViewModelMain>
     public UndoViewModel(ViewModelMain owner)
         : base(owner)
     {
-        var result = Directory.CreateDirectory(StorageBasedChange.DefaultUndoChangeLocation);
+        //var result = Directory.CreateDirectory(StorageBasedChange.DefaultUndoChangeLocation);
 
         //ClearUndoTempDirectory();
     }
@@ -30,8 +28,8 @@ public class UndoViewModel : SubViewModel<ViewModelMain>
         //sometimes CanRedo gets changed after UndoRedoCalled invoke, so check again (normally this is checked by the relaycommand)
         if (CanRedo())
         {
-            Owner.BitmapManager.ActiveDocument.UndoManager.Redo();
-            Owner.BitmapManager.ActiveDocument.ChangesSaved = false;
+            //Owner.BitmapManager.ActiveDocument.UndoManager.Redo();
+            //Owner.BitmapManager.ActiveDocument.ChangesSaved = false;
         }
     }
 
@@ -47,8 +45,8 @@ public class UndoViewModel : SubViewModel<ViewModelMain>
         //sometimes CanUndo gets changed after UndoRedoCalled invoke, so check again (normally this is checked by the relaycommand)
         if (CanUndo())
         {
-            Owner.BitmapManager.ActiveDocument.UndoManager.Undo();
-            Owner.BitmapManager.ActiveDocument.ChangesSaved = false;
+            //Owner.BitmapManager.ActiveDocument.UndoManager.Undo();
+            //Owner.BitmapManager.ActiveDocument.ChangesSaved = false;
         }
     }
 
@@ -57,11 +55,11 @@ public class UndoViewModel : SubViewModel<ViewModelMain>
     /// </summary>
     public void ClearUndoTempDirectory()
     {
-        DirectoryInfo dirInfo = new DirectoryInfo(StorageBasedChange.DefaultUndoChangeLocation);
+        /*DirectoryInfo dirInfo = new DirectoryInfo(StorageBasedChange.DefaultUndoChangeLocation);
         foreach (FileInfo file in dirInfo.GetFiles())
         {
             file.Delete();
-        }
+        }*/
     }
 
     /// <summary>
@@ -72,7 +70,7 @@ public class UndoViewModel : SubViewModel<ViewModelMain>
     [Evaluator.CanExecute("PixiEditor.Undo.CanUndo")]
     public bool CanUndo()
     {
-        return Owner.BitmapManager.ActiveDocument?.UndoManager.CanUndo ?? false;
+        return false;
     }
 
     /// <summary>
@@ -83,6 +81,6 @@ public class UndoViewModel : SubViewModel<ViewModelMain>
     [Evaluator.CanExecute("PixiEditor.Undo.CanRedo")]
     public bool CanRedo()
     {
-        return Owner.BitmapManager.ActiveDocument?.UndoManager.CanRedo ?? false;
+        return false;
     }
-}
+}

+ 0 - 1
src/PixiEditor/ViewModels/SubViewModels/Main/UpdateViewModel.cs

@@ -8,7 +8,6 @@ using System.Windows;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands.Attributes;
 using PixiEditor.Models.Dialogs;
-using PixiEditor.Models.Processes;
 using PixiEditor.Models.UserPreferences;
 using PixiEditor.UpdateModule;
 

+ 5 - 3
src/PixiEditor/ViewModels/SubViewModels/Main/ViewportViewModel.cs

@@ -1,5 +1,5 @@
-using PixiEditor.Models.Commands.Attributes;
-using System.Windows.Input;
+using System.Windows.Input;
+using PixiEditor.Models.Commands.Attributes;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -28,9 +28,11 @@ public class ViewportViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.View.Zoomout", -1, "Zoom out", "Zoom out", CanExecute = "PixiEditor.HasDocument", Key = Key.OemMinus)]
     public void ZoomViewport(double zoom)
     {
+        /*
         if (Owner.BitmapManager.ActiveDocument is not null)
         {
             Owner.BitmapManager.ActiveDocument.ZoomViewportTrigger.Execute(this, zoom);
         }
+        */
     }
-}
+}

+ 12 - 27
src/PixiEditor/ViewModels/ViewModelMain.cs

@@ -1,18 +1,14 @@
-using Microsoft.Extensions.DependencyInjection;
+using System.ComponentModel;
+using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Commands;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Dialogs;
-using PixiEditor.Models.Enums;
 using PixiEditor.Models.Events;
-using PixiEditor.Models.Position;
 using PixiEditor.Models.Tools;
 using PixiEditor.Models.UserPreferences;
 using PixiEditor.ViewModels.SubViewModels.Main;
 using SkiaSharp;
-using System.ComponentModel;
-using System.Windows;
 
 namespace PixiEditor.ViewModels;
 
@@ -120,8 +116,6 @@ public class ViewModelMain : ViewModelBase
 
         Preferences.Init();
         BitmapManager = services.GetRequiredService<BitmapManager>();
-        BitmapManager.BitmapOperations.BitmapChanged += BitmapUtility_BitmapChanged;
-        BitmapManager.DocumentChanged += BitmapManager_DocumentChanged;
 
         SelectionSubViewModel = services.GetService<SelectionViewModel>();
 
@@ -164,17 +158,6 @@ public class ViewModelMain : ViewModelBase
         SearchSubViewModel = services.GetService<SearchViewModel>();
     }
 
-    /// <summary>
-    ///     Resets most variables and controller, so new documents can be handled.
-    /// </summary>
-    public void ResetProgramStateValues()
-    {
-        foreach (var document in BitmapManager.Documents)
-        {
-            document.PreviewLayer.Reset();
-        }
-    }
-
     public bool DocumentIsNotNull(object property)
     {
         return BitmapManager.ActiveDocument != null;
@@ -244,6 +227,7 @@ public class ViewModelMain : ViewModelBase
     /// <returns>If document was removed successfully.</returns>
     private bool RemoveDocumentWithSaveConfirmation()
     {
+        /*
         ConfirmationType result = ConfirmationType.No;
 
         if (!BitmapManager.ActiveDocument.ChangesSaved)
@@ -269,7 +253,8 @@ public class ViewModelMain : ViewModelBase
         else
         {
             return false;
-        }
+        }*/
+        return false;
     }
 
     private void OnStartup(object parameter)
@@ -277,27 +262,27 @@ public class ViewModelMain : ViewModelBase
         OnStartupEvent?.Invoke(this, EventArgs.Empty);
     }
 
-    private void BitmapManager_DocumentChanged(object sender, DocumentChangedEventArgs e)
+    private void BitmapManager_DocumentChanged(object sender)
     {
+        /*
         if (e.NewDocument != null)
         {
             e.NewDocument.DocumentSizeChanged += ActiveDocument_DocumentSizeChanged;
-        }
+        }*/
     }
 
     private void ActiveDocument_DocumentSizeChanged(object sender, DocumentSizeChangedEventArgs e)
     {
-        BitmapManager.ActiveDocument.ActiveSelection = new Selection(Array.Empty<Coordinates>(), new PixelSize(e.NewWidth, e.NewHeight));
-        BitmapManager.ActiveDocument.ChangesSaved = false;
-        BitmapManager.ActiveDocument.CenterViewportTrigger.Execute(this, new Size(BitmapManager.ActiveDocument.Width, BitmapManager.ActiveDocument.Height));
+        //BitmapManager.ActiveDocument.ChangesSaved = false;
+        //BitmapManager.ActiveDocument.CenterViewportTrigger.Execute(this, new Size(BitmapManager.ActiveDocument.Width, BitmapManager.ActiveDocument.Height));
     }
 
     private void BitmapUtility_BitmapChanged(object sender, EventArgs e)
     {
-        BitmapManager.ActiveDocument.ChangesSaved = false;
+        //BitmapManager.ActiveDocument.ChangesSaved = false;
         if (ToolsSubViewModel.ActiveTool is BitmapOperationTool)
         {
             ColorsSubViewModel.AddSwatch(ColorsSubViewModel.PrimaryColor);
         }
     }
-}
+}

+ 4 - 24
src/PixiEditor/Views/MainWindow.xaml

@@ -50,8 +50,6 @@
                 x:Key="BoolToIntConverter" />
             <converters:NotNullToBoolConverter
                 x:Key="NotNullToBoolConverter" />
-            <converters:LayersToStructuredLayersConverter
-                x:Key="LayersToStructuredLayersConverter" />
             <converters:DoubleToIntConverter
                 x:Key="DoubleToIntConverter" />
             <converters:IsSpecifiedTypeConverter
@@ -659,28 +657,10 @@
                                             CanDockAsTabbedDocument="True"
                                             CanFloat="True">
                                             <layerUserControls:LayersManager
-                                                LayerCommandsViewModel="{Binding LayersSubViewModel}"
                                                 OpacityInputEnabled="{Binding BitmapManager.ActiveDocument, 
                     Converter={converters:NotNullToBoolConverter}}">
-                                                <layerUserControls:LayersManager.LayerTreeRoot>
-                                                    <MultiBinding
-                                                        Converter="{converters:LayersToStructuredLayersConverter}">
-                                                        <Binding
-                                                            Path="BitmapManager.ActiveDocument.Layers" />
-                                                        <Binding
-                                                            Path="BitmapManager.ActiveDocument.LayerStructure" />
-                                                    </MultiBinding>
-                                                </layerUserControls:LayersManager.LayerTreeRoot>
                                             </layerUserControls:LayersManager>
                                         </LayoutAnchorable>
-                                        <LayoutAnchorable
-                                            x:Name="rawLayerAnchorable"
-                                            ContentId="rawLayer"
-                                            Title="Raw layers">
-                                            <layerUserControls:RawLayersViewer
-                                                Layers="{Binding BitmapManager.ActiveDocument.Layers}"
-                                                Structure="{Binding BitmapManager.ActiveDocument.LayerStructure}" />
-                                        </LayoutAnchorable>
                                     </LayoutAnchorablePane>
                                     <LayoutAnchorablePane>
                                         <LayoutAnchorable
@@ -773,20 +753,20 @@
                             Text="X:"
                             Foreground="White"
                             FontSize="16" />
-                        <TextBlock
+                        <!--<TextBlock
                             Margin="4,0,10,0"
                             Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={converters:DoubleToIntConverter}}"
                             Foreground="White"
-                            FontSize="16" />
+                            FontSize="16" />-->
                         <TextBlock
                             Text="Y:"
                             Foreground="White"
                             FontSize="16" />
-                        <TextBlock
+                        <!--<TextBlock
                             Margin="4,0,10,0"
                             Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={converters:DoubleToIntConverter}}"
                             Foreground="White"
-                            FontSize="16" />
+                            FontSize="16" />-->
                     </StackPanel>
                 </DockPanel>
                 <StackPanel

+ 16 - 25
src/PixiEditor/Views/MainWindow.xaml.cs

@@ -1,23 +1,16 @@
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Interop;
+using System.Windows.Media.Imaging;
 using Microsoft.Extensions.DependencyInjection;
 using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
-using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.IO;
 using PixiEditor.Models.UserPreferences;
 using PixiEditor.ViewModels;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Linq;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Windows.Interop;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using AvalonDock.Layout;
 
 namespace PixiEditor;
 
@@ -60,12 +53,11 @@ public partial class MainWindow : Window
 
         DataContext.CloseAction = Close;
         Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
-
-        DataContext.BitmapManager.DocumentChanged += BitmapManager_DocumentChanged;
-        preferences.AddCallback<bool>("ImagePreviewInTaskbar", x =>
-        {
-            UpdateTaskbarIcon(x ? DataContext.BitmapManager.ActiveDocument : null);
-        });
+        /*
+                preferences.AddCallback<bool>("ImagePreviewInTaskbar", x =>
+                {
+                    UpdateTaskbarIcon(x ? DataContext.BitmapManager.ActiveDocument : null);
+                });*/
 
         OnReleaseBuild();
     }
@@ -115,9 +107,9 @@ public partial class MainWindow : Window
     [Conditional("RELEASE")]
     private void OnReleaseBuild()
     {
-        rawLayerAnchorable.Hide();
+        //rawLayerAnchorable.Hide();
     }
-
+    /*
     private void BitmapManager_DocumentChanged(object sender, Models.Events.DocumentChangedEventArgs e)
     {
         if (preferences.GetPreference("ImagePreviewInTaskbar", false))
@@ -125,7 +117,6 @@ public partial class MainWindow : Window
             UpdateTaskbarIcon(e.NewDocument);
         }
     }
-
     private void UpdateTaskbarIcon(Document document)
     {
         if (document?.PreviewImage == null)
@@ -140,7 +131,7 @@ public partial class MainWindow : Window
         previewCopy.Blit(new Rect(256, 256, 256, 256), pixiEditorLogo, new Rect(0, 0, 512, 512));
 
         Icon = previewCopy;
-    }
+    }*/
 
     private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
     {
@@ -205,7 +196,7 @@ public partial class MainWindow : Window
         if (e.Data.GetDataPresent(DataFormats.FileDrop))
         {
             string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
-            if(files != null && files.Length > 0)
+            if (files != null && files.Length > 0)
             {
                 if (Importer.IsSupportedFile(files[0]))
                 {
@@ -214,4 +205,4 @@ public partial class MainWindow : Window
             }
         }
     }
-}
+}

Деякі файли не було показано, через те що забагато файлів було змінено