Skip to content

Commit d173d08

Browse files
committed
Port WPF's FormattedText and use TextLayout instead of FormattedText in TextPresenter
1 parent c85fa2b commit d173d08

File tree

83 files changed

+5929
-2191
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+5929
-2191
lines changed

samples/ControlCatalog/Pages/ScreenPage.cs

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Globalization;
23
using Avalonia;
34
using Avalonia.Controls;
45
using Avalonia.Markup.Xaml;
@@ -47,29 +48,34 @@ public override void Render(DrawingContext context)
4748
screen.WorkingArea.Height / 10f);
4849
context.DrawRectangle(p, boundsRect);
4950
context.DrawRectangle(p, workingAreaRect);
50-
51-
FormattedText text = new FormattedText()
52-
{
53-
Typeface = Typeface.Default
54-
};
5551

56-
text.Text = $"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}";
57-
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text);
58-
59-
text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
60-
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
6152

62-
text.Text = $"Scaling: {screen.PixelDensity * 100}%";
63-
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
64-
65-
text.Text = $"Primary: {screen.Primary}";
66-
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
67-
68-
text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}";
69-
context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text);
53+
var formattedText = CreateFormattedText($"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}");
54+
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height));
55+
56+
formattedText =
57+
CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}");
58+
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20));
59+
60+
formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%");
61+
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40));
62+
63+
formattedText = CreateFormattedText($"Primary: {screen.Primary}");
64+
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60));
65+
66+
formattedText =
67+
CreateFormattedText(
68+
$"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}");
69+
context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 80));
7070
}
7171

7272
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10, w.Bounds.Width / 10, w.Bounds.Height / 10));
7373
}
74+
75+
private FormattedText CreateFormattedText(string textToFormat)
76+
{
77+
return new FormattedText(textToFormat, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
78+
Typeface.Default, 12, Brushes.Green);
79+
}
7480
}
7581
}

samples/RenderDemo/MainWindow.xaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
<TabItem Header="GlyphRun">
5555
<pages:GlyphRunPage/>
5656
</TabItem>
57+
<TabItem Header="FormattedText">
58+
<pages:FormattedTextPage/>
59+
</TabItem>
5760
<TabItem Header="LineBounds">
5861
<pages:LineBoundsPage />
5962
</TabItem>

samples/RenderDemo/Pages/CustomSkiaPage.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Globalization;
34
using Avalonia;
45
using Avalonia.Controls;
56
using Avalonia.Media;
@@ -41,7 +42,10 @@ public void Render(IDrawingContextImpl context)
4142
{
4243
var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas;
4344
if (canvas == null)
44-
context.DrawText(Brushes.Black, new Point(), _noSkia.PlatformImpl);
45+
using (var c = new DrawingContext(context, false))
46+
{
47+
c.DrawText(_noSkia, new Point());
48+
}
4549
else
4650
{
4751
canvas.Save();
@@ -108,11 +112,11 @@ static int Animate(int d, int from, int to)
108112

109113
public override void Render(DrawingContext context)
110114
{
111-
var noSkia = new FormattedText()
112-
{
113-
Text = "Current rendering API is not Skia"
114-
};
115+
var noSkia = new FormattedText("Current rendering API is not Skia", CultureInfo.CurrentCulture,
116+
FlowDirection.LeftToRight, Typeface.Default, 12, Brushes.Black);
117+
115118
context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), noSkia));
119+
116120
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
117121
}
118122
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
6+
x:Class="RenderDemo.Pages.FormattedTextPage">
7+
</UserControl>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Globalization;
2+
using Avalonia;
3+
using Avalonia.Controls;
4+
using Avalonia.Markup.Xaml;
5+
using Avalonia.Media;
6+
7+
namespace RenderDemo.Pages
8+
{
9+
public class FormattedTextPage : UserControl
10+
{
11+
public FormattedTextPage()
12+
{
13+
this.InitializeComponent();
14+
}
15+
16+
private void InitializeComponent()
17+
{
18+
AvaloniaXamlLoader.Load(this);
19+
}
20+
21+
public override void Render(DrawingContext context)
22+
{
23+
const string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor";
24+
25+
// Create the initial formatted text string.
26+
var formattedText = new FormattedText(
27+
testString,
28+
CultureInfo.GetCultureInfo("en-us"),
29+
FlowDirection.LeftToRight,
30+
new Typeface("Verdana"),
31+
32,
32+
Brushes.Black) { MaxTextWidth = 300, MaxTextHeight = 240 };
33+
34+
// Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
35+
36+
// Use a larger font size beginning at the first (zero-based) character and continuing for 5 characters.
37+
// The font size is calculated in terms of points -- not as device-independent pixels.
38+
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);
39+
40+
// Use a Bold font weight beginning at the 6th character and continuing for 11 characters.
41+
formattedText.SetFontWeight(FontWeight.Bold, 6, 11);
42+
43+
var gradient = new LinearGradientBrush
44+
{
45+
GradientStops =
46+
new GradientStops { new GradientStop(Colors.Orange, 0), new GradientStop(Colors.Teal, 1) },
47+
StartPoint = new RelativePoint(0,0, RelativeUnit.Relative),
48+
EndPoint = new RelativePoint(0,1, RelativeUnit.Relative)
49+
};
50+
51+
// Use a linear gradient brush beginning at the 6th character and continuing for 11 characters.
52+
formattedText.SetForegroundBrush(gradient, 6, 11);
53+
54+
// Use an Italic font style beginning at the 28th character and continuing for 28 characters.
55+
formattedText.SetFontStyle(FontStyle.Italic, 28, 28);
56+
57+
context.DrawText(formattedText, new Point(10, 0));
58+
}
59+
}
60+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Compat issues with assembly Avalonia.Controls:
2+
TypesMustExist : Type 'Avalonia.Controls.IndexPath' does not exist in the implementation but it does exist in the contract.
3+
TypesMustExist : Type 'Avalonia.Controls.ISelectedItemInfo' does not exist in the implementation but it does exist in the contract.
4+
TypesMustExist : Type 'Avalonia.Controls.ISelectionModel' does not exist in the implementation but it does exist in the contract.
5+
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.ListBox.SelectionProperty' does not exist in the implementation but it does exist in the contract.
6+
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.ListBox.Selection.get()' does not exist in the implementation but it does exist in the contract.
7+
MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
8+
TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract.
9+
TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract.
10+
TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract.
11+
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.ContentProperty' does not exist in the implementation but it does exist in the contract.
12+
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.PaneProperty' does not exist in the implementation but it does exist in the contract.
13+
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Content.get()' does not exist in the implementation but it does exist in the contract.
14+
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Content.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
15+
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Pane.get()' does not exist in the implementation but it does exist in the contract.
16+
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Pane.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
17+
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract.
18+
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract.
19+
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract.
20+
MembersMustExist : Member 'public void Avalonia.Controls.TreeView.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
21+
InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.Args' is present in the implementation but not in the contract.
22+
InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.Args.get()' is present in the implementation but not in the contract.
23+
MembersMustExist : Member 'protected Avalonia.Media.FormattedText Avalonia.Controls.Presenters.TextPresenter.CreateFormattedText()' does not exist in the implementation but it does exist in the contract.
24+
MembersMustExist : Member 'public Avalonia.Media.FormattedText Avalonia.Controls.Presenters.TextPresenter.FormattedText.get()' does not exist in the implementation but it does exist in the contract.
25+
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract.
26+
MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract.
27+
MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
28+
Total Issues: 26

0 commit comments

Comments
 (0)