135 lines
3.5 KiB
Lua

local helper = require("druid.helper")
local druid_const = require("druid.const")
---@class examples.hover_hint: druid.widget
---@field root node
---@field panel_hint node
---@field text_hint druid.text
---@field hovers druid.hover[]
---@field is_shown boolean
---@field private _hint_text string
---@field private _hover_timer_id hash
local M = {}
local TIMER_DELAY = 0.5
local MIN_PANEL_WIDTH = 100
local MIN_PANEL_HEIGHT = 50
local PANEL_MARGIN = 40
local HINT_OFFSET = 20
function M:init()
self.root = self:get_node("root")
self.panel_hint = self:get_node("panel_hint")
self.text_hint = self.druid:new_text("text_hint")
self.hovers = {}
self._timer_id = nil
self.is_shown = false
gui.set_enabled(self.root, false)
end
---@param node node|string
---@param hint_text string
---@param pivot_point constant
---@param content_pivot constant
function M:add_hover_hint(node, hint_text, pivot_point, content_pivot)
local hover = self.druid:new_hover(node, nil, function(_, is_hover)
self:hide_hint()
if is_hover then
self._timer_id = timer.delay(TIMER_DELAY, false, function()
self._timer_id = nil
self:show_hint(node, hint_text, pivot_point, content_pivot)
end)
end
end)
table.insert(self.hovers, hover)
end
function M:hide_hint()
if self._timer_id then
timer.cancel(self._timer_id)
self._timer_id = nil
end
if self.is_shown then
self.is_shown = false
gui.animate(self.root, "color.w", 0, gui.EASING_OUTSINE, 0.2, 0, function()
gui.set_enabled(self.root, false)
end)
end
end
---@param hint_text string
---@param pivot_point constant
---@param content_pivot constant
function M:show_hint(node, hint_text, pivot_point, content_pivot)
self:refresh_content(node, hint_text, pivot_point, content_pivot)
self.is_shown = true
do -- Animate appear
gui.set_enabled(self.root, true)
gui.set_alpha(self.root, 0)
gui.animate(self.root, "color.w", 1, gui.EASING_OUTSINE, 0.2)
end
end
---@private
function M:refresh_content(node, hint_text, pivot_point, content_pivot)
self.text_hint:set_text(hint_text)
local text_width, text_height = self.text_hint:get_text_size()
local panel_width = math.max(text_width, MIN_PANEL_WIDTH) + PANEL_MARGIN
local panel_height = math.max(text_height, MIN_PANEL_HEIGHT) + PANEL_MARGIN
gui.set(self.root, "size.x", panel_width)
gui.set(self.root, "size.y", panel_height)
gui.set(self.panel_hint, "size.x", panel_width)
gui.set(self.panel_hint, "size.y", panel_height)
self:refresh_position(node, pivot_point, content_pivot)
end
---@private
---@param node node
---@param pivot_point constant
---@param content_pivot constant
function M:refresh_position(node, pivot_point, content_pivot)
local screen_position = gui.get_screen_position(node)
local node_size = gui.get_size(node)
node_size.x = node_size.x + HINT_OFFSET * 2
node_size.y = node_size.y + HINT_OFFSET * 2
-- Offset for trigger node
local offset = -vmath.mul_per_elem(node_size, druid_const.PIVOTS[gui.get_pivot(node)])
-- Offset from center to pivot pointi
offset = offset + vmath.mul_per_elem(node_size, druid_const.PIVOTS[pivot_point])
-- Offset for hint component
local hint_size = gui.get_size(self.root)
offset = offset - vmath.mul_per_elem(hint_size, druid_const.PIVOTS[content_pivot])
-- Position
local world_scale = helper.get_scene_scale(self.root)
local local_pos = gui.screen_to_local(self.root, screen_position) / world_scale.x
gui.set_position(self.root, local_pos)
local position = gui.get_position(self.root)
if offset then
position = position + offset
end
gui.set_position(self.root, position)
end
return M