Browse Source

Font features in test app (#19493)

Co-authored-by: Jan Kučera <miloush@users.noreply.github.com>
Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com>
pull/19583/head
Jan Kučera 5 months ago
committed by GitHub
parent
commit
c3de4bbbe0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 20
      samples/TextTestApp/FontFeatureCollectionConverter.cs
  2. 28
      samples/TextTestApp/InteractiveLineControl.cs
  3. 3
      samples/TextTestApp/MainWindow.axaml
  4. 4
      samples/TextTestApp/Program.cs
  5. 48
      src/Avalonia.Base/Media/FontFeatureCollection.cs

20
samples/TextTestApp/FontFeatureCollectionConverter.cs

@ -0,0 +1,20 @@
using System;
using System.ComponentModel;
using System.Globalization;
using Avalonia.Media;
namespace TextTestApp
{
public class FontFeatureCollectionConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return FontFeatureCollection.Parse((string)value);
}
}
}

28
samples/TextTestApp/InteractiveLineControl.cs

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Avalonia;
@ -374,6 +376,14 @@ namespace TextTestApp
InvalidateTextRunProperties();
break;
case nameof(FontFeatures):
if (change.OldValue is FontFeatureCollection oc)
oc.CollectionChanged -= OnFeatureCollectionChanged;
if (change.NewValue is FontFeatureCollection nc)
nc.CollectionChanged += OnFeatureCollectionChanged;
OnFeatureCollectionChanged(null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
break;
case nameof(FontStyle):
case nameof(FontWeight):
case nameof(FontStretch):
@ -422,6 +432,11 @@ namespace TextTestApp
base.OnPropertyChanged(change);
}
private void OnFeatureCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
InvalidateTextRunProperties();
}
protected override Size MeasureOverride(Size availableSize)
{
if (TextLine == null)
@ -433,6 +448,7 @@ namespace TextTestApp
private const double VerticalSpacing = 5;
private const double HorizontalSpacing = 5;
private const double ArrowSize = 5;
private const double LabelFontSize = 9;
private Dictionary<string, FormattedText> _labelsCache = new();
protected FormattedText GetOrCreateLabel(string label, IBrush brush, bool disableCache = false)
@ -440,7 +456,7 @@ namespace TextTestApp
if (_labelsCache.TryGetValue(label, out var text))
return text;
text = new FormattedText(label, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface.Default, 8, brush);
text = new FormattedText(label, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface.Default, LabelFontSize, brush);
if (!disableCache)
_labelsCache[label] = text;
@ -519,7 +535,7 @@ namespace TextTestApp
}
}
double y = inkBounds.Bottom - lineBounds.Top + VerticalSpacing * 2;
double y = Math.Max(inkBounds.Bottom, lineBounds.Bottom) + VerticalSpacing * 2;
if (NextHitStroke != null)
{
@ -565,6 +581,14 @@ namespace TextTestApp
leftLabelX -= nextLabel.WidthIncludingTrailingWhitespace;
}
if (BackspaceHitStroke != null)
{
CharacterHit backHit = textLine.GetBackspaceCaretCharacterHit(hit);
var x1 = textLine.GetDistanceFromCharacterHit(new CharacterHit(backHit.FirstCharacterIndex, 0));
var x2 = textLine.GetDistanceFromCharacterHit(new CharacterHit(backHit.FirstCharacterIndex + backHit.TrailingLength, 0));
RenderHorizontalPoint(context, x1, x2, y, BackspaceHitPen, ArrowSize);
}
if (PreviousHitStroke != null)
{
prevHit = textLine.GetPreviousCaretCharacterHit(hit);

3
samples/TextTestApp/MainWindow.axaml

@ -23,6 +23,8 @@
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
<Label Content="_Font:" Target="{Binding ElementName=_font}" VerticalAlignment="Center" Margin="5,0,0,0" />
<ComboBox Name="_font" ItemsSource="{Binding SystemFonts, Source={x:Static FontManager.Current}}" />
<Label Content="Fea_tures:" Target="{Binding ElementName=_features}" VerticalAlignment="Center" Margin="5,0,0,0" />
<TextBox Name="_features" VerticalAlignment="Center" Text="calt clig kern liga" />
<Label Content="_Size:" Target="{Binding ElementName=_size}" VerticalAlignment="Center" Margin="5,0,0,0" />
<TextBox Name="_size" VerticalAlignment="Center" Text="64" />
<Button VerticalAlignment="Center" Click="OnNewWindowClick" ToolTip.Tip="New window" Margin="5,0,0,0">+</Button>
@ -37,6 +39,7 @@
Text="{Binding Text, ElementName=_text}"
FontFamily="{Binding SelectedValue, ElementName=_font}"
FontFeatures="{Binding Text, ElementName=_features}"
FontSize="{Binding Text, ElementName=_size}"
Background="BlanchedAlmond"
ExtentStroke="Black"

4
samples/TextTestApp/Program.cs

@ -1,5 +1,7 @@
using System;
using System.ComponentModel;
using Avalonia;
using Avalonia.Media;
namespace TextTestApp
{
@ -11,6 +13,8 @@ namespace TextTestApp
[STAThread]
public static void Main(string[] args)
{
TypeDescriptor.AddAttributes(typeof(FontFeatureCollection), new TypeConverterAttribute(typeof(FontFeatureCollectionConverter)));
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}

48
src/Avalonia.Base/Media/FontFeatureCollection.cs

@ -1,4 +1,6 @@
using System.Collections.Generic;
using Avalonia.Collections;
using Avalonia.Utilities;
namespace Avalonia.Media;
@ -7,4 +9,50 @@ namespace Avalonia.Media;
/// </summary>
public class FontFeatureCollection : AvaloniaList<FontFeature>
{
/// <summary>
/// Initializes a new instance of the <see cref="FontFeatureCollection"/>.
/// </summary>
public FontFeatureCollection()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="FontFeatureCollection"/> that is empty and has the specified initial capacity.
/// </summary>
/// <param name="capacity">The number of font features that the new collection can initially store.</param>
public FontFeatureCollection(int capacity) : base(capacity)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="FontFeatureCollection"/> that contains font features copied from the specified collection.
/// </summary>
/// <param name="fontFeatures">The collection whose font features are copied to the new collection.</param>
public FontFeatureCollection(IEnumerable<FontFeature> fontFeatures) : base(fontFeatures)
{
}
/// <summary>
/// Parses a <see cref="FontFeatureCollection"/> string.
/// </summary>
/// <param name="s">The string.</param>
/// <returns>The <see cref="FontFeatureCollection"/>.</returns>
public static FontFeatureCollection Parse(string s)
{
var features = new List<FontFeature>();
using (var tokenizer = new SpanStringTokenizer(s, ',', "Invalid font feature specification."))
{
while (tokenizer.TryReadSpan(out var token))
{
FontFeature feature = FontFeature.Parse(token.ToString());
features.Add(feature);
}
}
return new FontFeatureCollection(features);
}
}

Loading…
Cancel
Save