Browse Source

Improve lasso tool ever so slightly

Equbuxu 2 years ago
parent
commit
62ea01a92b

+ 29 - 0
src/PixiEditor/Helpers/ChangeInfoListOptimizer.cs

@@ -0,0 +1,29 @@
+using PixiEditor.ChangeableDocument.ChangeInfos;
+using PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
+
+namespace PixiEditor.Helpers;
+
+#nullable enable
+internal class ChangeInfoListOptimizer
+{
+    public static List<IChangeInfo> Optimize(List<IChangeInfo?> input)
+    {
+        List<IChangeInfo> output = new();
+        bool selectionInfoOccured = false;
+        // discard all Selection_ChangeInfos apart from the last one
+        for (int i = input.Count - 1; i >= 0; i--)
+        {
+            IChangeInfo? info = input[i];
+            if (info is null)
+                continue;
+            if (info is Selection_ChangeInfo && !selectionInfoOccured)
+                selectionInfoOccured = true;
+            else if (selectionInfoOccured)
+                continue;
+            output.Add(info);
+        }
+
+        output.Reverse();
+        return output;
+    }
+}

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

@@ -6,6 +6,7 @@ using PixiEditor.ChangeableDocument.Actions;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Helpers;
 using PixiEditor.Models.Rendering;
 using PixiEditor.Models.Rendering;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Document;
@@ -81,8 +82,9 @@ internal class ActionAccumulator
                 changes = await internals.Tracker.ProcessActions(toExecute);
                 changes = await internals.Tracker.ProcessActions(toExecute);
 
 
             // update viewmodels based on changes
             // update viewmodels based on changes
+            List<IChangeInfo> optimizedChanges = ChangeInfoListOptimizer.Optimize(changes);
             bool undoBoundaryPassed = toExecute.Any(static action => action is ChangeBoundary_Action or Redo_Action or Undo_Action);
             bool undoBoundaryPassed = toExecute.Any(static action => action is ChangeBoundary_Action or Redo_Action or Undo_Action);
-            foreach (IChangeInfo? info in changes)
+            foreach (IChangeInfo info in optimizedChanges)
             {
             {
                 internals.Updater.ApplyChangeFromChangeInfo(info);
                 internals.Updater.ApplyChangeFromChangeInfo(info);
             }
             }
@@ -109,7 +111,7 @@ internal class ActionAccumulator
             // Also, there is a bug report for this on github https://github.com/dotnet/wpf/issues/5816
             // Also, there is a bug report for this on github https://github.com/dotnet/wpf/issues/5816
 
 
             // update the contents of the bitmaps
             // update the contents of the bitmaps
-            var affectedChunks = new AffectedChunkGatherer(internals.Tracker, changes);
+            var affectedChunks = new AffectedChunkGatherer(internals.Tracker, optimizedChanges);
             var renderResult = await renderer.UpdateGatheredChunks(affectedChunks, undoBoundaryPassed);
             var renderResult = await renderer.UpdateGatheredChunks(affectedChunks, undoBoundaryPassed);
             
             
             // lock bitmaps
             // lock bitmaps

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

@@ -40,7 +40,7 @@ internal class DocumentUpdater
     /// <summary>
     /// <summary>
     /// Don't call this outside ActionAccumulator
     /// Don't call this outside ActionAccumulator
     /// </summary>
     /// </summary>
-    public void ApplyChangeFromChangeInfo(IChangeInfo? arbitraryInfo)
+    public void ApplyChangeFromChangeInfo(IChangeInfo arbitraryInfo)
     {
     {
         if (arbitraryInfo is null)
         if (arbitraryInfo is null)
             return;
             return;

+ 3 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/LassoToolExecutor.cs

@@ -14,7 +14,7 @@ internal sealed class LassoToolExecutor : UpdateableChangeExecutor
     {
     {
         mode = ViewModelMain.Current?.ToolsSubViewModel.GetTool<LassoToolViewModel>()?.SelectMode;
         mode = ViewModelMain.Current?.ToolsSubViewModel.GetTool<LassoToolViewModel>()?.SelectMode;
 
 
-        if (mode == null)
+        if (mode is null)
             return ExecutionState.Error;
             return ExecutionState.Error;
         
         
         AddStartAction(controller!.LastPixelPosition);
         AddStartAction(controller!.LastPixelPosition);
@@ -26,13 +26,13 @@ internal sealed class LassoToolExecutor : UpdateableChangeExecutor
 
 
     public override void OnLeftMouseButtonUp()
     public override void OnLeftMouseButtonUp()
     {
     {
-        internals!.ActionAccumulator.AddActions(new EndSelectLasso_Action());
+        internals!.ActionAccumulator.AddFinishedActions(new EndSelectLasso_Action());
         onEnded!(this);
         onEnded!(this);
     }
     }
 
 
     public override void ForceStop()
     public override void ForceStop()
     {
     {
-        OnLeftMouseButtonUp();
+        internals!.ActionAccumulator.AddFinishedActions(new EndSelectLasso_Action());
     }
     }
 
 
     private void AddStartAction(VecI pos)
     private void AddStartAction(VecI pos)

+ 2 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/SelectToolExecutor.cs

@@ -68,6 +68,7 @@ internal class SelectToolExecutor : UpdateableChangeExecutor
 
 
     public override void ForceStop()
     public override void ForceStop()
     {
     {
-        OnLeftMouseButtonUp();
+        IAction action = CreateEndAction(selectShape);
+        internals!.ActionAccumulator.AddFinishedActions(action);
     }
     }
 }
 }

+ 19 - 19
src/PixiEditor/Models/Rendering/AffectedChunkGatherer.cs

@@ -15,17 +15,17 @@ internal class AffectedChunkGatherer
 {
 {
     private readonly DocumentChangeTracker tracker;
     private readonly DocumentChangeTracker tracker;
 
 
-    public HashSet<VecI> mainImageChunks { get; private set; } = new();
-    public Dictionary<Guid, HashSet<VecI>> imagePreviewChunks { get; private set; } = new();
-    public Dictionary<Guid, HashSet<VecI>> maskPreviewChunks { get; private set; } = new();
+    public HashSet<VecI> MainImageChunks { get; private set; } = new();
+    public Dictionary<Guid, HashSet<VecI>> ImagePreviewChunks { get; private set; } = new();
+    public Dictionary<Guid, HashSet<VecI>> MaskPreviewChunks { get; private set; } = new();
 
 
-    public AffectedChunkGatherer(DocumentChangeTracker tracker, IReadOnlyList<IChangeInfo?> changes)
+    public AffectedChunkGatherer(DocumentChangeTracker tracker, IReadOnlyList<IChangeInfo> changes)
     {
     {
         this.tracker = tracker;
         this.tracker = tracker;
         ProcessChanges(changes);
         ProcessChanges(changes);
     }
     }
 
 
-    private void ProcessChanges(IReadOnlyList<IChangeInfo?> changes)
+    private void ProcessChanges(IReadOnlyList<IChangeInfo> changes)
     {
     {
         foreach (var change in changes)
         foreach (var change in changes)
         {
         {
@@ -144,7 +144,7 @@ internal class AffectedChunkGatherer
 
 
     private void AddToMainImage(HashSet<VecI> chunks)
     private void AddToMainImage(HashSet<VecI> chunks)
     {
     {
-        mainImageChunks.UnionWith(chunks);
+        MainImageChunks.UnionWith(chunks);
     }
     }
 
 
     private void AddToImagePreviews(Guid memberGuid, HashSet<VecI> chunks, bool ignoreSelf = false)
     private void AddToImagePreviews(Guid memberGuid, HashSet<VecI> chunks, bool ignoreSelf = false)
@@ -155,25 +155,25 @@ internal class AffectedChunkGatherer
         for (int i = ignoreSelf ? 1 : 0; i < path.Count - 1; i++)
         for (int i = ignoreSelf ? 1 : 0; i < path.Count - 1; i++)
         {
         {
             var member = path[i];
             var member = path[i];
-            if (!imagePreviewChunks.ContainsKey(member.GuidValue))
-                imagePreviewChunks[member.GuidValue] = new HashSet<VecI>(chunks);
+            if (!ImagePreviewChunks.ContainsKey(member.GuidValue))
+                ImagePreviewChunks[member.GuidValue] = new HashSet<VecI>(chunks);
             else
             else
-                imagePreviewChunks[member.GuidValue].UnionWith(chunks);
+                ImagePreviewChunks[member.GuidValue].UnionWith(chunks);
         }
         }
     }
     }
 
 
     private void AddToMaskPreview(Guid memberGuid, HashSet<VecI> chunks)
     private void AddToMaskPreview(Guid memberGuid, HashSet<VecI> chunks)
     {
     {
-        if (!maskPreviewChunks.ContainsKey(memberGuid))
-            maskPreviewChunks[memberGuid] = new HashSet<VecI>(chunks);
+        if (!MaskPreviewChunks.ContainsKey(memberGuid))
+            MaskPreviewChunks[memberGuid] = new HashSet<VecI>(chunks);
         else
         else
-            maskPreviewChunks[memberGuid].UnionWith(chunks);
+            MaskPreviewChunks[memberGuid].UnionWith(chunks);
     }
     }
 
 
 
 
     private void AddWholeCanvasToMainImage()
     private void AddWholeCanvasToMainImage()
     {
     {
-        AddAllChunks(mainImageChunks);
+        AddAllChunks(MainImageChunks);
     }
     }
 
 
     private void AddWholeCanvasToImagePreviews(Guid memberGuid, bool ignoreSelf = false)
     private void AddWholeCanvasToImagePreviews(Guid memberGuid, bool ignoreSelf = false)
@@ -185,17 +185,17 @@ internal class AffectedChunkGatherer
         for (int i = ignoreSelf ? 1 : 0; i < path.Count - 1; i++)
         for (int i = ignoreSelf ? 1 : 0; i < path.Count - 1; i++)
         {
         {
             var member = path[i];
             var member = path[i];
-            if (!imagePreviewChunks.ContainsKey(member.GuidValue))
-                imagePreviewChunks[member.GuidValue] = new HashSet<VecI>();
-            AddAllChunks(imagePreviewChunks[member.GuidValue]);
+            if (!ImagePreviewChunks.ContainsKey(member.GuidValue))
+                ImagePreviewChunks[member.GuidValue] = new HashSet<VecI>();
+            AddAllChunks(ImagePreviewChunks[member.GuidValue]);
         }
         }
     }
     }
 
 
     private void AddWholeCanvasToMaskPreview(Guid memberGuid)
     private void AddWholeCanvasToMaskPreview(Guid memberGuid)
     {
     {
-        if (!maskPreviewChunks.ContainsKey(memberGuid))
-            maskPreviewChunks[memberGuid] = new HashSet<VecI>();
-        AddAllChunks(maskPreviewChunks[memberGuid]);
+        if (!MaskPreviewChunks.ContainsKey(memberGuid))
+            MaskPreviewChunks[memberGuid] = new HashSet<VecI>();
+        AddAllChunks(MaskPreviewChunks[memberGuid]);
     }
     }
 
 
 
 

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

@@ -73,7 +73,7 @@ internal class WriteableBitmapUpdater
         // add all affected chunks to postponed
         // add all affected chunks to postponed
         foreach (var (_, postponed) in globalPostponedChunks)
         foreach (var (_, postponed) in globalPostponedChunks)
         {
         {
-            postponed.UnionWith(chunkGatherer.mainImageChunks);
+            postponed.UnionWith(chunkGatherer.MainImageChunks);
         }
         }
 
 
         // find all chunks that are on viewports and on delayed viewports
         // find all chunks that are on viewports and on delayed viewports
@@ -141,8 +141,8 @@ internal class WriteableBitmapUpdater
     private (Dictionary<Guid, HashSet<VecI>> image, Dictionary<Guid, HashSet<VecI>> mask) FindPreviewChunksToRerender
     private (Dictionary<Guid, HashSet<VecI>> image, Dictionary<Guid, HashSet<VecI>> mask) FindPreviewChunksToRerender
         (AffectedChunkGatherer chunkGatherer, bool postpone)
         (AffectedChunkGatherer chunkGatherer, bool postpone)
     {
     {
-        AddChunks(chunkGatherer.imagePreviewChunks, previewDelayedChunks);
-        AddChunks(chunkGatherer.maskPreviewChunks, maskPreviewDelayedChunks);
+        AddChunks(chunkGatherer.ImagePreviewChunks, previewDelayedChunks);
+        AddChunks(chunkGatherer.MaskPreviewChunks, maskPreviewDelayedChunks);
         if (postpone)
         if (postpone)
             return (new(), new());
             return (new(), new());
         var result = (previewPostponedChunks: previewDelayedChunks, maskPostponedChunks: maskPreviewDelayedChunks);
         var result = (previewPostponedChunks: previewDelayedChunks, maskPostponedChunks: maskPreviewDelayedChunks);