Skip to content

Commit

Permalink
(#281) WinForms: initial support
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Feb 12, 2023
1 parent a504540 commit bf8d1f7
Show file tree
Hide file tree
Showing 17 changed files with 477 additions and 1 deletion.
39 changes: 39 additions & 0 deletions WinFormsApp.Example/Form1.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions WinFormsApp.Example/Form1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using WinFormsMath.Controls;

namespace WinFormsApp.Example;

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var control = new FormulaControl();
Controls.Add(control);

control.Top = 5;
control.Left = 5;
control.Width = Width - 5;
control.Height = Height - 5;
control.FormulaText = @"\sqrt 2";
}
}
16 changes: 16 additions & 0 deletions WinFormsApp.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace WinFormsApp.Example;

static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
15 changes: 15 additions & 0 deletions WinFormsApp.Example/WinFormsApp.Example.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\src\WinFormsMath\WinFormsMath.csproj" />
</ItemGroup>

</Project>
12 changes: 12 additions & 0 deletions XamlMath.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "api", "api", "{3F2FED19-93A
api\XamlMath.Shared.net6.0.verified.cs = api\XamlMath.Shared.net6.0.verified.cs
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsMath", "src\WinFormsMath\WinFormsMath.csproj", "{4236794D-83A5-46B8-8F1C-8777D525DCD9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinFormsApp.Example", "WinFormsApp.Example\WinFormsApp.Example.csproj", "{7AD0440C-A9E8-4153-883C-B595E8B7346F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -124,6 +128,14 @@ Global
{54F77EF7-F918-46F8-A615-56BC0BFE8AAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54F77EF7-F918-46F8-A615-56BC0BFE8AAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54F77EF7-F918-46F8-A615-56BC0BFE8AAB}.Release|Any CPU.Build.0 = Release|Any CPU
{4236794D-83A5-46B8-8F1C-8777D525DCD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4236794D-83A5-46B8-8F1C-8777D525DCD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4236794D-83A5-46B8-8F1C-8777D525DCD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4236794D-83A5-46B8-8F1C-8777D525DCD9}.Release|Any CPU.Build.0 = Release|Any CPU
{7AD0440C-A9E8-4153-883C-B595E8B7346F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AD0440C-A9E8-4153-883C-B595E8B7346F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AD0440C-A9E8-4153-883C-B595E8B7346F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AD0440C-A9E8-4153-883C-B595E8B7346F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
22 changes: 22 additions & 0 deletions src/WinFormsMath/Controls/FormulaControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using WinFormsMath.Parsers;
using WinFormsMath.Rendering;
using XamlMath;
using XamlMath.Rendering;

namespace WinFormsMath.Controls;

public class FormulaControl : Control
{
public string FormulaText { get; set; } // TODO: Naming?

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);

var texFormula = WinFormsFormulaParser.Instance.Parse(FormulaText);
var environment = WinFormsTeXEnvironment.Create();

var renderer = new WinFormsRenderer(e.Graphics);
texFormula.RenderTo(renderer, environment, 0.0, 0.0);
}
}
5 changes: 5 additions & 0 deletions src/WinFormsMath/Fonts/WinFormsGlyphTypeface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using XamlMath.Fonts;

namespace WinFormsMath.Fonts;

internal record WinFormsGlyphTypeface(Font Font) : IFontTypeface;
30 changes: 30 additions & 0 deletions src/WinFormsMath/Fonts/WinFormsMathFontProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Drawing.Text;
using XamlMath.Fonts;
using XamlMath.Utils;

namespace WinFormsMath.Fonts;

/// <summary>A font provider implementation specifically for the WinFormsMath assembly.</summary>
internal class WinFormsMathFontProvider : IFontProvider
{
private WinFormsMathFontProvider() {}

public static WinFormsMathFontProvider Instance = new();

private const string FontsDirectory = "WinFormsMath.Fonts";

public unsafe IFontTypeface ReadFontFile(string fontFileName)
{
using var resource = typeof(WinFormsMathFontProvider).Assembly.ReadResource($"{FontsDirectory}.{fontFileName}");
using var byteStream = new MemoryStream();
resource.CopyTo(byteStream);
var bytes = byteStream.ToArray();

var c = new PrivateFontCollection(); // TODO: Dispose?
fixed (byte* p = bytes)
c.AddMemoryFont((IntPtr)p, bytes.Length);

var ff = c.Families.Single();
return new WinFormsGlyphTypeface(new Font(ff, 1.0f));
}
}
114 changes: 114 additions & 0 deletions src/WinFormsMath/Fonts/WinFormsSystemFont.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using XamlMath;
using XamlMath.Exceptions;
using XamlMath.Fonts;
using XamlMath.Utils;

namespace WinFormsMath.Fonts;

internal class WinFormsSystemFont : ITeXFont
{
private readonly Lazy<Font> _font;

public WinFormsSystemFont(double size, FontFamily fontFamily)
{
Size = size;
_font = new Lazy<Font>(() => new Font(fontFamily, (float)Size));
}

public bool SupportsMetrics => false;

public double Size { get; }

public ExtensionChar GetExtension(CharInfo charInfo, TexStyle style) =>
throw MethodNotSupported(nameof(GetExtension));

public CharFont? GetLigature(CharFont leftChar, CharFont rightChar) => null;

public CharInfo GetNextLargerCharInfo(CharInfo charInfo, TexStyle style) =>
throw MethodNotSupported(nameof(GetNextLargerCharInfo));

public Result<CharInfo> GetDefaultCharInfo(char character, TexStyle style) =>
Result.Error<CharInfo>(MethodNotSupported(nameof(this.GetDefaultCharInfo)));

public Result<CharInfo> GetCharInfo(char character, string textStyle, TexStyle style)
{
var font = _font.Value;
var metrics = GetFontMetrics(character, font);
return Result.Ok(
new CharInfo(character, new WinFormsGlyphTypeface(font), 1.0, TexFontUtilities.NoFontId, metrics));
}

public Result<CharInfo> GetCharInfo(CharFont charFont, TexStyle style) =>
Result.Error<CharInfo>(MethodNotSupported(nameof(this.GetCharInfo)));

public Result<CharInfo> GetCharInfo(string name, TexStyle style) =>
Result.Error<CharInfo>(MethodNotSupported(nameof(GetCharInfo)));

public double GetKern(CharFont leftChar, CharFont rightChar, TexStyle style) => 0.0;

public double GetQuad(int fontId, TexStyle style) => throw MethodNotSupported(nameof(GetQuad));

public double GetSkew(CharFont charFont, TexStyle style) => throw MethodNotSupported(nameof(GetSkew));

public bool HasSpace(int fontId) => throw MethodNotSupported(nameof(HasSpace));

public bool HasNextLarger(CharInfo charInfo) => throw MethodNotSupported(nameof(HasNextLarger));

public bool IsExtensionChar(CharInfo charInfo) => throw MethodNotSupported(nameof(IsExtensionChar));

public int GetMuFontId() => throw MethodNotSupported(nameof(GetMuFontId));

public double GetXHeight(TexStyle style, int fontId) => throw MethodNotSupported(nameof(GetXHeight));

public double GetSpace(TexStyle style) => throw MethodNotSupported(nameof(GetSpace));

public double GetAxisHeight(TexStyle style) => throw MethodNotSupported(nameof(GetAxisHeight));

public double GetBigOpSpacing1(TexStyle style) => throw MethodNotSupported(nameof(GetBigOpSpacing1));

public double GetBigOpSpacing2(TexStyle style) => throw MethodNotSupported(nameof(GetBigOpSpacing2));

public double GetBigOpSpacing3(TexStyle style) => throw MethodNotSupported(nameof(GetBigOpSpacing3));

public double GetBigOpSpacing4(TexStyle style) => throw MethodNotSupported(nameof(GetBigOpSpacing4));

public double GetBigOpSpacing5(TexStyle style) => throw MethodNotSupported(nameof(GetBigOpSpacing5));

public double GetSub1(TexStyle style) => throw MethodNotSupported(nameof(GetSub1));

public double GetSub2(TexStyle style) => throw MethodNotSupported(nameof(GetSub2));

public double GetSubDrop(TexStyle style) => throw MethodNotSupported(nameof(GetSubDrop));

public double GetSup1(TexStyle style) => throw MethodNotSupported(nameof(GetSup1));

public double GetSup2(TexStyle style) => throw MethodNotSupported(nameof(GetSup2));

public double GetSup3(TexStyle style) => throw MethodNotSupported(nameof(GetSup3));

public double GetSupDrop(TexStyle style) => throw MethodNotSupported(nameof(GetSupDrop));

public double GetNum1(TexStyle style) => throw MethodNotSupported(nameof(GetNum1));

public double GetNum2(TexStyle style) => throw MethodNotSupported(nameof(GetNum2));

public double GetNum3(TexStyle style) => throw MethodNotSupported(nameof(GetNum3));

public double GetDenom1(TexStyle style) => throw MethodNotSupported(nameof(GetDenom1));

public double GetDenom2(TexStyle style) => throw MethodNotSupported(nameof(GetDenom2));

public double GetDefaultLineThickness(TexStyle style) => throw MethodNotSupported(nameof(GetDefaultLineThickness));

private static TexNotSupportedException MethodNotSupported(string callerMethod)
{
return new TexNotSupportedException(
$"Call of method {callerMethod} on {nameof(WinFormsSystemFont)} is not supported");
}

private static TeXFontMetrics GetFontMetrics(char c, Font font)
{
var size = TextRenderer.MeasureText(c.ToString(), font);
return new TeXFontMetrics(size.Width, size.Height, 0.0, size.Width, 1.0);
}
}
22 changes: 22 additions & 0 deletions src/WinFormsMath/Parsers/WinFormsFormulaParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using WinFormsMath.Rendering;
using XamlMath;

namespace WinFormsMath.Parsers;

public static class WinFormsFormulaParser
{
public static TexFormulaParser Instance { get; }
static WinFormsFormulaParser()
{
var predefinedFormulae = LoadPredefinedFormulae();
Instance = new TexFormulaParser(WinFormsBrushFactory.Instance, predefinedFormulae);
}

private static IReadOnlyDictionary<string, Func<SourceSpan, TexFormula?>> LoadPredefinedFormulae()
{
var predefinedFormulaParser = new TexPredefinedFormulaParser(WinFormsBrushFactory.Instance);
var predefinedFormulae = new Dictionary<string, Func<SourceSpan, TexFormula?>>();
predefinedFormulaParser.Parse(predefinedFormulae);
return predefinedFormulae;
}
}
32 changes: 32 additions & 0 deletions src/WinFormsMath/Rendering/WinFormsBrush.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Diagnostics.CodeAnalysis;
using XamlMath.Colors;
using XamlMath.Rendering;

namespace WinFormsMath.Rendering;

public record WinFormsBrush : GenericBrush<Brush>
{
private WinFormsBrush(Brush brush) : base(brush)
{
}

public static WinFormsBrush FromBrush(Brush value) => new(value);
}

public class WinFormsBrushFactory : IBrushFactory
{
public static readonly WinFormsBrushFactory Instance = new();

private WinFormsBrushFactory() {}

public IBrush FromColor(RgbaColor color) =>
new SolidBrush(
Color.FromArgb(color.A, color.R, color.G, color.B)).ToPlatform();
}

public static class WinFormsBrushExtensions
{
public static Brush? ToWinForms(this IBrush? brush) => ((WinFormsBrush?)brush)?.Value;
[return: NotNullIfNotNull(nameof(brush))]
public static IBrush? ToPlatform(this Brush? brush) => brush == null ? null : WinFormsBrush.FromBrush(brush);
}
7 changes: 7 additions & 0 deletions src/WinFormsMath/Rendering/WinFormsRectangleExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace WinFormsMath.Rendering;

internal static class WinFormsRectangleExtensions
{
public static RectangleF ToWinForms(this XamlMath.Rendering.Rectangle rectangle) =>
new((float)rectangle.X, (float)rectangle.Y, (float)rectangle.Width, (float)rectangle.Height);
}
Loading

0 comments on commit bf8d1f7

Please sign in to comment.