Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Windows Forms apps #281

Open
pavledev opened this issue Oct 7, 2020 · 13 comments · May be fixed by #378
Open

Support for Windows Forms apps #281

pavledev opened this issue Oct 7, 2020 · 13 comments · May be fixed by #378

Comments

@pavledev
Copy link

pavledev commented Oct 7, 2020

Can you please add support for Windows Forms Apps?

@Happypig375
Copy link

Happypig375 commented Oct 7, 2020

@pavledev
Copy link
Author

pavledev commented Oct 7, 2020

ElementHost host = new ElementHost();
host.Dock = DockStyle.Fill;

WpfMath.Controls.FormulaControl formulaControl = new WpfMath.Controls.FormulaControl();
host.Child = formulaControl;

this.Controls.Add(host);

@Happypig375 I get error: the type 'UIElement' is defined in an assembly that is not referenced. You must add a reference to assembly 'PresentationCore'

@FoggyFinder
Copy link

I get error: the type 'UIElement' is defined in an assembly that is not referenced. You must add a reference to assembly 'PresentationCore'

Well, cause you have to add that reference.

@pavledev
Copy link
Author

pavledev commented Oct 7, 2020

I added references to PresentationCore, PresentationFramework and WindowsBase and now it works.
@FoggyFinder Thank you.

@pavledev
Copy link
Author

pavledev commented Oct 7, 2020

@FoggyFinder
Copy link

you could try something like this:

var style = new Style
{
    TargetType = typeof(FormulaControl)
};
style.Setters.Add(new Setter(TextOptions.TextRenderingModeProperty,
                             TextRenderingMode.ClearType));
style.Setters.Add(new Setter(TextOptions.TextHintingModeProperty, 
                             TextHintingMode.Fixed));
style.Setters.Add(new Setter(TextOptions.TextFormattingModeProperty, 
                             TextFormattingMode.Display));

var formulaControl = new FormulaControl()
{
    Style = style
};

@pavledev
Copy link
Author

pavledev commented Oct 8, 2020

@FoggyFinder I tried that code but it still looks same.

@FoggyFinder
Copy link

I don't know then

@ForNeVeR
Copy link
Owner

Hello. I doubt proper support for Windows Forms is possible for WPF-Math in the nearest future.

For now, we heavily rely on WPF geometry and font rendering support.

  1. As a general (right) solution, we'd better get a Windows Forms-specific renderer (in the same way we're getting Avalonia one), but that's a lot of work.

  2. As a light workaround, you, for sure, should be able to embed WPF elements into your Windows Forms apps, as explained above.

    About the blurry fonts inside of ElementHost in a Windows Forms apps, I've no idea. I guess, we'll need someone with heavy experience in both WPF and Windows Forms to dedug the accompanying issues.

  3. There's another workaround possible: check the code sample to generate a PNG image. You may use it in runtime, and then embed the resulting PNG into a Windows Forms application. I guess it would be less problematic than messing with the ElementHost.

I am leaving the issue open in favor of (eventually, some time) doing it in the "right" way, approach # 1 described above.

@pavledev
Copy link
Author

@ForNeVeR Ok. Thank you.
Can you please add /angle symbol to wpf-math?

ForNeVeR added a commit that referenced this issue Feb 12, 2023
ForNeVeR added a commit that referenced this issue Feb 12, 2023
ForNeVeR added a commit that referenced this issue Feb 12, 2023
ForNeVeR added a commit that referenced this issue Feb 12, 2023
@ForNeVeR
Copy link
Owner

ForNeVeR commented Feb 12, 2023

Okay, I've taken a look at it, it wasn't too hard (since we now have pretty much platform-neutral rendering pipeline), and got some results. Here's the result of rendering \sqrt 2 on Windows Forms:

image

The general rendering quality is awful, but I think there are some ways to improve it (like setting some flag on Graphics or something), but there's also a font metric issue: see how the bar is misaligned over the X axis. The bar is drawn using the graphics API (FillRectangle in this case), while the radical sign and the 2 are drawn using the font API. It looks like the bar is drawn correctly, but the font characters are a bit misaligned.

I wasn't still able to figure out what exactly is happening there. If you want to experiment, see the code in the branch experiment/281.winforms:

public void RenderCharacter(CharInfo info, double x, double y, IBrush? foreground)
{
var font = ((WinFormsGlyphTypeface)info.Font).Font;
var newF = new Font(font.FontFamily, (float)info.Size * Scale, GraphicsUnit.Pixel);
var brush = foreground.ToWinForms() ?? Brushes.Black; // TODO: Make IBrush disposable?
int mm;
var hdc = _graphics.GetHdc();
try
{
mm = GetTextCharacterExtra(hdc);
}
finally
{
_graphics.ReleaseHdc(hdc);
}
var metric = _graphics.MeasureString(info.Character.ToString(), newF);
// Renderer wants upper left corner from us, while we have baseline here. Let's convert.
var ff = newF.FontFamily;
var lineSpace = ff.GetLineSpacing(font.Style);
var ascent = ff.GetCellAscent(font.Style);
var fontBaseline = newF.GetHeight(_graphics.DpiX) * ascent / lineSpace;
var baselineX = x * Scale; // TODO: It looks like we should subtract several pixels here for some reason,
// I don't understand why. Probably a font metric issue. It's possible
// that we won't be able to get the right metrics using WinForms without
// falling back to DirectX?
var baselineY = y * Scale;
var topY = baselineY - fontBaseline;
_graphics.DrawString(info.Character.ToString(), newF, brush, (float)baselineX, (float)topY);
}

In WPF and Avalonia, we use x and y to determine the text baseline origin. On what the baseline origin is, see this helpful image from Microsoft documentation:
Explanation of font metrics

WinForms API, on the contrary, expects us to pass the top left corner of the glyph drawing area.

I've used some tricks to shift the Y axis of the WinForms renderer to correctly apply the baseline (and it, indeed, looks correct), but I haven't found any tricks to do the same for the X axis: it looks like normally the baseline origin should be zero. But, as you see, the zero origin doesn't correspond to our WPF/Avalonia rendering results, and doesn't correspond to what should really happen.

I'm not sure how to proceed. Maybe just ditch the idea of using WinForms Font/DrawString directly, and go with DirectX renderer (#96) instead?

@ForNeVeR
Copy link
Owner

Applying StringFormat.Typographic (whatever that means) to DrawString fixed the problem.

@ForNeVeR ForNeVeR linked a pull request Feb 12, 2023 that will close this issue
6 tasks
@ygra
Copy link
Contributor

ygra commented Feb 17, 2023

GDI+ normally fits the characters to the pixel grid, which results in more legible characters on low-DPI screens and small font sizes. But it throws the exact font metrics off. So in this case I don't think there's even another option than to go with Typographic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants