Working with Embedded Wizard: Using dynamically configured fonts
Usually the font data necessary in the GUI application to render text is represented by corresponding font resource members. By using those resource members, you can incorporate in your project any arbitrary number of fonts (as long as those are installed properly on your Windows system or available as *.TTF or *.OTF TrueType font files). During code generation or prototyping the fonts are automatically converted in format optimized for your particular target system. This includes the adequate glyph rasterization, metric calculation and compression. This approach is as such optimal for all static fonts, which are known and available at the compilation time.
At the runtime of the application, the content of existing font resources can't be exchanged nor new resources can be added. This prevents the font resources from being suitable to provide font data determined dynamically at the runtime e.g. to raster text with flexible font size or with at the runtime specified font name. Similarly, using TrueType *.TTF or *.OTF font files loaded from an SD memory card or received from a network adapter is not possible with font resources.
In order to be able to deal with such demanding application cases, the Mosaic framework provides the class Resources::ExternFont. Unlike font resources, objects of this class are optimized to represent and manage fonts being obtained dynamically at the runtime of the GUI application - thus unknown at the compilation time. This functionality is achieved by processing the font data at the runtime by using a TrueType font engine.
Since Resources::ExternFont descends from the class Resources::Font, you can use the Extern Font objects similarly as you do with ordinary font resources. For example, you can assign an Extern Font object to a text or attributed text view in order to render text with the font. Should the content of an Extern Font object change (e.g. after the font name or font size have been modified), all affected views are automatically updated.
Please note, the class Resources::ExternFont expects the Platform Package being optimized to use a TrueType font engine in your target system. This is usually the case if you have explicitly ordered such Platform Package version. If the selected Platform Package does not include the TrueType font engine support, dedicated error messages are displayed when trying to use Resources::ExternFont.
Similarly to font resources, you can manage as many Extern Font objects as necessary. For example, in an application intended to raster a complex text document loaded at the runtime from an SD memory card, you could maintain for each differently formatted text section an individual Extern Font object. Extern Font objects are economical with the memory usage. The TrueType font engine, however, needed to process the TrueType fonts at the runtime may very well occupy a lot of memory and affect the performance negatively. Finally it is a trade-off between the optimized font resources and the flexible Extern Font objects.
The following sections are intended to provide you an introduction and useful tips of how to work with the Extern Font object. For the complete reference please see the documentation of the Resources::ExternFont class.
Add new Extern Font object
Depending on your application case, you have the option to add the Extern Font as an embedded object directly to a GUI component or to add it as an autoobject to a unit. The first case is suitable if you want the Extern Font being used locally within the GUI component only. The second case, in turn, is appropriate if you intend to share the Extern Font among multiple GUI components like a kind of common font resource.
To add a new Extern Font object do following:
★Depending on your preferred option switch to the Composer page for the respective GUI component class or the unit where you want to add the Extern Font object.
★Then ensure that the Templates window is visible.
★In Templates window switch to the folder Resources.
★In the folder locate the template Extern Font.
★Drag & Drop the template into the Composer window:
★Eventually name the new added Extern Font object.
Inspect the Extern Font object
As long as the Extern Font object is selected you can inspect and modify its properties conveniently in the Inspector window as demonstrated with the property FontName in the screenshot below:
This is in so far worth mentioning as the following sections describe features of the Extern Font object by explicitly referring to its corresponding properties. If you are not familiar with the concept of a property and the usage of Inspector window, please read first the preceding chapter Compositing component appearance.
Configure the Extern Font object
The font data, an Extern Font object does represent at the runtime is determined by its diverse properties. In this manner you specify the name of the font, its size and other attributes. The following table provides an overview for the available properties:
The name of the desired TrueType font to use (e.g. "Roboto"). The value is a string thus note the both quote signs.
The height of the font in pixel. Please note, the font size calculation corresponds to how regular font resources calculate their size with the HeightMode selected to Popular.
The desired style of the font.
Aspect-ratio for the font. In this way you can stretch the glyphs horizontally or vertically. See also the similar attribute in case of font resources: AspectRatio
Determines whether font kerning information is used. With the kerning being enabled, distances between glyphs are automatically adjusted. See also the similar attribute in case of font resources: Kerning.
Overrides the distance between two consecutive text rows resulting from the font metrics. See also the similar attribute in case of font resources: RowDistance.
For example, if you want an Extern Font object to represent a 60 pixel large Roboto font, configure the property FontName with a string "Roboto" and the property Height with the number 60. If necessary, the properties can change at the runtime of the application. For example, you can reduce the value in the property Height in order to get smaller glyphs.
Please ensure, that the TrueType file containing the specified FontName is available on your target system and it is properly registered by the TrueType font engine so it can find, load and process this file.
Modifying the above explained properties triggers the Extern Font object to reload the font data and notify all text views associated actually with the Extern Font object. Thereupon the views update their appearance and render text with the new font automatically.
Use the Extern Font object
Every Extern Font object is represented at the runtime by an instance of the Mosaic class Resources::ExternFont. As such the Extern Font objects can be involved within Chora expressions wherever an operand of the mentioned Mosaic class (or a base class) is expected. It can, for example, be assigned to a Font property of a text view. Moreover, the properties exposed by the Resources::ExternFont class can be evaluated. Let's assume, the Extern Font object exists as an embedded object within the actual component, then you could for example do:
// Assign the Extern Font object 'MessageFont' to a text view SomeTextView.Font = MessageFont; // Evaluate the properties of the Extern Font object var int32 ascent = MessageFont.Ascent; var int32 descent = MessageFont.Descent; var int32 leading = MessageFont.Leading; // Calculate the area for a text fragment if it would be rendered // by the font var rect extent = MessageFont.GetTextExtent ( "Hello world!", 0, -1 ); var rect advance = MessageFont.GetTextAdvance( "Hello world!", 0, -1 ); // Query if the font does contain a particular glyph? if ( MessageFont.IsGlyphAvailable( '\x1234' )) ...
If you have put the Extern Font object directly within a unit creating thus an autoobject, you access it exactly as you do with other global entities. In particular, the Extern Font object is identified by its full name, composed of the unit name, the object is defined inside, and the name of the object itself, both separated by :: (double colon) signs. For example:
// Assign the Extern Font object 'Example::MessageFont' to a text view SomeTextView.Font = Example::MessageFont; // Evaluate the properties of the Extern Font object var int32 ascent = Example::MessageFont.Ascent; var int32 descent = Example::MessageFont.Descent; var int32 leading = Example::MessageFont.Leading; [...]
Please note, the above used properties Ascent, Descent and Leading are read-only. Trying to modify one of them will result in a runtime error. The properties exist only to query the metrics of the font represented by the Extern Font object. This information, in turn, is determined just in the moment when the configuration of an Extern Font object changes.
Use Extern Font object to adjust text within a given area
Extern Font object is very well suitable to display text with flexible font height according to space available for the text. For such purpose, the height for the font has to be calculated at the runtime and assigned to the Extern Font property Height. The associated text view is thereupon updated automatically.
You can perform the necessary calculation steps by using diverse methods available in the Resources::ExternFont class. For example, the method GetTextAdvance() calculates the width of the area needed to display a text portion. By changing the properties of the Extern Font object and repeatedly calculating the area you can find out the right Extern Font parameters so the text e.g. fills a predetermined space optimally.
Similar can be achieved, by using the convenience method AdjustHeight(). This method expects in its parameter a string you intend to display and the width of the available area. Based on this information the method updates the Height property of the Extern Font object so that the resulting text does optimally fill the area. For example, let's assume you have a text view connected to an Extern Font object and you want the view to display a single (unique) text row filling as good as possible 250 pixel large area, then following operation could achieve this effect:
// Get the content of the first (unique) text row ... var string textRow = TextView.GetRowString( 0 ); // Instruct the Extern Font object to calculate its optimal height // so the string 'textRow' does fill 250 pixel. The height should not // exceed the range 16 .. 60 pixel. ExternFont.AdjustHeight( textRow, 250, 16, 60 );
If you have an application case displaying multiple text rows you can ask the text view for the widest row and use it to calculate the optimal Extern Font height. The text view provides for this purpose the method GetWidestRow():
// Get the number and the content of the widest row var int32 rowNo = TextView.GetWidestRow(); var string textRow = TextView.GetRowString( rowNo ); // Instruct the Extern Font object to calculate its optimal height // so that 'textRow' fills 250 pixel. The height should lie between // 16 .. 60 pixel. ExternFont.AdjustHeight( textRow, 250, 16, 60 );
Lifetime of an Extern Font object
The Extern Font object exists, similarly to other embedded objects and autoobjects as long as it is in use. During this time the font data represented by the object persists and occupies the memory within the TrueType engine. If the object is not referenced anymore by any GUI component, the Garbage Collector deletes the object automatically. With this operation also the memory used by the TrueType engine is released.