Skip to content

Commit

Permalink
Added support for vertically aligning the words on a line
Browse files Browse the repository at this point in the history
Fixes #55
  • Loading branch information
britzl committed Jul 4, 2020
1 parent 2abb584 commit a37aee4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 6 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ The `settings` table can contain the following values:
* `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 of `richtext.ALIGN_LEFT`, `richtext.ALIGN_CENTER`, `richtext.ALIGN_RIGHT` and `richtext.ALIGN_JUSTIFY`. Defaults to `richtext.ALIGN_LEFT`. Defines how the words of a line of text are positioned in relation the provided `position`. Width must be specified for `richtext.ALIGN_JUSTIFY`.
* `valign` (hash) - One of `richtext.VALIGN_TOP`, `richtext.VALIGN_MIDDLE` and `richtext.VALIGN_BOTTOM`. Defaults to `richtext.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.
Expand Down Expand Up @@ -280,10 +281,20 @@ Center text. The words of a line are centered on the specified position (see `ri
### richtext.ALIGN_RIGHT
Right-align text. The words of a line ends at the specified position (see `richtext.create` settings above).

### richtext.ALIGN_JUSTIFT
### richtext.ALIGN_JUSTIFY
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).


### richtext.VALIGN_TOP
Vertically align the words on a line so that the top of the words on the line align.

### richtext.VALIGN_MIDDLE
Vertically align the words on a line so that the middle of the words on the line align.

### richtext.VALIGN_BOTTOM
Vertically align the words on a line so that the bottom of the words on the line align.


# Credits
* Smiley icons in example app from [Flaticons](https://www.flaticon.com/packs/smileys-3)
* UTF8 decoding from [utf8.lua](https://github.com/Stepets/utf8.lua)
34 changes: 29 additions & 5 deletions richtext/richtext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ M.ALIGN_LEFT = hash("ALIGN_LEFT")
M.ALIGN_RIGHT = hash("ALIGN_RIGHT")
M.ALIGN_JUSTIFY = hash("ALIGN_JUSTIFY")

M.VALIGN_TOP = hash("VALIGN_TOP")
M.VALIGN_MIDDLE = hash("VALIGN_MIDDLE")
M.VALIGN_BOTTOM = hash("VALIGN_BOTTOM")


local V4_ZERO = vmath.vector4(0)
local V4_ONE = vmath.vector4(1)
Expand Down Expand Up @@ -277,7 +281,6 @@ local function create_node(word, parent, font, node, metrics)
else
node, metrics = create_text_node(word, font, metrics)
end
gui.set_pivot(node, gui.PIVOT_NW)
gui.set_parent(node, parent)
gui.set_inherit_alpha(node, true)
return node, metrics
Expand Down Expand Up @@ -312,6 +315,7 @@ function M.create(text, font, settings)
assert(font, "You must provide a font")
settings = settings or {}
settings.align = settings.align or M.ALIGN_LEFT
settings.valign = settings.valign or M.VALIGN_TOP
settings.fonts = settings.fonts or {}
settings.fonts[font] = settings.fonts[font] or { regular = hash(font) }
settings.layers = settings.layers or {}
Expand All @@ -329,7 +333,20 @@ function M.create(text, font, settings)
if settings.align == M.ALIGN_JUSTIFY and not settings.width then
error("Width must be specified if text should be justified")
end


local line_increment_before = 0
local line_increment_after = 1
local pivot = gui.PIVOT_NW
if settings.valign == M.VALIGN_MIDDLE then
line_increment_before = 0.5
line_increment_after = 0.5
pivot = gui.PIVOT_W
elseif settings.valign == M.VALIGN_BOTTOM then
line_increment_before = 1
line_increment_after = 0
pivot = gui.PIVOT_SW
end

-- default settings for a word
-- will be assigned to each word unless tags override the values
local word_settings = {
Expand Down Expand Up @@ -380,6 +397,7 @@ function M.create(text, font, settings)

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)
position.x = settings.position.x
position.y = settings.position.y - text_metrics.height
position_words(line_words, line_width, line_height, position, settings)
Expand All @@ -389,7 +407,7 @@ function M.create(text, font, settings)

-- update text metrics
text_metrics.width = math.max(text_metrics.width, line_width)
text_metrics.height = text_metrics.height + (line_height * settings.line_spacing) + paragraph_spacing
text_metrics.height = text_metrics.height + (line_height * line_increment_after * settings.line_spacing) + paragraph_spacing
line_width = word_metrics.total_width
line_height = word_metrics.height
paragraph_spacing = 0
Expand All @@ -410,6 +428,7 @@ function M.create(text, font, settings)

if should_create_node then
word.node, word.metrics = create_node(word, settings.parent, font_for_word, node, word_metrics)
gui.set_pivot(word.node, pivot)

-- assign layer
local layer = get_layer(word, settings.layers)
Expand All @@ -434,12 +453,13 @@ function M.create(text, font, settings)
-- handle line break
if word.linebreak then
-- position all words on the line up until the linebreak
text_metrics.height = text_metrics.height + (line_height * line_increment_before * settings.line_spacing)
position.x = settings.position.x
position.y = settings.position.y - text_metrics.height
position_words(line_words, line_width, line_height, position, settings)

-- update text metrics
text_metrics.height = text_metrics.height + (line_height * settings.line_spacing) + paragraph_spacing
text_metrics.height = text_metrics.height + (line_height * line_increment_after * settings.line_spacing) + paragraph_spacing
line_height = word_metrics.height
line_width = 0
paragraph_spacing = 0
Expand All @@ -448,10 +468,11 @@ function M.create(text, font, settings)

-- position remaining words
if #line_words > 0 then
text_metrics.height = text_metrics.height + (line_height * line_increment_before * settings.line_spacing)
position.x = settings.position.x
position.y = settings.position.y - text_metrics.height
position_words(line_words, line_width, line_height, position, settings)
text_metrics.height = text_metrics.height + line_height
text_metrics.height = text_metrics.height + (line_height * line_increment_after * settings.line_spacing)
end

-- compact words table
Expand Down Expand Up @@ -571,13 +592,15 @@ function M.characters(word)
local parent = gui.get_parent(word.node)
local font = gui.get_font(word.node)
local layer = gui.get_layer(word.node)
local pivot = gui.get_pivot(word.node)

local word_length = utf8.len(word.text)

-- exit early if word is a single character or empty
if word_length <= 1 then
local char = deepcopy(word)
char.node, char.metrics = create_node(char, parent, font)
gui.set_pivot(char.node, pivot)
gui.set_position(char.node, gui.get_position(word.node))
gui.set_layer(char.node, layer)
return { char }
Expand All @@ -594,6 +617,7 @@ function M.characters(word)
char.text = utf8.sub(word.text, i, i)
char.node, char.metrics = create_node(char, parent, font)
gui.set_layer(char.node, layer)
gui.set_pivot(char.node, pivot)

local sub_metrics = get_text_metrics(word, font, utf8.sub(word.text, 1, i))
position.x = position_x + sub_metrics.width - char.metrics.width
Expand Down

0 comments on commit a37aee4

Please sign in to comment.