mirror of
https://github.com/Insality/druid.git
synced 2025-06-27 10:27:47 +02:00
Update
This commit is contained in:
parent
d6bec60ba9
commit
46223f0bb8
@ -39,23 +39,6 @@ local component = require("druid.component")
|
||||
local M = component.create("button")
|
||||
|
||||
|
||||
---@param style druid.button.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
LONGTAP_TIME = style.LONGTAP_TIME or 0.4,
|
||||
AUTOHOLD_TRIGGER = style.AUTOHOLD_TRIGGER or 0.8,
|
||||
DOUBLETAP_TIME = style.DOUBLETAP_TIME or 0.4,
|
||||
|
||||
on_click = style.on_click or function(_, node) end,
|
||||
on_click_disabled = style.on_click_disabled or function(_, node) end,
|
||||
on_mouse_hover = style.on_mouse_hover or function(_, node, state) end,
|
||||
on_hover = style.on_hover or function(_, node, state) end,
|
||||
on_set_enabled = style.on_set_enabled or function(_, node, state) end,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---Button constructor
|
||||
---@param node_or_node_id node|string Node name or GUI Node itself
|
||||
---@param callback fun()|nil Callback on button click
|
||||
---@param custom_args any|nil Custom args for any Button event
|
||||
@ -94,6 +77,22 @@ function M:init(node_or_node_id, callback, custom_args, anim_node)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.button.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
LONGTAP_TIME = style.LONGTAP_TIME or 0.4,
|
||||
AUTOHOLD_TRIGGER = style.AUTOHOLD_TRIGGER or 0.8,
|
||||
DOUBLETAP_TIME = style.DOUBLETAP_TIME or 0.4,
|
||||
|
||||
on_click = style.on_click or function(_, node) end,
|
||||
on_click_disabled = style.on_click_disabled or function(_, node) end,
|
||||
on_mouse_hover = style.on_mouse_hover or function(_, node, state) end,
|
||||
on_hover = style.on_hover or function(_, node, state) end,
|
||||
on_set_enabled = style.on_set_enabled or function(_, node, state) end,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function M:on_late_init()
|
||||
if not self.click_zone then
|
||||
local stencil_node = helper.get_closest_stencil_node(self.node)
|
||||
|
@ -34,129 +34,6 @@ local component = require("druid.component")
|
||||
local M = component.create("drag", const.PRIORITY_INPUT_HIGH)
|
||||
|
||||
|
||||
local function start_touch(self, touch)
|
||||
self.is_touch = true
|
||||
self.is_drag = false
|
||||
|
||||
self.touch_start_pos.x = touch.x
|
||||
self.touch_start_pos.y = touch.y
|
||||
|
||||
self.x = touch.x
|
||||
self.y = touch.y
|
||||
|
||||
self.screen_x = touch.screen_x
|
||||
self.screen_y = touch.screen_y
|
||||
|
||||
self._scene_scale = helper.get_scene_scale(self.node)
|
||||
|
||||
self.on_touch_start:trigger(self:get_context(), touch)
|
||||
end
|
||||
|
||||
|
||||
local function end_touch(self, touch)
|
||||
if self.is_drag then
|
||||
self.on_drag_end:trigger(
|
||||
self:get_context(),
|
||||
self.x - self.touch_start_pos.x,
|
||||
self.y - self.touch_start_pos.y,
|
||||
touch
|
||||
)
|
||||
end
|
||||
|
||||
self.is_drag = false
|
||||
if self.is_touch then
|
||||
self.is_touch = false
|
||||
self.on_touch_end:trigger(self:get_context(), touch)
|
||||
end
|
||||
self:reset_input_priority()
|
||||
self.touch_id = 0
|
||||
end
|
||||
|
||||
|
||||
local function process_touch(self, touch)
|
||||
if not self.can_x then
|
||||
self.touch_start_pos.x = touch.x
|
||||
end
|
||||
|
||||
if not self.can_y then
|
||||
self.touch_start_pos.y = touch.y
|
||||
end
|
||||
|
||||
local distance = helper.distance(touch.x, touch.y, self.touch_start_pos.x, self.touch_start_pos.y)
|
||||
if not self.is_drag and distance >= self.style.DRAG_DEADZONE then
|
||||
self.is_drag = true
|
||||
self.on_drag_start:trigger(self:get_context(), touch)
|
||||
self:set_input_priority(const.PRIORITY_INPUT_MAX, true)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---Return current touch action from action input data
|
||||
---If touch_id stored - return exact this touch action
|
||||
---@param action_id hash Action id from on_input
|
||||
---@param action table Action from on_input
|
||||
---@param touch_id number Touch id
|
||||
---@return table|nil Touch action
|
||||
local function find_touch(action_id, action, touch_id)
|
||||
local act = helper.is_mobile() and const.ACTION_MULTITOUCH or const.ACTION_TOUCH
|
||||
|
||||
if action_id ~= act then
|
||||
return
|
||||
end
|
||||
|
||||
if action.touch then
|
||||
local touch = action.touch
|
||||
for i = 1, #touch do
|
||||
if touch[i].id == touch_id then
|
||||
return touch[i]
|
||||
end
|
||||
end
|
||||
return touch[1]
|
||||
else
|
||||
return action
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---Process on touch release. We should to find, if any other
|
||||
---touches exists to switch to another touch.
|
||||
---@param self druid.drag
|
||||
---@param action_id hash Action id from on_input
|
||||
---@param action table Action from on_input
|
||||
local function on_touch_release(self, action_id, action)
|
||||
if #action.touch >= 2 then
|
||||
-- Find next unpressed touch
|
||||
local next_touch
|
||||
for i = 1, #action.touch do
|
||||
if not action.touch[i].released then
|
||||
next_touch = action.touch[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if next_touch then
|
||||
self.x = next_touch.x
|
||||
self.y = next_touch.y
|
||||
self.touch_id = next_touch.id
|
||||
else
|
||||
end_touch(self)
|
||||
end
|
||||
elseif #action.touch == 1 then
|
||||
end_touch(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.drag.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
DRAG_DEADZONE = style.DRAG_DEADZONE or 10,
|
||||
NO_USE_SCREEN_KOEF = style.NO_USE_SCREEN_KOEF or false,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---Drag constructor
|
||||
---@param node_or_node_id node|string
|
||||
---@param on_drag_callback function
|
||||
function M:init(node_or_node_id, on_drag_callback)
|
||||
@ -193,6 +70,15 @@ function M:init(node_or_node_id, on_drag_callback)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.drag.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
DRAG_DEADZONE = style.DRAG_DEADZONE or 10,
|
||||
NO_USE_SCREEN_KOEF = style.NO_USE_SCREEN_KOEF or false,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---Set Drag component enabled state.
|
||||
---@param is_enabled boolean
|
||||
function M:set_drag_cursors(is_enabled)
|
||||
@ -226,12 +112,11 @@ end
|
||||
|
||||
function M:on_input_interrupt()
|
||||
if self.is_drag or self.is_touch then
|
||||
end_touch(self)
|
||||
self:_end_touch()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@local
|
||||
---@param action_id hash
|
||||
---@param action table
|
||||
function M:on_input(action_id, action)
|
||||
@ -245,12 +130,12 @@ function M:on_input(action_id, action)
|
||||
|
||||
local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone)
|
||||
if not is_pick and not self.is_drag then
|
||||
end_touch(self)
|
||||
self:_end_touch()
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
local touch = find_touch(action_id, action, self.touch_id)
|
||||
local touch = self:_find_touch(action_id, action, self.touch_id)
|
||||
if not touch then
|
||||
return false
|
||||
end
|
||||
@ -263,24 +148,24 @@ function M:on_input(action_id, action)
|
||||
self.dy = 0
|
||||
|
||||
if touch.pressed and not self.is_touch then
|
||||
start_touch(self, touch)
|
||||
self:_start_touch(touch)
|
||||
end
|
||||
|
||||
if touch.released and self.is_touch then
|
||||
if action.touch then
|
||||
-- Mobile
|
||||
on_touch_release(self, action_id, action)
|
||||
self:_on_touch_release(action_id, action)
|
||||
else
|
||||
-- PC
|
||||
end_touch(self, touch)
|
||||
self:_end_touch(touch)
|
||||
end
|
||||
end
|
||||
|
||||
if self.is_touch then
|
||||
process_touch(self, touch)
|
||||
self:_process_touch(touch)
|
||||
end
|
||||
|
||||
local touch_modified = find_touch(action_id, action, self.touch_id)
|
||||
local touch_modified = self:_find_touch(action_id, action, self.touch_id)
|
||||
if touch_modified and self.is_drag then
|
||||
self.dx = touch_modified.x - self.x
|
||||
self.dy = touch_modified.y - self.y
|
||||
@ -338,4 +223,118 @@ function M:is_enabled()
|
||||
end
|
||||
|
||||
|
||||
function M:_start_touch(touch)
|
||||
self.is_touch = true
|
||||
self.is_drag = false
|
||||
|
||||
self.touch_start_pos.x = touch.x
|
||||
self.touch_start_pos.y = touch.y
|
||||
|
||||
self.x = touch.x
|
||||
self.y = touch.y
|
||||
|
||||
self.screen_x = touch.screen_x
|
||||
self.screen_y = touch.screen_y
|
||||
|
||||
self._scene_scale = helper.get_scene_scale(self.node)
|
||||
|
||||
self.on_touch_start:trigger(self:get_context(), touch)
|
||||
end
|
||||
|
||||
|
||||
---@param touch touch|nil
|
||||
function M:_end_touch(touch)
|
||||
if self.is_drag then
|
||||
self.on_drag_end:trigger(
|
||||
self:get_context(),
|
||||
self.x - self.touch_start_pos.x,
|
||||
self.y - self.touch_start_pos.y,
|
||||
touch
|
||||
)
|
||||
end
|
||||
|
||||
self.is_drag = false
|
||||
if self.is_touch then
|
||||
self.is_touch = false
|
||||
self.on_touch_end:trigger(self:get_context(), touch)
|
||||
end
|
||||
self:reset_input_priority()
|
||||
self.touch_id = 0
|
||||
end
|
||||
|
||||
|
||||
---@param touch touch
|
||||
function M:_process_touch(touch)
|
||||
if not self.can_x then
|
||||
self.touch_start_pos.x = touch.x
|
||||
end
|
||||
|
||||
if not self.can_y then
|
||||
self.touch_start_pos.y = touch.y
|
||||
end
|
||||
|
||||
local distance = helper.distance(touch.x, touch.y, self.touch_start_pos.x, self.touch_start_pos.y)
|
||||
if not self.is_drag and distance >= self.style.DRAG_DEADZONE then
|
||||
self.is_drag = true
|
||||
self.on_drag_start:trigger(self:get_context(), touch)
|
||||
self:set_input_priority(const.PRIORITY_INPUT_MAX, true)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---Return current touch action from action input data
|
||||
---If touch_id stored - return exact this touch action
|
||||
---@param action_id hash Action id from on_input
|
||||
---@param action table Action from on_input
|
||||
---@param touch_id number Touch id
|
||||
---@return table|nil Touch action
|
||||
function M:_find_touch(action_id, action, touch_id)
|
||||
local act = helper.is_mobile() and const.ACTION_MULTITOUCH or const.ACTION_TOUCH
|
||||
|
||||
if action_id ~= act then
|
||||
return
|
||||
end
|
||||
|
||||
if action.touch then
|
||||
local touch = action.touch
|
||||
for i = 1, #touch do
|
||||
if touch[i].id == touch_id then
|
||||
return touch[i]
|
||||
end
|
||||
end
|
||||
return touch[1]
|
||||
else
|
||||
return action
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---Process on touch release. We should to find, if any other
|
||||
---touches exists to switch to another touch.
|
||||
---@param action_id hash Action id from on_input
|
||||
---@param action table Action from on_input
|
||||
function M:_on_touch_release(action_id, action)
|
||||
if #action.touch >= 2 then
|
||||
-- Find next unpressed touch
|
||||
local next_touch
|
||||
for i = 1, #action.touch do
|
||||
if not action.touch[i].released then
|
||||
next_touch = action.touch[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if next_touch then
|
||||
self.x = next_touch.x
|
||||
self.y = next_touch.y
|
||||
self.touch_id = next_touch.id
|
||||
else
|
||||
self:_end_touch()
|
||||
end
|
||||
elseif #action.touch == 1 then
|
||||
self:_end_touch()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
@ -46,59 +46,6 @@ local component = require("druid.component")
|
||||
local M = component.create("scroll")
|
||||
|
||||
|
||||
local function inverse_lerp(min, max, current)
|
||||
return helper.clamp((current - min) / (max - min), 0, 1)
|
||||
end
|
||||
|
||||
|
||||
---Update vector with next conditions:
|
||||
-- Field x have to <= field z
|
||||
-- Field y have to <= field w
|
||||
local function get_border_vector(vector, offset)
|
||||
if vector.x > vector.z then
|
||||
vector.x, vector.z = vector.z, vector.x
|
||||
end
|
||||
if vector.y > vector.w then
|
||||
vector.y, vector.w = vector.w, vector.y
|
||||
end
|
||||
vector.x = vector.x - offset.x
|
||||
vector.z = vector.z - offset.x
|
||||
vector.y = vector.y - offset.y
|
||||
vector.w = vector.w - offset.y
|
||||
return vector
|
||||
end
|
||||
|
||||
|
||||
---Return size from scroll border vector4
|
||||
local function get_size_vector(vector)
|
||||
return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.scroll.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {}
|
||||
self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0
|
||||
self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2
|
||||
self.style.BACK_SPEED = style.BACK_SPEED or 0.35
|
||||
|
||||
self.style.FRICT = style.FRICT or 0
|
||||
self.style.FRICT_HOLD = style.FRICT_HOLD or 0
|
||||
|
||||
self.style.INERT_THRESHOLD = style.INERT_THRESHOLD or 3
|
||||
self.style.INERT_SPEED = style.INERT_SPEED or 30
|
||||
self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20
|
||||
self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false
|
||||
self.style.WHEEL_SCROLL_SPEED = style.WHEEL_SCROLL_SPEED or 0
|
||||
self.style.WHEEL_SCROLL_INVERTED = style.WHEEL_SCROLL_INVERTED or false
|
||||
self.style.WHEEL_SCROLL_BY_INERTION = style.WHEEL_SCROLL_BY_INERTION or false
|
||||
|
||||
self._is_inert = not (self.style.FRICT == 0 or
|
||||
self.style.FRICT_HOLD == 0 or
|
||||
self.style.INERT_SPEED == 0)
|
||||
end
|
||||
|
||||
|
||||
---The Scroll constructor
|
||||
---@param view_node string|node GUI view scroll node
|
||||
---@param content_node string|node GUI content scroll node
|
||||
@ -140,6 +87,30 @@ function M:init(view_node, content_node)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.scroll.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {}
|
||||
self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0
|
||||
self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2
|
||||
self.style.BACK_SPEED = style.BACK_SPEED or 0.35
|
||||
|
||||
self.style.FRICT = style.FRICT or 0
|
||||
self.style.FRICT_HOLD = style.FRICT_HOLD or 0
|
||||
|
||||
self.style.INERT_THRESHOLD = style.INERT_THRESHOLD or 3
|
||||
self.style.INERT_SPEED = style.INERT_SPEED or 30
|
||||
self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20
|
||||
self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false
|
||||
self.style.WHEEL_SCROLL_SPEED = style.WHEEL_SCROLL_SPEED or 0
|
||||
self.style.WHEEL_SCROLL_INVERTED = style.WHEEL_SCROLL_INVERTED or false
|
||||
self.style.WHEEL_SCROLL_BY_INERTION = style.WHEEL_SCROLL_BY_INERTION or false
|
||||
|
||||
self._is_inert = not (self.style.FRICT == 0 or
|
||||
self.style.FRICT_HOLD == 0 or
|
||||
self.style.INERT_SPEED == 0)
|
||||
end
|
||||
|
||||
|
||||
function M:on_late_init()
|
||||
if not self.click_zone then
|
||||
local stencil_node = helper.get_closest_stencil_node(self.node)
|
||||
@ -260,8 +231,8 @@ end
|
||||
-- Values will be in [0..1] interval
|
||||
---@return vector3 New vector with scroll progress values
|
||||
function M:get_percent()
|
||||
local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x)
|
||||
local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y)
|
||||
local x_perc = 1 - self:_inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x)
|
||||
local y_perc = self:_inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y)
|
||||
|
||||
return vmath.vector3(x_perc, y_perc, 0)
|
||||
end
|
||||
@ -470,11 +441,11 @@ function M:_on_scroll_drag(dx, dy)
|
||||
|
||||
-- Right border (minimum x)
|
||||
if t.x < b.x and dx < 0 then
|
||||
x_perc = inverse_lerp(eb.x, b.x, t.x)
|
||||
x_perc = self:_inverse_lerp(eb.x, b.x, t.x)
|
||||
end
|
||||
-- Left border (maximum x)
|
||||
if t.x > b.z and dx > 0 then
|
||||
x_perc = inverse_lerp(eb.z, b.z, t.x)
|
||||
x_perc = self:_inverse_lerp(eb.z, b.z, t.x)
|
||||
end
|
||||
-- Disable x scroll
|
||||
if not self.drag.can_x then
|
||||
@ -483,11 +454,11 @@ function M:_on_scroll_drag(dx, dy)
|
||||
|
||||
-- Top border (minimum y)
|
||||
if t.y < b.y and dy < 0 then
|
||||
y_perc = inverse_lerp(eb.y, b.y, t.y)
|
||||
y_perc = self:_inverse_lerp(eb.y, b.y, t.y)
|
||||
end
|
||||
-- Bot border (maximum y)
|
||||
if t.y > b.w and dy > 0 then
|
||||
y_perc = inverse_lerp(eb.w, b.w, t.y)
|
||||
y_perc = self:_inverse_lerp(eb.w, b.w, t.y)
|
||||
end
|
||||
-- Disable y scroll
|
||||
if not self.drag.can_y then
|
||||
@ -692,8 +663,8 @@ function M:_update_size()
|
||||
local content_border = helper.get_border(self.content_node)
|
||||
local content_size = helper.get_scaled_size(self.content_node)
|
||||
|
||||
self.available_pos = get_border_vector(self.view_border - content_border, self._offset)
|
||||
self.available_size = get_size_vector(self.available_pos)
|
||||
self.available_pos = self:_get_border_vector(self.view_border - content_border, self._offset)
|
||||
self.available_size = self:_get_size_vector(self.available_pos)
|
||||
|
||||
self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll
|
||||
self.drag.can_y = self.available_size.y > 0 and self._is_vertical_scroll
|
||||
@ -717,8 +688,8 @@ function M:_update_size()
|
||||
self.drag.can_y = content_size.y > self.view_size.y and self._is_vertical_scroll
|
||||
end
|
||||
|
||||
self.available_pos_extra = get_border_vector(self.view_border - content_border_extra, self._offset)
|
||||
self.available_size_extra = get_size_vector(self.available_pos_extra)
|
||||
self.available_pos_extra = self:_get_border_vector(self.view_border - content_border_extra, self._offset)
|
||||
self.available_size_extra = self:_get_size_vector(self.available_pos_extra)
|
||||
|
||||
self:_set_scroll_position(self.position.x, self.position.y)
|
||||
self.target_position.x = self.position.x
|
||||
@ -770,4 +741,35 @@ function M:_on_mouse_hover(state)
|
||||
end
|
||||
|
||||
|
||||
function M:_inverse_lerp(min, max, current)
|
||||
return helper.clamp((current - min) / (max - min), 0, 1)
|
||||
end
|
||||
|
||||
|
||||
---Update vector with next conditions:
|
||||
---Field x have to <= field z
|
||||
---Field y have to <= field w
|
||||
function M:_get_border_vector(vector, offset)
|
||||
if vector.x > vector.z then
|
||||
vector.x, vector.z = vector.z, vector.x
|
||||
end
|
||||
if vector.y > vector.w then
|
||||
vector.y, vector.w = vector.w, vector.y
|
||||
end
|
||||
vector.x = vector.x - offset.x
|
||||
vector.z = vector.z - offset.x
|
||||
vector.y = vector.y - offset.y
|
||||
vector.w = vector.w - offset.y
|
||||
return vector
|
||||
end
|
||||
|
||||
|
||||
---Return size from scroll border vector4
|
||||
---@param vector vector4
|
||||
---@return vector3
|
||||
function M:_get_size_vector(vector)
|
||||
return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0)
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
@ -26,28 +26,6 @@ local component = require("druid.component")
|
||||
local M = component.create("grid")
|
||||
|
||||
|
||||
local function _extend_border(border, pos, size, pivot)
|
||||
local left = pos.x - size.x/2 - (size.x * pivot.x)
|
||||
local right = pos.x + size.x/2 - (size.x * pivot.x)
|
||||
local top = pos.y + size.y/2 - (size.y * pivot.y)
|
||||
local bottom = pos.y - size.y/2 - (size.y * pivot.y)
|
||||
|
||||
border.x = math.min(border.x, left)
|
||||
border.y = math.max(border.y, top)
|
||||
border.z = math.max(border.z, right)
|
||||
border.w = math.min(border.w, bottom)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.grid.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
IS_DYNAMIC_NODE_POSES = style.IS_DYNAMIC_NODE_POSES or false,
|
||||
IS_ALIGN_LAST_ROW = style.IS_ALIGN_LAST_ROW or false,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---@param parent string|node The GUI Node container, where grid's items will be placed
|
||||
---@param element node Element prefab. Need to get it size
|
||||
---@param in_row number|nil How many nodes in row can be placed. By default 1
|
||||
@ -82,6 +60,15 @@ function M:init(parent, element, in_row)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.grid.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
IS_DYNAMIC_NODE_POSES = style.IS_DYNAMIC_NODE_POSES or false,
|
||||
IS_ALIGN_LAST_ROW = style.IS_ALIGN_LAST_ROW or false,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
local _temp_pos = vmath.vector3(0)
|
||||
---Return pos for grid node index
|
||||
---@param index number The grid element index
|
||||
@ -257,10 +244,10 @@ function M:get_size_for(count)
|
||||
|
||||
local size = self.node_size
|
||||
local pivot = self.node_pivot
|
||||
_extend_border(border, self:get_pos(1), size, pivot)
|
||||
_extend_border(border, self:get_pos(count), size, pivot)
|
||||
self:_extend_border(border, self:get_pos(1), size, pivot)
|
||||
self:_extend_border(border, self:get_pos(count), size, pivot)
|
||||
if count >= self.in_row then
|
||||
_extend_border(border, self:get_pos(self.in_row), size, pivot)
|
||||
self:_extend_border(border, self:get_pos(self.in_row), size, pivot)
|
||||
end
|
||||
|
||||
return vmath.vector3(
|
||||
@ -425,7 +412,7 @@ function M:_update_borders()
|
||||
local size = self.node_size
|
||||
local pivot = self.node_pivot
|
||||
for index, node in pairs(self.nodes) do
|
||||
_extend_border(self.border, self:get_pos(index), size, pivot)
|
||||
self:_extend_border(self.border, self:get_pos(index), size, pivot)
|
||||
end
|
||||
end
|
||||
|
||||
@ -453,7 +440,7 @@ end
|
||||
|
||||
|
||||
---Return elements offset for correct posing nodes. Correct posing at
|
||||
-- parent pivot node (0:0) with adjusting of node sizes and anchoring
|
||||
---parent pivot node (0:0) with adjusting of node sizes and anchoring
|
||||
---@return vector3 The offset vector
|
||||
---@private
|
||||
function M:_get_zero_offset()
|
||||
@ -491,4 +478,21 @@ function M:_get_zero_offset_x(row_index)
|
||||
end
|
||||
|
||||
|
||||
---@param border vector4 Will be updated with new border values
|
||||
---@param pos vector3
|
||||
---@param size vector3
|
||||
---@param pivot vector3
|
||||
function M:_extend_border(border, pos, size, pivot)
|
||||
local left = pos.x - size.x/2 - (size.x * pivot.x)
|
||||
local right = pos.x + size.x/2 - (size.x * pivot.x)
|
||||
local top = pos.y + size.y/2 - (size.y * pivot.y)
|
||||
local bottom = pos.y - size.y/2 - (size.y * pivot.y)
|
||||
|
||||
border.x = math.min(border.x, left)
|
||||
border.y = math.max(border.y, top)
|
||||
border.z = math.max(border.z, right)
|
||||
border.w = math.min(border.w, bottom)
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
@ -22,227 +22,6 @@ local utf8 = utf8 or utf8_lua --[[@as utf8]]
|
||||
---@field private scale vector3
|
||||
local M = component.create("text")
|
||||
|
||||
local function update_text_size(self)
|
||||
if self.scale.x == 0 or self.scale.y == 0 then
|
||||
return
|
||||
end
|
||||
if self.start_scale.x == 0 or self.start_scale.y == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local size = vmath.vector3(
|
||||
self.start_size.x * (self.start_scale.x / self.scale.x),
|
||||
self.start_size.y * (self.start_scale.y / self.scale.y),
|
||||
self.start_size.z
|
||||
)
|
||||
gui.set_size(self.node, size)
|
||||
end
|
||||
|
||||
|
||||
---Reset initial scale for text
|
||||
local function reset_default_scale(self)
|
||||
self.scale.x = self.start_scale.x
|
||||
self.scale.y = self.start_scale.y
|
||||
self.scale.z = self.start_scale.z
|
||||
gui.set_scale(self.node, self.start_scale)
|
||||
gui.set_size(self.node, self.start_size)
|
||||
end
|
||||
|
||||
|
||||
local function is_fit_info_area(self, metrics)
|
||||
return metrics.width * self.scale.x <= self.text_area.x and
|
||||
metrics.height * self.scale.y <= self.text_area.y
|
||||
end
|
||||
|
||||
|
||||
---Setup scale x, but can only be smaller, than start text scale
|
||||
local function update_text_area_size(self)
|
||||
reset_default_scale(self)
|
||||
|
||||
local metrics = helper.get_text_metrics_from_node(self.node)
|
||||
|
||||
if metrics.width == 0 then
|
||||
reset_default_scale(self)
|
||||
self.on_update_text_scale:trigger(self:get_context(), self.start_scale, metrics)
|
||||
return
|
||||
end
|
||||
|
||||
local text_area_width = self.text_area.x
|
||||
local text_area_height = self.text_area.y
|
||||
|
||||
-- Adjust by width
|
||||
local scale_modifier = text_area_width / metrics.width
|
||||
|
||||
-- Adjust by height
|
||||
if self:is_multiline() then
|
||||
-- Approximate scale by height to start adjust scale
|
||||
scale_modifier = math.sqrt(text_area_height / metrics.height)
|
||||
if metrics.width * scale_modifier > text_area_width then
|
||||
scale_modifier = text_area_width / metrics.width
|
||||
end
|
||||
|
||||
-- #RMME
|
||||
if self._minimal_scale then
|
||||
scale_modifier = math.max(scale_modifier, self._minimal_scale)
|
||||
end
|
||||
-- Limit max scale by initial scale
|
||||
scale_modifier = math.min(scale_modifier, self.start_scale.x)
|
||||
-- #RMME
|
||||
|
||||
local is_fit = is_fit_info_area(self, metrics)
|
||||
local step = is_fit and self.style.ADJUST_SCALE_DELTA or -self.style.ADJUST_SCALE_DELTA
|
||||
|
||||
for i = 1, self.style.ADJUST_STEPS do
|
||||
-- Grow down to check if we fit
|
||||
if step < 0 and is_fit then
|
||||
break
|
||||
end
|
||||
-- Grow up to check if we still fit
|
||||
if step > 0 and not is_fit then
|
||||
break
|
||||
end
|
||||
|
||||
scale_modifier = scale_modifier + step
|
||||
|
||||
if self._minimal_scale then
|
||||
scale_modifier = math.max(scale_modifier, self._minimal_scale)
|
||||
end
|
||||
-- Limit max scale by initial scale
|
||||
scale_modifier = math.min(scale_modifier, self.start_scale.x)
|
||||
|
||||
self.scale.x = scale_modifier
|
||||
self.scale.y = scale_modifier
|
||||
self.scale.z = self.start_scale.z
|
||||
gui.set_scale(self.node, self.scale)
|
||||
update_text_size(self)
|
||||
metrics = helper.get_text_metrics_from_node(self.node)
|
||||
is_fit = is_fit_info_area(self, metrics)
|
||||
end
|
||||
end
|
||||
|
||||
if self._minimal_scale then
|
||||
scale_modifier = math.max(scale_modifier, self._minimal_scale)
|
||||
end
|
||||
|
||||
-- Limit max scale by initial scale
|
||||
scale_modifier = math.min(scale_modifier, self.start_scale.x)
|
||||
|
||||
self.scale.x = scale_modifier
|
||||
self.scale.y = scale_modifier
|
||||
self.scale.z = self.start_scale.z
|
||||
gui.set_scale(self.node, self.scale)
|
||||
update_text_size(self)
|
||||
|
||||
self.on_update_text_scale:trigger(self:get_context(), self.scale, metrics)
|
||||
end
|
||||
|
||||
|
||||
---@param self druid.text
|
||||
---@param trim_postfix string
|
||||
local function update_text_with_trim(self, trim_postfix)
|
||||
local max_width = self.text_area.x
|
||||
local text_width = self:get_text_size()
|
||||
|
||||
if text_width > max_width then
|
||||
local text_length = utf8.len(self.last_value)
|
||||
local new_text = self.last_value
|
||||
while text_width > max_width do
|
||||
text_length = text_length - 1
|
||||
new_text = utf8.sub(self.last_value, 1, text_length)
|
||||
text_width = self:get_text_size(new_text .. trim_postfix)
|
||||
if text_length == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
gui.set_text(self.node, new_text .. trim_postfix)
|
||||
else
|
||||
gui.set_text(self.node, self.last_value)
|
||||
end
|
||||
end
|
||||
|
||||
local function update_text_with_trim_left(self, trim_postfix)
|
||||
local max_width = self.text_area.x
|
||||
local text_width = self:get_text_size()
|
||||
local text_length = utf8.len(self.last_value)
|
||||
local trim_index = 1
|
||||
|
||||
if text_width > max_width then
|
||||
local new_text = self.last_value
|
||||
while text_width > max_width and trim_index < text_length do
|
||||
trim_index = trim_index + 1
|
||||
new_text = trim_postfix .. utf8.sub(self.last_value, trim_index, text_length)
|
||||
text_width = self:get_text_size(new_text)
|
||||
end
|
||||
|
||||
gui.set_text(self.node, new_text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function update_text_with_anchor_shift(self)
|
||||
if self:get_text_size() >= self.text_area.x then
|
||||
self:set_pivot(const.REVERSE_PIVOTS[self.start_pivot])
|
||||
else
|
||||
self:set_pivot(self.start_pivot)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param self druid.text
|
||||
local function update_adjust(self)
|
||||
if not self.adjust_type or self.adjust_type == const.TEXT_ADJUST.NO_ADJUST then
|
||||
reset_default_scale(self)
|
||||
return
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.DOWNSCALE then
|
||||
update_text_area_size(self)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.TRIM then
|
||||
update_text_with_trim(self, self.style.TRIM_POSTFIX)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.TRIM_LEFT then
|
||||
update_text_with_trim_left(self, self.style.TRIM_POSTFIX)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.DOWNSCALE_LIMITED then
|
||||
update_text_area_size(self)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCROLL then
|
||||
update_text_with_anchor_shift(self)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_SCROLL then
|
||||
update_text_area_size(self)
|
||||
update_text_with_anchor_shift(self)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_TRIM then
|
||||
update_text_area_size(self)
|
||||
update_text_with_trim(self, self.style.TRIM_POSTFIX)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_TRIM_LEFT then
|
||||
update_text_area_size(self)
|
||||
update_text_with_trim_left(self, self.style.TRIM_POSTFIX)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.text.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
TRIM_POSTFIX = style.TRIM_POSTFIX or "...",
|
||||
DEFAULT_ADJUST = style.DEFAULT_ADJUST or const.TEXT_ADJUST.DOWNSCALE,
|
||||
ADJUST_STEPS = style.ADJUST_STEPS or 20,
|
||||
ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---The Text constructor
|
||||
---@param node string|node Node name or GUI Text Node itself
|
||||
@ -274,6 +53,18 @@ function M:init(node, value, adjust_type)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.text.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
TRIM_POSTFIX = style.TRIM_POSTFIX or "...",
|
||||
DEFAULT_ADJUST = style.DEFAULT_ADJUST or const.TEXT_ADJUST.DOWNSCALE,
|
||||
ADJUST_STEPS = style.ADJUST_STEPS or 20,
|
||||
ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
function M:on_layout_change()
|
||||
self:set_text(self.last_value)
|
||||
end
|
||||
@ -348,7 +139,7 @@ function M:set_to(set_to)
|
||||
|
||||
self.on_set_text:trigger(self:get_context(), set_to)
|
||||
|
||||
update_adjust(self)
|
||||
self:_update_adjust()
|
||||
|
||||
return self
|
||||
end
|
||||
@ -373,7 +164,7 @@ function M:set_size(size)
|
||||
self.text_area = vmath.vector3(size)
|
||||
self.text_area.x = self.text_area.x * self.start_scale.x
|
||||
self.text_area.y = self.text_area.y * self.start_scale.y
|
||||
update_adjust(self)
|
||||
self:_update_adjust()
|
||||
|
||||
return self
|
||||
end
|
||||
@ -476,4 +267,224 @@ function M:get_text_adjust()
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
function M:_update_text_size()
|
||||
if self.scale.x == 0 or self.scale.y == 0 then
|
||||
return
|
||||
end
|
||||
if self.start_scale.x == 0 or self.start_scale.y == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local size = vmath.vector3(
|
||||
self.start_size.x * (self.start_scale.x / self.scale.x),
|
||||
self.start_size.y * (self.start_scale.y / self.scale.y),
|
||||
self.start_size.z
|
||||
)
|
||||
gui.set_size(self.node, size)
|
||||
end
|
||||
|
||||
|
||||
---Reset initial scale for text
|
||||
---@private
|
||||
function M:_reset_default_scale()
|
||||
self.scale.x = self.start_scale.x
|
||||
self.scale.y = self.start_scale.y
|
||||
self.scale.z = self.start_scale.z
|
||||
gui.set_scale(self.node, self.start_scale)
|
||||
gui.set_size(self.node, self.start_size)
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
---@param metrics table
|
||||
---@return boolean
|
||||
function M:_is_fit_info_area(metrics)
|
||||
return metrics.width * self.scale.x <= self.text_area.x and
|
||||
metrics.height * self.scale.y <= self.text_area.y
|
||||
end
|
||||
|
||||
|
||||
---Setup scale x, but can only be smaller, than start text scale
|
||||
---@private
|
||||
function M:_update_text_area_size()
|
||||
self:_reset_default_scale()
|
||||
|
||||
local metrics = helper.get_text_metrics_from_node(self.node)
|
||||
|
||||
if metrics.width == 0 then
|
||||
self:_reset_default_scale()
|
||||
self.on_update_text_scale:trigger(self:get_context(), self.start_scale, metrics)
|
||||
return
|
||||
end
|
||||
|
||||
local text_area_width = self.text_area.x
|
||||
local text_area_height = self.text_area.y
|
||||
|
||||
-- Adjust by width
|
||||
local scale_modifier = text_area_width / metrics.width
|
||||
|
||||
-- Adjust by height
|
||||
if self:is_multiline() then
|
||||
-- Approximate scale by height to start adjust scale
|
||||
scale_modifier = math.sqrt(text_area_height / metrics.height)
|
||||
if metrics.width * scale_modifier > text_area_width then
|
||||
scale_modifier = text_area_width / metrics.width
|
||||
end
|
||||
|
||||
-- #RMME
|
||||
if self._minimal_scale then
|
||||
scale_modifier = math.max(scale_modifier, self._minimal_scale)
|
||||
end
|
||||
-- Limit max scale by initial scale
|
||||
scale_modifier = math.min(scale_modifier, self.start_scale.x)
|
||||
-- #RMME
|
||||
|
||||
local is_fit = self:_is_fit_info_area(metrics)
|
||||
local step = is_fit and self.style.ADJUST_SCALE_DELTA or -self.style.ADJUST_SCALE_DELTA
|
||||
|
||||
for i = 1, self.style.ADJUST_STEPS do
|
||||
-- Grow down to check if we fit
|
||||
if step < 0 and is_fit then
|
||||
break
|
||||
end
|
||||
-- Grow up to check if we still fit
|
||||
if step > 0 and not is_fit then
|
||||
break
|
||||
end
|
||||
|
||||
scale_modifier = scale_modifier + step
|
||||
|
||||
if self._minimal_scale then
|
||||
scale_modifier = math.max(scale_modifier, self._minimal_scale)
|
||||
end
|
||||
-- Limit max scale by initial scale
|
||||
scale_modifier = math.min(scale_modifier, self.start_scale.x)
|
||||
|
||||
self.scale.x = scale_modifier
|
||||
self.scale.y = scale_modifier
|
||||
self.scale.z = self.start_scale.z
|
||||
gui.set_scale(self.node, self.scale)
|
||||
self:_update_text_size()
|
||||
metrics = helper.get_text_metrics_from_node(self.node)
|
||||
is_fit = self:_is_fit_info_area(metrics)
|
||||
end
|
||||
end
|
||||
|
||||
if self._minimal_scale then
|
||||
scale_modifier = math.max(scale_modifier, self._minimal_scale)
|
||||
end
|
||||
|
||||
-- Limit max scale by initial scale
|
||||
scale_modifier = math.min(scale_modifier, self.start_scale.x)
|
||||
|
||||
self.scale.x = scale_modifier
|
||||
self.scale.y = scale_modifier
|
||||
self.scale.z = self.start_scale.z
|
||||
gui.set_scale(self.node, self.scale)
|
||||
self:_update_text_size()
|
||||
|
||||
self.on_update_text_scale:trigger(self:get_context(), self.scale, metrics)
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
---@param trim_postfix string
|
||||
function M:_update_text_with_trim(trim_postfix)
|
||||
local max_width = self.text_area.x
|
||||
local text_width = self:get_text_size()
|
||||
|
||||
if text_width > max_width then
|
||||
local text_length = utf8.len(self.last_value)
|
||||
local new_text = self.last_value
|
||||
while text_width > max_width do
|
||||
text_length = text_length - 1
|
||||
new_text = utf8.sub(self.last_value, 1, text_length)
|
||||
text_width = self:get_text_size(new_text .. trim_postfix)
|
||||
if text_length == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
gui.set_text(self.node, new_text .. trim_postfix)
|
||||
else
|
||||
gui.set_text(self.node, self.last_value)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param trim_postfix string
|
||||
function M:_update_text_with_trim_left(trim_postfix)
|
||||
local max_width = self.text_area.x
|
||||
local text_width = self:get_text_size()
|
||||
local text_length = utf8.len(self.last_value)
|
||||
local trim_index = 1
|
||||
|
||||
if text_width > max_width then
|
||||
local new_text = self.last_value
|
||||
while text_width > max_width and trim_index < text_length do
|
||||
trim_index = trim_index + 1
|
||||
new_text = trim_postfix .. utf8.sub(self.last_value, trim_index, text_length)
|
||||
text_width = self:get_text_size(new_text)
|
||||
end
|
||||
|
||||
gui.set_text(self.node, new_text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
function M:_update_text_with_anchor_shift()
|
||||
if self:get_text_size() >= self.text_area.x then
|
||||
self:set_pivot(const.REVERSE_PIVOTS[self.start_pivot])
|
||||
else
|
||||
self:set_pivot(self.start_pivot)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
function M:_update_adjust()
|
||||
if not self.adjust_type or self.adjust_type == const.TEXT_ADJUST.NO_ADJUST then
|
||||
self:_reset_default_scale()
|
||||
return
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.DOWNSCALE then
|
||||
self:_update_text_area_size()
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.TRIM then
|
||||
self:_update_text_with_trim(self.style.TRIM_POSTFIX)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.TRIM_LEFT then
|
||||
self:_update_text_with_trim_left(self.style.TRIM_POSTFIX)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.DOWNSCALE_LIMITED then
|
||||
self:_update_text_area_size()
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCROLL then
|
||||
self:_update_text_with_anchor_shift()
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_SCROLL then
|
||||
self:_update_text_area_size()
|
||||
self:_update_text_with_anchor_shift()
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_TRIM then
|
||||
self:_update_text_area_size()
|
||||
self:_update_text_with_trim(self.style.TRIM_POSTFIX)
|
||||
end
|
||||
|
||||
if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_TRIM_LEFT then
|
||||
self:_update_text_area_size()
|
||||
self:_update_text_with_trim_left(self.style.TRIM_POSTFIX)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
@ -15,6 +15,21 @@ local helper = require("druid.helper")
|
||||
local component = require("druid.component")
|
||||
local event = require("event.event")
|
||||
|
||||
local abs = math.abs
|
||||
local min = math.min
|
||||
local max = math.max
|
||||
|
||||
local CORNER_PIVOTS = {
|
||||
gui.PIVOT_NE,
|
||||
gui.PIVOT_NW,
|
||||
gui.PIVOT_SE,
|
||||
gui.PIVOT_SW,
|
||||
}
|
||||
|
||||
---@class druid.container.style
|
||||
---@field DRAGGABLE_CORNER_SIZE vector3 Size of box node for debug draggable corners
|
||||
---@field DRAGGABLE_CORNER_COLOR vector4 Color of debug draggable corners
|
||||
|
||||
---@class druid.container: druid.component
|
||||
---@field node node
|
||||
---@field druid druid.instance
|
||||
@ -35,19 +50,7 @@ local event = require("event.event")
|
||||
---@field _draggable_corners table
|
||||
local M = component.create("container")
|
||||
|
||||
local abs = math.abs
|
||||
local min = math.min
|
||||
local max = math.max
|
||||
|
||||
local CORNER_PIVOTS = {
|
||||
gui.PIVOT_NE,
|
||||
gui.PIVOT_NW,
|
||||
gui.PIVOT_SE,
|
||||
gui.PIVOT_SW,
|
||||
}
|
||||
|
||||
|
||||
---The Container init
|
||||
---@param node node Gui node
|
||||
---@param mode string Layout mode
|
||||
---@param callback fun(self: druid.container, size: vector3)|nil Callback on size changed
|
||||
@ -118,16 +121,12 @@ function M:set_pivot(pivot)
|
||||
end
|
||||
|
||||
|
||||
---Component style params.
|
||||
-- You can override this component styles params in Druid styles table
|
||||
-- or create your own style
|
||||
-- @table style
|
||||
-- @tfield[opt=vector3(24, 24, 0)] vector3 DRAGGABLE_CORNER_SIZE Size of box node for debug draggable corners
|
||||
-- @tfield[opt=vector4(1)] vector4 DRAGGABLE_CORNER_COLOR Color of debug draggable corners
|
||||
---@param style druid.container.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {}
|
||||
self.style.DRAGGABLE_CORNER_SIZE = style.DRAGGABLE_CORNER_SIZE or vmath.vector3(24, 24, 0)
|
||||
self.style.DRAGGABLE_CORNER_COLOR = style.DRAGGABLE_CORNER_COLOR or vmath.vector4(10)
|
||||
self.style = {
|
||||
DRAGGABLE_CORNER_SIZE = style.DRAGGABLE_CORNER_SIZE or vmath.vector3(24, 24, 0),
|
||||
DRAGGABLE_CORNER_COLOR = style.DRAGGABLE_CORNER_COLOR or vmath.vector4(10)
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,85 +1,3 @@
|
||||
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
|
||||
|
||||
---Druid input text component.
|
||||
-- Carry on user text input
|
||||
--
|
||||
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_input" target="_blank"><b>Example Link</b></a>
|
||||
-- @author Part of code from Britzl gooey input component
|
||||
-- @module Input
|
||||
-- @within BaseComponent
|
||||
-- @alias druid.input
|
||||
|
||||
---On input field select callback(self, input_instance)
|
||||
-- @tfield event on_input_select event
|
||||
|
||||
---On input field unselect callback(self, input_text, input_instance)
|
||||
-- @tfield event on_input_unselect event
|
||||
|
||||
---On input field text change callback(self, input_text)
|
||||
-- @tfield event on_input_text event
|
||||
|
||||
---On input field text change to empty string callback(self, input_text)
|
||||
-- @tfield event on_input_empty event
|
||||
|
||||
---On input field text change to max length string callback(self, input_text)
|
||||
-- @tfield event on_input_full event
|
||||
|
||||
---On trying user input with not allowed character callback(self, params, input_text)
|
||||
-- @tfield event on_input_wrong event
|
||||
|
||||
---On cursor position change callback(self, cursor_index, start_index, end_index)
|
||||
-- @tfield event on_select_cursor_change event
|
||||
|
||||
---The cursor index. The index of letter cursor after. Leftmost cursor - 0
|
||||
-- @tfield number cursor_index
|
||||
|
||||
---The selection start index. The index of letter cursor after. Leftmost selection - 0
|
||||
-- @tfield number start_index
|
||||
|
||||
---Theselection end index. The index of letter cursor before. Rightmost selection - #text
|
||||
-- @tfield number end_index
|
||||
|
||||
---Text component
|
||||
-- @tfield Text text Text
|
||||
|
||||
---Current input value
|
||||
-- @tfield string value
|
||||
|
||||
---Previous input value
|
||||
-- @tfield string previous_value
|
||||
|
||||
---Current input value with marked text
|
||||
-- @tfield string current_value
|
||||
|
||||
---Marked text for input field. Info: https://defold.com/manuals/input-key-and-text/#marked-text
|
||||
-- @tfield string marked_value
|
||||
|
||||
---Text width
|
||||
-- @tfield number text_width
|
||||
|
||||
---Marked text width
|
||||
-- @tfield number marked_text_width
|
||||
|
||||
---Button component
|
||||
-- @tfield Button button Button
|
||||
|
||||
---Is current input selected now
|
||||
-- @tfield boolean is_selected
|
||||
|
||||
---Is current input is empty now
|
||||
-- @tfield boolean is_empty
|
||||
|
||||
---Max length for input text
|
||||
-- @tfield number|nil max_length
|
||||
|
||||
---Pattern matching for user input
|
||||
-- @tfield string|nil allowerd_characters
|
||||
|
||||
---Gui keyboard type for input field
|
||||
-- @tfield number keyboard_type
|
||||
|
||||
---
|
||||
|
||||
local event = require("event.event")
|
||||
local const = require("druid.const")
|
||||
local helper = require("druid.helper")
|
||||
@ -87,6 +5,14 @@ local component = require("druid.component")
|
||||
local utf8_lua = require("druid.system.utf8")
|
||||
local utf8 = utf8 or utf8_lua
|
||||
|
||||
---@class druid.input.style
|
||||
---@field MASK_DEFAULT_CHAR string Default character mask for password input
|
||||
---@field IS_LONGTAP_ERASE boolean Is long tap will erase current input data
|
||||
---@field IS_UNSELECT_ON_RESELECT boolean If true, call unselect on select selected input
|
||||
---@field on_select fun(self: druid.input, button_node: node) Callback on input field selecting
|
||||
---@field on_unselect fun(self: druid.input, button_node: node) Callback on input field unselecting
|
||||
---@field on_input_wrong fun(self: druid.input, button_node: node) Callback on wrong user input
|
||||
|
||||
---@class druid.input: druid.component
|
||||
---@field on_input_select event
|
||||
---@field on_input_unselect event
|
||||
@ -132,30 +58,6 @@ local function clear_and_select(self)
|
||||
end
|
||||
|
||||
|
||||
---Component style params.
|
||||
-- You can override this component styles params in druid styles table
|
||||
-- or create your own style
|
||||
-- @table style
|
||||
-- @tfield boolean IS_LONGTAP_ERASE Is long tap will erase current input data. Default: false
|
||||
-- @tfield string MASK_DEFAULT_CHAR Default character mask for password input. Default: *]
|
||||
-- @tfield boolean IS_UNSELECT_ON_RESELECT If true, call unselect on select selected input. Default: false
|
||||
-- @tfield function on_select (self, button_node) Callback on input field selecting
|
||||
-- @tfield function on_unselect (self, button_node) Callback on input field unselecting
|
||||
-- @tfield function on_input_wrong (self, button_node) Callback on wrong user input
|
||||
function M:on_style_change(style)
|
||||
self.style = {}
|
||||
|
||||
self.style.IS_LONGTAP_ERASE = style.IS_LONGTAP_ERASE or false
|
||||
self.style.MASK_DEFAULT_CHAR = style.MASK_DEFAULT_CHAR or "*"
|
||||
self.style.IS_UNSELECT_ON_RESELECT = style.IS_UNSELECT_ON_RESELECT or false
|
||||
|
||||
self.style.on_select = style.on_select or function(_, button_node) end
|
||||
self.style.on_unselect = style.on_unselect or function(_, button_node) end
|
||||
self.style.on_input_wrong = style.on_input_wrong or function(_, button_node) end
|
||||
end
|
||||
|
||||
|
||||
---The Input constructor
|
||||
---@param click_node node Node to enabled input component
|
||||
---@param text_node node|druid.text Text node what will be changed on user input. You can pass text component instead of text node name Text
|
||||
---@param keyboard_type number|nil Gui keyboard type for input field
|
||||
@ -210,6 +112,20 @@ function M:init(click_node, text_node, keyboard_type)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.input.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
IS_LONGTAP_ERASE = style.IS_LONGTAP_ERASE or false,
|
||||
MASK_DEFAULT_CHAR = style.MASK_DEFAULT_CHAR or "*",
|
||||
IS_UNSELECT_ON_RESELECT = style.IS_UNSELECT_ON_RESELECT or false,
|
||||
|
||||
on_select = style.on_select or function(_, button_node) end,
|
||||
on_unselect = style.on_unselect or function(_, button_node) end,
|
||||
on_input_wrong = style.on_input_wrong or function(_, button_node) end,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function M:on_input(action_id, action)
|
||||
if not (action_id == nil or M.ALLOWED_ACTIONS[action_id]) then
|
||||
return false
|
||||
|
@ -75,16 +75,6 @@ local function set_bar_to(self, set_to, is_silent)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.progress.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
SPEED = style.SPEED or 5,
|
||||
MIN_DELTA = style.MIN_DELTA or 0.005,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---The Progress constructor
|
||||
---@param node string|node Node name or GUI Node itself.
|
||||
---@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y
|
||||
---@param init_value number|nil Initial value of progress bar. Default: 1
|
||||
@ -114,6 +104,15 @@ function M:init(node, key, init_value)
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.progress.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
SPEED = style.SPEED or 5,
|
||||
MIN_DELTA = style.MIN_DELTA or 0.005,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function M:on_layout_change()
|
||||
self:set_to(self.last_value)
|
||||
end
|
||||
@ -124,6 +123,7 @@ function M:on_remove()
|
||||
end
|
||||
|
||||
|
||||
---@param dt number Delta time
|
||||
function M:update(dt)
|
||||
if self.target then
|
||||
local prev_value = self.last_value
|
||||
|
@ -18,17 +18,6 @@ local component = require("druid.component")
|
||||
local M = component.create("slider", const.PRIORITY_INPUT_HIGH)
|
||||
|
||||
|
||||
local function on_change_value(self)
|
||||
self.on_change_value:trigger(self:get_context(), self.value)
|
||||
end
|
||||
|
||||
|
||||
local function set_position(self, value)
|
||||
value = helper.clamp(value, 0, 1)
|
||||
gui.set_position(self.node, self.start_pos + self.dist * value)
|
||||
end
|
||||
|
||||
|
||||
---The Slider constructor
|
||||
---@param node node Gui pin node
|
||||
---@param end_pos vector3 The end position of slider
|
||||
@ -141,11 +130,11 @@ function M:on_input(action_id, action)
|
||||
end
|
||||
|
||||
if prev_value ~= self.value then
|
||||
on_change_value(self)
|
||||
self:_on_change_value()
|
||||
end
|
||||
end
|
||||
|
||||
set_position(self, self.value)
|
||||
self:_set_position(self.value)
|
||||
end
|
||||
|
||||
if action.released then
|
||||
@ -161,10 +150,10 @@ end
|
||||
---@param is_silent boolean|nil Don't trigger event if true
|
||||
function M:set(value, is_silent)
|
||||
value = helper.clamp(value, 0, 1)
|
||||
set_position(self, value)
|
||||
self:_set_position(value)
|
||||
self.value = value
|
||||
if not is_silent then
|
||||
on_change_value(self)
|
||||
self:_on_change_value()
|
||||
end
|
||||
end
|
||||
|
||||
@ -210,4 +199,17 @@ function M:is_enabled()
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
function M:_on_change_value()
|
||||
self.on_change_value:trigger(self:get_context(), self.value)
|
||||
end
|
||||
|
||||
|
||||
---@private
|
||||
function M:_set_position(value)
|
||||
value = helper.clamp(value, 0, 1)
|
||||
gui.set_position(self.node, self.start_pos + self.dist * value)
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
@ -21,16 +21,6 @@ local component = require("druid.component")
|
||||
local M = component.create("swipe")
|
||||
|
||||
|
||||
---@param style druid.swipe.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
SWIPE_TIME = style.SWIPE_TIME or 0.4,
|
||||
SWIPE_THRESHOLD = style.SWIPE_THRESHOLD or 50,
|
||||
SWIPE_TRIGGER_ON_MOVE = style.SWIPE_TRIGGER_ON_MOVE or false,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---@param node_or_node_id node|string
|
||||
---@param on_swipe_callback function
|
||||
function M:init(node_or_node_id, on_swipe_callback)
|
||||
@ -55,6 +45,16 @@ function M:on_late_init()
|
||||
end
|
||||
|
||||
|
||||
---@param style druid.swipe.style
|
||||
function M:on_style_change(style)
|
||||
self.style = {
|
||||
SWIPE_TIME = style.SWIPE_TIME or 0.4,
|
||||
SWIPE_THRESHOLD = style.SWIPE_THRESHOLD or 50,
|
||||
SWIPE_TRIGGER_ON_MOVE = style.SWIPE_TRIGGER_ON_MOVE or false,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
---@param action_id hash
|
||||
---@param action action
|
||||
function M:on_input(action_id, action)
|
||||
@ -154,6 +154,4 @@ function M:_check_swipe(action)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
return M
|
||||
|
@ -21,7 +21,6 @@ local function second_string_min(sec)
|
||||
end
|
||||
|
||||
|
||||
---The Timer constructor
|
||||
---@param node node Gui text node
|
||||
---@param seconds_from number|nil Start timer value in seconds
|
||||
---@param seconds_to number|nil End timer value in seconds
|
||||
|
Loading…
x
Reference in New Issue
Block a user