2
0
Equbuxu 3 жил өмнө
parent
commit
63d9f779c0

+ 0 - 46
PixiEditor/Helpers/SelectionHelpers.cs

@@ -1,46 +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);
-        }
-    }
-}

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

@@ -24,6 +24,7 @@ namespace PixiEditor.Models.DataHolders
             SetRelayCommands();
             UndoManager = new UndoManager();
             LayerStructure = new LayerStructure(this);
+            ActiveSelection = new Selection(this);
             XamlAccesibleViewModel = ViewModelMain.Current;
             GeneratePreviewLayer();
             Layers.CollectionChanged += Layers_CollectionChanged;

+ 1 - 11
PixiEditor/Models/DataHolders/Document/Document.cs

@@ -61,17 +61,7 @@ namespace PixiEditor.Models.DataHolders
             }
         }
 
-        private Selection selection = new Selection(Array.Empty<Coordinates>());
-
-        public Selection ActiveSelection
-        {
-            get => selection;
-            set
-            {
-                selection = value;
-                RaisePropertyChanged(nameof(ActiveSelection));
-            }
-        }
+        public Selection ActiveSelection { get; }
 
         private double mouseXonCanvas;
         public double MouseXOnCanvas // Mouse X coordinate relative to canvas

+ 54 - 42
PixiEditor/Models/DataHolders/Selection.cs

@@ -1,12 +1,11 @@
 using PixiEditor.Helpers;
+using PixiEditor.Helpers.Extensions;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Layers;
-using PixiEditor.Models.Position;
+using PixiEditor.Models.Undo;
 using SkiaSharp;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
+using System;
 using System.Diagnostics;
-using System.Linq;
 using System.Windows;
 
 namespace PixiEditor.Models.DataHolders
@@ -14,59 +13,48 @@ namespace PixiEditor.Models.DataHolders
     [DebuggerDisplay("{SelectedPoints.Count} selected Pixels")]
     public class Selection : NotifyableObject
     {
-        private readonly SKColor selectionBlue;
-        private Layer selectionLayer;
+        public bool isEmpty { get; private set; } = true;
 
-        public Selection(Coordinates[] selectedPoints)
+        private readonly SKColor selectionBlue = new SKColor(142, 202, 255, 255);
+        private Layer selectionLayer = new Layer("_selectionLayer");
+        private Document owner;
+
+        public Selection(Document owner)
         {
-            SelectedPoints = new ObservableCollection<Coordinates>(selectedPoints);
-            SelectionLayer = new Layer("_selectionLayer");
-            selectionBlue = new SKColor(142, 202, 255, 255);
+            this.owner = owner;
         }
 
-        public ObservableCollection<Coordinates> SelectedPoints { get; private set; }
-
         public Layer SelectionLayer
         {
             get => selectionLayer;
-            set
+            private set
             {
                 selectionLayer = value;
                 RaisePropertyChanged(nameof(SelectionLayer));
             }
         }
 
-        public void SetSelection(IEnumerable<Coordinates> selection, SelectionType mode)
+        public void TranslateSelection(int dX, int dY)
         {
-            SKColor selectionColor = selectionBlue;
-            switch (mode)
-            {
-                case SelectionType.New:
-                    SelectedPoints = new ObservableCollection<Coordinates>(selection);
-                    SelectionLayer.Reset();
-                    break;
-                case SelectionType.Add:
-                    SelectedPoints = new ObservableCollection<Coordinates>(SelectedPoints.Concat(selection).Distinct());
-                    break;
-                case SelectionType.Subtract:
-                    SelectedPoints = new ObservableCollection<Coordinates>(SelectedPoints.Except(selection));
-                    selectionColor = SKColors.Transparent;
-                    break;
-            }
-
-            SelectionLayer.SetPixels(BitmapPixelChanges.FromSingleColoredArray(selection, selectionColor));
+            selectionLayer.Offset = new Thickness(selectionLayer.OffsetX + dX, selectionLayer.OffsetY + dY, 0, 0);
         }
 
-        public void TranslateSelection(int dX, int dY)
+        public void SetSelectionWithUndo(Int32Rect rect, SelectionShape shape, SelectionType mode)
         {
-            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);
-            }
+            Int32Rect updateRect;
+            if (mode == SelectionType.New)
+                updateRect = rect.Expand(new(selectionLayer.OffsetX, selectionLayer.OffsetY, selectionLayer.Width, selectionLayer.Height));
+            else
+                updateRect = rect;
+            LayerChunk chunk = new LayerChunk(selectionLayer, new(updateRect.X, updateRect.Y, updateRect.X + updateRect.Width, updateRect.Y + updateRect.Height));
+            StorageBasedChange change = new(owner, new LayerChunk[] { chunk });
+
+            DrawSelection(rect, shape, mode);
+
+            owner.UndoManager.AddUndoChange(change.ToChange(SelectionUndoProcess, new object[] { owner }, "Update selection"));
         }
 
-        public void SetSelection(Int32Rect rect, bool isCirclular, SelectionType mode)
+        private void DrawSelection(Int32Rect rect, SelectionShape shape, SelectionType mode)
         {
             using SKPaint paint = new()
             {
@@ -84,23 +72,47 @@ namespace PixiEditor.Models.DataHolders
                     break;
             }
 
+            if (!rect.HasArea)
+                return;
+            isEmpty = false;
             SelectionLayer.DynamicResizeAbsolute(new Int32Rect(rect.X, rect.Y, rect.Width, rect.Height));
-            if (isCirclular)
+            if (shape == SelectionShape.Circle)
             {
                 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
+            else if (shape == SelectionShape.Rectangle)
             {
                 SelectionLayer.LayerBitmap.SkiaSurface.Canvas.DrawRect(rect.X, rect.Y, rect.Width, rect.Height, paint);
             }
+            else
+            {
+                throw new NotImplementedException($"Selection shape '{shape}' has not been implemented");
+            }
+        }
+
+        private static void SelectionUndoProcess(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.ActiveSelection.SelectionLayer;
+                    StorageBasedChange.ApplyChunkToLayer(foundLayer, layerData, layer.LayerBitmap);
+                }
+            }
         }
 
-        public void Clear()
+        public void ClearWithUndo()
         {
+            SKRectI updateRect = new SKRectI(selectionLayer.OffsetX, selectionLayer.OffsetY, selectionLayer.OffsetX + selectionLayer.Width, selectionLayer.OffsetY + selectionLayer.Height);
+            StorageBasedChange change = new(owner, new LayerChunk[] { new(selectionLayer, updateRect) });
             SelectionLayer.Reset();
-            SelectedPoints.Clear();
+            isEmpty = true;
+            owner.UndoManager.AddUndoChange(change.ToChange(SelectionUndoProcess, new object[] { owner }, "Clear selection"));
         }
     }
 }

+ 12 - 54
PixiEditor/Models/Tools/Tools/SelectTool.cs

@@ -1,16 +1,14 @@
-using PixiEditor.Helpers;
-using PixiEditor.Helpers.Extensions;
+using PixiEditor.Helpers.Extensions;
 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 System;
+using SkiaSharp;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
-using SkiaSharp;
+using System.Windows;
 
 namespace PixiEditor.Models.Tools.Tools
 {
@@ -63,64 +61,24 @@ namespace PixiEditor.Models.Tools.Tools
             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)
-        {
-            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);
-
+            Int32Rect rect;
             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]);
+                rect = Int32Rect.Empty;
             }
             else
             {
-                throw new NotImplementedException($"Selection shape '{shape}' has not been implemented");
+                DoubleCoords fixedCoordinates = ShapeTool.CalculateCoordinatesForShapeRotation(pixels[^1], pixels[0]);
+                rect = new(
+                    fixedCoordinates.Coords1.X,
+                    fixedCoordinates.Coords2.X,
+                    fixedCoordinates.Coords2.X - fixedCoordinates.Coords1.X + 1,
+                    fixedCoordinates.Coords2.Y - fixedCoordinates.Coords1.Y + 1);
             }
 
-            BitmapManager.ActiveDocument.ActiveSelection.SetSelection(selection, SelectionType);
+            BitmapManager.ActiveDocument.ActiveSelection.SetSelectionWithUndo(rect, shape, SelectionType);
         }
     }
 }

+ 1 - 1
PixiEditor/Models/Undo/StorageBasedChange.cs

@@ -335,7 +335,7 @@ namespace PixiEditor.Models.Undo
             }
         }
 
-        private static void ApplyChunkToLayer(Layer layer, UndoLayer layerData, Surface chunk)
+        public static void ApplyChunkToLayer(Layer layer, UndoLayer layerData, Surface chunk)
         {
             bool widthBigger = layer.Width < chunk.Width;
             bool heightBigger = layer.Height < chunk.Height;

+ 9 - 18
PixiEditor/ViewModels/SubViewModels/Main/SelectionViewModel.cs

@@ -1,11 +1,7 @@
-using System;
-using System.Collections.Generic;
-using PixiEditor.Helpers;
-using PixiEditor.Models.DataHolders;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Enums;
-using PixiEditor.Models.Position;
-using PixiEditor.Models.Tools;
 using PixiEditor.Models.Tools.Tools;
+using System.Windows;
 
 namespace PixiEditor.ViewModels.SubViewModels.Main
 {
@@ -28,25 +24,20 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
 
         public void SelectAll(object parameter)
         {
-            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);
+            var doc = Owner.BitmapManager.ActiveDocument;
+            Int32Rect area = new(0, 0, doc.Width, doc.Height);
+            doc.ActiveSelection.SetSelectionWithUndo(area, false, SelectionType.New);
         }
 
         public void Deselect(object parameter)
         {
-            var oldSelection = new List<Coordinates>(Owner.BitmapManager.ActiveDocument.ActiveSelection.SelectedPoints);
-
-            Owner.BitmapManager.ActiveDocument.ActiveSelection?.Clear();
-
-            SelectionHelpers.AddSelectionUndoStep(Owner.BitmapManager.ActiveDocument, oldSelection, SelectionType.New);
+            Owner.BitmapManager.ActiveDocument.ActiveSelection?.ClearWithUndo();
         }
 
         public bool SelectionIsNotEmpty(object property)
         {
-            var selectedPoints = Owner.BitmapManager.ActiveDocument?.ActiveSelection.SelectedPoints;
-            return selectedPoints != null && selectedPoints.Count > 0;
+            var empty = Owner.BitmapManager.ActiveDocument?.ActiveSelection.isEmpty;
+            return empty != null && !empty.Value;
         }
 
         private bool CanSelectAll(object property)
@@ -54,4 +45,4 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
             return Owner.BitmapManager.ActiveDocument != null && Owner.BitmapManager.ActiveDocument.Layers.Count > 0;
         }
     }
-}
+}

+ 0 - 1
PixiEditor/ViewModels/ViewModelMain.cs

@@ -360,7 +360,6 @@ namespace PixiEditor.ViewModels
 
         private void ActiveDocument_DocumentSizeChanged(object sender, DocumentSizeChangedEventArgs e)
         {
-            BitmapManager.ActiveDocument.ActiveSelection = new Selection(Array.Empty<Coordinates>());
             BitmapManager.ActiveDocument.ChangesSaved = false;
             BitmapManager.ActiveDocument.CenterViewportTrigger.Execute(this, new Size(BitmapManager.ActiveDocument.Width, BitmapManager.ActiveDocument.Height));
         }

+ 4 - 5
PixiEditorTests/ModelsTests/DataHoldersTests/SelectionTests.cs

@@ -2,7 +2,6 @@
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Position;
-using System;
 using System.Collections.Generic;
 using Xunit;
 
@@ -13,7 +12,7 @@ namespace PixiEditorTests.ModelsTests.DataHoldersTests
         [Fact]
         public void TestThatSetSelectionNewSetsCorrectSelection()
         {
-            Selection selection = new Selection(Array.Empty<Coordinates>());
+            Selection selection = new Selection();
             Coordinates[] points = { new Coordinates(0, 0), new Coordinates(1, 1) };
 
             selection.SetSelection(points, SelectionType.New);
@@ -25,7 +24,7 @@ namespace PixiEditorTests.ModelsTests.DataHoldersTests
         [Fact]
         public void TestThatSetSelectionAddSetsCorrectSelection()
         {
-            Selection selection = new Selection(Array.Empty<Coordinates>());
+            Selection selection = new Selection();
             Coordinates[] points = { new Coordinates(0, 0), new Coordinates(1, 1) };
             Coordinates[] points2 = { new Coordinates(2, 4), new Coordinates(5, 7) };
 
@@ -38,7 +37,7 @@ namespace PixiEditorTests.ModelsTests.DataHoldersTests
         [Fact]
         public void TestThatSetSelectionSubtractSetsCorrectSelection()
         {
-            Selection selection = new Selection(Array.Empty<Coordinates>());
+            Selection selection = new Selection();
             Coordinates[] points = { new Coordinates(0, 0), new Coordinates(1, 1) };
             Coordinates[] points2 = { new Coordinates(1, 1) };
 
@@ -62,7 +61,7 @@ namespace PixiEditorTests.ModelsTests.DataHoldersTests
         [Fact]
         public void TestThatUndoWorks()
         {
-            Document document = new Document(10, 10);
+            using Document document = new Document(10, 10);
 
             IEnumerable<Coordinates> oldSelection = new List<Coordinates>(document.ActiveSelection.SelectedPoints);