Skip to content

Commit

Permalink
Added support for splitting very long words that span more than a ful…
Browse files Browse the repository at this point in the history
…l line

Fixes #67
  • Loading branch information
britzl committed Sep 14, 2021
1 parent 0d3e543 commit d7bdc73
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 11 deletions.
12 changes: 8 additions & 4 deletions example/example.gui_script
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ local function create_complex_example()
[hash("spineboy")] = hash("spine-spineboy"),
},
},
width = 460,
width = 480,
position = vmath.vector3(0, 0, 0),
parent = gui.get_node("bg"),
color = vmath.vector4(0.95, 0.95, 1.0, 1.0),
Expand Down Expand Up @@ -197,13 +197,17 @@ local function create_language_example()
end


local function create_nobreak_example()
local function create_linebreak_example()
local settings_nobr = { position = vmath.vector3(0, 600, 0), align = richtext.ALIGN_LEFT, width = 245 }
local words1 = richtext.create("The image at the end should end up on a new line <nobr><img=smileys:cyclops/></nobr>", "Roboto-Regular", settings_nobr)

local settings_right = { position = vmath.vector3(320, 600, 0), align = richtext.ALIGN_LEFT, width = 245 }
local words2 = richtext.create("The image at the end should end up on a new line <img=smileys:cyclops/>", "Roboto-Regular", settings_right)
return merge(words1, words2)

local settings_nobr = { position = vmath.vector3(0, 900, 0), align = richtext.ALIGN_LEFT, width = 245 }
local longword = richtext.create("THIS IS AVERYLONGWORDWITHOUTANYLINEBREAKS", "Roboto-Regular", settings_nobr)

return merge(words1, words2, longword)
end

local function create_overlapping_tags_example()
Expand Down Expand Up @@ -320,7 +324,7 @@ function init(self)
{ name = "CHARACTERS", fn = create_characters_example },
{ name = "SPINE", fn = create_spine_example },
{ name = "LANGUAGE", fn = create_language_example },
{ name = "NO BREAK", fn = create_nobreak_example },
{ name = "LINEBREAK", fn = create_linebreak_example },
{ name = "CLICKABLE", fn = create_clickable_words_example },
{ name = "OVERLAPPING", fn = create_overlapping_tags_example },
{ name = "HTML ENTITIES", fn = create_html_entities_example },
Expand Down
55 changes: 48 additions & 7 deletions richtext/richtext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,27 @@ local function measure_node(word, font, previous_word)
return metrics, combined_metrics, node
end

local function split_word(word, font, max_width)
local one = deepcopy(word)
local two = deepcopy(word)
local text = word.text
local metrics = get_text_metrics(one, font)
local char_count = utf8.len(text)
local split_index = math.floor(char_count * (max_width / metrics.total_width))
local rest = ""
while split_index > 1 do
one.text = utf8.sub(text, 1, split_index)
one.linebreak = true
metrics = get_text_metrics(one, font)
if metrics.width <= max_width then
rest = utf8.sub(text, split_index + 1)
break
end
split_index = split_index - 1
end
two.text = rest
return one, two
end


--- Create rich text gui nodes from text
Expand Down Expand Up @@ -364,7 +385,8 @@ function M.create(text, font, settings)
local paragraph_spacing = 0
local position = vmath.vector3(settings.position)
local word_count = #words
for i = 1, word_count do
local i = 1
repeat
local word = words[i]
if word.image then
text_metrics.img_count = text_metrics.img_count + 1
Expand All @@ -390,12 +412,29 @@ function M.create(text, font, settings)
local word_metrics, combined_metrics, node = measure_node(word, font_for_word, previous_word)
local should_create_node = true

-- does the word fit on the line or does it overflow?
local overflow = (settings.width and ((combined_metrics
and (line_width - previous_word.metrics.total_width + combined_metrics.width)
or (line_width + word_metrics.width)
) > settings.width))
-- check if the line overflows due to this word
local overflow = false
if settings.width then
if combined_metrics then
overflow = (line_width - previous_word.metrics.total_width + combined_metrics.width) > settings.width
else
overflow = (line_width + word_metrics.width) > settings.width
end

-- if we overflow and the word is longer than a full line we
-- split the word and add the first part to the current line
if overflow and word.text and word_metrics.width > settings.width then
local remaining_width = settings.width - line_width
local one, two = split_word(word, font_for_word, remaining_width)
word_metrics, combined_metrics, node = measure_node(one, font_for_word, previous_word)
words[i] = one
word = one
table.insert(words, i + 1, two)
word_count = word_count + 1
overflow = false
end
end

if overflow and not word.nobr then
-- overflow, position the words that fit on the line
text_metrics.height = text_metrics.height + (line_height * line_increment_before * settings.line_spacing)
Expand Down Expand Up @@ -465,7 +504,9 @@ function M.create(text, font, settings)
line_width = 0
paragraph_spacing = 0
end
end

i = i + 1
until i > word_count

-- position remaining words
if #line_words > 0 then
Expand Down

0 comments on commit d7bdc73

Please sign in to comment.