Selaa lähdekoodia

Serialization and missing font handling

flabbet 7 kuukautta sitten
vanhempi
commit
d6b37d0d5d

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit e946d71436a59ba5503aefd195811e44bd982ab2
+Subproject commit d56a15d08ea1893eb6be4684fe6c939ae1ce2e45

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

@@ -22,10 +22,10 @@ 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
@@ -42,6 +42,8 @@ public class TextVectorData : ShapeVectorData, IDisposable
 
     public override RectD VisualAABB => GeometryAABB;
     public VectorPath? Path { get; set; }
+    public FontFamilyName? MissingFontFamily { get; set; }
+    public string MissingFontText { get; set; }
 
     private RichText richText;
 
@@ -80,7 +82,15 @@ public class TextVectorData : ShapeVectorData, IDisposable
         richText.StrokeWidth = StrokeWidth;
         richText.Spacing = Spacing;
 
-        PaintText(canvas, paint);
+        if (MissingFontFamily != null)
+        {
+            paint.Color = Fill ? FillColor : StrokeColor;
+            canvas.DrawText($"{MissingFontText}: " + MissingFontFamily.Value.Name, Position, Font, paint);
+        }
+        else
+        {
+            PaintText(canvas, paint);
+        }
 
         if (applyTransform)
         {

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

@@ -841,5 +841,7 @@
   "UNIT_PT": "pt",
   "FONT_LABEL": "Family",
   "FONT_SIZE_LABEL": "Size",
-  "SPACING_LABEL": "Spacing"
+  "SPACING_LABEL": "Spacing",
+  "TEXT_TOOL": "Text",
+  "MISSING_FONT": "Missing font"
 }

+ 44 - 0
src/PixiEditor/Models/Controllers/FontDomain.cs

@@ -0,0 +1,44 @@
+using System.Collections.ObjectModel;
+using Avalonia.Media;
+using Drawie.Backend.Core.Text;
+
+namespace PixiEditor.Models.Controllers;
+
+public static class FontDomain
+{
+    private static List<FontFamilyName> _customFonts = new List<FontFamilyName>();
+    private static List<FontFamilyName> _allFonts = new List<FontFamilyName>();
+
+    public static FontFamilyName DefaultFontFamily { get; } = new FontFamilyName("Arial");
+
+    public static FontFamilyName[] SystemFonts { get; } = FontManager.Current.SystemFonts.Select(x => new FontFamilyName(x.Name)).ToArray();
+    
+    public static IReadOnlyList<FontFamilyName> CustomFonts => _customFonts;
+
+    public static FontFamilyName[] AllFonts
+    {
+        get
+        {
+            if (_allFonts.Count != SystemFonts.Length + CustomFonts.Count)
+            {
+                _allFonts = SystemFonts.Concat(CustomFonts).ToList();
+            }
+
+            return _allFonts.ToArray();
+        }
+    }
+
+    public static event Action<FontFamilyName> FontAdded;
+
+    public static bool TryAddCustomFont(FontFamilyName fontFamily)
+    {
+        if (!CustomFonts.Any(x => x.Name == fontFamily.Name && x.FontUri == fontFamily.FontUri))
+        {
+            _customFonts.Add(fontFamily);
+            FontAdded?.Invoke(fontFamily);
+            return true;
+        }
+        
+        return false;
+    }
+}

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

@@ -5,7 +5,7 @@ namespace PixiEditor.Models.Handlers.Toolbars;
 internal interface ITextToolbar : IFillableShapeToolbar
 {
     public double FontSize { get; set; }
-    public FontFamilyName? FontFamily { get; set; }
+    public FontFamilyName FontFamily { get; set; }
     public double Spacing { get; set; }
 
     public Font ConstructFont();

+ 98 - 0
src/PixiEditor/Models/Serialization/Factories/TextSerializationFactory.cs

@@ -0,0 +1,98 @@
+using Drawie.Backend.Core.ColorsImpl;
+using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Text;
+using Drawie.Backend.Core.Vector;
+using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
+using PixiEditor.Extensions.Common.Localization;
+using PixiEditor.Models.Controllers;
+
+namespace PixiEditor.Models.Serialization.Factories;
+
+internal class TextSerializationFactory : VectorShapeSerializationFactory<TextVectorData>
+{
+    public override string DeserializationId { get; } = "PixiEditor.Text";
+
+    protected override void AddSpecificData(ByteBuilder builder, TextVectorData original)
+    {
+        builder.AddString(original.Text);
+        builder.AddVecD(original.Position);
+        builder.AddString(original.Font.Family.Name);
+        builder.AddBool(original.Font.Family.FontUri?.IsFile ?? false);
+        if (original.Font.Family.FontUri?.IsFile ?? false)
+        {
+            builder.AddString(original.Font.Family.FontUri.AbsolutePath);
+        }
+
+        builder.AddDouble(original.Font.Size);
+        builder.AddDouble(original.MaxWidth);
+        builder.AddDouble(original.Spacing ?? original.Font.Size);
+        builder.AddBool(original.Path != null);
+        if (original.Path != null)
+        {
+            builder.AddString(original.Path.ToSvgPathData());
+        }
+    }
+
+    protected override bool DeserializeVectorData(ByteExtractor extractor, Matrix3X3 matrix, Color strokeColor,
+        bool fill, Color fillColor,
+        float strokeWidth, (string serializerName, string serializerVersion) serializerData,
+        out TextVectorData original)
+    {
+        string text = extractor.GetString();
+        VecD position = extractor.GetVecD();
+        string fontFamily = extractor.GetString();
+        bool isFontFromFile = extractor.GetBool();
+        string fontPath = null;
+        if (isFontFromFile)
+        {
+            fontPath = extractor.GetString();
+        }
+
+        double fontSize = extractor.GetDouble();
+        double maxWidth = extractor.GetDouble();
+        double spacing = extractor.GetDouble();
+        bool hasPath = extractor.GetBool();
+        VectorPath path = null;
+        if (hasPath)
+        {
+            path = VectorPath.FromSvgPath(extractor.GetString());
+        }
+
+        FontFamilyName family =
+            new FontFamilyName(fontFamily) { FontUri = isFontFromFile ? new Uri(fontPath, UriKind.Absolute) : null };
+        Font font = Font.FromFontFamily(family);
+        FontFamilyName? missingFamily = null;
+        
+        if (font == null)
+        {
+            font = Font.CreateDefault();
+            missingFamily = family;
+        }
+        else if (isFontFromFile)
+        {
+            FontDomain.TryAddCustomFont(family);
+        }
+
+        font.Size = fontSize;
+
+        original = new TextVectorData()
+        {
+            TransformationMatrix = matrix,
+            StrokeColor = strokeColor,
+            Fill = fill,
+            FillColor = fillColor,
+            StrokeWidth = strokeWidth,
+            Text = text,
+            Position = position,
+            Font = font,
+            MaxWidth = maxWidth,
+            Spacing = spacing,
+            Path = path,
+            MissingFontFamily = missingFamily,
+            MissingFontText = new LocalizedString("MISSING_FONT")
+        };
+
+        return true;
+    }
+}

+ 7 - 2
src/PixiEditor/ViewModels/Tools/ToolSettings/Settings/FontFamilySettingViewModel.cs

@@ -8,6 +8,7 @@ using Avalonia.Platform.Storage;
 using CommunityToolkit.Mvvm.Input;
 using Drawie.Backend.Core.Text;
 using PixiEditor.Extensions.Common.Localization;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.IO;
 using PixiEditor.ViewModels.UserPreferences;
 
@@ -51,7 +52,8 @@ internal class FontFamilySettingViewModel : Setting<FontFamilyName>
     public FontFamilySettingViewModel(string name, string displayName) : base(name)
     {
         Label = displayName;
-        Fonts = new ObservableCollection<FontFamilyName>(FontManager.Current.SystemFonts.Select(x => new FontFamilyName(x.Name)));
+        Fonts = new ObservableCollection<FontFamilyName>(FontDomain.AllFonts);
+        FontDomain.FontAdded += (font) => Fonts.Add(font); 
         UploadFontCommand = new AsyncRelayCommand(UploadFont);
     }
 
@@ -73,7 +75,10 @@ internal class FontFamilySettingViewModel : Setting<FontFamilyName>
                 return;
 
             var fontPath = dialog[0];
-            Fonts.Add(new FontFamilyName(fontPath.Path, Path.GetFileNameWithoutExtension(fontPath.Name)));
+            FontFamilyName familyName = new FontFamilyName(fontPath.Path, Path.GetFileNameWithoutExtension(fontPath.Name));
+            FontDomain.TryAddCustomFont(familyName);
+            
+            FontIndex = Fonts.IndexOf(familyName);
         }
     }
 }

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

@@ -68,7 +68,7 @@ internal class TextToolbar : FillableShapeToolbar, ITextToolbar
     public Font ConstructFont()
     {
         Font font = null;
-        if (FontFamily != null)
+        if (!string.IsNullOrEmpty(FontFamily.Name))
         {
             font = Font.FromFontFamily(FontFamily);
         }