Tuesday, 13 March 2012

FireMonkey Fonts and Native Look & Feel

Since XE2 Update 4 was released, there have been a few online complaints (12) about FireMonkey's fonts on Windows.  I had most of a blog post written explaining why it actually was fine, when I read that there will be a hot fix targeting this and other issues.  I guess it is an issue after all, then!

But when it comes to FireMonkey's text, there are more important things than antialiasing or fitting to the pixel grid.

From the perspective of text UI controls & fonts, this article will examine:
  • FireMonkey as a cross-platform UI framework
  • How FireMonkey actually looks on different OSes
  • What you can do to improve the native look and feel of FireMonkey
  • Some ideas for FireMonkey enhancements (because you shouldn't have to do anything.)

FireMonkey is a cross-platform UI framework

FireMonkey allows you to design your forms once, and run your application using the same windows on both Windows and OSX.  The immediate problem is that these platforms do not look the same, and it goes beyond styles.  (Styles are not skins: they are how FireMonkey controls render.  It's almost a side-effect that you can have a variety of different styles to skin the application.)

Consider this simple app which I originally wrote to demonstrate font rendering.  There are three versions, built with the VCL, with FireMonkey, and with Cocoa.  It has a couple of labels of two different sizes (a heading-like size and a normal one), an edit box, a memo and a button.

VCL on Windows 7
FireMonkey on Windows 7
The differences are not vast on Windows.  Two things are immediately obvious: the text is lighter due to its antialiasing, and the controls are not quite identical: the scrollbar doesn't look the same and the button has a slightly different shadow.  These things, and similar issues with other controls, can be fixed by improving the Windows style.

Here is the same app in FireMonkey and Cocoa incarnations on OSX:
FireMonkey on OSX Lion
Cocoa on OSX Lion
The differences on OSX are larger, and this illustrates a specific example of a more general issue.  On OSX, FireMonkey controls do not look or behave very like native controls.

Some obvious differences just in the screenshots are:
  • The fonts are different.  FireMonkey is not using system-like fonts, and the text is visibly different to native apps.  This is most visible in the memo control, where the FireMonkey text is tiny compared to the default Cocoa font, and on the button, again where the text size is smaller.
  • The presence of scrollbars.  Lion does not show scrollbars; they only appear when you begin scrolling.
  • More minor things: labels don't truncate with ellipses (I don't think FireMonkey can do this yet, I couldn't find a property for it) and the Cocoa 'memo' is focused by default when the window opens.
  • One issue not in the screenshot is that the memo changes it background colour to grey when it is focused.
These are too large to focus on today, but in the spirit of discussing fonts, and to pick the low-hanging fruit as far as consistency goes, let's focus on what can be done to make this app look more native on OSX.

Manually making the app look more native: fonts only

This Cocoa app uses three fonts:
  • System 13 for the memo, edit, and button
  • Label 10 for the small label
  • Title 13 for the larger label
The FireMonkey one, by default, uses:
  • Segoe UI 11 for all controls, unless changed
at least when it is created on Windows 7.  I have no idea what it uses on XP.  OSX, of course, doesn't use Segoe UI.

At first glance this is simple to fix: let's change the controls' Font properties to match the Cocoa app.  You get this:
FireMonkey on OSX with tweaked fonts
First off, woohoo!  It looks a lot more native already.  Second, the memo looks... broken.  In spite of entering the lorem ipsum text as one paragraph, the lines seem to be automatically split where they are wrapped on Windows, and now when using a different font the line breaks are in the wrong place.  (This is terrible.  The only line breaks present in the text should be where they were deliberately entered.)  Still, it's a good step forward.

But what happens when you run this OS X-specific version on Windows?
FireMonkey on Windows with OSX fonts
Now, that doesn't look bad at all... but it doesn't look like a standard Windows app any more now either.  (Note that the memo, even if it has inserted line breaks, has at least got them in the right spot.)

What can you do, right now?

So, if you're a developer using FireMonkey right now, and don't want to wait for any changes or tweaks that might arrive in the future (such as those I'm about to suggest...), what do you do?

If you are writing only for Windows: FireMonkey looks and behaves pretty close to a native app.  You don't have much to worry about.

If you are writing only for OSX: I suggest you change your fonts manually to match the default system ones.  These are easy to find by dropping a control on a window in XCode, and looking at its properties.

If you are writing for both Windows and OSX: it is more complicated.  Remember, FireMonkey is meant to be a cross-platform UI framework, and you're supposed to be able to use your forms 'as is' on both OSes.  Some possible solutions are:
  • Design two different forms, one for each OS.  For a cross-platform framework this shouldn't be necessary; you might as well write your front-end in Cocoa.
  • At runtime, depending on the OS, iterate through the controls on your form and adjust the fonts.
  • Do nothing.  You can at least compile for both OSes; getting a perfect look isn't necessary.

Moving forward

In spite of FireMonkey's imperfections there are heaps of great things about it (it's always easier to spot problems than the absence of problems), and I'd like to see it become commonly used, robust, and as close to native as possible.  Here are some suggestions for improving it.

First, fonts (and control sizes etc) are important.  Apple does something very interesting in XCode: while you can select a specific font if you want, by default you are given a number of preset options:
FireMonkey should do something similar.  In a cross-platform framework, there is little point in the default way of changing a font's properties being as detailed as 'Segoe UI, 11, italic and underlined.'  Instead, while these should be accessible just as they are in XCode, a TFont object should have a number of basic types available.  Only if you manually change the font properties would it revert to 'Custom'.  These types represent basic UI functionality, and map to different fonts on different OSes.

A mockup:
This is what FireMonkey's TFont should have.
(The items shown are examples, not gospel.)
There is some precedent for this, even in the VCL: TBitBtn controls have a Kind property; TScreen lists some standard OS fonts; even Align has a custom option.  NSFont has a number of methods for getting various default fonts, such as the standard interface font and the document or user-editable text font

This would also be useful for the VCL.  In my professional outside-of-blogging life, the software I work on suffers from the default font being Tahoma 8: fine for XP, but not right for Window Vista or 7.  At least it's consistent throughout the app, but I wish I could just say 'This is a normal control, render how it should look on whatever version of Windows you run on, please.'

The principle here is to use a standard by default, and change custom details when necessary.  Here it's for fonts; I tend to think the same applies in many areas, far beyond the scope of UI controls.

Wrapping up

The ideas here can be generalised and extrapolated to much more than fonts.  I may look at other UI consistency issues in another article.

Being able to compile a Delphi app to OSX is pretty amazing - as anyone who spent most of the 2000s hoping for it to happen knows :)  This sort of thing really is polish and detailing.  Polish and detailing matter - I wouldn't hire anyone who thought they didn't - but in the grand scheme of a developer's life, it doesn't matter that much.  It tells you a lot about FireMonkey that the biggest internet arguments about it in the past few weeks have been about, of all things, text antialiasing, even though there are bigger design issues.  Nevertheless, it would be nice to have cross-platform apps feeling native on whichever OS you deploy them, and I hope some design changes are made that make this easier by default.

Don't forget: this should be your take-away image:



15 comments:

  1. Fantastic article, and I agree with everything you stated, except that I think that the Firemonkey STYLES should handle the font-stylesheet information instead of a simple enum in the Font property. Rather I'd like to see the font Family set to some "Automatic" string that means "Use the firemonkey stylsheet" so that the Fmx form doesn't hard code any "Segoe UI" like Windows font names.

    Warren P

    ReplyDelete
  2. So in a nutshell, FireMonkey is a cross-platform framework that doesn't work very well even when it works properly, and right now it doesn't even work properly so here are a list of things you need to do beyond developing your actual application to make the framework behave even remotely as it should on ANY of the platforms it can compile for.

    Yes ?

    I think it would be more accurate to say that FireMonkey is a cross platform 2D/3D graphics library with a half-baked attempt at providing a GUI control library on top.

    ReplyDelete
    Replies
    1. Jolyon, yes described perfectly, the GUI controls are not half baked, they simply fit to the original purpose of the XXScene library:) I expected this ... take a library that has many advantages, avoid 'any' communication that Delphi does now support 2D/3D, give data-base developers something beyond a grid - and you are there.

      Warrens suggestion is the way to go I think, but applied at design-time and showing how the application looks like on the target OS.

      Delete
  3. Warren, thanks! And that's not a bad idea at all... sounds a good way of doing it!

    Jolyon, that is a bit harsher than I might phrase it :) It seems to work fairly well to me, although I think your description of a cross-platform graphics library with a GUI library on top is accurate. All that means is that you need to improve the GUI library :) Getting fonts, sizing, and other control behaviour to perfectly emulate a target system is hard - look how long it's taken Mozilla to get Firefox to something that feels OS X-ish, and even that still isn't right. Qt doesn't get it perfect either, although it's pretty good. I'm just pointing out there's room for improvement in FMX, and a few things that you can do to make it better.

    Embarcadero have an advantage over other frameworks in that it's brand new and they can even make breaking changes if they want, and I think they should take advantage of that to get design for cross-platform issues like this baked in as early as possible. Fonts are not the only thing they need to think about. I can write about other issues if it would interest you?

    ReplyDelete
  4. (With apologies if this comment has come through twice - I've had trouble getting it through Blogger...) For me, the situation is the exact opposite to what you describe: FMX applications look terrible on Windows and reasonable on OS X (admittedly not quite so reasonable since I upgraded to Lion, but still OK). One reason for the former is that I run with what used to be called 'large fonts' (i.e., a screen DPI other than 96), and FMX does not take account of that. FMX's built-in scaling isn't the solution it should be due to a combination of bugs and the fact a native control's borders shouldn't thicken when the screen DPI is upped.

    FMX also doesn't use the correct font size on Vista+ - it should be 9 in VCL terms, but 8 (near enough) is used instead ('near enough', because the FMX TFont.Size assumes 96 points per logical inch not the normal 72). This makes the font look utterly tiny on my computer. Furthermore, for me, FMX's text rendering, even before update 4, is nothing like as nice to read as the text rendering of classic GDI, as used in a VCL application.

    WRT OS X, you actually make a factual error - FMX doesn't default to the MS font, it defaults to Helvetica (check the source). Also, Lion has numerous 'standard' font sizes - compare the default Finder left hand pane to the TextEdit toolbar - which I think would be difficult for FMX to take account of, though the default FMX size is a bit too small as you say.

    I do agree with your constructive suggestion, which is a good one...

    ReplyDelete
    Replies
    1. Interesting! I hadn't noticed the difference in default font size.

      Re Helvetica: I know Segoe UI doesn't exist in OSX - do you mean that on OSX, when a font is set to a font name that doesn't exist, it reverts to Helvetica? FMX does definitely default to the MS font on my system, when I create a new form.

      On related thing I'm not sure about is OSX's handling of pseudofonts. "Label 10", for example, is not a real font, but that's how it's shown in Xcode. Using the same definition in an FMX font works, but I'm not sure if it's because the OS maps that to the right font, or if FMX happens to map that to Helvetica which happens to look right.

      Delete
    2. 'FMX does definitely default to the MS font on my system, when I create a new form'

      Er, that's because the form designer is running on Windows... The font name is determined globally at runtime - it's not stored in the .fmx or a style file (or if one is, it is ignored). You will need to actually build for OS X and run the resulting program on a Mac to observe this behaviour.

      Delete
  5. "In my professional outside-of-blogging life, the software I work on suffers from the default font being Tahoma 8: fine for XP, but not right for Window Vista or 7. At least it's consistent throughout the app, but I wish I could just say 'This is a normal control, render how it should look on whatever version of Windows you run on, please.'"

    Turns out there is an easy way of doing this. When I expressed the same complaint, I was made aware that forms also have a ParentFont property. Simply set the ParentFont property of all your forms to True, then insert the following line in WinMain() and you're Tahoma-free:

    Application->DefaultFont = Screen->MessageFont;

    Some components (such as the Ribbon) are a little more persistent and require extra work. I could get them to render in the system message font by doing this in WinMain():

    Graphics::DefFontData = GetSystemFont (sfMessage);

    where GetSystemFont() is a function of my own; it is almost trivial, just a lot of typing work. I can post it if desired.

    ReplyDelete
    Replies
    1. Thanks mb! I tried this, and it only partially worked. Some controls don't seem to have ParentFont set themselves, and some controls have custom fonts as well (e.g., bold version of the default.) In the past I've written code that iterated through all controls and adjusted the font, but I think that code needs to be smarter to guess if the font is intended to be 'system font + bold', for example, or if it truly is meant to be the font it is set to.

      I would like to be able to avoid all these problems with FireMonkey!

      Delete
  6. > there are more important things than antialiasing or fitting to the pixel grid.

    Actually you can't do cross-platform font rights if you don't care about *how* they are anti-aliased and if they are pixel-aligned.

    The manual adjustment of fonts in styles is a workaround, not a solution. It's okay for games or UI with large fonts, but outside those, it's only feasible if you have enough time to tweak everything on every target platform.

    >These things, and similar issues with other controls, can be fixed by improving the Windows style.

    That's more a workaround than a solution too, the user can tweak the Windows style colors, sizes, and Windows/MacOS native style can and does evolve.
    The FMX style on the other hand is static for a given executable.

    A solution would have an FMX application build its style textures by having them rendered natively by the OS (at first use, startup, in a cache, whatever), rather than having them baked into the executable.

    > Two things are immediately obvious: the text is lighter due to its antialiasing,

    Both texts *are* anti-aliased, they just use different anti-aliasing approaches wrt pixel-alignment.

    ReplyDelete
    Replies
    1. "Actually you can't do cross-platform font rights if you don't care about *how* they are anti-aliased and if they are pixel-aligned."

      Yes, you're quite right. I didn't meant to belittle the antialiasing as not being an issue at all, rather that there are bigger differences on OSX, and that I think the font system needs to be changed in general.

      FMX (as of Update 4)'s antialiasing is actually something I'm ok with - it doesn't look very different on Windows, and I think a non-pixel-grid-aligned font is good for something zoomable and scaleable like FireMonkey controls. I've written a zoomable UI on Wndows using GDI+, and I actually chose the same font antialiasing option as is used in Update 4 for this reason. Otherwise you will end up with "popping" if you animate a change. (I think - I haven't tried it in FMX before Update 4 was released. I'll be interested to see what the hot fix looks like.)

      "A solution would have an FMX application build its style textures by having them rendered natively by the OS"

      A hundred times yes. I actually wondered this when I first saw XE2 - have a look at my review. I haven't had time to dig into this though and figure out if it's possible / easy.

      Delete
  7. "If you are writing only for Windows" - you should ask yourself why you are using it in the first place. Your suggestion about font management suffer from "OS perspective" as well. Different OS may have different font use conventions for controls, it could be difficult to "categorize" them in a true general way. Moreover changing sizes at runtime may create havoc in form design, as even relatively little changes in the native OS UI will do.
    Every xplat approach forces compromises. The only real way to have a native-looking GUI is to write a native GUI. Otherwise you have to live with an approximation.

    ReplyDelete
  8. LDS - although, the manual tweaking at runtime required to make a FMX application look better is similar to the manual tweaking needed for a VCL application to work well with different screen DPI settings, or use the appropriate font depending on Windows version (in practice, simply just changing one setting and allowing it to percolate down is never enough by itself). For me, the FMX limitations here come as much from the similarities with the VCL (pixel-based positioning) as the differences (styling not determined by the OS).

    ReplyDelete
  9. I need your help I’m trying to develop a Mobile firemonky application in Arabic.
    The problem I’m facing that The Arabic fonts are shown on design time but at run time on the iphone simulator they are shown as empty spaces. I tried to use ShowMessage with Arabic fonts and the text is displayed correctly!
    Please help I cannot find the solution anywhere
    Thank you very much
    Ray

    ReplyDelete
    Replies
    1. Hi Ray,

      I'm afraid I know nothing about fonts on iOS, at all. I'd recommend you ask on Stack Overflow - http://stackoverflow.com. Tag your question 'delphi', 'ios' and 'FireMonkey' and you should get a reply. I would suggest including screenshots and sample code with your question.

      Delete