Browse Source

Added selection to mask command

CPKreuz 2 years ago
parent
commit
6965c490fe

+ 16 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs

@@ -189,6 +189,22 @@ public static class FloodFillHelper
         return pixelStates;
     }
 
+    public static Surface FillSelection(IReadOnlyDocument document, VectorPath selection)
+    {
+        Surface surface = new Surface(document.Size);
+
+        var inverse = new VectorPath();
+        inverse.AddRect(new RectI(new(0, 0), document.Size));
+
+        surface.DrawingSurface.Canvas.Clear(new Color(255, 255, 255, 255));
+        surface.DrawingSurface.Canvas.Flush();
+        surface.DrawingSurface.Canvas.ClipPath(inverse.Op(selection, VectorPathOp.Difference));
+        surface.DrawingSurface.Canvas.Clear(new Color(0, 0, 0, 0));
+        surface.DrawingSurface.Canvas.Flush();
+
+        return surface;
+    }
+
     /// <summary>
     /// Use skia to set all pixels in array that are inside selection to InSelection
     /// </summary>

+ 69 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/SelectionToMask_Change.cs

@@ -0,0 +1,69 @@
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
+using PixiEditor.ChangeableDocument.Enums;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
+using BlendMode = PixiEditor.DrawingApi.Core.Surface.BlendMode;
+
+namespace PixiEditor.ChangeableDocument.Changes.Drawing;
+
+internal class SelectionToMask_Change : Change
+{
+    private readonly SelectionMode mode;
+    private readonly Guid targetMember;
+    private Changeables.Selection? selection;
+    private CommittedChunkStorage? chunkStorage = null;
+    
+    [GenerateMakeChangeAction]
+    public SelectionToMask_Change(Guid targetMember, SelectionMode mode)
+    {
+        this.targetMember = targetMember;
+        this.mode = mode;
+    }
+    
+    public override bool InitializeAndValidate(Document target)
+    {
+        selection = target.Selection;
+        return true;
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
+    {
+        var image = DrawingChangeHelper.GetTargetImageOrThrow(target, targetMember, true);
+        
+        VectorPath? selection = target.Selection.SelectionPath.IsEmpty ? null : target.Selection.SelectionPath;
+        HashSet<Guid> membersToReference = new();
+        membersToReference.Add(targetMember);
+        
+        var blendMode = mode switch
+        {
+            SelectionMode.New => BlendMode.DstATop,
+            SelectionMode.Add => BlendMode.Plus,
+            SelectionMode.Subtract => BlendMode.DstOut,
+            SelectionMode.Intersect => BlendMode.SrcIn
+        };
+
+        image.SetBlendMode(blendMode);
+
+        var selectionImage = FloodFillHelper.FillSelection(target, selection!);
+        
+        selectionImage.SaveToDesktop();
+
+        image.EnqueueDrawImage(new VecI(0, 0), selectionImage);
+        
+        var affArea = image.FindAffectedArea();
+        chunkStorage = new CommittedChunkStorage(image, affArea.Chunks);
+        image.CommitChanges();
+
+        ignoreInUndo = false;
+        return DrawingChangeHelper.CreateAreaChangeInfo(targetMember, affArea, true);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        var affArea = DrawingChangeHelper.ApplyStoredChunksDisposeAndSetToNull(target, targetMember, true, ref chunkStorage);
+        return DrawingChangeHelper.CreateAreaChangeInfo(targetMember, affArea, true);
+    }
+}

+ 13 - 0
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -536,4 +536,17 @@ internal class DocumentOperationsModule
             new EndTransformReferenceLayer_Action()
             );
     }
+
+    public void SelectionToMask(SelectionMode mode)
+    {
+        if (Document.SelectedStructureMember is not { } member || Document.SelectionPathBindable.IsEmpty)
+            return;
+
+        if (!Document.SelectedStructureMember.HasMaskBindable)
+        {
+            Internals.ActionAccumulator.AddActions(new CreateStructureMemberMask_Action(member.GuidValue));
+        }
+        
+        Internals.ActionAccumulator.AddFinishedActions(new SelectionToMask_Action(member.GuidValue, mode));
+    }
 }

+ 10 - 0
src/PixiEditor/ViewModels/SubViewModels/Main/SelectionViewModel.cs

@@ -1,4 +1,5 @@
 using System.Windows.Input;
+using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Models.Commands.Attributes.Commands;
 
@@ -52,6 +53,15 @@ internal class SelectionViewModel : SubViewModel<ViewModelMain>
         Owner.DocumentManagerSubViewModel.ActiveDocument?.Operations.NudgeSelectedObject(distance);
     }
 
+    [Command.Basic("PixiEditor.Selection.NewToMask", SelectionMode.New, "Selection to mask", "Selection to new mask")]
+    [Command.Basic("PixiEditor.Selection.AddToMask", SelectionMode.Add, "Add selection to mask", "Add selection to mask")]
+    [Command.Basic("PixiEditor.Selection.SubtractFromMask", SelectionMode.Subtract, "Subtract selection from mask", "Subtract selection from mask")]
+    [Command.Basic("PixiEditor.Selection.IntersectSelectionMask", SelectionMode.Intersect, "Intersect selection with mask", "Intersect selection with mask")]
+    public void SelectionToMask(SelectionMode mode)
+    {
+        Owner.DocumentManagerSubViewModel.ActiveDocument?.Operations.SelectionToMask(mode);
+    }
+
     [Evaluator.CanExecute("PixiEditor.Selection.CanNudgeSelectedObject")]
     public bool CanNudgeSelectedObject(int[] dist) => Owner.DocumentManagerSubViewModel.ActiveDocument?.UpdateableChangeActive == true;
 }