Skip to content

Commit 4f971bb

Browse files
committed
Initial UWP/Uno support library, replacing float-based DP
1 parent 2431d7d commit 4f971bb

File tree

7 files changed

+184
-25
lines changed

7 files changed

+184
-25
lines changed

CSharpMath.Rendering/FrontEnd/ICSharpMathAPI.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ public interface ICSharpMathAPI<TContent, TColor> where TContent : class {
99
TColor TextColor { get; set; }
1010
TColor ErrorColor { get; set; }
1111
///<summary>Unit of measure: points; Defaults to <see cref="FontSize"/>.</summary>
12-
float? ErrorFontSize { get; set; }
12+
double ErrorFontSize { get; set; }
1313
bool DisplayErrorInline { get; set; }
1414
PaintStyle PaintStyle { get; set; }
15-
float Magnification { get; set; }
15+
double Magnification { get; set; }
1616
string? ErrorMessage { get; }
1717
#endregion Non-display-recreating properties
1818
#region Display-recreating properties
1919
/// <summary>Unit of measure: points</summary>
20-
float FontSize { get; set; }
20+
double FontSize { get; set; }
2121
System.Collections.Generic.IEnumerable<Typeface> LocalTypefaces { get; set; }
2222
Atom.LineStyle LineStyle { get; set; }
2323
TContent? Content { get; set; }

CSharpMath.Rendering/FrontEnd/MathPainter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ protected override void UpdateDisplayCore(float unused) {
2525
public override void Draw(TCanvas canvas, TextAlignment alignment = TextAlignment.Center, Thickness padding = default, float offsetX = 0, float offsetY = 0) {
2626
var c = WrapCanvas(canvas);
2727
UpdateDisplay(float.NaN);
28-
DrawCore(c, Display, Display == null ? new PointF?() : IPainterExtensions.GetDisplayPosition(Display.Width, Display.Ascent, Display.Descent, FontSize, c.Width, c.Height, alignment, padding, offsetX, offsetY));
28+
DrawCore(c, Display, Display == null ? new PointF?() : IPainterExtensions.GetDisplayPosition(Display.Width, Display.Ascent, Display.Descent, (float)FontSize, c.Width, c.Height, alignment, padding, offsetX, offsetY));
2929
}
3030
public void Draw(TCanvas canvas, float x, float y) {
3131
var c = WrapCanvas(canvas);

CSharpMath.Rendering/FrontEnd/Painter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ public Painter() {
3030
/// Unit of measure: points;
3131
/// Defaults to <see cref="FontSize"/>.
3232
/// </summary>
33-
public float? ErrorFontSize { get; set; }
33+
public double ErrorFontSize { get; set; }
3434
public bool DisplayErrorInline { get; set; } = true;
3535
public TColor ErrorColor { get; set; }
3636
public TColor TextColor { get; set; }
3737
public TColor HighlightColor { get; set; }
3838
public (TColor glyph, TColor textRun)? GlyphBoxColor { get; set; }
3939
public PaintStyle PaintStyle { get; set; } = PaintStyle.Fill;
40-
public float Magnification { get; set; } = 1;
40+
public double Magnification { get; set; } = 1;
4141
public string? ErrorMessage { get; protected set; }
4242
public abstract IDisplay<Fonts, Glyph>? Display { get; protected set; }
4343
#endregion Non-redisplaying properties
@@ -47,9 +47,9 @@ public Painter() {
4747
protected abstract void SetRedisplay();
4848
protected Fonts Fonts { get; private set; } = new Fonts(Array.Empty<Typeface>(), DefaultFontSize);
4949
/// <summary>Unit of measure: points</summary>
50-
public float FontSize { get => Fonts.PointSize; set { Fonts = new Fonts(Fonts, value); SetRedisplay(); } }
50+
public double FontSize { get => Fonts.PointSize; set { Fonts = new Fonts(Fonts, (float)value); SetRedisplay(); } }
5151
IEnumerable<Typeface> __localTypefaces = Array.Empty<Typeface>();
52-
public IEnumerable<Typeface> LocalTypefaces { get => __localTypefaces; set { Fonts = new Fonts(value, FontSize); __localTypefaces = value; SetRedisplay(); } }
52+
public IEnumerable<Typeface> LocalTypefaces { get => __localTypefaces; set { Fonts = new Fonts(value, (float)FontSize); __localTypefaces = value; SetRedisplay(); } }
5353
Atom.LineStyle __style = Atom.LineStyle.Display;
5454
public Atom.LineStyle LineStyle { get => __style; set { __style = value; SetRedisplay(); } }
5555
TContent? __content;
@@ -74,7 +74,7 @@ protected void UpdateDisplay(float textPainterCanvasWidth) {
7474
UpdateDisplayCore(textPainterCanvasWidth);
7575
if (Display == null && DisplayErrorInline && ErrorMessage != null) {
7676
var font = Fonts;
77-
if (ErrorFontSize is { } errorSize) font = new Fonts(font, errorSize);
77+
if (ErrorFontSize > 0) font = new Fonts(font, (float)ErrorFontSize);
7878
var errorLines = ErrorMessage.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
7979
var runs = new List<Display.Displays.TextRunDisplay<Fonts, Glyph>>();
8080
float y = 0;
@@ -116,7 +116,7 @@ protected void DrawCore(ICanvas canvas, IDisplay<Fonts, Glyph>? display, PointF?
116116
canvas.Save();
117117
//invert the canvas vertically: displays are drawn with mathematical coordinates, not graphical coordinates
118118
canvas.Scale(1, -1);
119-
canvas.Scale(Magnification, Magnification);
119+
canvas.Scale((float)Magnification, (float)Magnification);
120120
if (position is { } p) display.Position = new PointF(p.X, p.Y);
121121
canvas.DefaultColor = WrapColor(TextColor);
122122
canvas.CurrentColor = WrapColor(HighlightColor);

CSharpMath.Rendering/FrontEnd/TextPainter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private void DrawCore(TCanvas canvas, float? width, TextAlignment alignment,
5656
System.Math.Max(_relativeXCoordDisplay.Width, _absoluteXCoordDisplay.Width),
5757
System.Math.Max(_relativeXCoordDisplay.Ascent, _absoluteXCoordDisplay.Ascent),
5858
System.Math.Max(_relativeXCoordDisplay.Descent, _absoluteXCoordDisplay.Descent),
59-
FontSize, width ?? c.Width,
59+
(float)FontSize, width ?? c.Width,
6060
c.Height, alignment, padding, offsetX, offsetY
6161
));
6262
var adjustedCanvasWidth =
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
3+
<PropertyGroup>
4+
<TargetFrameworks>xamarinmac20;MonoAndroid11.0;xamarinios10;netstandard2.0;uap10.0.17763</TargetFrameworks>
5+
<Description>The UWP and Uno Platform front end for CSharpMath using SkiaSharp rendering.</Description>
6+
<PackageTags>$(PackageTags) unoplatform uwp wasm</PackageTags>
7+
<!-- Ensures the .xr.xml files are generated in a proper layout folder -->
8+
<GenerateLibraryLayout>true</GenerateLibraryLayout>
9+
<LangVersion>8.0</LangVersion>
10+
</PropertyGroup>
11+
<ItemGroup>
12+
<Page Include="**\*.xaml" Exclude="bin\**\*.xaml;obj\**\*.xaml" />
13+
<Compile Update="**\*.xaml.cs">
14+
<DependentUpon>%(Filename)</DependentUpon>
15+
</Compile>
16+
</ItemGroup>
17+
<ItemGroup>
18+
<UpToDateCheckInput Include="**\*.xaml" Exclude="bin\**\*.xaml;obj\**\*.xaml" />
19+
</ItemGroup>
20+
<Import Project="..\CSharpMath.Xaml\CSharpMath.Xaml.projitems" Label="Shared" />
21+
<ItemGroup>
22+
<ProjectReference Include="..\CSharpMath.SkiaSharp\CSharpMath.SkiaSharp.csproj" />
23+
</ItemGroup>
24+
<ItemGroup Condition="'$(TargetFramework)'=='uap10.0.17763'">
25+
<PackageReference Include="SkiaSharp.Views" Version="2.80.2" />
26+
</ItemGroup>
27+
<ItemGroup Condition="'$(TargetFramework)'!='uap10.0.17763'">
28+
<PackageReference Include="SkiaSharp.Views.Uno" Version="2.80.2" />
29+
<PackageReference Include="Uno.UI" Version="3.4.0" />
30+
</ItemGroup>
31+
</Project>

CSharpMath.Xaml/Views.cs

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,24 @@ namespace CSharpMath.Avalonia {
2525
using TextPainter = CSharpMath.SkiaSharp.TextPainter;
2626
namespace CSharpMath.Forms {
2727
[Xamarin.Forms.ContentProperty(nameof(LaTeX))]
28+
#elif HAS_UNO || WINDOWS_UWP
29+
using Windows.UI.Xaml;
30+
using System.Drawing;
31+
using Windows.UI.Core;
32+
using Windows.UI.Xaml.Input;
33+
using XCanvas = SkiaSharp.SKCanvas;
34+
using XCanvasColor = SkiaSharp.SKColor;
35+
using XColor = Windows.UI.Color;
36+
using XThickness = Windows.UI.Xaml.Thickness;
37+
using XControl = Windows.UI.Xaml.Controls.Control;
38+
using XInheritControl = SkiaSharp.Views.UWP.SKXamlCanvas;
39+
using XProperty = Windows.UI.Xaml.DependencyProperty;
40+
using MathPainter = CSharpMath.SkiaSharp.MathPainter;
41+
using TextPainter = CSharpMath.SkiaSharp.TextPainter;
42+
namespace CSharpMath.UWPUno {
43+
[global::Windows.UI.Xaml.Markup.ContentProperty(Name = nameof(LaTeX))]
2844
#endif
29-
public class BaseView<TPainter, TContent> : XInheritControl, ICSharpMathAPI<TContent, XColor>
45+
public partial class BaseView<TPainter, TContent> : XInheritControl, ICSharpMathAPI<TContent, XColor>
3046
where TPainter : Painter<XCanvas, TContent, XCanvasColor>, new() where TContent : class {
3147
public TPainter Painter { get; } = new TPainter();
3248

@@ -164,16 +180,74 @@ protected sealed override void OnPaintSurface(global::SkiaSharp.Views.Forms.SKPa
164180
// SkiaSharp deals with raw pixels as opposed to Xamarin.Forms's device-independent units.
165181
// We should scale to occupy the full view size.
166182
canvas.Scale(e.Info.Width / (float)Width);
183+
#elif HAS_UNO || WINDOWS_UWP
184+
@this.Invalidate();
185+
}
186+
return XProperty.Register(propertyName, typeof(TValue), typeof(TThis),
187+
new PropertyMetadata(defaultValue, (b, n) => PropertyChanged((TThis)b, n.NewValue)));
188+
}
189+
public BaseView() {
190+
PointerPressed += OnPointerPressed;
191+
PointerMoved += OnPointerMoved;
192+
PointerReleased += OnPointerReleased;
193+
}
194+
protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize) =>
195+
Painter.Measure((float)availableSize.Width) is { } rect
196+
? new Windows.Foundation.Size(rect.Width, rect.Height)
197+
: base.MeasureOverride(availableSize);
198+
struct ReadOnlyProperty<TThis, TValue> where TThis : BaseView<TPainter, TContent> {
199+
public ReadOnlyProperty(string propertyName,
200+
Func<TPainter, TValue> getter) {
201+
Property = XProperty.RegisterDirect<TThis, TValue>(propertyName, b => getter(b.Painter), null, getter(staticPainter));
202+
_value = getter(staticPainter);
203+
}
204+
TValue _value;
205+
public global::Avalonia.DirectProperty<TThis, TValue> Property;
206+
public void SetValue(TThis @this, TValue value) => @this.SetAndRaise(Property, ref _value, value);
207+
}
208+
static XCanvasColor XColorToXCanvasColor(XColor color) => new XCanvasColor(color.R, color.G, color.B, color.A);
209+
static XColor XCanvasColorToXColor(XCanvasColor color) => XColor.FromArgb(color.Alpha, color.Red, color.Green, color.Blue);
210+
static CSharpMathThickness XThicknessToCSharpMathThickness(XThickness thickness) => new CSharpMathThickness((float)thickness.Left, (float)thickness.Top, (float)thickness.Right, (float)thickness.Bottom);
211+
static XThickness CSharpMathThicknessToXThickness(CSharpMathThickness thickness) => new XThickness(thickness.Left, thickness.Top, thickness.Right, thickness.Bottom);
212+
global::Avalonia.Point _origin;
213+
private void OnPointerPressed(object sender, PointerRoutedEventArgs e) {
214+
var point = e.GetCurrentPoint(this);
215+
if (point.Properties.IsLeftButtonPressed && EnablePanning) {
216+
_origin = point.Position;
217+
}
218+
}
219+
private void OnPointerMoved(object sender, PointerRoutedEventArgs e) {
220+
var point = e.GetCurrentPoint(this);
221+
if (point.Properties.IsLeftButtonPressed && EnablePanning) {
222+
var displacement = point.Position - _origin;
223+
_origin = point.Position;
224+
DisplacementX += (float)displacement.X;
225+
DisplacementY += (float)displacement.Y;
226+
}
227+
}
228+
private void OnPointerReleased(object sender, PointerRoutedEventArgs e) {
229+
var point = e.GetCurrentPoint(this);
230+
if (point.Properties.IsLeftButtonPressed && EnablePanning) {
231+
_origin = point.Position;
232+
}
233+
}
234+
protected override void OnPaintSurface(global::SkiaSharp.Views.UWP.SKPaintSurfaceEventArgs e) {
235+
base.OnPaintSurface(e);
236+
var canvas = e.Surface.Canvas;
237+
canvas.Clear();
238+
// SkiaSharp deals with raw pixels as opposed to Xamarin.Forms's device-independent units.
239+
// We should scale to occupy the full view size.
240+
canvas.Scale(e.Info.Width / (float)Width);
167241
#endif
168-
Painter.Draw(canvas, TextAlignment, Padding, DisplacementX, DisplacementY);
242+
Painter.Draw(canvas, TextAlignment, Padding, (float)DisplacementX, (float)DisplacementY);
169243
}
170244
/// <summary>Requires touch events to be enabled in SkiaSharp/Xamarin.Forms</summary>
171245
public bool EnablePanning { get => (bool)GetValue(DisablePanningProperty); set => SetValue(DisablePanningProperty, value); }
172246
public static readonly XProperty DisablePanningProperty = CreateProperty<BaseView<TPainter, TContent>, bool>(nameof(EnablePanning), false, _ => false, (_, __) => { });
173247

174248
static readonly System.Reflection.ParameterInfo[] drawMethodParams = typeof(TPainter)
175249
.GetMethod(nameof(Painter<XCanvas, TContent, XColor>.Draw),
176-
new[] { typeof(XCanvas), typeof(TextAlignment), typeof(Thickness), typeof(float), typeof(float) }).GetParameters();
250+
new[] { typeof(XCanvas), typeof(TextAlignment), typeof(Thickness), typeof(double), typeof(double) }).GetParameters();
177251
static T? Nullable<T>(T value) where T : struct => new T?(value);
178252
public (XColor glyph, XColor textRun)? GlyphBoxColor { get => ((XColor glyph, XColor textRun)?)GetValue(GlyphBoxColorProperty); set => SetValue(GlyphBoxColorProperty, value); }
179253
public static readonly XProperty GlyphBoxColorProperty = CreateProperty<BaseView<TPainter, TContent>, (XColor glyph, XColor textRun)?>(nameof(GlyphBoxColor), false,
@@ -189,11 +263,11 @@ protected sealed override void OnPaintSurface(global::SkiaSharp.Views.Forms.SKPa
189263
public bool DisplayErrorInline { get => (bool)GetValue(DisplayErrorInlineProperty); set => SetValue(DisplayErrorInlineProperty, value); }
190264
public static readonly XProperty DisplayErrorInlineProperty = CreateProperty<BaseView<TPainter, TContent>, bool>(nameof(DisplayErrorInline), true, p => p.DisplayErrorInline, (p, v) => p.DisplayErrorInline = v);
191265
/// <summary>Unit of measure: points</summary>
192-
public float FontSize { get => (float)GetValue(FontSizeProperty); set => SetValue(FontSizeProperty, value); }
193-
public static readonly XProperty FontSizeProperty = CreateProperty<BaseView<TPainter, TContent>, float>(nameof(FontSize), true, p => p.FontSize, (p, v) => p.FontSize = v);
266+
public double FontSize { get => (double)GetValue(FontSizeProperty); set => SetValue(FontSizeProperty, value); }
267+
public static readonly XProperty FontSizeProperty = CreateProperty<BaseView<TPainter, TContent>, double>(nameof(FontSize), true, p => p.FontSize, (p, v) => p.FontSize = (float)v);
194268
/// <summary>Unit of measure: points; Defaults to <see cref="FontSize"/>.</summary>
195-
public float? ErrorFontSize { get => (float?)GetValue(ErrorFontSizeProperty); set => SetValue(ErrorFontSizeProperty, value); }
196-
public static readonly XProperty ErrorFontSizeProperty = CreateProperty<BaseView<TPainter, TContent>, float?>(nameof(ErrorFontSize), true, p => p.ErrorFontSize, (p, v) => p.ErrorFontSize = v);
269+
public double ErrorFontSize { get => (double)GetValue(ErrorFontSizeProperty); set => SetValue(ErrorFontSizeProperty, value); }
270+
public static readonly XProperty ErrorFontSizeProperty = CreateProperty<BaseView<TPainter, TContent>, double>(nameof(ErrorFontSize), true, p => p.ErrorFontSize, (p, v) => p.ErrorFontSize = (float)v);
197271
public IEnumerable<Typeface> LocalTypefaces { get => (IEnumerable<Typeface>)GetValue(LocalTypefacesProperty); set => SetValue(LocalTypefacesProperty, value); }
198272
public static readonly XProperty LocalTypefacesProperty = CreateProperty<BaseView<TPainter, TContent>, IEnumerable<Typeface>>(nameof(LocalTypefaces), true, p => p.LocalTypefaces, (p, v) => p.LocalTypefaces = v);
199273
public XColor TextColor { get => (XColor)GetValue(TextColorProperty); set => SetValue(TextColorProperty, value); }
@@ -206,12 +280,12 @@ protected sealed override void OnPaintSurface(global::SkiaSharp.Views.Forms.SKPa
206280
public static readonly XProperty TextAlignmentProperty = CreateProperty<BaseView<TPainter, TContent>, TextAlignment>(nameof(Rendering.FrontEnd.TextAlignment), false, p => (TextAlignment)drawMethodParams[1].DefaultValue, (p, v) => { });
207281
public Thickness Padding { get => (Thickness)GetValue(PaddingProperty); set => SetValue(PaddingProperty, value); }
208282
public static readonly XProperty PaddingProperty = CreateProperty<BaseView<TPainter, TContent>, Thickness>(nameof(Padding), false, p => (Thickness)(drawMethodParams[2].DefaultValue ?? new Thickness()), (p, v) => { });
209-
public float DisplacementX { get => (float)GetValue(DisplacementXProperty); set => SetValue(DisplacementXProperty, value); }
210-
public static readonly XProperty DisplacementXProperty = CreateProperty<BaseView<TPainter, TContent>, float>(nameof(DisplacementX), false, p => (float)drawMethodParams[3].DefaultValue, (p, v) => { });
211-
public float DisplacementY { get => (float)GetValue(DisplacementYProperty); set => SetValue(DisplacementYProperty, value); }
212-
public static readonly XProperty DisplacementYProperty = CreateProperty<BaseView<TPainter, TContent>, float>(nameof(DisplacementY), false, p => (float)drawMethodParams[4].DefaultValue, (p, v) => { });
213-
public float Magnification { get => (float)GetValue(MagnificationProperty); set => SetValue(MagnificationProperty, value); }
214-
public static readonly XProperty MagnificationProperty = CreateProperty<BaseView<TPainter, TContent>, float>(nameof(Magnification), false, p => p.Magnification, (p, v) => p.Magnification = v);
283+
public double DisplacementX { get => (float)GetValue(DisplacementXProperty); set => SetValue(DisplacementXProperty, value); }
284+
public static readonly XProperty DisplacementXProperty = CreateProperty<BaseView<TPainter, TContent>, double>(nameof(DisplacementX), false, p => (double)drawMethodParams[3].DefaultValue, (p, v) => { });
285+
public double DisplacementY { get => (float)GetValue(DisplacementYProperty); set => SetValue(DisplacementYProperty, value); }
286+
public static readonly XProperty DisplacementYProperty = CreateProperty<BaseView<TPainter, TContent>, double>(nameof(DisplacementY), false, p => (double)drawMethodParams[4].DefaultValue, (p, v) => { });
287+
public double Magnification { get => (float)GetValue(MagnificationProperty); set => SetValue(MagnificationProperty, value); }
288+
public static readonly XProperty MagnificationProperty = CreateProperty<BaseView<TPainter, TContent>, double>(nameof(Magnification), false, p => p.Magnification, (p, v) => p.Magnification = (float)v);
215289
public PaintStyle PaintStyle { get => (PaintStyle)GetValue(PaintStyleProperty); set => SetValue(PaintStyleProperty, value); }
216290
public static readonly XProperty PaintStyleProperty = CreateProperty<BaseView<TPainter, TContent>, PaintStyle>(nameof(PaintStyle), false, p => p.PaintStyle, (p, v) => p.PaintStyle = v);
217291
public LineStyle LineStyle { get => (LineStyle)GetValue(LineStyleProperty); set => SetValue(LineStyleProperty, value); }

0 commit comments

Comments
 (0)