-- Copyright (c) 2022 Maksim Tuprikov . This code is licensed under MIT license --- Druid Rich Text Custom Component. -- # Overview # -- -- This custom component is inspired by defold-richtext by britzl. -- It uses a similar syntax for tags but currently supports fewer tags. -- -- Create Rich Text on your GUI Text Node. All properties of the text node will be used as default for the text. -- -- # Notes # -- -- • Nested tags are supported -- -- Example Link -- @usage -- local RichText = require("druid.custom.rich_text.rich_text") -- ... -- self.rich_text = self.druid:new(RichText, "rich_text") -- self.rich_text:set_text("Hello, Druid Rich Text!") -- @usage -- type druid.rich_text.word = { -- node: Node, -- relative_scale: number, -- color: vector4, -- position: vector3, -- offset: vector3, -- scale: vector3, -- size: vector3, -- metrics: druid.rich_text.metrics, -- pivot: Pivot, -- text: string, -- shadow: vector4, -- outline: vector4, -- font: string, -- image: druid.rich_text.image, -- br: boolean, -- nobr: boolean, -- } -- -- type druid.rich_text.word.image = { -- texture: string, -- anim: string, -- width: number, -- height: number, -- } -- -- type druid.rich_text.lines_metrics = { -- text_width: number, -- text_height: number, -- lines: table, -- } -- -- type druid.rich_text.metrics = { -- width: number, -- height: number, -- offset_x: number|nil, -- offset_y: number|nil, -- node_size: vector3|nil @For images only, -- } -- @module RichText -- @within BaseComponent -- @alias druid.rich_text --- The component druid instance -- @tfield DruidInstance druid DruidInstance --- The root node of the Rich Text -- @tfield node root --- The text prefab node -- @tfield node text_prefab -- local component = require("druid.component") local rich_text = require("druid.custom.rich_text.module.rt") ---@class druid.rich_text: druid.base_component ---@field root node ---@field text_prefab node ---@field private _last_value string ---@field private _settings table local M = component.create("rich_text") --- The RichText constructor -- @tparam RichText self RichText -- @tparam node|string text_node The text node to make Rich Text -- @tparam string|nil value The initial text value. Default will be gui.get_text(text_node) function M:init(text_node, value) self.root = self:get_node(text_node) self.text_prefab = self.root self._last_value = value or gui.get_text(self.text_prefab) self._settings = self:_create_settings() gui.set_text(self.root, "") if value then self:set_text(value) end end function M:on_layout_change() if self._last_value then self:set_text(self._last_value) end end --- Component style params. -- You can override this component styles params in Druid styles table -- or create your own style -- @table style -- @tfield table|nil COLORS Rich Text color aliases. Default: {} -- @tfield number|nil ADJUST_STEPS Amount steps of attemps text adjust by height. Default: 20 -- @tfield number|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02 function M:on_style_change(style) self.style = {} self.style.COLORS = style.COLORS or {} self.style.ADJUST_STEPS = style.ADJUST_STEPS or 20 self.style.ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02 end --- Set text for Rich Text -- @tparam RichText self RichText -- @tparam string|nil text The text to set -- @treturn druid.rich_text.word[] words -- @treturn druid.rich_text.lines_metrics line_metrics -- @usage -- • color: Change text color -- -- Foobar -- Foobar -- Foobar -- Foobar -- -- • shadow: Change text shadow -- -- Foobar -- Foobar -- Foobar -- Foobar -- -- • outline: Change text shadow -- -- Foobar -- Foobar -- Foobar -- Foobar -- -- • font: Change font -- -- Foobar -- -- • size: Change text size, relative to default size -- -- Twice as large -- -- • br: Insert a line break -- --
-- -- • nobr: Prevent the text from breaking -- -- Words inside tag won't break -- -- • img: Display image -- -- -- -- function M:set_text(text) text = text or "" self:clear() self._last_value = text local words, settings, line_metrics = rich_text.create(text, self._settings, self.style) line_metrics = rich_text.adjust_to_area(words, settings, line_metrics, self.style) self._words = words self._line_metrics = line_metrics return words, line_metrics end --- Get current text -- @tparam RichText self RichText -- @treturn string text function M:get_text() return self._last_value end function M:on_remove() gui.set_scale(self.root, self._default_scale) gui.set_size(self.root, self._default_size) self:clear() end --- Clear all created words. function M:clear() if self._words then rich_text.remove(self._words) self._words = nil end self._last_value = nil end --- Get all words, which has a passed tag. -- @tparam RichText self RichText -- @tparam string tag -- @treturn druid.rich_text.word[] words function M:tagged(tag) if not self._words then return end return rich_text.tagged(self._words, tag) end ---Split a word into it's characters -- @tparam RichText self RichText -- @tparam druid.rich_text.word word -- @treturn druid.rich_text.word[] characters function M:characters(word) return rich_text.characters(word) end --- Get all current words. -- @treturn table druid.rich_text.word[] function M:get_words() return self._words end --- Get current line metrics --- @treturn druid.rich_text.lines_metrics function M:get_line_metric() return self._line_metrics end function M:_create_settings() local root_size = gui.get_size(self.root) local scale = gui.get_scale(self.root) self._default_size = root_size self._default_scale = scale root_size.x = root_size.x * scale.x root_size.y = root_size.y * scale.y gui.set_size(self.root, root_size) gui.set_scale(self.root, vmath.vector3(1)) return { -- General settings -- Adjust scale using to fit the text to the root node area adjust_scale = 1, parent = self.root, scale = scale, width = root_size.x, height = root_size.y, combine_words = false, -- disabled now text_prefab = self.text_prefab, pivot = gui.get_pivot(self.root), -- Text Settings shadow = gui.get_shadow(self.root), outline = gui.get_outline(self.root), text_leading = gui.get_leading(self.root), is_multiline = gui.get_line_break(self.root), -- Image settings image_pixel_grid_snap = false, -- disabled now } end return M