diff --git a/druid/base/text.lua b/druid/base/text.lua
index 8981ccc..e4bdf4c 100755
--- a/druid/base/text.lua
+++ b/druid/base/text.lua
@@ -83,10 +83,12 @@ local function update_text_area_size(self)
scale_modifier = math.min(scale_modifier, self.start_scale.x)
if self:is_multiline() then
- local max_text_area_square = max_width * max_height
- local cur_text_area_square = metrics.height * metrics.width * self.start_scale.x
- scale_modifier = self.start_scale.x * math.sqrt(max_text_area_square / cur_text_area_square)
- scale_modifier = math.min(scale_modifier, self.start_scale.x)
+ local scale_modifier_by_height = math.sqrt(max_height / metrics.height)
+ scale_modifier = math.min(self.start_scale.y, scale_modifier_by_height)
+
+ if metrics.width * scale_modifier > max_width then
+ scale_modifier = math.min(max_width / metrics.width, self.start_scale.x)
+ end
end
if self._minimal_scale then
diff --git a/druid/custom/rich_text/rich_text.lua b/druid/custom/rich_text/rich_text.lua
index 5ba247b..5756cd4 100644
--- a/druid/custom/rich_text/rich_text.lua
+++ b/druid/custom/rich_text/rich_text.lua
@@ -12,14 +12,14 @@ local SCHEME = {
local ALIGN_MAP = {
[gui.PIVOT_CENTER] = { rich_text.ALIGN_CENTER, rich_text.VALIGN_MIDDLE },
- [gui.PIVOT_N] = { rich_text.ALIGN_CENTER, rich_text.VALIGN_TOP },
- [gui.PIVOT_S] = { rich_text.ALIGN_CENTER, rich_text.VALIGN_BOTTOM },
- [gui.PIVOT_NE] = { rich_text.ALIGN_RIGHT, rich_text.VALIGN_TOP },
- [gui.PIVOT_E] = { rich_text.ALIGN_RIGHT, rich_text.VALIGN_MIDDLE },
- [gui.PIVOT_SE] = { rich_text.ALIGN_RIGHT, rich_text.VALIGN_BOTTOM },
- [gui.PIVOT_SW] = { rich_text.ALIGN_LEFT, rich_text.VALIGN_BOTTOM },
- [gui.PIVOT_W] = { rich_text.ALIGN_LEFT, rich_text.VALIGN_MIDDLE },
- [gui.PIVOT_NW] = { rich_text.ALIGN_LEFT, rich_text.VALIGN_TOP },
+ [gui.PIVOT_N] = { rich_text.ALIGN_CENTER, rich_text.VALIGN_TOP },
+ [gui.PIVOT_S] = { rich_text.ALIGN_CENTER, rich_text.VALIGN_BOTTOM },
+ [gui.PIVOT_NE] = { rich_text.ALIGN_RIGHT, rich_text.VALIGN_TOP },
+ [gui.PIVOT_E] = { rich_text.ALIGN_RIGHT, rich_text.VALIGN_MIDDLE },
+ [gui.PIVOT_SE] = { rich_text.ALIGN_RIGHT, rich_text.VALIGN_BOTTOM },
+ [gui.PIVOT_SW] = { rich_text.ALIGN_LEFT, rich_text.VALIGN_BOTTOM },
+ [gui.PIVOT_W] = { rich_text.ALIGN_LEFT, rich_text.VALIGN_MIDDLE },
+ [gui.PIVOT_NW] = { rich_text.ALIGN_LEFT, rich_text.VALIGN_TOP },
}
@@ -28,6 +28,7 @@ function RichText:init(template, nodes)
self:set_nodes(nodes)
self.root = self:get_node(SCHEME.ROOT)
self.druid = self:get_druid()
+ self.root_size = gui.get_size(self.root)
self.text_prefab = self:get_node(SCHEME.TEXT_PREFAB)
self.icon_prefab = self:get_node(SCHEME.ICON_PREFAB)
@@ -42,11 +43,44 @@ end
function RichText:set_text(text)
self:_clean_words()
- pprint(self._settings)
+ local is_already_adjusted = self._settings.adjust_scale ~= 1
+
+ -- Make text singleline if prefab without line break
+ local is_multiline = gui.get_line_break(self.text_prefab)
+ if not is_multiline then
+ text = string.format("%s", text)
+ end
+
local words, metrics = rich_text.create(text, self._text_font, self._settings)
self._words = words
self._metrics = metrics
+
+ for _, word in ipairs(words) do
+ print(word.text)
+ end
+
+ if not is_multiline then
+ local scale_koef = self.root_size.x / self._metrics.width
+ self._settings.adjust_scale = math.min(scale_koef, 1)
+ else
+ local scale_koef = math.sqrt(self.root_size.y / self._metrics.height)
+ if self._metrics.width * scale_koef > self.root_size.x then
+ scale_koef = math.sqrt(self.root_size.x / self._metrics.width)
+ end
+ self._settings.adjust_scale = math.min(scale_koef, 1)
+ end
+
+ if not is_already_adjusted and self._settings.adjust_scale < 1 then
+ print("Again set text with adjusted scale", self._settings.adjust_scale)
+ self:set_text(text)
+ return
+ end
+
+ -- Align vertically, different behaviour from rich text
+ self:_align_vertically()
+
+ pprint(self._metrics)
end
@@ -56,17 +90,23 @@ end
function RichText:_get_settings()
- local root_size = gui.get_size(self.root)
local anchor = gui.get_pivot(self.root)
- pprint(ALIGN_MAP[anchor])
+ local align = ALIGN_MAP[anchor][1]
+ local valign = ALIGN_MAP[anchor][2]
+
return {
- width = root_size.x,
+ width = self.root_size.x,
parent = self.root,
color = gui.get_color(self.text_prefab),
shadow = gui.get_shadow(self.text_prefab),
outline = gui.get_outline(self.text_prefab),
- align = ALIGN_MAP[anchor][1],
- valign = ALIGN_MAP[anchor][2],
+ text_scale = gui.get_scale(self.text_prefab),
+ default_texture = gui.get_texture(self.icon_prefab),
+ default_anim = gui.get_flipbook(self.icon_prefab),
+ combine_words = true,
+ adjust_scale = 1,
+ align = align,
+ valign = valign,
}
end
@@ -82,4 +122,21 @@ function RichText:_clean_words()
end
+function RichText:_align_vertically()
+ local text_height = self._metrics.height
+ local offset = 0
+ if self._settings.valign == rich_text.VALIGN_MIDDLE then
+ offset = text_height * 0.5
+ end
+ if self._settings.valign == rich_text.VALIGN_BOTTOM then
+ offset = text_height
+ end
+
+ for _, word in ipairs(self._words) do
+ word.position.y = word.position.y + offset
+ gui.set_position(word.node, word.position)
+ end
+end
+
+
return RichText
diff --git a/druid/custom/rich_text/rich_text/parse.lua b/druid/custom/rich_text/rich_text/parse.lua
index 2c74f95..a68d581 100755
--- a/druid/custom/rich_text/rich_text/parse.lua
+++ b/druid/custom/rich_text/rich_text/parse.lua
@@ -115,7 +115,7 @@ function M.parse(text, default_settings)
local open_tags = {}
while true do
-- merge list of word settings from defaults and all open tags
- local word_settings = { tags = {}}
+ local word_settings = { tags = {} }
merge_tags(word_settings, default_settings)
for _,open_tag in ipairs(open_tags) do
merge_tags(word_settings, open_tag)
diff --git a/druid/custom/rich_text/rich_text/richtext.lua b/druid/custom/rich_text/rich_text/richtext.lua
index 03d21fc..89058bf 100755
--- a/druid/custom/rich_text/rich_text/richtext.lua
+++ b/druid/custom/rich_text/rich_text/richtext.lua
@@ -157,6 +157,7 @@ local function position_words(words, line_width, line_height, position, settings
else
gui.set_position(word.node, position)
end
+ word.position = vmath.vector3(position)
position.x = position.x + word.metrics.total_width + spacing
words[i] = nil
end
@@ -188,32 +189,34 @@ local function create_box_node(word)
local node = gui.new_box_node(V3_ZERO, V3_ZERO)
local word_image = word.image
local image_width = word_image.width
- local image_height = word_image.height
gui.set_id(node, new_id("box"))
+ gui.set_size_mode(node, gui.SIZE_MODE_AUTO)
+ gui.set_texture(node, word.image.texture or word.default_texture)
+ gui.play_flipbook(node, hash(word.image.anim or word.default_anim))
+
if image_width then
+ local image_size = gui.get_size(node)
gui.set_size_mode(node, gui.SIZE_MODE_MANUAL)
size_vector.x = image_width
- size_vector.y = image_height
+ -- Use height or autoscale to keep aspect ratio
+ size_vector.y = word_image.height or ((image_size.y / image_size.x) * image_width)
size_vector.z = 0
gui.set_size(node, size_vector)
- else
- gui.set_size_mode(node, gui.SIZE_MODE_AUTO)
end
- gui.set_texture(node, word.image.texture)
- local word_size = word.size
+
+ local word_size = word.size * word.adjust_scale
size_vector.x = word_size
size_vector.y = word_size
size_vector.z = word_size
- gui.set_scale(node, size_vector)
-
- gui.play_flipbook(node, hash(word.image.anim))
+ word.scale = vmath.vector3(size_vector)
+ gui.set_scale(node, word.scale)
-- get metrics of node based on image size
local size = gui.get_size(node)
local metrics = {}
- metrics.total_width = size.x * word.size
- metrics.width = size.x * word.size
- metrics.height = size.y * word.size
+ metrics.total_width = size.x * word.size * word.adjust_scale
+ metrics.width = size.x * word.size * word.adjust_scale
+ metrics.height = size.y * word.size * word.adjust_scale
return node, metrics
end
@@ -222,7 +225,8 @@ local function create_spine_node(word)
local node = gui.new_spine_node(V3_ZERO, word.spine.scene)
gui.set_id(node, new_id("spine"))
gui.set_size_mode(node, gui.SIZE_MODE_AUTO)
- gui.set_scale(node, vmath.vector3(word.size))
+ word.scale = vmath.vector3(word.size)
+ gui.set_scale(node, word.scale)
gui.play_spine_anim(node, word.spine.anim, gui.PLAYBACK_LOOP_FORWARD)
local size = gui.get_size(node)
@@ -243,11 +247,11 @@ local function get_text_metrics(word, font, text)
metrics = gui.get_text_metrics(font, "|")
metrics.width = 0
metrics.total_width = 0
- metrics.height = metrics.height * word.size
+ metrics.height = metrics.height * word.size * word.text_scale.y * word.adjust_scale
else
metrics = gui.get_text_metrics(font, text)
- metrics.width = metrics.width * word.size
- metrics.height = metrics.height * word.size
+ metrics.width = metrics.width * word.size * word.text_scale.x * word.adjust_scale
+ metrics.height = metrics.height * word.size * word.text_scale.y * word.adjust_scale
metrics.total_width = metrics.width
end
return metrics
@@ -261,7 +265,8 @@ local function create_text_node(word, font, metrics)
gui.set_color(node, word.color)
if word.shadow then gui.set_shadow(node, word.shadow) end
if word.outline then gui.set_outline(node, word.outline) end
- gui.set_scale(node, V3_ONE * word.size)
+ word.scale = word.text_scale * word.size * word.adjust_scale
+ gui.set_scale(node, word.scale)
metrics = metrics or get_text_metrics(word, font)
gui.set_size_mode(node, gui.SIZE_MODE_MANUAL)
@@ -312,6 +317,7 @@ 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)
@@ -320,7 +326,7 @@ local function split_word(word, font, max_width)
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
+ while split_index >= 1 do
one.text = utf8.sub(text, 1, split_index)
one.linebreak = true
metrics = get_text_metrics(one, font)
@@ -362,6 +368,9 @@ function M.create(text, font, settings)
settings.paragraph_spacing = settings.paragraph_spacing or 0.5
settings.image_pixel_grid_snap = settings.image_pixel_grid_snap or false
settings.combine_words = settings.combine_words or false
+ settings.text_scale = settings.text_scale or V3_ONE
+ settings.default_texture = settings.default_texture or nil
+ settings.default_anim = settings.default_anim or nil
if settings.align == M.ALIGN_JUSTIFY and not settings.width then
error("Width must be specified if text should be justified")
end
@@ -386,7 +395,14 @@ function M.create(text, font, settings)
shadow = settings.shadow,
outline = settings.outline,
font = font,
- size = settings.size
+ size = settings.size,
+ -- Autofill properties
+ text_scale = settings.text_scale,
+ adjust_scale = settings.adjust_scale, -- scale for content adjust to fit into root size
+ position = nil,
+ scale = nil,
+ default_texture = nil, -- for image only
+ default_anim = nil, -- for image only
}
local words = parser.parse(text, word_settings)
local text_metrics = {
@@ -406,6 +422,8 @@ function M.create(text, font, settings)
repeat
local word = words[i]
if word.image then
+ word.default_texture = settings.default_texture
+ word.default_anim = settings.default_anim
text_metrics.img_count = text_metrics.img_count + 1
elseif word.spine then
text_metrics.spine_count = text_metrics.spine_count + 1
@@ -680,7 +698,8 @@ function M.characters(word)
local sub_metrics = get_text_metrics(word, font, utf8.sub(word.text, 1, i))
position.x = position_x + sub_metrics.width - char.metrics.width
- gui.set_position(char.node, position)
+ char.position = vmath.vector3(position)
+ gui.set_position(char.node, char.position)
end
return chars
diff --git a/druid/custom/rich_text/rich_text/tags.lua b/druid/custom/rich_text/rich_text/tags.lua
index ded8372..eba23a0 100644
--- a/druid/custom/rich_text/rich_text/tags.lua
+++ b/druid/custom/rich_text/rich_text/tags.lua
@@ -97,9 +97,13 @@ M.register("img", function(params, settings)
width, params = split(params, ",")
height = split(params, ",")
local texture, anim = split(texture_and_anim, ":")
+ if not anim then
+ anim = texture
+ texture = nil
+ end
width = width and tonumber(width)
- height = height and tonumber(height) or width
+ height = height and tonumber(height)
settings.image = {
texture = texture,
diff --git a/example/examples/custom/rich_text/rich_text.gui b/example/examples/custom/rich_text/rich_text.gui
index 3c2643b..4e70236 100644
--- a/example/examples/custom/rich_text/rich_text.gui
+++ b/example/examples/custom/rich_text/rich_text.gui
@@ -84,8 +84,8 @@ nodes {
w: 1.0
}
scale {
- x: 1.0
- y: 1.0
+ x: 1.3
+ y: 1.3
z: 1.0
w: 1.0
}
@@ -126,8 +126,8 @@ nodes {
w: 1.0
}
scale {
- x: 1.0
- y: 1.0
+ x: 1.2
+ y: 1.2
z: 1.0
w: 1.0
}
@@ -149,7 +149,7 @@ nodes {
id: "rich_text/root"
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
- pivot: PIVOT_E
+ pivot: PIVOT_N
adjust_mode: ADJUST_MODE_FIT
parent: "rich_text"
layer: ""
@@ -164,6 +164,7 @@ nodes {
clipping_visible: true
clipping_inverted: false
alpha: 1.0
+ overridden_fields: 3
overridden_fields: 5
overridden_fields: 14
overridden_fields: 46
@@ -187,8 +188,8 @@ nodes {
w: 1.0
}
scale {
- x: 1.0
- y: 1.0
+ x: 0.8
+ y: 0.8
z: 1.0
w: 1.0
}
@@ -225,13 +226,15 @@ nodes {
w: 1.0
}
adjust_mode: ADJUST_MODE_FIT
- line_break: false
+ line_break: true
parent: "rich_text/root"
layer: ""
inherit_alpha: true
alpha: 1.0
outline_alpha: 1.0
shadow_alpha: 0.0
+ overridden_fields: 3
+ overridden_fields: 18
template_node_child: true
text_leading: 1.0
text_tracking: 0.0
@@ -297,6 +300,64 @@ nodes {
enabled: true
visible: true
}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 150.0
+ y: 4.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "middle_line"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.56
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+ enabled: true
+ visible: true
+}
layers {
name: "image"
}
diff --git a/example/examples/custom/rich_text/rich_text.gui_script b/example/examples/custom/rich_text/rich_text.gui_script
new file mode 100644
index 0000000..c6f6234
--- /dev/null
+++ b/example/examples/custom/rich_text/rich_text.gui_script
@@ -0,0 +1,34 @@
+local druid = require("druid.druid")
+
+local RichText = require("druid.custom.rich_text.rich_text")
+
+
+function init(self)
+ self.druid = druid.new(self)
+
+ self.rich_text = self.druid:new(RichText, "rich_text")
+ -- self.rich_text:set_text("Lorem long text with differrent placeholder or just text without any sense here to check multiline without long words")
+ -- self.rich_text:set_text("Lorem long text with differrent placeholder or just text without any sense here to check multiline without long wordswordwordwrodwrodwrodswrodword he")
+ self.rich_text:set_text("Some text with image
in the middle")
+ self.rich_text:set_text("Some text with image
in the middle")
+end
+
+
+function final(self)
+ self.druid:final()
+end
+
+
+function update(self, dt)
+ self.druid:update(dt)
+end
+
+
+function on_message(self, message_id, message, sender)
+ self.druid:on_message(message_id, message, sender)
+end
+
+
+function on_input(self, action_id, action)
+ return self.druid:on_input(action_id, action)
+end