Skip to content

Commit e6ca0db

Browse files
authored
Add option to truncate down to nearest full word (#46)
* Add option to truncate down to nearest full word
1 parent c7de1f5 commit e6ca0db

File tree

3 files changed

+58
-24
lines changed

3 files changed

+58
-24
lines changed

README.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,17 @@ Get all words with a specific tag.
220220
* `words` (table) - A table with all the words that matches the tag.
221221

222222

223-
### richtext.truncate(words, length)
224-
Truncate a text such that only a specific number of characters and images are visible. The function will disable nodes that shouldn't be seen at all and updates the text in nodes that should be partially visible. The text metrics of a truncated word will be updated.
223+
### richtext.truncate(words, length, [options])
224+
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.
225225

226226
**PARAMETERS**
227227
* `words` (table) - The words to truncate, as received by a call to `richtext.create()`.
228-
* `length` (number) - Maximum number of characters or images to show.
228+
* `length` (number) - Maximum number of words or characters and images to show.
229+
* `options` (table) - Optional table with options when truncating.
230+
231+
Available options in the `option` table are:
232+
233+
* `words` (boolean) - True if the function should truncate down to the nearest full word instead of truncating to a partial word.
229234

230235
**RETURNS**
231236
* `word` (table) - The last visible word.

example/example.gui_script

+16-3
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,24 @@ local function create_truncate_example()
7676
local settings = { position = vmath.vector3(0, 240, 0) }
7777
local words, metrics = richtext.create("This text should be shown one <img=smileys:cyclops/> at a time...", "Roboto-Regular", settings)
7878
local length = 0
79-
richtext.truncate(words, length)
79+
local max_length = #words
80+
local options = { words = true }
81+
richtext.truncate(words, length, options)
8082
timer.delay(0.1, true, function()
81-
length = (length + 1) % (metrics.char_count + 1)
83+
length = length + 1
84+
if length > max_length then
85+
-- alternate between truncating full words and per character
86+
if options.words then
87+
options.words = false
88+
max_length = metrics.char_count
89+
else
90+
options.words = true
91+
max_length = #words
92+
end
93+
length = 0
94+
end
8295

83-
local last_word = richtext.truncate(words, length)
96+
local last_word = richtext.truncate(words, length, options)
8497
local pos = vmath.vector3(settings.position)
8598
if last_word then
8699
pos = gui.get_position(last_word.node)

richtext/richtext.lua

+34-18
Original file line numberDiff line numberDiff line change
@@ -490,29 +490,45 @@ end
490490
-- and images are visible
491491
-- @param words List of words to truncate
492492
-- @param length Maximum number of characters to show
493-
function M.truncate(words, length)
493+
-- @param options Optional table with truncate options. Available options are: words
494+
-- @return Last visible word
495+
function M.truncate(words, length, options)
494496
assert(words)
495497
assert(length)
496-
local count = 0
497498
local last_visible_word = nil
498-
for i=1, #words do
499-
local word = words[i]
500-
local is_text_node = not word.image and not word.spine
501-
local word_length = is_text_node and utf8.len(word.text) or 1
502-
local visible = count < length
503-
last_visible_word = visible and word or last_visible_word
504-
gui.set_enabled(word.node, visible)
505-
if count < length and is_text_node then
506-
local text = word.text
507-
-- partial word?
508-
if count + word_length > length then
509-
local overflow = (count + word_length) - length
510-
text = utf8.sub(word.text, 1, word_length - overflow)
499+
if options and options.words then
500+
for i=1, #words do
501+
local word = words[i]
502+
local visible = i <= length
503+
if visible then
504+
last_visible_word = word
505+
end
506+
gui.set_enabled(word.node, visible)
507+
end
508+
else
509+
local count = 0
510+
for i=1, #words do
511+
local word = words[i]
512+
local is_text_node = not word.image and not word.spine
513+
local word_length = is_text_node and utf8.len(word.text) or 1
514+
local visible = count < length
515+
if visible then
516+
last_visible_word = word
517+
end
518+
gui.set_enabled(word.node, visible)
519+
if count < length and is_text_node then
520+
local text = word.text
521+
-- partial word?
522+
if count + word_length > length then
523+
-- remove overflowing characters from word
524+
local overflow = (count + word_length) - length
525+
text = utf8.sub(word.text, 1, word_length - overflow)
526+
end
527+
gui.set_text(word.node, text)
528+
word.metrics = get_text_metrics(word, word.font, text)
511529
end
512-
gui.set_text(word.node, text)
513-
word.metrics = get_text_metrics(word, word.font, text)
530+
count = count + word_length
514531
end
515-
count = count + word_length
516532
end
517533
return last_visible_word
518534
end

0 commit comments

Comments
 (0)