Skip to content

Commit

Permalink
Added support for linebreaks
Browse files Browse the repository at this point in the history
  • Loading branch information
britzl committed Feb 26, 2018
1 parent c810826 commit 430777f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 20 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ The following named colors are supported:
| white | `#ffffffff` | ![](https://placehold.it/15/ffffff/000000?text=+) |
| yellow | `#ffff00ff` | ![](https://placehold.it/15/ffff00/000000?text=+) |

## Line breaks
There is no need for the HTML `<br>` tag since line breaks (i.e. `\n`) are parsed and presented by the system.

# Usage
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:

Expand Down
2 changes: 1 addition & 1 deletion example/example.gui_script
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local richtext = require "richtext.richtext"

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."
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."

function init(self)
local settings = {
Expand Down
44 changes: 32 additions & 12 deletions richtext/parse.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ local function parse_tag(tag, params)
return settings
end


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

local function split_and_add(text, settings, words)
local ws_start, trimmed_text, ws_end = text:match("^(%s*)(.-)(%s*)$")
-- split a line into words
local function split_line(line, settings, words)
local ws_start, trimmed_text, ws_end = line:match("^(%s*)(.-)(%s*)$")
if trimmed_text == "" then
add_word(ws_start .. ws_end, settings, words)
else
local wi = #words
for word in text:gmatch("%S+") do
for word in trimmed_text:gmatch("%S+") do
add_word(word .. " ", settings, words)
end
if #words > wi then
local first = words[wi + 1]
first.text = ws_start .. first.text
local last = words[#words]
last.text = last.text:sub(1,#last.text - 1) .. ws_end
end
local first = words[wi + 1]
first.text = ws_start .. first.text
local last = words[#words]
last.text = last.text:sub(1,#last.text - 1) .. ws_end
end
end

-- split text
-- split by lines first
local function split_text(text, settings, words)
local added_linebreak = false
if text:sub(-1)~="\n" then
added_linebreak = true
text = text .. "\n"
end

for line in text:gmatch("(.-)\n") do
split_line(line, settings, words)
local last = words[#words]
last.linebreak = true
end

if added_linebreak then
local last = words[#words]
last.linebreak = false
end
end

Expand Down Expand Up @@ -114,13 +134,13 @@ function M.parse(s, parent_settings)
local before, tag, params, text, after = find_tag(s)
-- no more tags? Split and add the entire string
if not tag then
split_and_add(s, parent_settings, all_words)
split_text(s, parent_settings, all_words)
break
end

-- split and add text before the encountered tag
if before ~= "" then
split_and_add(before, parent_settings, all_words)
split_text(before, parent_settings, all_words)
end

-- parse the tag and merge it with settings for the parent tag
Expand Down
27 changes: 20 additions & 7 deletions richtext/richtext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function M.create(text, font, settings)
settings.position = settings.position or vmath.vector3()

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

local position = vmath.vector3(settings.position)

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

-- measure width of a single space for current font
if not space_widths[font] then
space_widths[font] = gui.get_text_metrics(font, " _").width - gui.get_text_metrics(font, "_").width
if not font_sizes[font] then
font_sizes[font] = {
space = gui.get_text_metrics(font, " _").width - gui.get_text_metrics(font, "_").width,
height = gui.get_text_metrics(font, "Ij").height,
}
end

-- get metrics of node
word.metrics = gui.get_text_metrics_from_node(node)
word.metrics.total_width = (word.metrics.width + #get_trailing_whitespace(word.text) * space_widths[font]) * word.size
word.metrics.total_width = (word.metrics.width + #get_trailing_whitespace(word.text) * font_sizes[font].space) * word.size
word.metrics.width = word.metrics.width * word.size
word.metrics.height = word.metrics.height * word.size
highest_word = math.max(highest_word, word.metrics.height)

-- adjust position and position node
-- move word to next row if it overflows the width
local width = position.x + word.metrics.width - settings.position.x
if settings.width and width > settings.width then
position.y = position.y - highest_word
position.x = settings.position.x
highest_word = 0
highest_word = font_sizes[font].height
end

-- position word
gui.set_position(node, position)
position.x = position.x + word.metrics.total_width

-- handle linebreak or advance on same line
if word.linebreak then
position.y = position.y - highest_word
position.x = settings.position.x
highest_word = font_sizes[font].height
else
position.x = position.x + word.metrics.total_width
end
end

return nodes
Expand Down

0 comments on commit 430777f

Please sign in to comment.