Defold-RichText is a system to create styled text based on an HTML inspired markup language.
You can use RichText in your own project by adding this project as a Defold library dependency. Open your game.project file and in the dependencies field under project add:
https://github.com/britzl/defold-richtext/archive/master.zip
Or point to the ZIP file of a specific release.
The markup format is HTML inspired, but not intended to be fully compatible with standard HTML. Just like in HTML the idea is that sections of text can be enclosed in matching start and end tags:
This is a <b>bold</b> statement!
This is a bold statement!
Nested elements are supported. Use this to give a section of text a combination of styles:
This is a <b>bold <i>italic</i></b> statement!
This is a bold italic statement!
The following tags are supported:
Tag | Description | Example |
---|---|---|
a | Create a "hyperlink" that generates a message | <a=message_id>Foobar</a> |
when clicked (see richtext.on_click ) |
||
b | The text should be bold | <b>Foobar</b> |
br | Insert a line break (see notes on linebreak) | <br/> |
color | Change text color | <color=red>Foobar</color> |
<color=1.0,0,0,1.0>Foobar</color> |
||
<color=#ff0000>Foobar</color> |
||
<color=#ff0000ff>Foobar</color> |
||
shadow | Change text shadow | <shadow=red>Foobar</shadow> |
<shadow=1.0,0,0,1.0>Foobar</shadow> |
||
<shadow=#ff0000>Foobar</shadow> |
||
<shadow=#ff0000ff>Foobar</shadow> |
||
outline | Change text shadow | <outline=red>Foobar</outline> |
<outline=1.0,0,0,1.0>Foobar</outline> |
||
<outline=#ff0000>Foobar</outline> |
||
<outline=#ff0000ff>Foobar</outline> |
||
font | Change font | <font=MyCoolFont>Foobar</font> |
i | The text should be italic | <i>Foobar</i> |
img | Display image | <img=texture:image/> |
Display image in fixed square | <img=texture:image,size/> |
|
Display image in fixed rectangle | <img=texture:image,width,height/> |
|
nobr | Prevent the text from breaking | Words <nobr>inside tag</nobr> won't break |
size | Change text size, relative to default size | <size=2>Twice as large</size> |
spine | Display spine model | <spine=scene:anim/> |
p | Adds extra spacing below the line where this | <p>A paragraph</p>\nSome other text |
tag ends. Adds a newline before its opening | <p=2.5>This has 2.5 lines of spacing</p> |
|
tag if it doesn't already exist. | ||
repeat | Repeat the text enclosed by the tag | <repeat=5>Echo </repeat> five times |
Note that there is no need for the HTML <br/>
tag since line breaks (i.e. \n
) are parsed and presented by the system. Note that a single <br>
(ie without a closing or empty tag) isn't supported (even though most browsers accept it).
The following named colors are supported:
You can add your own named colors as well:
local color = require "richtext.color"
color.add("blood", "#8A0303")
color.add("asparagus", "#87a96b")
color.add("denim", "#1560bd")
The RichText library has limited support for HTML entities (reserved characters):
>
converts into>
<
converts into<
converts into a non-breaking space between two words, ie100 km
becomes100 km
with100
andkm
acting as a single word with a space between.&zwsp;
converts into a zero-width space character (\226\128\139
). This is not an official HTML entity but it is provided as a convenient way to insert one into text.
The RichText library will create gui text nodes representing the markup in the text passed to the library. It will search for tags and split the entire text into words, where each word contains additional meta-data that is used to create and configure text nodes. This means that the library will create as many text nodes as there are words in the text.
A simple example with some color and linebreaks:
richtext.create("Single line text with a dash of <color=red>color</color>\nBy default left aligned.", "Roboto-Regular")
A more complex example with different fonts, colors, inline images and automatic linebreaks:
local settings = {
fonts = {
Roboto = {
regular = hash("Roboto-Regular"),
italic = hash("Roboto-Italic"),
bold = hash("Roboto-Bold"),
bold_italic = hash("Roboto-BoldItalic"),
},
Nanum = {
regular = hash("Nanum-Regular"),
},
},
width = 400,
parent = gui.get_node("bg"),
color = vmath.vector4(0.95, 0.95, 1.0, 1.0),
shadow = vmath.vector4(0.0, 0.0, 0.0, 1.0),
}
local text = "<size=3><outline=green>RichText</outline></size>Lorem <color=0,0.5,0,1>ipsum </color><img=smileys:zombie/> dolor <color=red>sit </color><color=#ff00ffff>amet, </color><size=1.15><font=Nanum>consectetur </font></size>adipiscing elit. <b>Nunc </b>tincidunt <b><i>mattis</i> libero</b> <i>non viverra</i>.\n\nNullam ornare <img=smileys:hungry/>accumsan rhoncus.\n\nNunc placerat nibh a purus auctor, id scelerisque massa <size=2>rutrum.</size>"
richtext.create(text, "Roboto", settings)
Custom tags can be accessed and used in two ways:
- Use
richtext.tagged(words, tag)
to get all words with a certain tag, even a custom one - Use
tags.register(tag, fn)
to register a custom tag handler:
tags.register("boldred", function(params, settings)
tags.apply("color", "red", settings)
tags.apply("b", nil, settings)
end)
richtext.create("I am <boldred>bold and red</boldred>!", "Roboto", settings)
Creates rich text gui nodes from a text containing markup.
PARAMETERS
text
(string) - The text to create rich text fromfont
(string) - Name of default font. Must match the name of a font in the gui scene or a key in thefonts
table insettings
(see below).settings
(table) - Optional table containing settings
The settings
table can contain the following values:
width
(number) - Maximum width of a line of text. Omit this value to present the entire text on a single lineposition
(vector3) - The position that the text aligns to (refer to thealign
setting for details). Defaults to 0,0 if not specified.size
(number) - Default size of any created node. Same as using a<size=2>
tag in the text. Defaults to 1 if not specified.parent
(node) - GUI nodes will be attached to this node if specified.fonts
(table) - Table with fonts, keyed on font name. See separate section below. If nofonts
table is provided the font used will be the one passed torichtext.create()
.layers
(table) - Table with font, texture and spine scene mappings to layer names. See separate section below.color
(vector4) - The default color of text. Will be white if not specified.shadow
(vector4) - The default shadow color of text. Will be transparent if not specified.outline
(vector4) - The default outline color of text. Will be transparent if not specified.align
(hash) - One ofrichtext.ALIGN_LEFT
,richtext.ALIGN_CENTER
,richtext.ALIGN_RIGHT
andrichtext.ALIGN_JUSTIFY
. Defaults torichtext.ALIGN_LEFT
. Defines how the words of a line of text are positioned in relation the providedposition
. Width must be specified forrichtext.ALIGN_JUSTIFY
.valign
(hash) - One ofrichtext.VALIGN_TOP
,richtext.VALIGN_MIDDLE
andrichtext.VALIGN_BOTTOM
. Defaults torichtext.VALIGN_TOP
. Defines how the words of a line of text are positioned vertically on the line.line_spacing
(number) - Value to multiply line height with. Set to a value lower than 1.0 to reduce space between lines and a value higher than 1.0 to increase space between lines. Defaults to 1.0.paragraph_spacing
(number) - Space to leave after lines with where<p>
tags end. Relative to the line height. Defaults to 0.5 lines.image_pixel_grid_snap
(boolean) - Set to true to position image on full pixels (positions rounded to nearest integer) to avoid effects of anti-aliasing. Defaults to false.combine_words
(boolean) - Set to true to combine words with the same style on a line into a single node. This is useful for very long texts where the maximum number of nodes would exceed the limit set in the GUI. The disadvantage is that any per word operations will not work since the words have been combined.dryrun
(boolean) - Set to true to perform a complete layout of the words without creating gui nodes.
The fonts
table should have the following format:
name (string) = {
regular (string) = font (hash),
italic (string) = font (hash),
bold (string) = font (hash),
bold_italic (string) = font (hash),
},
name (string) = {
...
},
Where name
is the name specified in a <font>
tag and the font
for each of regular
, italic
, bold
and bold_italic
should correspond to the name of a font added to a .gui scene.
The layers
table should map fonts, textures and spine scenes to layer names. It should have the following format:
fonts = {
font (hash) = layer (hash),
...
font (hash) = layer (hash),
},
images = {
texture (hash) = layer (hash),
...
texture (hash) = layer (hash),
},
spinescenes = {
spinescene (hash) = layer (hash),
...
spinescene (hash) = layer (hash),
}
Where layer
is the name of a layer in the .gui scene, font
is the value returned from a call to gui.get_font(node)
, texture
is the value returned from a call to gui.get_texture(node)
and finally spinescene
is the value returned from a call to gui.get_spine_scene(node)
.
RETURNS
words
(table) - A table with all the words that the text has been broken up into. Each word is represented by a table with keys such asnode
,tags
,text
etcmetrics
(table) - A table with text metrics.
The metrics
table contains the following values:
width
(number) - Width of the textheight
(number) - Height of the textchar_count
(number) - Number of characters in the text including whitespaceimg_count
(number) - Number of images in the textspine_count
(number) - Number of spine models in the text
A word in the words
table contains the following values:
size
(number) - Size of the wordcolor
(vector4) - Color of the wordshadow
(vector4) - Shadow color of the wordoutline
(vector4) - Outline color of the wordnode
(node) - The GUI node representing the wordmetrics
(table) - Word metrics (width
,height
,total_width
and additionally for text nodes:max_descent
,max_ascent
)font
(string) - Font nametext
(string) - Word text (empty for non text nodes)
Get all words with a specific tag.
PARAMETERS
words
(table) - The words to search, as received by a call torichtext.create()
.tag
(string) - Name of the tag to search for. Passnil
to get all words without tags.
RETURNS
words
(table) - A table with all the words that matches the tag.
Truncate a text down to a specific length. This function has two modes of operation: 1) It can truncate the text on a per word basis or 2) on a per character/image basis. The function will disable nodes that shouldn't be visible and in the case of truncating on a per character basis also update the text in nodes that should be partially visible. The text metrics of a truncated word will be updated.
PARAMETERS
words
(table) - The words to truncate, as received by a call torichtext.create()
.length
(number) - Maximum number of words or characters and images to show.options
(table) - Optional table with options when truncating.
Available options in the option
table are:
words
(boolean) - True if the function should truncate down to the nearest full word instead of truncating to a partial word.
RETURNS
word
(table) - The last visible word.
Get the length of a text ignoring any tags except image and spine tags which are treated as having a length of 1.
PARAMETERS
text
(string|table) - The text to measure. This can either be a string or a list of words, as received by a call torichtext.create()
.
RETURNS
length
(number) - The length of the provided text.
Split a word into it's characters, including the creation of the gui nodes. Each of the characters will be given the same attributes as the word, and they will be positioned correctly within the word.
PARAMETERS
word
(table) - The word to split, as received from a call torichtext.create()
orrichtext.tagged()
.
RETURNS
characters
(table) - The individual characters of the word.
Call this function when a click/touch has been detected and your text contains words with an a
tag. These words act as "hyperlinks" and will generate a message when clicked. The generated message will contain the following values:
node_id
(hash) - Id of the node which was clickedtext
(string) - Text of the clicked wordscreen_x
(number) - Horizontal position of the clickscreen_y
(number) - Vertical position of the clicktags
(table) - All tags on the clicked word
PARAMETERS
words
(table) - A list of words, as received fromrichtext.create()
orrichtext.tagged()
.action
(table) - Theaction
table from theon_input
lifecycle function.
RETURNS
consumed
(boolean) - True if any word was clicked.
Removes all gui text nodes created by richtext.create()
.
PARAMETERS
words
(table) - Table of words, as received from a call torichtext.create()
.
Returns the words created by richtext.create()
as a plain text string without any formatting or tags. Linebreaks are included in the returned string.
PARAMETERS
words
(table) - Table of words, as received from a call torichtext.create()
.
RETURNS
plaintext
(string) - Plain text version of the words.
Left-align text. The words of a line starts at the specified position (see richtext.create
settings above).
Center text. The words of a line are centered on the specified position (see richtext.create
settings above).
Right-align text. The words of a line ends at the specified position (see richtext.create
settings above).
Justify text. The words of a line start at the specified position and are spaced such that the last character of the last word ends at the right edge of the line bounds (see richtext.create
settings above).
Vertically align the words on a line so that the top of the words on the line align.
Vertically align the words on a line so that the middle of the words on the line align.
Vertically align the words on a line so that the bottom of the words on the line align.