Texts and Fonts
Fonts and texts are a very important aspect of modern graphical user interfaces. It is important to be able to display high quality anti-aliased texts in all the languages that your application supports.
TouchGFX supports creation and modification of texts and typographies through the Texts View of TouchGFX Designer. The TouchGFX Designer outputs text and typography configurations into a spreadsheet located at assets/texts/texts.xlsx
.
This spreadsheet, along with font files are feed to the font- and text-converter tools, producing generated C++ code files, that TouchGFX can render.
This article introduces the text and font converter tools and explains how to use the generated texts in an application through code and TouchGFX Designer.
Texts and Typographies
The texts, translations and typographies in a TouchGFX application are stored in the assets/texts/texts.xlsx
spreadsheet. This spreadsheet consists of two sheets. One defining the typographies used in the application and one defining the texts and all their translations. This spreadsheet is commonly referred to as the "Text Database"
The typographies can be edited in TouchGFX Designer with the Texts View, which allows for real-time editing and handling of texts and translations. It is, however, possible to edit the typographies and texts directly in the texts.xlsx spreadsheet. This is in general not recommended, at least not during development. If using an external resource for translation it can however be easier to share the spreadsheet instead of requiring it to be done in TouchGFX Designer. If editing the spreadsheet during development, the TouchGFX Designer must be closed while editing as it locks the texts.xlsx file while open.
Further reading
Note
The Text Converter
The text converter is the tool that converts the text information in the text database to an internal C++ format used by TouchGFX applications. The tool is an integrated part of the build tool-chain and will be executed automatically when building the simulator. The text converter is not executed if the text database has not been updated since the last build.
Note
generated/texts/
.The text converter converts all the texts specified in the text database into the text format used by TouchGFX. The format is wrapped in an object called TypedText
. A TypedText
in TouchGFX is a combined entity of the text contents itself and the typography of the text. The typography contains, the font and font size of the text and the bits per pixel (bpp) used in anti aliasing the glyphs of the font.
The text converter generates a file called generated/texts/include/texts/TextKeysAndLanguages.hpp
. This file contains an enum TEXTS
that references all texts in the text database.
Notice that all entries in the enum are generated from the text id stated in each row in the text database, but with a T_ prepended and converted to uppercase. These enum values are used in applications to initialize TypedTexts.
The TextKeysAndLanguages.hpp
also contains an enum LANGUAGES
that specifies all the languages that are present in the text database. The naming is the same as in the language column in the text database.
generated/texts/include/texts/TextKeysAndLanguages.hpp
/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#ifndef TEXT_KEYS_AND_LANGUAGES_HPP
#define TEXT_KEYS_AND_LANGUAGES_HPP
typedef enum {
GB,
DE,
NUMBER_OF_LANGUAGES
} LANGUAGES;
typedef enum {
T_TEMPERATURE_READOUT,
T_TEMPERATURE_HEADLINE,
NUMBER_OF_TEXT_KEYS
} TEXTS;
#endif /* TEXT_KEYS_AND_LANGUAGES_HPP */
The Font Converter
The font converter is a tool that combines the information in font files with information in the text database and generates the characters needed by the application. The output format is an internal C++ format used by TouchGFX applications. The tool is an integrated part of the build tool-chain and will be executed automatically when building the simulator.
The Font Converter accepts
- TrueType (.ttf)
- OpenType (.otf)
- Glyph Bitmap Distribution Format (.bdf).
Simply place the font in the assets/fonts/
folder and the font will be available for reference in TouchGFX Designer (If the font is added while TouchGFX Designer is running, it must be restarted to update the available fonts).
In TouchGFX Designer, it is also possible to use the fonts installed in Windows, selecting any of these fonts will automatically add them to the assets/fonts/
folder
The Font Converter supports kerning by using the kerning information in the supplied font.
Note
Character Memory Optimization
TouchGFX is optimized for low memory consumption. By analysing the characters used for a specific typography, the number of generated characters (in internal C++ format) are minimized to the characters that are actually used by the application.
Text memory consumption is also optimized by compacting texts that use common suffixes by enabeling the option to remap texts in the Text Configuration.
Wildcards
It is possible to use runtime values as part of texts. This is possible by use of wildcards in the texts. These are specified in the given format <*>
, where the * represents an optional helping text which will not be included in the resulting text. It is possible to have up to two wildcards in one text.
All translations for a given text must contain the same number of wildcards. The wildcard values are inserted at runtime in the application C++ code.
Example of wildcard usage: The temperature is <insert_temperature>°
One detail to notice is that due to the character memory optimization (see section above) the only characters that are generated for a specific typography are the ones used in texts having this typography. To force the font generator to include certain characters, you can use "Wildcard Characters" and "Character Ranges" for each typography.
The wildcard format <*>
can be escaped by using backslash notation like this: \<not a wildcard\>. This will result in the literal text "<not a wildcard>" being used in the application.
Using Wildcards in TouchGFX Designer
In TouchGFX Designer, wildcards can be added to regular TextAreas. Effectively this now makes the TextArea widget cover the functionality previously covered by the TextAreaWithOneWildcard/TextAreaWithTwoWildcards widgets, although there is no changes to how the code is generated in TouchGFX.
In TouchGFX Designer you can add Wildcards to TextAreas by either using the usual syntax <*>
, or by simply clicking the Add Wildcard button in properties for the selected TextArea. A well-known example is adding a temperature reading to a TextArea, which could say The temperature is °. In this case it could be an outdoor temperature reading. Here we want to insert a Wildcard that not only displays a static number, but also updates according to temperature readings. The Wildcard will be added to the current position of the in-text caret:
Now our text in properties will display The temperature is <value>°, while our text on canvas displays The temperature is °:
To setup the specific wildcard you can click the corresponding Wildcard button (in this example Wildcard 1), which allows for editing the Wildcard we just added.
Here you can choose how you will update the wildcard. Either with predefined resource texts or by dynamic run-time created texts. In both cases, you can update the text at run-time. For the latter you need a Wildcard buffer for storing the dynamic text. Such a buffer is created by selecting the Wildcard Buffer check mark. In this case you also need to specify a size (number of characters) of the buffer. If you want to be memory efficient, you need to match the specified size as close as possible with your actual needed text size. Remember to add one extra space for the string termination (‘\0’).
You can also set an initial value for the Wildcard, enabling you to see how the final TextArea could look with a temperature reading. Setting an initial value will either create a hard coded Single Use text in the Text Database or if you have selected to use Wildcard buffer insert it into the Wildcard buffer:
Using Wildcards in User Code
Wildcards can also be added and updated via User Code as shown in the code example below, where a Unicode::UnicodeChar
array is managed and updated.
gui/include/gui/some_screen/SomeView.hpp
#include <touchgfx/widgets/TextAreaWithWildcard.hpp>
...
class SomeView : public View<SomePresenter>
{
TextAreaWithOneWildcard txt;
Unicode::UnicodeChar txtBuffer[10];
}
gui/src/some_screen/SomeView.cpp
#include <texts/TextKeysAndLanguages.hpp>
#include <touchgfx/Color.hpp>
void SomeView::setupScreen()
{
txt.setTypedText(TypedText(T_TEMPERATURE_READOUT));
txt.setXY(10, 20);
txt.setColor(Color::getColorFrom24BitRGB(0xFF, 0xFF, 0xFF))
txt.setWildcard(txtBuffer);
add(txt);
updateTxt(5);
}
void SomeView::updateTxt(int newValue)
{
Unicode::snprintf(txtBuffer, 10, "%d", newValue);
txt.invalidate();
}
Text Placement
As for all TouchGFX widgets a TextArea is placed on the screen by specifing a position (X and Y) and a dimension (width and height). This is easily done via TouchGFX Designer in the widgets properties, However the rendering of text in TouchGFX Designer is not always 100% acurate compared to how the text is rendered by TouchGFX.
There are also a few more details and possibilites to be aware of when dealing with texts, decribed in this section.
Alignment
The text inside the TextArea is aligned according to the alignment specified for the chosen text entry in the text database. The text is aligned with respect to the area of the TextArea. In the following screenshots the area of the TextArea is highlighted in blue.
These settings can be set in TouchGFX Designer Texts View.
Setting the Correct Width and Height of a TextArea
A TextArea is able to adjust its width and height according to the currently selected text. This is done by calling the TextArea::resizeToCurrentText()
method.
Note
resizeToCurrentText()
is called automatically when instantiating a TextArea with a new TypedText if the width and height are not set.When using center/right aligned text you most often do not want to resize the width and height because your text need to be centered/right aligned in a fixed area. In this case set the width and height manually. This can be done by calling TextArea::setPosition(x, y, width, height)
, TextArea::setWidth(width)
and TextArea::setHeight(height)
.
If your width and/or height is too small to fit the text, the text will be clipped to the area as can be seen below.
Setting the Correct X and Y for a TextArea
To place a TextArea at the correct X and Y position, you need to be aware of the fact that the font used will have some extra spacing above the characters to allow for large characters. This makes it a bit hard to place a TextArea according to a Y position for the upper left corner, since you do not know the exact spacing above your text. One way of placing a text is to specify the position where you believe it should be and then fine tune the position by inspecting the placement in the simulator. This is most often a fairly simple task but it has to be redone if you change the font or font size later on.
A more robust way of doing it is to use text baseline. The baseline is the line upon which most letters "sit" and below which descenders (characters like p and j) extend.
To set a text baseline use the TextArea::setBaselineY(y)
or TextArea::setXBaselineY(x, y)
. For these methods you do not specify the upper left corner of the TextArea but instead the baseline of the first text line. This will take the font size and spacing into account and set the Y position of the TextArea accordingly.
The baseline functionality is not available in TouchGFX Designer, since TextArea widget placement is easily done via TouchGFX Designer Canvas, and can therefore only be used in User Code.
Note
setBaselineY
again if you change the TextAreas TypedText to one with a different font or font size.Automatic Wrapping of Long Text Lines
Sometimes a TextArea needs to contain a text which is very long. By default, such text is simply written as a single line and all text that does not fit inside the TextArea is simpy cut off. If instead the text should be wrapped at spaces and re-flowed to fill several lines, simply call:
myTextArea.setWideTextAction(WIDE_TEXT_WORDWRAP); // Default is WIDE_TEXT_NONE
Available Wide Text Actions
WIDE_TEXT_NONE
: Do nothing, simply cut the text in the middle of any character that extends beyond the width of the TextArea.WIDE_TEXT_WORDWRAP
: Wrap between words, ellipsis anywhere "Very long t...".WIDE_TEXT_WORDWRAP_ELLIPSIS_AFTER_SPACE
: Wrap between words, ellipsis anywhere only after space "Very long ...".WIDE_TEXT_CHARWRAP
: Wrap between any two characters, ellipsis anywhere, as used in Chinese.WIDE_TEXT_CHARWRAP_DOUBLE_ELLIPSIS
:Wrap between any two characters, double ellipsis anywhere, as used in Chinese.
Further reading
This will probably make the TextArea need more vertical space. This can either be achieved by increasing the height of the TextArea in the Designer or it can be done in user code as follows.
myTextArea.setWidth(200);
myTextArea.resizeHeightToCurrentText(); // Will set height by wrapping text at 200px long lines
myTextArea.invalidate();
Remember to call myTextArea.invalidate()
before resizing myTextArea
if you are decreasing the text area size. If not, you will still see part of the old text area, since it is not covered by the new smaller text area.
Switching Language
TouchGFX supports multi language interfaces. The current language used in the interface can be changed by calling the static method Texts::setLanguage
:
Texts::setLanguage(GB);
The value GB is found in the LANGUAGES
enum in the TextKeysAndLanguages.hpp
as shown in the example in The Text Converter section.
After this call, invalidate all widgets that display texts (or simply invalidate the entire screen) and they will display texts in the newly selected language.
In TouchGFX Designer
You can switch between languages, enabling testing for all translations. This is done from General section of the Config view. Here you simply change the startup language of the application by changing the Selected Language. Languages will need to be created and translated before they are selectable in the Config view.