Explorar o código

Added rectangle tool

flabbet %!s(int64=3) %!d(string=hai) anos
pai
achega
422fd0c219

+ 2 - 1
src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs

@@ -1,6 +1,7 @@
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Models.DocumentModels;
@@ -35,7 +36,7 @@ internal class ChangeExecutionController
             return false;
         T executor = new T();
         executor.Initialize(document, helpers, this, EndChange);
-        if (executor.Start().IsT0)
+        if (executor.Start() == ExecutionState.Success)
         {
             currentSession = executor;
             return true;

+ 6 - 6
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/EllipseToolExecutor.cs

@@ -1,5 +1,6 @@
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 using PixiEditor.ViewModels.SubViewModels.Tools.ToolSettings.Toolbars;
@@ -19,20 +20,19 @@ internal class EllipseToolExecutor : UpdateableChangeExecutor
     private VecI startPos;
     private RectI lastRect;
 
-    public override OneOf<Success, Error> Start()
+    public override ExecutionState Start()
     {
         ColorsViewModel? colorsVM = ViewModelMain.Current?.ColorsSubViewModel;
         ellipseTool = (EllipseToolViewModel?)(ViewModelMain.Current?.ToolsSubViewModel.GetTool<EllipseToolViewModel>());
         BasicShapeToolbar? toolbar = (BasicShapeToolbar?)ellipseTool?.Toolbar;
         ViewModels.SubViewModels.Document.StructureMemberViewModel? member = document?.SelectedStructureMember;
         if (colorsVM is null || toolbar is null || member is null || ellipseTool is null)
-            return new Error();
+            return ExecutionState.Error;
         drawOnMask = member.ShouldDrawOnMask;
         if (drawOnMask && !member.HasMaskBindable)
-            return new Error();
+            return ExecutionState.Error;
         if (!drawOnMask && member is not LayerViewModel)
-            return new Error();
-
+            return ExecutionState.Error;
 
         fillColor = toolbar.Fill ? toolbar.FillColor.ToSKColor() : SKColors.Transparent;
         startPos = controller!.LastPixelPosition;
@@ -42,7 +42,7 @@ internal class EllipseToolExecutor : UpdateableChangeExecutor
 
         colorsVM.AddSwatch(strokeColor);
         DrawEllipseOrCircle(startPos);
-        return new Success();
+        return ExecutionState.Success;
     }
 
     private void DrawEllipseOrCircle(VecI curPos)

+ 6 - 5
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/PenToolExecutor.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.ChangeableDocument.Actions;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
 using PixiEditor.ViewModels.SubViewModels.Tools.ToolSettings.Toolbars;
@@ -14,19 +15,19 @@ internal class PenToolExecutor : UpdateableChangeExecutor
     private bool drawOnMask;
     private bool pixelPerfect;
 
-    public override OneOf<Success, Error> Start()
+    public override ExecutionState Start()
     {
         ViewModelMain? vm = ViewModelMain.Current;
         StructureMemberViewModel? member = document!.SelectedStructureMember;
         PenToolViewModel? penTool = (PenToolViewModel?)(vm?.ToolsSubViewModel.GetTool<PenToolViewModel>());
         PenToolbar? toolbar = penTool?.Toolbar as PenToolbar;
         if (vm is null || penTool is null || member is null || toolbar is null)
-            return new Error();
+            return ExecutionState.Error;
         drawOnMask = member.ShouldDrawOnMask;
         if (drawOnMask && !member.HasMaskBindable)
-            return new Error();
+            return ExecutionState.Error;
         if (!drawOnMask && member is not LayerViewModel)
-            return new Error();
+            return ExecutionState.Error;
 
         guidValue = member.GuidValue;
         color = vm.ColorsSubViewModel.PrimaryColor;
@@ -41,7 +42,7 @@ internal class PenToolExecutor : UpdateableChangeExecutor
         };
         helpers!.ActionAccumulator.AddActions(action);
 
-        return new Success();
+        return ExecutionState.Success;
     }
 
     public override void OnPixelPositionChange(VecI pos)

+ 100 - 0
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/RectangleToolExecutor.cs

@@ -0,0 +1,100 @@
+using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.Models.Enums;
+using PixiEditor.ViewModels.SubViewModels.Document;
+using PixiEditor.ViewModels.SubViewModels.Tools.Tools;
+using PixiEditor.ViewModels.SubViewModels.Tools.ToolSettings.Toolbars;
+
+namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
+#nullable enable
+internal class RectangleToolExecutor : UpdateableChangeExecutor
+{
+    private int strokeWidth;
+    private SKColor fillColor;
+    private SKColor strokeColor;
+    private Guid memberGuid;
+    private bool drawOnMask;
+
+    private bool transforming = false;
+    private RectangleToolViewModel? rectangleTool;
+    private VecI startPos;
+    private RectI lastRect;
+
+    public override ExecutionState Start()
+    {
+        ColorsViewModel? colorsVM = ViewModelMain.Current?.ColorsSubViewModel;
+        rectangleTool = (RectangleToolViewModel?)(ViewModelMain.Current?.ToolsSubViewModel.GetTool<RectangleToolViewModel>());
+        BasicShapeToolbar? toolbar = (BasicShapeToolbar?)rectangleTool?.Toolbar;
+        StructureMemberViewModel? member = document?.SelectedStructureMember;
+        if (colorsVM is null || toolbar is null || member is null || rectangleTool is null)
+            return ExecutionState.Error;
+        drawOnMask = member.ShouldDrawOnMask;
+        if (drawOnMask && !member.HasMaskBindable)
+            return ExecutionState.Error;
+        if (!drawOnMask && member is not LayerViewModel)
+            return ExecutionState.Error;
+
+        fillColor = toolbar.Fill ? toolbar.FillColor.ToSKColor() : SKColors.Transparent;
+        startPos = controller!.LastPixelPosition;
+        strokeColor = colorsVM.PrimaryColor;
+        strokeWidth = toolbar.ToolSize;
+        memberGuid = member.GuidValue;
+
+        colorsVM.AddSwatch(strokeColor);
+        DrawRectangle(startPos);
+        return ExecutionState.Success;
+    }
+
+    private void DrawRectangle(VecI curPos)
+    {
+        RectI rect = RectI.FromTwoPoints(startPos, curPos);
+        if (rect.Width == 0)
+            rect.Width = 1;
+        if (rect.Height == 0)
+            rect.Height = 1;
+        
+        lastRect = rect;
+
+        helpers!.ActionAccumulator.AddActions(new DrawRectangle_Action(memberGuid, new ShapeData(rect.Center, rect.Size, 0, strokeWidth, strokeColor, fillColor), drawOnMask));
+    }
+
+    public override void OnTransformMoved(ShapeCorners corners)
+    {
+        if (!transforming)
+            return;
+
+        var rect = (RectI)RectD.FromCenterAndSize(corners.RectCenter, corners.RectSize);
+        
+        helpers!.ActionAccumulator.AddActions(
+            new DrawRectangle_Action(memberGuid, new ShapeData(rect.Center, rect.Size, corners.RectRotation, strokeWidth, strokeColor, fillColor), drawOnMask));
+    }
+
+    public override void OnTransformApplied()
+    {
+        helpers!.ActionAccumulator.AddFinishedActions(new EndDrawRectangle_Action());
+        document!.TransformViewModel.HideTransform();
+        onEnded?.Invoke(this);
+    }
+
+    public override void OnPixelPositionChange(VecI pos)
+    {
+        if (transforming)
+            return;
+        DrawRectangle(pos);
+    }
+
+    public override void OnLeftMouseButtonUp()
+    {
+        if (transforming)
+            return;
+        transforming = true;
+        document!.TransformViewModel.ShowFixedAngleShapeTransform(new ShapeCorners(lastRect));
+    }
+    
+    public override void ForceStop()
+    {
+        if (transforming)
+            document!.TransformViewModel.HideTransform();
+        helpers!.ActionAccumulator.AddFinishedActions(new EndDrawRectangle_Action());
+    }
+}

+ 6 - 4
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/StructureMemberOpacityExecutor.cs

@@ -1,15 +1,17 @@
-namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
+using PixiEditor.Models.Enums;
+
+namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
 internal class StructureMemberOpacityExecutor : UpdateableChangeExecutor
 {
     private Guid memberGuid;
-    public override OneOf<Success, Error> Start()
+    public override ExecutionState Start()
     {
         if (document.SelectedStructureMember is null)
-            return new Error();
+            return ExecutionState.Error;
         memberGuid = document.SelectedStructureMember.GuidValue;
         StructureMemberOpacity_Action action = new StructureMemberOpacity_Action(memberGuid, document.SelectedStructureMember.OpacityBindable);
         helpers.ActionAccumulator.AddActions(action);
-        return new Success();
+        return ExecutionState.Success;
     }
 
     public override void OnOpacitySliderDragged(float newValue)

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

@@ -1,5 +1,6 @@
 using System.Windows.Input;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.Models.Enums;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
 namespace PixiEditor.Models.DocumentModels.UpdateableChangeExecutors;
@@ -25,7 +26,7 @@ internal abstract class UpdateableChangeExecutor
         this.onEnded = onEnded;
     }
 
-    public abstract OneOf<Success, Error> Start();
+    public abstract ExecutionState Start();
     public abstract void ForceStop();
     public virtual void OnPixelPositionChange(VecI pos) { }
     public virtual void OnPrecisePositionChange(VecD pos) { }

+ 7 - 0
src/PixiEditor/Models/Enums/ExecutionState.cs

@@ -0,0 +1,7 @@
+namespace PixiEditor.Models.Enums;
+
+public enum ExecutionState
+{
+    Success,
+    Error
+}

+ 1 - 0
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -302,6 +302,7 @@ internal class DocumentViewModel : NotifyableObject
 
     public void UsePenTool() => Helpers.ChangeController.TryStartUpdateableChange<PenToolExecutor>();
 
+    public void UseRectangleTool() => Helpers.ChangeController.TryStartUpdateableChange<RectangleToolExecutor>();
     public void UseEllipseTool() => Helpers.ChangeController.TryStartUpdateableChange<EllipseToolExecutor>();
 
     public void Undo()

+ 6 - 0
src/PixiEditor/ViewModels/SubViewModels/Tools/Tools/RectangleToolViewModel.cs

@@ -1,4 +1,5 @@
 using System.Windows.Input;
+using ChunkyImageLib.DataHolders;
 using PixiEditor.Models.Commands.Attributes.Commands;
 
 namespace PixiEditor.ViewModels.SubViewModels.Tools.Tools;
@@ -23,4 +24,9 @@ internal class RectangleToolViewModel : ShapeTool
         else
             ActionDisplay = defaultActionDisplay;
     }
+    
+    public override void OnLeftMouseButtonDown(VecD pos)
+    {
+        ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.UseRectangleTool();
+    }
 }