Răsfoiți Sursa

Added pixel art and painting text tool

flabbet 10 luni în urmă
părinte
comite
43ac69503e

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit d56a15d08ea1893eb6be4684fe6c939ae1ce2e45
+Subproject commit caab060fde13ac34ea13f85bf6e6ed63b5162d63

+ 5 - 5
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/ShapeVectorData.cs

@@ -11,18 +11,18 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
 
 public abstract class ShapeVectorData : ICacheable, ICloneable, IReadOnlyShapeVectorData
 {
-    public Matrix3X3 TransformationMatrix { get; set; } = Matrix3X3.Identity; 
-    
+    public Matrix3X3 TransformationMatrix { get; set; } = Matrix3X3.Identity;
+
     public Color StrokeColor { get; set; } = Colors.White;
     public Color FillColor { get; set; } = Colors.White;
     public float StrokeWidth { get; set; } = 0;
     public bool Fill { get; set; } = true;
-    public abstract RectD GeometryAABB { get; } 
+    public abstract RectD GeometryAABB { get; }
     public abstract RectD VisualAABB { get; }
     public RectD TransformedAABB => new ShapeCorners(GeometryAABB).WithMatrix(TransformationMatrix).AABBBounds;
     public RectD TransformedVisualAABB => new ShapeCorners(VisualAABB).WithMatrix(TransformationMatrix).AABBBounds;
-    public abstract ShapeCorners TransformationCorners { get; } 
-    
+    public abstract ShapeCorners TransformationCorners { get; }
+
     protected void ApplyTransformTo(Canvas canvas)
     {
         Matrix3X3 canvasMatrix = canvas.TotalMatrix;

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/TextVectorData.cs

@@ -25,8 +25,8 @@ public class TextVectorData : ShapeVectorData, IDisposable
 
     public double MaxWidth { get; set; } = double.MaxValue;
     public Font Font { get; set; } = Font.CreateDefault();
-
     public double? Spacing { get; set; }
+    public bool AntiAlias { get; set; } = true;
 
     public override RectD GeometryAABB
     {
@@ -74,7 +74,7 @@ public class TextVectorData : ShapeVectorData, IDisposable
             ApplyTransformTo(canvas);
         }
 
-        using Paint paint = new Paint() { IsAntiAliased = true };
+        using Paint paint = new Paint() { IsAntiAliased = AntiAlias };
 
         richText.Fill = Fill;
         richText.FillColor = FillColor;

+ 46 - 0
src/PixiEditor.ChangeableDocument/Changes/Structure/SetLowDpiRendering_Change.cs

@@ -0,0 +1,46 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+
+namespace PixiEditor.ChangeableDocument.Changes.Structure;
+
+internal class SetLowDpiRendering_Change : Change
+{
+    public readonly Guid memberId;
+    public bool value;
+    
+    private bool originalValue;
+    
+    [GenerateMakeChangeAction]
+    public SetLowDpiRendering_Change(Guid memberId, bool value)
+    {
+        this.memberId = memberId;
+        this.value = value;
+    }
+    
+    public override bool InitializeAndValidate(Document target)
+    {
+        return target.TryFindNode(memberId, out RenderNode node);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
+    {
+        RenderNode node = target.FindNodeOrThrow<RenderNode>(memberId);
+        
+        bool toSet = !value;
+        
+        originalValue = node.AllowHighDpiRendering;
+        node.AllowHighDpiRendering = toSet;
+        
+        ignoreInUndo = originalValue == toSet;
+
+        return new None();
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        RenderNode node = target.FindNodeOrThrow<RenderNode>(memberId);
+        
+        node.AllowHighDpiRendering = originalValue;
+
+        return new None();
+    }
+}

+ 24 - 3
src/PixiEditor/Data/Configs/ToolSetsConfig.json

@@ -25,6 +25,13 @@
           "Spacing": 0
         }
       },
+      {
+        "ToolName": "Text",
+        "Settings": {
+          "AntiAliasing": false,
+          "ForceLowDpiRendering": true
+        }
+      },
       "ColorPicker",
       "Brightness",
       "Zoom"
@@ -42,7 +49,7 @@
           "AntiAliasing": true,
           "ExposeHardness": true,
           "ExposeSpacing": true,
-          "BrushShapeSetting": "CircleSmooth" 
+          "BrushShapeSetting": "CircleSmooth"
         }
       },
       "Select",
@@ -78,7 +85,14 @@
         "Settings": {
           "AntiAliasing": true
         },
-        "Icon": "\uE953" 
+        "Icon": "\uE953"
+      },
+      {
+        "ToolName": "Text",
+        "Settings": {
+          "AntiAliasing": true,
+          "ForceLowDpiRendering": true
+        }
       },
       {
         "ToolName": "Eraser",
@@ -103,7 +117,14 @@
       "VectorLine",
       "VectorEllipse",
       "VectorRectangle",
-      "Text"
+      {
+        "ToolName": "Text",
+        "Settings": 
+        {
+          "AntiAliasing": true,
+          "ForceLowDpiRendering": false
+        }
+      }
     ]
   }
 ]

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

@@ -843,5 +843,6 @@
   "FONT_SIZE_LABEL": "Size",
   "SPACING_LABEL": "Spacing",
   "TEXT_TOOL": "Text",
-  "MISSING_FONT": "Missing font"
+  "MISSING_FONT": "Missing font",
+  "TEXT_LAYER_NAME": "Text"
 }

+ 1 - 1
src/PixiEditor/Models/DocumentModels/Public/DocumentToolsModule.cs

@@ -80,7 +80,7 @@ internal class DocumentToolsModule
 
     public void UseMagicWandTool() => Internals.ChangeController.TryStartExecutor<MagicWandToolExecutor>();
 
-    public void UseVectorTextTool()
+    public void UseTextTool()
     {
         bool force = Internals.ChangeController.GetCurrentExecutorType() == ExecutorType.ToolLinked;
         Internals.ChangeController.TryStartExecutor<VectorTextToolExecutor>(force);

+ 20 - 8
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/VectorTextToolExecutor.cs

@@ -24,6 +24,8 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
     private VecD position;
     private Matrix3X3 lastMatrix = Matrix3X3.Identity;
 
+    public override ExecutorType Type => ExecutorType.ToolLinked;
+
     public override ExecutionState Start()
     {
         textHandler = GetHandler<ITextToolHandler>();
@@ -48,14 +50,16 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
         var shape = layerHandler.GetShapeData(document.AnimationHandler.ActiveFrameBindable);
         if (shape is TextVectorData textData)
         {
-            document.TextOverlayHandler.Show(textData.Text, textData.Position, textData.Font, textData.TransformationMatrix, textData.Spacing);
+            document.TextOverlayHandler.Show(textData.Text, textData.Position, textData.Font,
+                textData.TransformationMatrix, textData.Spacing);
             lastText = textData.Text;
             position = textData.Position;
             lastMatrix = textData.TransformationMatrix;
         }
         else if (shape is null)
         {
-            document.TextOverlayHandler.Show("", controller.LastPrecisePosition, toolbar.ConstructFont(), Matrix3X3.Identity, toolbar.Spacing);
+            document.TextOverlayHandler.Show("", controller.LastPrecisePosition, toolbar.ConstructFont(),
+                Matrix3X3.Identity, toolbar.Spacing);
             lastText = "";
             position = controller.LastPrecisePosition;
         }
@@ -76,7 +80,10 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
     public void OnTextChanged(string text)
     {
         var constructedText = ConstructTextData(text);
-        internals.ActionAccumulator.AddActions(new SetShapeGeometry_Action(selectedMember.Id, constructedText));
+        internals.ActionAccumulator.AddFinishedActions();
+        internals.ActionAccumulator.AddActions(
+            new SetShapeGeometry_Action(selectedMember.Id, constructedText),
+            new SetLowDpiRendering_Action(selectedMember.Id, toolbar.ForceLowDpiRendering));
         lastText = text;
         document.TextOverlayHandler.Font = constructedText.Font;
     }
@@ -87,10 +94,12 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
         {
             document.TextOverlayHandler.Font = toolbar.ConstructFont();
         }
-        
+
         var constructedText = ConstructTextData(lastText);
-        internals.ActionAccumulator.AddActions(new SetShapeGeometry_Action(selectedMember.Id, constructedText));
-        
+        internals.ActionAccumulator.AddActions(
+            new SetShapeGeometry_Action(selectedMember.Id, constructedText),
+            new SetLowDpiRendering_Action(selectedMember.Id, toolbar.ForceLowDpiRendering));
+
         document.TextOverlayHandler.Font = constructedText.Font;
         document.TextOverlayHandler.Spacing = toolbar.Spacing;
     }
@@ -108,7 +117,7 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
 
     private TextVectorData ConstructTextData(string text)
     {
-        Font font = toolbar.ConstructFont(); 
+        Font font = toolbar.ConstructFont();
         return new TextVectorData()
         {
             Text = text,
@@ -119,7 +128,10 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
             StrokeColor = toolbar.StrokeColor.ToColor(),
             TransformationMatrix = lastMatrix,
             Font = font,
-            Spacing = toolbar.Spacing
+            Spacing = toolbar.Spacing,
+            AntiAlias = toolbar.AntiAliasing,
+            // TODO: MaxWidth = toolbar.MaxWidth
+            // TODO: Path
         };
     }
 

+ 1 - 0
src/PixiEditor/Models/Handlers/Toolbars/ITextToolbar.cs

@@ -7,6 +7,7 @@ internal interface ITextToolbar : IFillableShapeToolbar
     public double FontSize { get; set; }
     public FontFamilyName FontFamily { get; set; }
     public double Spacing { get; set; }
+    public bool ForceLowDpiRendering { get; set; }
 
     public Font ConstructFont();
 }

+ 4 - 1
src/PixiEditor/Models/Serialization/Factories/TextSerializationFactory.cs

@@ -17,6 +17,7 @@ internal class TextSerializationFactory : VectorShapeSerializationFactory<TextVe
     {
         builder.AddString(original.Text);
         builder.AddVecD(original.Position);
+        builder.AddBool(original.AntiAlias);
         builder.AddString(original.Font.Family.Name);
         builder.AddBool(original.Font.Family.FontUri?.IsFile ?? false);
         if (original.Font.Family.FontUri?.IsFile ?? false)
@@ -41,6 +42,7 @@ internal class TextSerializationFactory : VectorShapeSerializationFactory<TextVe
     {
         string text = extractor.GetString();
         VecD position = extractor.GetVecD();
+        bool antiAlias = extractor.GetBool();
         string fontFamily = extractor.GetString();
         bool isFontFromFile = extractor.GetBool();
         string fontPath = null;
@@ -90,7 +92,8 @@ internal class TextSerializationFactory : VectorShapeSerializationFactory<TextVe
             Spacing = spacing,
             Path = path,
             MissingFontFamily = missingFamily,
-            MissingFontText = new LocalizedString("MISSING_FONT")
+            MissingFontText = new LocalizedString("MISSING_FONT"),
+            AntiAlias = antiAlias
         };
 
         return true;

+ 21 - 0
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/TextToolbar.cs

@@ -1,5 +1,6 @@
 using Drawie.Backend.Core.Text;
 using PixiEditor.Extensions.Common.Localization;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Handlers.Toolbars;
 using PixiEditor.ViewModels.Tools.ToolSettings.Settings;
 
@@ -42,10 +43,24 @@ internal class TextToolbar : FillableShapeToolbar, ITextToolbar
             GetSetting<SizeSettingViewModel>(nameof(Spacing)).Value = value;
         }
     }
+    
+    public bool ForceLowDpiRendering
+    {
+        get
+        {
+            return GetSetting<BoolSettingViewModel>(nameof(ForceLowDpiRendering)).Value;
+        }
+        set
+        {
+            GetSetting<BoolSettingViewModel>(nameof(ForceLowDpiRendering)).Value = value;
+        }
+    }
 
     public TextToolbar()
     {
         AddSetting(new FontFamilySettingViewModel(nameof(FontFamily), "FONT_LABEL"));
+        FontFamily = FontDomain.DefaultFontFamily;
+        
         var sizeSetting =
             new SizeSettingViewModel(nameof(FontSize), "FONT_SIZE_LABEL", unit: new LocalizedString("UNIT_PT"))
             {
@@ -63,6 +78,11 @@ internal class TextToolbar : FillableShapeToolbar, ITextToolbar
         };
 
         AddSetting(spacingSetting);
+        
+        AddSetting(new BoolSettingViewModel(nameof(ForceLowDpiRendering), "__force_low_dpi_rendering")
+        {
+            IsExposed = false, Value = false
+        });
     }
 
     public Font ConstructFont()
@@ -79,6 +99,7 @@ internal class TextToolbar : FillableShapeToolbar, ITextToolbar
         }
 
         font.Size = (float)FontSize;
+        font.Edging = AntiAliasing ? FontEdging.AntiAlias : FontEdging.Alias;
 
         return font;
     }

+ 4 - 2
src/PixiEditor/ViewModels/Tools/Tools/TextToolViewModel.cs

@@ -20,6 +20,8 @@ internal class TextToolViewModel : ToolViewModel, ITextToolHandler
     public override bool IsErasable => false;
     public override bool StopsLinkedToolOnUse => false;
 
+    public string? DefaultNewLayerName { get; } = new LocalizedString("TEXT_LAYER_NAME");
+
     [Settings.Inherited]
     public double FontSize
     {
@@ -33,14 +35,14 @@ internal class TextToolViewModel : ToolViewModel, ITextToolHandler
 
     public override void UseTool(VecD pos)
     {
-        ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseVectorTextTool();
+        ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseTextTool();
     }
 
     protected override void OnSelected(bool restoring)
     {
         if (!restoring)
         {
-            ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseVectorTextTool();
+            ViewModelMain.Current?.DocumentManagerSubViewModel.ActiveDocument?.Tools.UseTextTool();
         }
     }