Browse Source

Added painting eraser

flabbet 10 months ago
parent
commit
880281056b

+ 11 - 7
src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs

@@ -13,7 +13,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
     private readonly Guid memberGuid;
     private readonly Color color;
     private int strokeWidth;
-    private readonly bool replacing;
+    private readonly bool erasing;
     private readonly bool drawOnMask;
     private readonly bool antiAliasing;
     private float hardness;
@@ -26,7 +26,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
     private VecF lastPos;
 
     [GenerateUpdateableChangeActions]
-    public LineBasedPen_UpdateableChange(Guid memberGuid, Color color, VecI pos, int strokeWidth, bool replacing,
+    public LineBasedPen_UpdateableChange(Guid memberGuid, Color color, VecI pos, int strokeWidth, bool erasing,
         bool antiAliasing,
         float hardness,
         float spacing,
@@ -35,17 +35,21 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         this.memberGuid = memberGuid;
         this.color = color;
         this.strokeWidth = strokeWidth;
-        this.replacing = replacing;
+        this.erasing = erasing;
         this.antiAliasing = antiAliasing;
         this.drawOnMask = drawOnMask;
         this.hardness = hardness;
         this.spacing = spacing;
         points.Add(pos);
         this.frame = frame;
-        if (this.antiAliasing)
+        if (this.antiAliasing && !erasing)
         {
             srcPaint.BlendMode = BlendMode.SrcOver;
         }
+        else if (erasing)
+        {
+            srcPaint.BlendMode = BlendMode.DstOut;
+        }
     }
 
     [UpdateChangeMethod]
@@ -62,7 +66,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         if (strokeWidth < 1)
             return false;
         var image = DrawingChangeHelper.GetTargetImageOrThrow(target, memberGuid, drawOnMask, frame);
-        if (!replacing)
+        if (!erasing)
             image.SetBlendMode(BlendMode.SrcOver);
         DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
         srcPaint.IsAntiAliased = antiAliasing;
@@ -136,7 +140,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         float radius = strokeWidth / 2f;
         radius = MathF.Max(1, radius);
         srcPaint.Shader = Shader.CreateRadialGradient(
-            pos, radius, new Color[] { color, color.WithAlpha(0) },
+            pos, radius, new Color[] { color, color.WithAlpha(0) }, 
             new float[] { hardness, 1 }, ShaderTileMode.Clamp);
     }
 
@@ -158,7 +162,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         }
         else
         {
-            if (!replacing)
+            if (!erasing)
                 image.SetBlendMode(BlendMode.SrcOver);
             DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
 

+ 21 - 14
src/PixiEditor/Data/Configs/ToolSetsConfig.json

@@ -19,7 +19,12 @@
       "RasterLine",
       "RasterEllipse",
       "RasterRectangle",
-      "Eraser",
+      {
+        "ToolName": "Eraser",
+        "Settings": {
+          "Spacing": 0
+        }
+      },
       "ColorPicker",
       "Brightness",
       "Zoom"
@@ -59,24 +64,26 @@
           "AntiAliasing": true
         }
       },
-        {
-            "ToolName": "RasterEllipse",
-            "Settings": {
-            "AntiAliasing": true
-            }
-        },
-        {
-            "ToolName": "RasterRectangle",
-            "Settings": {
-            "AntiAliasing": true
-            }
-        },
       {
-        "ToolName": "Eraser",
+        "ToolName": "RasterEllipse",
+        "Settings": {
+          "AntiAliasing": true
+        }
+      },
+      {
+        "ToolName": "RasterRectangle",
         "Settings": {
           "AntiAliasing": true
         }
       },
+      {
+        "ToolName": "Eraser",
+        "Settings": {
+          "AntiAliasing": true,
+          "ExposeHardness": true,
+          "ExposeSpacing": true
+        }
+      },
       "ColorPicker",
       "Brightness",
       "Zoom"

+ 2 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -759,5 +759,6 @@
   "RENDER_OUTPUT": "Render Output",
   "PAINT_TOOLSET": "Painting",
   "HARDNESS_SETTING": "Hardness",
-  "SPACING_SETTING": "Spacing"
+  "SPACING_SETTING": "Spacing",
+  "ANTI_ALIASING_SETTING": "Anti-aliasing"
 }

+ 12 - 5
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs

@@ -17,18 +17,22 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
     private Guid guidValue;
     private Color color;
     private int toolSize;
+    private bool antiAliasing;
+    private float hardness;
+    private float spacing;
+    
     private bool drawOnMask;
 
     public override ExecutionState Start()
     {
         IStructureMemberHandler? member = document!.SelectedStructureMember;
         IEraserToolHandler? eraserTool = GetHandler<IEraserToolHandler>();
-        IBasicToolbar? toolbar = eraserTool?.Toolbar as IBasicToolbar;
+        IPenToolbar? toolbar = eraserTool?.Toolbar as IPenToolbar;
         IColorsHandler? colorsHandler = GetHandler<IColorsHandler>();
 
         if (colorsHandler is null || eraserTool is null || member is null || toolbar is null)
             return ExecutionState.Error;
-        drawOnMask = member is ILayerHandler layer ? layer.ShouldDrawOnMask : true;
+        drawOnMask = member is not ILayerHandler layer || layer.ShouldDrawOnMask;
         if (drawOnMask && !member.HasMaskBindable)
             return ExecutionState.Error;
         if (!drawOnMask && member is not ILayerHandler)
@@ -38,10 +42,13 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
         guidValue = member.Id;
         color = GetHandler<IColorsHandler>().PrimaryColor;
         toolSize = toolbar.ToolSize;
+        antiAliasing = toolbar.AntiAliasing;
+        hardness = toolbar.Hardness;
+        spacing = toolbar.Spacing;
 
         colorsHandler.AddSwatch(new PaletteColor(color.R, color.G, color.B));
-        IAction? action = new LineBasedPen_Action(guidValue, Colors.Transparent, controller!.LastPixelPosition, toolSize, true,
-            false, 1, 0, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
+        IAction? action = new LineBasedPen_Action(guidValue, Colors.White, controller!.LastPixelPosition, toolSize, true,
+            antiAliasing, hardness, spacing, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
         internals!.ActionAccumulator.AddActions(action);
 
         return ExecutionState.Success;
@@ -49,7 +56,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
 
     public override void OnPixelPositionChange(VecI pos)
     {
-        IAction? action = new LineBasedPen_Action(guidValue, Colors.Transparent, pos, toolSize, true, false, 1, 0, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
+        IAction? action = new LineBasedPen_Action(guidValue, Colors.White, pos, toolSize, true, antiAliasing, hardness, spacing, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
         internals!.ActionAccumulator.AddActions(action);
     }
 

+ 7 - 7
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs

@@ -14,14 +14,14 @@ internal class PenToolExecutor : UpdateableChangeExecutor
 {
     private Guid guidValue;
     private Color color;
-    public int ToolSize => basicToolbar.ToolSize;
+    public int ToolSize => penToolbar.ToolSize;
     private bool drawOnMask;
     private bool pixelPerfect;
     private bool antiAliasing;
     private float hardness;
     private float spacing = 1;
 
-    private IBasicToolbar basicToolbar;
+    private IBasicToolbar penToolbar;
 
     public override ExecutionState Start()
     {
@@ -29,7 +29,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         IColorsHandler? colorsHandler = GetHandler<IColorsHandler>();
 
         IPenToolHandler? penTool = GetHandler<IPenToolHandler>();
-        if (colorsHandler is null || penTool is null || member is null || penTool?.Toolbar is not IBasicToolbar toolbar)
+        if (colorsHandler is null || penTool is null || member is null || penTool?.Toolbar is not IPenToolbar toolbar)
             return ExecutionState.Error;
         drawOnMask = member is not ILayerHandler layer || layer.ShouldDrawOnMask;
         if (drawOnMask && !member.HasMaskBindable)
@@ -37,13 +37,13 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         if (!drawOnMask && member is not ILayerHandler)
             return ExecutionState.Error;
 
-        basicToolbar = toolbar;
+        penToolbar = toolbar;
         guidValue = member.Id;
         color = colorsHandler.PrimaryColor;
         pixelPerfect = penTool.PixelPerfectEnabled;
-        antiAliasing = penTool.AntiAliasing;
-        hardness = penTool.Hardness;
-        spacing = penTool.Spacing;
+        antiAliasing = toolbar.AntiAliasing;
+        hardness = toolbar.Hardness;
+        spacing = toolbar.Spacing;
 
         colorsHandler.AddSwatch(new PaletteColor(color.R, color.G, color.B));
         IAction? action = pixelPerfect switch

+ 8 - 0
src/PixiEditor/Models/Handlers/Toolbars/IPenToolbar.cs

@@ -0,0 +1,8 @@
+namespace PixiEditor.Models.Handlers.Toolbars;
+
+internal interface IPenToolbar : IBasicToolbar
+{
+    public bool AntiAliasing { get; set; }
+    public float Hardness { get; set; }
+    public float Spacing { get; set; }
+}

+ 0 - 3
src/PixiEditor/Models/Handlers/Tools/IPenToolHandler.cs

@@ -3,7 +3,4 @@
 internal interface IPenToolHandler : IToolHandler
 {
     public bool PixelPerfectEnabled { get; }
-    public bool AntiAliasing { get; }
-    public float Hardness { get; }
-    public float Spacing { get; }
 }

+ 6 - 0
src/PixiEditor/ViewModels/Tools/ToolSettings/Settings/Setting.cs

@@ -87,6 +87,12 @@ internal abstract class Setting : ObservableObject
 
     public bool HasLabel => !string.IsNullOrEmpty(Label);
 
+    public object UserValue
+    {
+        get => _value;
+        set => _value = value;
+    }
+
     public abstract Type GetSettingType();
     
     public void SetOverwriteValue(object value)

+ 32 - 0
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/PenToolbar.cs

@@ -0,0 +1,32 @@
+using PixiEditor.Models.Handlers.Toolbars;
+using PixiEditor.ViewModels.Tools.ToolSettings.Settings;
+
+namespace PixiEditor.ViewModels.Tools.ToolSettings.Toolbars;
+
+internal class PenToolbar : BasicToolbar, IPenToolbar
+{
+    public bool AntiAliasing
+    {
+        get => GetSetting<BoolSettingViewModel>(nameof(AntiAliasing)).Value;
+        set => GetSetting<BoolSettingViewModel>(nameof(AntiAliasing)).Value = value;
+    }
+
+    public float Hardness
+    {
+        get => GetSetting<PercentSettingViewModel>(nameof(Hardness)).Value;
+        set => GetSetting<PercentSettingViewModel>(nameof(Hardness)).Value = value;
+    }
+
+    public float Spacing
+    {
+        get => GetSetting<PercentSettingViewModel>(nameof(Spacing)).Value;
+        set => GetSetting<PercentSettingViewModel>(nameof(Spacing)).Value = value;
+    }
+
+    public PenToolbar()
+    {
+        AddSetting(new BoolSettingViewModel(nameof(AntiAliasing), "ANTI_ALIASING_SETTING") { IsExposed = false });
+        AddSetting(new PercentSettingViewModel(nameof(Hardness), 0.8f, "HARDNESS_SETTING") { IsExposed = false });
+        AddSetting(new PercentSettingViewModel(nameof(Spacing), 0.15f, "SPACING_SETTING") { IsExposed = false });
+    }
+}

+ 2 - 2
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/Toolbar.cs

@@ -61,7 +61,7 @@ internal abstract class Toolbar : ObservableObject, IToolbar
         {
             if (SharedSettings.Any(x => x.Name == Settings[i].Name))
             {
-                SharedSettings.First(x => x.Name == Settings[i].Name).Value = Settings[i].Value;
+                SharedSettings.First(x => x.Name == Settings[i].Name).UserValue = Settings[i].UserValue;
             }
             else
             {
@@ -79,7 +79,7 @@ internal abstract class Toolbar : ObservableObject, IToolbar
         {
             if (Settings.Any(x => x.Name == SharedSettings[i].Name))
             {
-                Settings.First(x => x.Name == SharedSettings[i].Name).Value = SharedSettings[i].Value;
+                Settings.First(x => x.Name == SharedSettings[i].Name).UserValue = SharedSettings[i].UserValue;
             }
         }
 

+ 1 - 1
src/PixiEditor/ViewModels/Tools/Tools/EraserToolViewModel.cs

@@ -18,7 +18,7 @@ internal class EraserToolViewModel : ToolViewModel, IEraserToolHandler
     public EraserToolViewModel()
     {
         ActionDisplay = "ERASER_TOOL_ACTION_DISPLAY";
-        Toolbar = ToolbarFactory.Create<EraserToolViewModel, BasicToolbar>(this);
+        Toolbar = ToolbarFactory.Create<EraserToolViewModel, PenToolbar>(this);
     }
 
     [Settings.Inherited]

+ 1 - 10
src/PixiEditor/ViewModels/Tools/Tools/PenToolViewModel.cs

@@ -27,7 +27,7 @@ namespace PixiEditor.ViewModels.Tools.Tools
         public PenToolViewModel()
         {
             Cursor = Cursors.PreciseCursor;
-            Toolbar = ToolbarFactory.Create<PenToolViewModel, BasicToolbar>(this);
+            Toolbar = ToolbarFactory.Create<PenToolViewModel, PenToolbar>(this);
             
             ViewModelMain.Current.ToolsSubViewModel.SelectedToolChanged += SelectedToolChanged;
         }
@@ -40,15 +40,6 @@ namespace PixiEditor.ViewModels.Tools.Tools
         [Settings.Bool("PIXEL_PERFECT_SETTING", Notify = nameof(PixelPerfectChanged), ExposedByDefault = false)]
         public bool PixelPerfectEnabled => GetValue<bool>();
 
-        [Settings.Bool("__antiAliasing", false, ExposedByDefault = false)]
-        public bool AntiAliasing => GetValue<bool>();
-        
-        [Settings.Percent("HARDNESS_SETTING", 0.8f, ExposedByDefault = false)]
-        public float Hardness => GetValue<float>();
-
-        [Settings.Percent("SPACING_SETTING", 0.15f, ExposedByDefault = false, Max = 5)]
-        public float Spacing => GetValue<float>();
-
         public override string Icon => PixiPerfectIcons.Pen;
 
         public override Type LayerTypeToCreateOnEmptyUse { get; } = typeof(ImageLayerNode);