Handling Text
Note
This assumes that you’ve read Drawing Text.
While drawing text is enough for many cases, there are some cases where you want to gain some information about text you’re about to draw. Think of user interfaces where text elements are neighbors of each other. This requires some kind of layouting algorithm, which in turn relies on the size of text elements so that it can properly figure out where to put each element.
For such cases, cer::Font
provides methods such as measure, lineHeight()
and forEachGlyph()
.
Measuring
We’ll first go over the measure method. It allows us to get the exact size of a text, in pixels, given a font and a size.
This should give us a yellow rectangle with black text on top:
Imagine we had two draw multiple independent text objects next to one another, including a margin between each of them. With this information we can now implement such a case, just like this:
This will greet us with all texts neatly lined up:
Next up is the lineHeight()
method. It gives you the fixed height of the font itself, in pixels. This is for example used to align text objects next to each other vertically (“line by line”). Let’s see an example:
This gives us perfectly aligned text:
And lastly, the most important of all: forEachGlyph()
. This is the method all others are based on.
Given a text, size and an std::function
, it allows you to iterate each glyph of a string and perform an arbitrary action.
For each iteration, your function gets information about the glyph such as codepoint and position as parameters.
Let’s look at its signature:
We see that we have to give it a function that takes the glyph’s Unicode codepoint and its occupied area within the text, in pixels. Additionally, it has to return a bool value to indicate whether to keep going.
If it returns false, the iteration stops after that glyph.
forEachGlyph()
itself returns nothing, as it’s just a forward iteration method.
With this, we could even implement a custom text rendering function. But for this example we’ll keep it simple and print glyph information to the console, just to show that it works:
Which prints the following to the console:
We can observe that the X-position increments steadily until the W is encountered, which starts at a new line. X is therefore reset, and Y is now offset. X increments steadily while Y remains the same until the end of the string.
There is one use case where forEachGlyph()
really shines, which is hit detection.
When implementing UI controls such as text boxes, the correct position for the caret must be determined.
This is only possible when we have information about each character’s location inside such a text box.
Whenever a user clicks somewhere inside the text box, we can iterate its text and compare the clicked position to each glyphs area.
Conversely, when the caret’s position is already known and the user presses the left or right key to go to the previous or next glyph, we can correctly move the caret, since we know the exact positions of each glyph.
DPI awareness
The text size we specify in text-related functions is given in pixels. However, different displays might have different pixel densities (DPI). cerlib does not handle drawing at different densities itself, but gives you the information so that you can handle it.
When working with text, you should obtain the current DPI scaling factor using Window::pixelRatio()
of the game’s window. This gives you a floating-point value by which you have to scale the font size, so that you get the “real” pixel size for that window’s display.
An example:
The same is true for other text-related functions such as Font::measure()
and Font::forEachGlyph()
.