Skip to content

Commit 430777f

Browse files
committed
Added support for linebreaks
1 parent c810826 commit 430777f

File tree

4 files changed

+56
-20
lines changed

4 files changed

+56
-20
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ The following named colors are supported:
6363
| white | `#ffffffff` | ![](https://placehold.it/15/ffffff/000000?text=+) |
6464
| yellow | `#ffff00ff` | ![](https://placehold.it/15/ffff00/000000?text=+) |
6565

66+
## Line breaks
67+
There is no need for the HTML `<br>` tag since line breaks (i.e. `\n`) are parsed and presented by the system.
68+
6669
# Usage
6770
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. Example:
6871

example/example.gui_script

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
local richtext = require "richtext.richtext"
22

3-
local TEXT = "<size=3>RichText</size>Lorem <color=0,0.5,0,1>ipsum </color>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>. Nullam ornare accumsan rhoncus. Nunc placerat nibh a purus auctor, id scelerisque massa rutrum."
3+
local TEXT = "<size=3>RichText</size>Lorem <color=0,0.5,0,1>ipsum </color>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 accumsan rhoncus.\n\nNunc placerat nibh a purus auctor, id scelerisque massa rutrum."
44

55
function init(self)
66
local settings = {

richtext/parse.lua

+32-12
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ local function parse_tag(tag, params)
5959
return settings
6060
end
6161

62-
62+
-- add a single word to the list of words
6363
local function add_word(text, settings, words)
6464
local data = { text = text }
6565
for k,v in pairs(settings) do
@@ -68,21 +68,41 @@ local function add_word(text, settings, words)
6868
words[#words + 1] = data
6969
end
7070

71-
local function split_and_add(text, settings, words)
72-
local ws_start, trimmed_text, ws_end = text:match("^(%s*)(.-)(%s*)$")
71+
-- split a line into words
72+
local function split_line(line, settings, words)
73+
local ws_start, trimmed_text, ws_end = line:match("^(%s*)(.-)(%s*)$")
7374
if trimmed_text == "" then
7475
add_word(ws_start .. ws_end, settings, words)
7576
else
7677
local wi = #words
77-
for word in text:gmatch("%S+") do
78+
for word in trimmed_text:gmatch("%S+") do
7879
add_word(word .. " ", settings, words)
7980
end
80-
if #words > wi then
81-
local first = words[wi + 1]
82-
first.text = ws_start .. first.text
83-
local last = words[#words]
84-
last.text = last.text:sub(1,#last.text - 1) .. ws_end
85-
end
81+
local first = words[wi + 1]
82+
first.text = ws_start .. first.text
83+
local last = words[#words]
84+
last.text = last.text:sub(1,#last.text - 1) .. ws_end
85+
end
86+
end
87+
88+
-- split text
89+
-- split by lines first
90+
local function split_text(text, settings, words)
91+
local added_linebreak = false
92+
if text:sub(-1)~="\n" then
93+
added_linebreak = true
94+
text = text .. "\n"
95+
end
96+
97+
for line in text:gmatch("(.-)\n") do
98+
split_line(line, settings, words)
99+
local last = words[#words]
100+
last.linebreak = true
101+
end
102+
103+
if added_linebreak then
104+
local last = words[#words]
105+
last.linebreak = false
86106
end
87107
end
88108

@@ -114,13 +134,13 @@ function M.parse(s, parent_settings)
114134
local before, tag, params, text, after = find_tag(s)
115135
-- no more tags? Split and add the entire string
116136
if not tag then
117-
split_and_add(s, parent_settings, all_words)
137+
split_text(s, parent_settings, all_words)
118138
break
119139
end
120140

121141
-- split and add text before the encountered tag
122142
if before ~= "" then
123-
split_and_add(before, parent_settings, all_words)
143+
split_text(before, parent_settings, all_words)
124144
end
125145

126146
-- parse the tag and merge it with settings for the parent tag

richtext/richtext.lua

+20-7
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function M.create(text, font, settings)
4646
settings.position = settings.position or vmath.vector3()
4747

4848
-- cache length of a single space, per font
49-
local space_widths = {}
49+
local font_sizes = {}
5050

5151
local position = vmath.vector3(settings.position)
5252

@@ -74,26 +74,39 @@ function M.create(text, font, settings)
7474
gui.set_scale(node, vmath.vector3(1) * (word.size or 1))
7575

7676
-- measure width of a single space for current font
77-
if not space_widths[font] then
78-
space_widths[font] = gui.get_text_metrics(font, " _").width - gui.get_text_metrics(font, "_").width
77+
if not font_sizes[font] then
78+
font_sizes[font] = {
79+
space = gui.get_text_metrics(font, " _").width - gui.get_text_metrics(font, "_").width,
80+
height = gui.get_text_metrics(font, "Ij").height,
81+
}
7982
end
8083

8184
-- get metrics of node
8285
word.metrics = gui.get_text_metrics_from_node(node)
83-
word.metrics.total_width = (word.metrics.width + #get_trailing_whitespace(word.text) * space_widths[font]) * word.size
86+
word.metrics.total_width = (word.metrics.width + #get_trailing_whitespace(word.text) * font_sizes[font].space) * word.size
8487
word.metrics.width = word.metrics.width * word.size
8588
word.metrics.height = word.metrics.height * word.size
8689
highest_word = math.max(highest_word, word.metrics.height)
8790

88-
-- adjust position and position node
91+
-- move word to next row if it overflows the width
8992
local width = position.x + word.metrics.width - settings.position.x
9093
if settings.width and width > settings.width then
9194
position.y = position.y - highest_word
9295
position.x = settings.position.x
93-
highest_word = 0
96+
highest_word = font_sizes[font].height
9497
end
98+
99+
-- position word
95100
gui.set_position(node, position)
96-
position.x = position.x + word.metrics.total_width
101+
102+
-- handle linebreak or advance on same line
103+
if word.linebreak then
104+
position.y = position.y - highest_word
105+
position.x = settings.position.x
106+
highest_word = font_sizes[font].height
107+
else
108+
position.x = position.x + word.metrics.total_width
109+
end
97110
end
98111

99112
return nodes

0 commit comments

Comments
 (0)