Răsfoiți Sursa

Added square brush to pen and eraser

Krzysztof Krysiński 5 luni în urmă
părinte
comite
4342fd157a
24 a modificat fișierele cu 149 adăugiri și 41 ștergeri
  1. 50 11
      src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs
  2. 1 0
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PixelPerfectPen_UpdateableChange.cs
  3. 9 5
      src/PixiEditor/Data/Configs/ToolSetsConfig.json
  4. 3 2
      src/PixiEditor/Data/Localization/Languages/en.json
  5. 5 2
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EraserToolExecutor.cs
  6. 4 2
      src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs
  7. 4 1
      src/PixiEditor/Models/Handlers/Toolbars/IPenToolbar.cs
  8. 7 0
      src/PixiEditor/Models/Handlers/Toolbars/PenBrushShape.cs
  9. 1 1
      src/PixiEditor/ViewModels/Tools/ShapeTool.cs
  10. 8 0
      src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/PenToolbar.cs
  11. 1 1
      src/PixiEditor/ViewModels/Tools/ToolViewModel.cs
  12. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/BrightnessToolViewModel.cs
  13. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/ColorPickerToolViewModel.cs
  14. 19 2
      src/PixiEditor/ViewModels/Tools/Tools/EraserToolViewModel.cs
  15. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/FloodFillToolViewModel.cs
  16. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/LassoToolViewModel.cs
  17. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/MagicWandToolViewModel.cs
  18. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs
  19. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/MoveViewportToolViewModel.cs
  20. 26 3
      src/PixiEditor/ViewModels/Tools/Tools/PenToolViewModel.cs
  21. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/RotateViewportToolViewModel.cs
  22. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/SelectToolViewModel.cs
  23. 1 1
      src/PixiEditor/ViewModels/Tools/Tools/ZoomToolViewModel.cs
  24. 1 1
      src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs

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

@@ -17,6 +17,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
     private readonly bool erasing;
     private readonly bool drawOnMask;
     private readonly bool antiAliasing;
+    private bool squareBrush;
     private float hardness;
     private float spacing = 1;
     private readonly Paint srcPaint = new Paint() { BlendMode = BlendMode.Src };
@@ -32,6 +33,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         bool antiAliasing,
         float hardness,
         float spacing,
+        bool squareBrush,
         bool drawOnMask, int frame)
     {
         this.memberGuid = memberGuid;
@@ -42,6 +44,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         this.drawOnMask = drawOnMask;
         this.hardness = hardness;
         this.spacing = spacing;
+        this.squareBrush = squareBrush;
         points.Add(pos);
         this.frame = frame;
 
@@ -101,12 +104,23 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
             lastPos = point;
             var rect = new RectI(point - new VecI((int)(strokeWidth / 2f)), new VecI((int)strokeWidth));
             Paintable finalPaintable = color;
-            if (antiAliasing)
+
+            if (!squareBrush)
             {
-                finalPaintable = ApplySoftnessGradient((VecD)point);
-            }
+                if (antiAliasing)
+                {
+                    finalPaintable = ApplySoftnessGradient((VecD)point);
+                }
 
-            image.EnqueueDrawEllipse((RectD)rect, finalPaintable, finalPaintable, 0, 0, antiAliasing, srcPaint);
+                image.EnqueueDrawEllipse((RectD)rect, finalPaintable, finalPaintable, 0, 0, antiAliasing, srcPaint);
+            }
+            else
+            {
+                BlendMode blendMode = srcPaint.BlendMode;
+                ShapeData shapeData = new ShapeData(rect.Center, rect.Size, 0, 0, 0, finalPaintable, finalPaintable,
+                    blendMode);
+                image.EnqueueDrawRectangle(shapeData);
+            }
         }
 
         lastAppliedPointIndex = points.Count - 1;
@@ -122,12 +136,25 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         {
             var rect = new RectI(points[0] - new VecI((int)(strokeWidth / 2f)), new VecI((int)strokeWidth));
             Paintable finalPaintable = color;
-            if (antiAliasing)
+
+            if (!squareBrush)
+            {
+                if (antiAliasing)
+                {
+                    finalPaintable = ApplySoftnessGradient(points[0]);
+                }
+
+                targetImage.EnqueueDrawEllipse((RectD)rect, finalPaintable, finalPaintable, 0, 0, antiAliasing,
+                    srcPaint);
+            }
+            else
             {
-                finalPaintable = ApplySoftnessGradient(points[0]);
+                BlendMode blendMode = srcPaint.BlendMode;
+                ShapeData shapeData = new ShapeData(rect.Center, rect.Size, 0, 0, 0, finalPaintable, finalPaintable,
+                    blendMode);
+                targetImage.EnqueueDrawRectangle(shapeData);
             }
 
-            targetImage.EnqueueDrawEllipse((RectD)rect, finalPaintable, finalPaintable, 0, 0, antiAliasing, srcPaint);
             return;
         }
 
@@ -143,12 +170,24 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
             lastPos = points[i];
             var rect = new RectI(points[i] - new VecI((int)(strokeWidth / 2f)), new VecI((int)strokeWidth));
             Paintable? finalPaintable = color;
-            if (antiAliasing)
+
+            if (!squareBrush)
             {
-                finalPaintable = ApplySoftnessGradient(points[i]);
-            }
+                if (antiAliasing)
+                {
+                    finalPaintable = ApplySoftnessGradient(points[i]);
+                }
 
-            targetImage.EnqueueDrawEllipse((RectD)rect, finalPaintable, finalPaintable, 0, 0, antiAliasing, srcPaint);
+                targetImage.EnqueueDrawEllipse((RectD)rect, finalPaintable, finalPaintable, 0, 0, antiAliasing,
+                    srcPaint);
+            }
+            else
+            {
+                BlendMode blendMode = srcPaint.BlendMode;
+                ShapeData shapeData = new ShapeData(rect.Center, rect.Size, 0, 0, 0, finalPaintable, finalPaintable,
+                    blendMode);
+                targetImage.EnqueueDrawRectangle(shapeData);
+            }
         }
     }
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changes/Drawing/PixelPerfectPen_UpdateableChange.cs

@@ -78,6 +78,7 @@ internal class PixelPerfectPen_UpdateableChange : UpdateableChange
         {
             pixelsToConfirm.Add(pixel);
         }
+
         image.EnqueueDrawPixels(line.Select(point => new VecI((int)point.X, (int)point.Y)), color, BlendMode.Src);
 
         if (pointsCount >= 3 && IsLShape(pointsCount - 1) && !confirmedPixels.Contains(incomingPoints[pointsCount - 2]))

+ 9 - 5
src/PixiEditor/Data/Configs/ToolSetsConfig.json

@@ -1,6 +1,6 @@
 [
   {
-    "Name": "PIXEL_ART_TOOLSET",
+    "Name": "PIXEL_PERFECT_TOOLSET",
     "Tools": [
       "MoveViewport",
       "RotateViewport",
@@ -9,7 +9,8 @@
         "ToolName": "Pen",
         "Settings": {
           "ExposePixelPerfectEnabled": true,
-          "Spacing": 0
+          "Spacing": 0,
+          "ExposePenShape": true
         }
       },
       "Select",
@@ -30,7 +31,8 @@
       {
         "ToolName": "Eraser",
         "Settings": {
-          "Spacing": 0
+          "Spacing": 0,
+          "ExposePenShape": true,
         }
       },
       "ColorPicker",
@@ -50,7 +52,8 @@
           "AntiAliasing": true,
           "ExposeHardness": true,
           "ExposeSpacing": true,
-          "BrushShapeSetting": "CircleSmooth"
+          "BrushShapeSetting": "CircleSmooth",
+          "PenShape": "Circle"
         }
       },
       "Select",
@@ -102,7 +105,8 @@
           "AntiAliasing": true,
           "ExposeHardness": true,
           "ExposeSpacing": true,
-          "BrushShapeSetting": "CircleSmooth"
+          "BrushShapeSetting": "CircleSmooth",
+          "PenShape": "Circle"
         }
       },
       "ColorPicker",

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

@@ -757,7 +757,7 @@
   "MODULO": "Modulo",
   "STEP": "Step",
   "SMOOTH_STEP": "Smoothstep",
-  "PIXEL_ART_TOOLSET": "Pixel Art",
+  "PIXEL_PERFECT_TOOLSET": "Pixel Perfect",
   "VECTOR_TOOLSET": "Vector",
   "VECTOR_LAYER": "Vector Layer",
   "STROKE_COLOR_LABEL": "Stroke",
@@ -997,5 +997,6 @@
   "SWITCH_TO_NEW_VERSION": "Switch",
   "DOWNLOAD_UPDATE": "Download",
   "DOWNLOADING_UPDATE": "Downloading update...",
-  "CHECKING_FOR_UPDATES": "Checking for updates..."
+  "CHECKING_FOR_UPDATES": "Checking for updates...",
+  "PEN_SHAPE_SETTING": "Brush shape"
 }

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

@@ -14,6 +14,7 @@ namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 
 internal class EraserToolExecutor : UpdateableChangeExecutor
 {
+    public bool SquareBrush => penToolbar.PenShape == PenBrushShape.Square;
     private Guid guidValue;
     private Color color;
     private double toolSize;
@@ -22,12 +23,14 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
     private float spacing;
     
     private bool drawOnMask;
+    private IPenToolbar penToolbar;
 
     public override ExecutionState Start()
     {
         IStructureMemberHandler? member = document!.SelectedStructureMember;
         IEraserToolHandler? eraserTool = GetHandler<IEraserToolHandler>();
         IPenToolbar? toolbar = eraserTool?.Toolbar as IPenToolbar;
+        penToolbar = toolbar;
         IColorsHandler? colorsHandler = GetHandler<IColorsHandler>();
 
         if (colorsHandler is null || eraserTool is null || member is null || toolbar is null)
@@ -48,7 +51,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
 
         colorsHandler.AddSwatch(new PaletteColor(color.R, color.G, color.B));
         IAction? action = new LineBasedPen_Action(guidValue, Colors.White, controller!.LastPixelPosition, (float)toolSize, true,
-            antiAliasing, hardness, spacing, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
+            antiAliasing, hardness, spacing, SquareBrush, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
         internals!.ActionAccumulator.AddActions(action);
 
         return ExecutionState.Success;
@@ -56,7 +59,7 @@ internal class EraserToolExecutor : UpdateableChangeExecutor
 
     public override void OnPixelPositionChange(VecI pos)
     {
-        IAction? action = new LineBasedPen_Action(guidValue, Colors.White, pos, (float)toolSize, true, antiAliasing, hardness, spacing, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
+        IAction? action = new LineBasedPen_Action(guidValue, Colors.White, pos, (float)toolSize, true, antiAliasing, hardness, spacing, SquareBrush, drawOnMask, document!.AnimationHandler.ActiveFrameBindable);
         internals!.ActionAccumulator.AddActions(action);
     }
 

+ 4 - 2
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs

@@ -15,6 +15,8 @@ internal class PenToolExecutor : UpdateableChangeExecutor
     private Guid guidValue;
     private Color color;
     public double ToolSize => penToolbar.ToolSize;
+    public bool SquareBrush => penToolbar.PenShape == PenBrushShape.Square;
+
     private bool drawOnMask;
     private bool pixelPerfect;
     private bool antiAliasing;
@@ -48,7 +50,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         colorsHandler.AddSwatch(new PaletteColor(color.R, color.G, color.B));
         IAction? action = pixelPerfect switch
         {
-            false => new LineBasedPen_Action(guidValue, color, controller!.LastPixelPosition, (float)ToolSize, false, antiAliasing, hardness, spacing, drawOnMask, document!.AnimationHandler.ActiveFrameBindable),
+            false => new LineBasedPen_Action(guidValue, color, controller!.LastPixelPosition, (float)ToolSize, false, antiAliasing, hardness, spacing, SquareBrush, drawOnMask, document!.AnimationHandler.ActiveFrameBindable),
             true => new PixelPerfectPen_Action(guidValue, controller!.LastPixelPosition, color, drawOnMask, document!.AnimationHandler.ActiveFrameBindable)
         };
         internals!.ActionAccumulator.AddActions(action);
@@ -60,7 +62,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
     {
         IAction? action = pixelPerfect switch
         {
-            false => new LineBasedPen_Action(guidValue, color, pos, (float)ToolSize, false, antiAliasing, hardness, spacing, drawOnMask, document!.AnimationHandler.ActiveFrameBindable),
+            false => new LineBasedPen_Action(guidValue, color, pos, (float)ToolSize, false, antiAliasing, hardness, spacing, SquareBrush, drawOnMask, document!.AnimationHandler.ActiveFrameBindable),
             true => new PixelPerfectPen_Action(guidValue, pos, color, drawOnMask, document!.AnimationHandler.ActiveFrameBindable)
         };
         internals!.ActionAccumulator.AddActions(action);

+ 4 - 1
src/PixiEditor/Models/Handlers/Toolbars/IPenToolbar.cs

@@ -1,8 +1,11 @@
-namespace PixiEditor.Models.Handlers.Toolbars;
+using PixiEditor.Views.Overlays.BrushShapeOverlay;
+
+namespace PixiEditor.Models.Handlers.Toolbars;
 
 internal interface IPenToolbar : IToolbar, IToolSizeToolbar
 {
     public bool AntiAliasing { get; set; }
     public float Hardness { get; set; }
     public float Spacing { get; set; }
+    public PenBrushShape PenShape { get; set; }
 }

+ 7 - 0
src/PixiEditor/Models/Handlers/Toolbars/PenBrushShape.cs

@@ -0,0 +1,7 @@
+namespace PixiEditor.Models.Handlers.Toolbars;
+
+public enum PenBrushShape
+{
+    Circle,
+    Square,
+}

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

@@ -8,7 +8,7 @@ namespace PixiEditor.ViewModels.Tools;
 
 internal abstract class ShapeTool : ToolViewModel, IShapeToolHandler
 {
-    public override BrushShape BrushShape => BrushShape.Hidden;
+    public override BrushShape FinalBrushShape => BrushShape.Hidden;
 
     public override bool UsesColor => true;
 

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

@@ -1,5 +1,6 @@
 using PixiEditor.Models.Handlers.Toolbars;
 using PixiEditor.ViewModels.Tools.ToolSettings.Settings;
+using PixiEditor.Views.Overlays.BrushShapeOverlay;
 
 namespace PixiEditor.ViewModels.Tools.ToolSettings.Toolbars;
 
@@ -29,6 +30,12 @@ internal class PenToolbar : Toolbar, IPenToolbar
         set => GetSetting<SizeSettingViewModel>(nameof(ToolSize)).Value = value;
     }
 
+    public PenBrushShape PenShape
+    {
+        get => GetSetting<EnumSettingViewModel<PenBrushShape>>(nameof(PenShape)).Value;
+        set => GetSetting<EnumSettingViewModel<PenBrushShape>>(nameof(PenShape)).Value = value;
+    }
+
     public override void OnLoadedSettings()
     {
         OnPropertyChanged(nameof(ToolSize));
@@ -42,5 +49,6 @@ internal class PenToolbar : Toolbar, IPenToolbar
         var setting = new SizeSettingViewModel(nameof(ToolSize), "TOOL_SIZE_LABEL");
         setting.ValueChanged += (_, _) => OnPropertyChanged(nameof(ToolSize));
         AddSetting(setting);
+        AddSetting(new EnumSettingViewModel<PenBrushShape>(nameof(PenShape), "PEN_SHAPE_SETTING") { IsExposed = false });
     }
 }

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

@@ -28,7 +28,7 @@ internal abstract class ToolViewModel : ObservableObject, IToolHandler
 
     public virtual string DefaultIcon => $"\u25a1";
 
-    public virtual BrushShape BrushShape => BrushShape.Square;
+    public virtual BrushShape FinalBrushShape => BrushShape.Square;
 
     public abstract Type[]? SupportedLayerTypes { get; }
 

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

@@ -29,7 +29,7 @@ internal class BrightnessToolViewModel : ToolViewModel, IBrightnessToolHandler
     public override bool IsErasable => true;
     public override LocalizedString Tooltip => new LocalizedString("BRIGHTNESS_TOOL_TOOLTIP", Shortcut);
 
-    public override BrushShape BrushShape => BrushShape.CirclePixelated;
+    public override BrushShape FinalBrushShape => BrushShape.CirclePixelated;
 
     public override string DefaultIcon => PixiPerfectIcons.Sun;
 

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

@@ -28,7 +28,7 @@ internal class ColorPickerToolViewModel : ToolViewModel, IColorPickerHandler
     public override bool UsesColor => true;
 
     public override string ToolNameLocalizationKey => "COLOR_PICKER_TOOL";
-    public override BrushShape BrushShape => BrushShape.Pixel;
+    public override BrushShape FinalBrushShape => BrushShape.Pixel;
 
     public override string DefaultIcon => PixiPerfectIcons.Picker;
 

+ 19 - 2
src/PixiEditor/ViewModels/Tools/Tools/EraserToolViewModel.cs

@@ -6,6 +6,7 @@ using PixiEditor.Models.Commands.Attributes.Commands;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers.Tools;
 using Drawie.Numerics;
+using PixiEditor.Models.Handlers.Toolbars;
 using PixiEditor.UI.Common.Fonts;
 using PixiEditor.ViewModels.Tools.ToolSettings.Toolbars;
 using PixiEditor.Views.Overlays.BrushShapeOverlay;
@@ -26,7 +27,7 @@ internal class EraserToolViewModel : ToolViewModel, IEraserToolHandler
     public override bool IsErasable => true;
 
     public override string ToolNameLocalizationKey => "ERASER_TOOL";
-    public override BrushShape BrushShape => BrushShapeSetting;
+    public override BrushShape FinalBrushShape => PenShape == PenBrushShape.Square ? BrushShape.Square : BrushShapeSetting;
     public override Type[]? SupportedLayerTypes { get; } = { typeof(IRasterLayerHandler) };
 
     public override string DefaultIcon => PixiPerfectIcons.Eraser;
@@ -39,6 +40,17 @@ internal class EraserToolViewModel : ToolViewModel, IEraserToolHandler
         Notify = nameof(BrushShapeChanged))]
     public BrushShape BrushShapeSetting => GetValue<BrushShape>();
 
+    [Settings.Inherited(Notify = nameof(PenShapeChanged))]
+    public PenBrushShape PenShape
+    {
+        get => GetValue<PenBrushShape>();
+        set
+        {
+            SetValue(value);
+            OnPropertyChanged(nameof(FinalBrushShape));
+        }
+    }
+
     public override void UseTool(VecD pos)
     {
         ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseEraserTool();
@@ -46,6 +58,11 @@ internal class EraserToolViewModel : ToolViewModel, IEraserToolHandler
 
     private void BrushShapeChanged()
     {
-        OnPropertyChanged(nameof(BrushShape));
+        OnPropertyChanged(nameof(FinalBrushShape));
+    }
+
+    private void PenShapeChanged()
+    {
+        OnPropertyChanged(nameof(FinalBrushShape));
     }
 }

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

@@ -18,7 +18,7 @@ internal class FloodFillToolViewModel : ToolViewModel, IFloodFillToolHandler
     private readonly string defaultActionDisplay = "FLOOD_FILL_TOOL_ACTION_DISPLAY_DEFAULT";
 
     public override string ToolNameLocalizationKey => "FLOOD_FILL_TOOL";
-    public override BrushShape BrushShape => BrushShape.Pixel;
+    public override BrushShape FinalBrushShape => BrushShape.Pixel;
     public override Type[]? SupportedLayerTypes { get; } = { typeof(IRasterLayerHandler) };
 
     public override LocalizedString Tooltip => new("FLOOD_FILL_TOOL_TOOLTIP", Shortcut);

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

@@ -50,7 +50,7 @@ internal class LassoToolViewModel : ToolViewModel, ILassoToolHandler
 
     public override string ToolNameLocalizationKey => "LASSO_TOOL";
     public override string DefaultIcon => PixiPerfectIcons.Lasso;
-    public override BrushShape BrushShape => BrushShape.Pixel;
+    public override BrushShape FinalBrushShape => BrushShape.Pixel;
     
     public override Type[]? SupportedLayerTypes { get; } = null; // all layer types are supported
 

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

@@ -19,7 +19,7 @@ internal class MagicWandToolViewModel : ToolViewModel, IMagicWandToolHandler
     public override LocalizedString Tooltip => new LocalizedString("MAGIC_WAND_TOOL_TOOLTIP", Shortcut);
 
     public override string ToolNameLocalizationKey => "MAGIC_WAND_TOOL";
-    public override BrushShape BrushShape => BrushShape.Pixel;
+    public override BrushShape FinalBrushShape => BrushShape.Pixel;
     public override Type[]? SupportedLayerTypes { get; } = { typeof(IRasterLayerHandler) }; 
 
     [Settings.Enum("MODE_LABEL")]

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

@@ -49,7 +49,7 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
         set => SetValue(value);
     }
 
-    public override BrushShape BrushShape => BrushShape.Hidden;
+    public override BrushShape FinalBrushShape => BrushShape.Hidden;
     public override Type[]? SupportedLayerTypes { get; } = null;
     public override Type LayerTypeToCreateOnEmptyUse { get; } = null;
     public override bool HideHighlight => true;

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

@@ -10,7 +10,7 @@ namespace PixiEditor.ViewModels.Tools.Tools;
 internal class MoveViewportToolViewModel : ToolViewModel
 {
     public override string ToolNameLocalizationKey => "MOVE_VIEWPORT_TOOL";
-    public override BrushShape BrushShape => BrushShape.Hidden;
+    public override BrushShape FinalBrushShape => BrushShape.Hidden;
     public override Type[]? SupportedLayerTypes { get; } = null;
     public override Type LayerTypeToCreateOnEmptyUse { get; } = null;
     public override bool HideHighlight => true;

+ 26 - 3
src/PixiEditor/ViewModels/Tools/Tools/PenToolViewModel.cs

@@ -7,6 +7,7 @@ using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers.Tools;
 using PixiEditor.Models.Input;
 using Drawie.Numerics;
+using PixiEditor.Models.Handlers.Toolbars;
 using PixiEditor.UI.Common.Fonts;
 using PixiEditor.ViewModels.Tools.ToolSettings.Settings;
 using PixiEditor.ViewModels.Tools.ToolSettings.Toolbars;
@@ -20,7 +21,9 @@ namespace PixiEditor.ViewModels.Tools.Tools
         private double actualToolSize;
 
         public override string ToolNameLocalizationKey => "PEN_TOOL";
-        public override BrushShape BrushShape => BrushShapeSetting;
+
+        public override BrushShape FinalBrushShape =>
+            PenShape == PenBrushShape.Square ? BrushShape.Square : BrushShapeSetting;
         
         public override Type[]? SupportedLayerTypes { get; } = { typeof(IRasterLayerHandler) };
 
@@ -41,7 +44,21 @@ namespace PixiEditor.ViewModels.Tools.Tools
         public bool PixelPerfectEnabled => GetValue<bool>();
         
         [Settings.Enum("BRUSH_SHAPE_SETTING", BrushShape.CirclePixelated, ExposedByDefault = false, Notify = nameof(BrushShapeChanged))]
-        public BrushShape BrushShapeSetting => GetValue<BrushShape>();
+        public BrushShape BrushShapeSetting
+        {
+            get
+            {
+                return GetValue<BrushShape>();
+            }
+            set
+            {
+                SetValue(value);
+                OnPropertyChanged(nameof(FinalBrushShape));
+            }
+        }
+
+        [Settings.Inherited(Notify = nameof(PenShapeChanged))]
+        public PenBrushShape PenShape => GetValue<PenBrushShape>();
 
         public override string DefaultIcon => PixiPerfectIcons.Pen;
 
@@ -133,7 +150,13 @@ namespace PixiEditor.ViewModels.Tools.Tools
         
         private void BrushShapeChanged()
         {
-            OnPropertyChanged(nameof(BrushShape));
+            OnPropertyChanged(nameof(FinalBrushShape));
+        }
+
+        private void PenShapeChanged()
+        {
+            OnPropertyChanged(nameof(PenShape));
+            OnPropertyChanged(nameof(FinalBrushShape));
         }
     }
 }

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

@@ -10,7 +10,7 @@ namespace PixiEditor.ViewModels.Tools.Tools;
 internal class RotateViewportToolViewModel : ToolViewModel
 {
     public override string ToolNameLocalizationKey => "ROTATE_VIEWPORT_TOOL";
-    public override BrushShape BrushShape => BrushShape.Hidden;
+    public override BrushShape FinalBrushShape => BrushShape.Hidden;
     public override Type[]? SupportedLayerTypes { get; } = null; // null = all
     public override Type LayerTypeToCreateOnEmptyUse { get; } = null;
     public override bool HideHighlight => true;

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

@@ -57,7 +57,7 @@ internal class SelectToolViewModel : ToolViewModel, ISelectToolHandler
     [Settings.Enum("SHAPE_LABEL")]
     public SelectionShape SelectShape => GetValue<SelectionShape>();
 
-    public override BrushShape BrushShape => BrushShape.Pixel;
+    public override BrushShape FinalBrushShape => BrushShape.Pixel;
     public override Type[]? SupportedLayerTypes { get; } = null;
 
     public override LocalizedString Tooltip => new LocalizedString("SELECT_TOOL_TOOLTIP", Shortcut);

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

@@ -19,7 +19,7 @@ internal class ZoomToolViewModel : ToolViewModel
     private string defaultActionDisplay = new LocalizedString("ZOOM_TOOL_ACTION_DISPLAY_DEFAULT");
 
     public override string ToolNameLocalizationKey => "ZOOM_TOOL";
-    public override BrushShape BrushShape => BrushShape.Hidden;
+    public override BrushShape FinalBrushShape => BrushShape.Hidden;
     public override Type[]? SupportedLayerTypes { get; } = null;
 
     public override bool StopsLinkedToolOnUse => false;

+ 1 - 1
src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs

@@ -432,7 +432,7 @@ internal class ViewportOverlays
 
         Binding brushShapeBinding = new()
         {
-            Source = ViewModelMain.Current.ToolsSubViewModel, Path = "ActiveTool.BrushShape", Mode = BindingMode.OneWay
+            Source = ViewModelMain.Current.ToolsSubViewModel, Path = "ActiveTool.FinalBrushShape", Mode = BindingMode.OneWay
         };
 
         MultiBinding isVisibleMultiBinding = new()