ソースを参照

Added spacing and fixed line height calculation

flabbet 7 ヶ月 前
コミット
4b311c5c40

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit dc510dbaf4de99e4c48746aaca5d593078cea480
+Subproject commit 2d841ec4e603ee31a54385532aeec70d4e58be00

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

@@ -22,8 +22,11 @@ public class TextVectorData : ShapeVectorData, IDisposable
     }
 
     public VecD Position { get; set; }
+    
     public double MaxWidth { get; set; } = double.MaxValue;
     public Font Font { get; set; } = Font.CreateDefault();
+    
+    public double? Spacing { get; set; }
 
     public override RectD GeometryAABB
     {
@@ -75,6 +78,7 @@ public class TextVectorData : ShapeVectorData, IDisposable
         richText.FillColor = FillColor;
         richText.StrokeColor = StrokeColor;
         richText.StrokeWidth = StrokeWidth;
+        richText.Spacing = Spacing;
 
         PaintText(canvas, paint);
 

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

@@ -838,5 +838,8 @@
   "CONVERT_TO_CURVE": "Convert to curve",
   "CONVERT_TO_CURVE_DESCRIPTIVE": "Convert selected vector layer to a curve/path",
   "FONT_FILES": "Font Files",
-  "UNIT_PT": "pt"
+  "UNIT_PT": "pt",
+  "FONT_LABEL": "Family",
+  "FONT_SIZE_LABEL": "Size",
+  "SPACING_LABEL": "Spacing"
 }

+ 5 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/VectorTextToolExecutor.cs

@@ -48,14 +48,14 @@ 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);
+            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);
+            document.TextOverlayHandler.Show("", controller.LastPrecisePosition, toolbar.ConstructFont(), Matrix3X3.Identity, toolbar.Spacing);
             lastText = "";
             position = controller.LastPrecisePosition;
         }
@@ -92,6 +92,7 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
         internals.ActionAccumulator.AddActions(new SetShapeGeometry_Action(selectedMember.Id, constructedText));
         
         document.TextOverlayHandler.Font = constructedText.Font;
+        document.TextOverlayHandler.Spacing = toolbar.Spacing;
     }
 
     public override void OnColorChanged(Color color, bool primary)
@@ -117,7 +118,8 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
             StrokeWidth = (float)toolbar.ToolSize,
             StrokeColor = toolbar.StrokeColor.ToColor(),
             TransformationMatrix = lastMatrix,
-            Font = font
+            Font = font,
+            Spacing = toolbar.Spacing
         };
     }
 

+ 2 - 1
src/PixiEditor/Models/Handlers/ITextOverlayHandler.cs

@@ -6,8 +6,9 @@ namespace PixiEditor.Models.Handlers;
 
 public interface ITextOverlayHandler : IHandler
 {
-    public void Show(string text, VecD position, Font font, Matrix3X3 matrix);
+    public void Show(string text, VecD position, Font font, Matrix3X3 matrix, double? spacing = null);
     public void Hide();
     public Font Font { get; set; }
     public VecD Position { get; set; }
+    public double? Spacing { get; set; }
 }

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

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

+ 11 - 1
src/PixiEditor/ViewModels/Document/TransformOverlays/TextOverlayViewModel.cs

@@ -15,6 +15,7 @@ internal class TextOverlayViewModel : ObservableObject, ITextOverlayHandler
     private Font font;
     private ExecutionTrigger<string> requestEditTextTrigger;
     private Matrix3X3 matrix = Matrix3X3.Identity;
+    private double? spacing;
 
     public event Action<string>? TextChanged;
 
@@ -60,6 +61,12 @@ internal class TextOverlayViewModel : ObservableObject, ITextOverlayHandler
         get => matrix;
         set => SetProperty(ref matrix, value);
     }
+    
+    public double? Spacing
+    {
+        get => spacing;
+        set => SetProperty(ref spacing, value);
+    }
 
     public TextOverlayViewModel()
     {
@@ -67,12 +74,13 @@ internal class TextOverlayViewModel : ObservableObject, ITextOverlayHandler
     }
 
 
-    public void Show(string text, VecD position, Font font, Matrix3X3 matrix)
+    public void Show(string text, VecD position, Font font, Matrix3X3 matrix, double? spacing = null)
     {
         Font = font;
         Position = position;
         Text = text;
         Matrix = matrix;
+        Spacing = spacing;
         IsActive = true;
         RequestEditTextTrigger.Execute(this, text);
     }
@@ -83,5 +91,7 @@ internal class TextOverlayViewModel : ObservableObject, ITextOverlayHandler
         Font = null!;
         Position = default;
         Text = string.Empty;
+        Matrix = Matrix3X3.Identity;
+        Spacing = null;
     }
 }

+ 7 - 6
src/PixiEditor/ViewModels/Tools/ToolSettings/Settings/SizeSettingViewModel.cs

@@ -14,12 +14,13 @@ internal sealed class SizeSettingViewModel : Setting<double>
     private int decimalPlaces;
     private string unit = "px";
     
-    public SizeSettingViewModel(string name, string label = null, double min = 1, double max = double.PositiveInfinity, int decimalPlaces = 0, string unit = "px")
+    public SizeSettingViewModel(string name, string label = null, double min = 1, double max = double.PositiveInfinity,
+        int decimalPlaces = 0, string unit = "px")
         : base(name)
     {
         Label = label;
         Value = 1;
-        
+
         this.min = min;
         this.max = max;
         this.decimalPlaces = decimalPlaces;
@@ -34,7 +35,7 @@ internal sealed class SizeSettingViewModel : Setting<double>
             SetProperty(ref isEnabled, value);
         }
     }
-    
+
     public double Min
     {
         get => min;
@@ -43,7 +44,7 @@ internal sealed class SizeSettingViewModel : Setting<double>
             SetProperty(ref min, value);
         }
     }
-    
+
     public double Max
     {
         get => max;
@@ -52,7 +53,7 @@ internal sealed class SizeSettingViewModel : Setting<double>
             SetProperty(ref max, value);
         }
     }
-    
+
     public int DecimalPlaces
     {
         get => decimalPlaces;
@@ -61,7 +62,7 @@ internal sealed class SizeSettingViewModel : Setting<double>
             SetProperty(ref decimalPlaces, value);
         }
     }
-    
+
     public string Unit
     {
         get => unit;

+ 29 - 3
src/PixiEditor/ViewModels/Tools/ToolSettings/Toolbars/TextToolbar.cs

@@ -31,12 +31,38 @@ internal class TextToolbar : FillableShapeToolbar, ITextToolbar
         }
     }
 
+    public double Spacing
+    {
+        get
+        {
+            return GetSetting<SizeSettingViewModel>(nameof(Spacing)).Value;
+        }
+        set
+        {
+            GetSetting<SizeSettingViewModel>(nameof(Spacing)).Value = value;
+        }
+    }
+
     public TextToolbar()
     {
         AddSetting(new FontFamilySettingViewModel(nameof(FontFamily), "FONT_LABEL"));
-        var sizeSetting = new SizeSettingViewModel(nameof(FontSize), "FONT_SIZE_LABEL", unit: new LocalizedString("UNIT_PT")) 
-            { Value = 12 };
+        var sizeSetting =
+            new SizeSettingViewModel(nameof(FontSize), "FONT_SIZE_LABEL", unit: new LocalizedString("UNIT_PT"))
+            {
+                Value = 12
+            };
         AddSetting(sizeSetting);
+        var spacingSetting =
+            new SizeSettingViewModel(nameof(Spacing), "SPACING_LABEL", unit: new LocalizedString("UNIT_PT"));
+        spacingSetting.Value = 12;
+
+        sizeSetting.ValueChanged += (sender, args) =>
+        {
+            double delta = args.NewValue - args.OldValue;
+            spacingSetting.Value += delta;
+        };
+
+        AddSetting(spacingSetting);
     }
 
     public Font ConstructFont()
@@ -53,7 +79,7 @@ internal class TextToolbar : FillableShapeToolbar, ITextToolbar
         }
 
         font.Size = (float)FontSize;
-        
+
         return font;
     }
 }

+ 6 - 0
src/PixiEditor/Views/Main/ViewportControls/ViewportOverlays.cs

@@ -482,6 +482,11 @@ internal class ViewportOverlays
         {
             Source = Viewport, Path = "Document.TextOverlayViewModel.Matrix", Mode = BindingMode.OneWay
         };
+        
+        Binding spacingBinding = new()
+        {
+            Source = Viewport, Path = "Document.TextOverlayViewModel.Spacing", Mode = BindingMode.OneWay
+        };
 
         textOverlay.Bind(Visual.IsVisibleProperty, isVisibleBinding);
         textOverlay.Bind(TextOverlay.TextProperty, textBinding);
@@ -489,6 +494,7 @@ internal class ViewportOverlays
         textOverlay.Bind(TextOverlay.FontProperty, fontBinding);
         textOverlay.Bind(TextOverlay.RequestEditTextProperty, requestEditTextBinding);
         textOverlay.Bind(TextOverlay.MatrixProperty, matrixBinding);
+        textOverlay.Bind(TextOverlay.SpacingProperty, spacingBinding);
     }
 }
 

+ 2 - 2
src/PixiEditor/Views/Overlays/TextOverlay/Blinker.cs

@@ -15,7 +15,7 @@ internal class Blinker : IDisposable
     public float[] GlyphWidths { get; set; }
     public float BlinkerWidth { get; set; } = 1;
 
-    private Paint paint = new Paint() { Color = Colors.White, Style = PaintStyle.StrokeAndFill, StrokeWidth = 1 };
+    private Paint paint = new Paint() { Color = Colors.White, Style = PaintStyle.StrokeAndFill, StrokeWidth = 3 };
 
     public void Render(Canvas canvas)
     {
@@ -35,7 +35,7 @@ internal class Blinker : IDisposable
         
         paint.StrokeWidth = BlinkerWidth;
 
-        VecD from = new VecD(x, y);
+        VecD from = new VecD(x, y + glyphHeight / 4f);
         VecD to = new VecD(x, y - glyphHeight);
         canvas.DrawLine(from, to, paint);
     }

+ 20 - 2
src/PixiEditor/Views/Overlays/TextOverlay/TextOverlay.cs

@@ -87,6 +87,15 @@ internal class TextOverlay : Overlay
         set => SetValue(IsEditingProperty, value);
     }
 
+    public static readonly StyledProperty<double?> SpacingProperty = AvaloniaProperty.Register<TextOverlay, double?>(
+        nameof(Spacing));
+
+    public double? Spacing
+    {
+        get => GetValue(SpacingProperty);
+        set => SetValue(SpacingProperty, value);
+    }
+
     private Dictionary<KeyCombination, Action> shortcuts;
 
     private Blinker blinker = new Blinker();
@@ -100,8 +109,10 @@ internal class TextOverlay : Overlay
         IsEditingProperty.Changed.Subscribe(IsEditingChanged);
         TextProperty.Changed.Subscribe(TextChanged);
         FontProperty.Changed.Subscribe(FontChanged);
+        SpacingProperty.Changed.Subscribe(SpaceChanged);
 
-        AffectsOverlayRender(FontProperty, TextProperty, CursorPositionProperty, SelectionLengthProperty);
+        AffectsOverlayRender(FontProperty, TextProperty, CursorPositionProperty, SelectionLengthProperty, IsEditingProperty,
+            MatrixProperty, SpacingProperty);
     }
 
     public TextOverlay()
@@ -223,6 +234,7 @@ internal class TextOverlay : Overlay
         if (Font == null) return;
 
         RichText richText = new(Text);
+        richText.Spacing = Spacing;
         glyphPositions = richText.GetGlyphPositions(Font);
         glyphWidths = richText.GetGlyphWidths(Font);
     }
@@ -275,7 +287,13 @@ internal class TextOverlay : Overlay
         TextOverlay sender = args.Sender as TextOverlay;
         sender.UpdateGlyphs();
     }
-
+    
+    private static void SpaceChanged(AvaloniaPropertyChangedEventArgs<double?> args)
+    {
+        TextOverlay sender = args.Sender as TextOverlay;
+        sender.UpdateGlyphs();
+    }
+    
     private static int ClampValue(AvaloniaObject sender, int newPos)
     {
         TextOverlay textOverlay = sender as TextOverlay;