mirror of
https://github.com/Insality/druid
synced 2025-09-27 18:12:21 +02:00
Move components to extended. Make stubs for ready to make it requirable
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
--- Druid checkbox component
|
||||
-- @module druid.checkbox
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_change_state On change state callback
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield node node Visual node
|
||||
-- @tfield[opt=node] node click_node Button trigger node
|
||||
-- @tfield druid.button button Button component from click_node
|
||||
|
||||
local const = require("druid.const")
|
||||
local Event = require("druid.event")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("checkbox", { const.ON_LAYOUT_CHANGE })
|
||||
|
||||
|
||||
local function on_click(self)
|
||||
M.set_state(self, not self.state)
|
||||
end
|
||||
|
||||
|
||||
--- Component style params.
|
||||
-- You can override this component styles params in druid styles table
|
||||
-- or create your own style
|
||||
-- @table Style
|
||||
-- @tfield function on_change_state (self, node, state)
|
||||
function M.on_style_change(self, style)
|
||||
self.style = {}
|
||||
|
||||
self.style.on_change_state = style.on_change_state or function(_, node, state)
|
||||
gui.set_enabled(node, state)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function checkbox:init
|
||||
-- @tparam node node Gui node
|
||||
-- @tparam function callback Checkbox callback
|
||||
-- @tparam[opt=node] node click node Trigger node, by default equals to node
|
||||
function M.init(self, node, callback, click_node)
|
||||
self.druid = self:get_druid()
|
||||
self.node = self:get_node(node)
|
||||
self.click_node = self:get_node(click_node)
|
||||
|
||||
self.button = self.druid:new_button(self.click_node or self.node, on_click)
|
||||
M.set_state(self, false, true)
|
||||
|
||||
self.on_change_state = Event(callback)
|
||||
end
|
||||
|
||||
|
||||
function M.on_layout_change(self)
|
||||
self:set_state(self.state, true)
|
||||
end
|
||||
|
||||
|
||||
--- Set checkbox state
|
||||
-- @function checkbox:set_state
|
||||
-- @tparam bool state Checkbox state
|
||||
-- @tparam bool is_silent Don't trigger on_change_state if true
|
||||
function M.set_state(self, state, is_silent)
|
||||
self.state = state
|
||||
self.style.on_change_state(self, self.node, state)
|
||||
|
||||
if not is_silent then
|
||||
self.on_change_state:trigger(self:get_context(), state)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Return checkbox state
|
||||
-- @function checkbox:get_state
|
||||
-- @treturn bool Checkbox state
|
||||
function M.get_state(self)
|
||||
return self.state
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,66 +0,0 @@
|
||||
--- Checkbox group module
|
||||
-- @module druid.checkbox_group
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_checkbox_click On any checkbox click
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield table checkboxes Array of checkbox components
|
||||
|
||||
local Event = require("druid.event")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("checkbox_group")
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function checkbox_group:init
|
||||
-- @tparam node[] node Array of gui node
|
||||
-- @tparam function callback Checkbox callback
|
||||
-- @tparam[opt=node] node[] click node Array of trigger nodes, by default equals to nodes
|
||||
function M.init(self, nodes, callback, click_nodes)
|
||||
self.druid = self:get_druid()
|
||||
self.checkboxes = {}
|
||||
|
||||
self.on_checkbox_click = Event(callback)
|
||||
|
||||
for i = 1, #nodes do
|
||||
local click_node = click_nodes and click_nodes[i] or nil
|
||||
local checkbox = self.druid:new_checkbox(nodes[i], function()
|
||||
self.on_checkbox_click:trigger(self:get_context(), i)
|
||||
end, click_node)
|
||||
|
||||
table.insert(self.checkboxes, checkbox)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Set checkbox group state
|
||||
-- @function checkbox_group:set_state
|
||||
-- @tparam bool[] indexes Array of checkbox state
|
||||
function M.set_state(self, indexes)
|
||||
for i = 1, #indexes do
|
||||
if self.checkboxes[i] then
|
||||
self.checkboxes[i]:set_state(indexes[i], true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Return checkbox group state
|
||||
-- @function checkbox_group:get_state
|
||||
-- @treturn bool[] Array if checkboxes state
|
||||
function M.get_state(self)
|
||||
local result = {}
|
||||
|
||||
for i = 1, #self.checkboxes do
|
||||
table.insert(result, self.checkboxes[i]:get_state())
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,64 +0,0 @@
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("my_component_name", { const.ON_UPDATE })
|
||||
|
||||
|
||||
-- Component constructor
|
||||
function M.init(self, ...)
|
||||
end
|
||||
|
||||
|
||||
-- Call only if exist interest: const.ON_UPDATE
|
||||
function M.update(self, dt)
|
||||
end
|
||||
|
||||
|
||||
-- Call only if exist interest: const.ON_INPUT or const.ON_INPUT_HIGH
|
||||
function M.on_input(self, action_id, action)
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- Call on component creation and on component:set_style() function
|
||||
function M.on_style_change(self, style)
|
||||
end
|
||||
|
||||
|
||||
-- Call only if exist interest: const.ON_MESSAGE
|
||||
function M.on_message(self, message_id, message, sender)
|
||||
end
|
||||
|
||||
|
||||
-- Call only if component with ON_LANGUAGE_CHANGE interest
|
||||
function M.on_language_change(self)
|
||||
end
|
||||
|
||||
|
||||
-- Call only if component with ON_LAYOUT_CHANGE interest
|
||||
function M.on_layout_change(self)
|
||||
end
|
||||
|
||||
|
||||
-- Call, if input was capturing before this component
|
||||
-- Example: scroll is start scrolling, so you need unhover button
|
||||
function M.on_input_interrupt(self)
|
||||
end
|
||||
|
||||
|
||||
-- Call, if game lost focus. Need ON_FOCUS_LOST intereset
|
||||
function M.on_focus_lost(self)
|
||||
end
|
||||
|
||||
|
||||
-- Call, if game gained focus. Need ON_FOCUS_GAINED intereset
|
||||
function M.on_focus_gained(self)
|
||||
end
|
||||
|
||||
|
||||
-- Call on component remove or on druid:final
|
||||
function M.on_remove(self)
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,312 +0,0 @@
|
||||
--- Druid input text component.
|
||||
-- Carry on user text input
|
||||
-- @author Part of code from Britzl gooey input component
|
||||
-- @module druid.input
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_input_select (self, button_node) On input field select callback
|
||||
-- @tfield druid_event on_input_unselect (self, button_node) On input field unselect callback
|
||||
-- @tfield druid_event on_input_text (self, input_text) On input field text change callback
|
||||
-- @tfield druid_event on_input_empty (self, input_text) On input field text change to empty string callback
|
||||
-- @tfield druid_event on_input_full (self, input_text) On input field text change to max length string callback
|
||||
-- @tfield druid_event on_input_wrong (self, params, button_instance) On trying user input with not allowed character callback
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield druid.text text Text component
|
||||
-- @tfield druid.button button Button component
|
||||
-- @tfield bool is_selected Is current input selected now
|
||||
-- @tfield bool is_empty Is current input is empty now
|
||||
-- @tfield[opt] number max_length Max length for input text
|
||||
-- @tfield[opt] string allowerd_characters Pattern matching for user input
|
||||
-- @tfield number keyboard_type Gui keyboard type for input field
|
||||
|
||||
local Event = require("druid.event")
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.component")
|
||||
local utf8 = require("druid.system.utf8")
|
||||
|
||||
local M = component.create("input", { const.ON_INPUT, const.ON_FOCUS_LOST })
|
||||
|
||||
|
||||
--- Mask text by replacing every character with a mask character
|
||||
-- @tparam string text
|
||||
-- @tparam string mask
|
||||
-- @treturn string Masked text
|
||||
local function mask_text(text, mask)
|
||||
mask = mask or "*"
|
||||
local masked_text = ""
|
||||
for uchar in utf8.gmatch(text, ".") do
|
||||
masked_text = masked_text .. mask
|
||||
end
|
||||
|
||||
return masked_text
|
||||
end
|
||||
|
||||
|
||||
local function select(self)
|
||||
gui.reset_keyboard()
|
||||
self.marked_value = ""
|
||||
if not self.selected then
|
||||
self:increase_input_priority()
|
||||
self.button:increase_input_priority()
|
||||
self.previous_value = self.value
|
||||
self.selected = true
|
||||
|
||||
gui.show_keyboard(self.keyboard_type, false)
|
||||
self.on_input_select:trigger(self:get_context())
|
||||
|
||||
self.style.on_select(self, self.button.node)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function unselect(self)
|
||||
gui.reset_keyboard()
|
||||
self.marked_value = ""
|
||||
if self.selected then
|
||||
self:reset_input_priority()
|
||||
self.button:reset_input_priority()
|
||||
self.selected = false
|
||||
|
||||
gui.hide_keyboard()
|
||||
self.on_input_unselect:trigger(self:get_context())
|
||||
|
||||
self.style.on_unselect(self, self.button.node)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function clear_and_select(self)
|
||||
if self.style.IS_LONGTAP_ERASE then
|
||||
self:set_text("")
|
||||
end
|
||||
|
||||
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[opt=false] bool IS_LONGTAP_ERASE Is long tap will erase current input data
|
||||
-- @tfield[opt=*] string MASK_DEFAULT_CHAR Default character mask for password input
|
||||
-- @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
|
||||
-- @tfield table button_style Custom button style for input node
|
||||
function M.on_style_change(self, 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.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
|
||||
|
||||
self.style.button_style = style.button_style or {
|
||||
LONGTAP_TIME = 0.4,
|
||||
AUTOHOLD_TRIGGER = 0.8,
|
||||
DOUBLETAP_TIME = 0.4
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function M.init(self, click_node, text_node, keyboard_type)
|
||||
self.druid = self:get_druid(self)
|
||||
self.text = self.druid:new_text(text_node)
|
||||
|
||||
self.selected = false
|
||||
self.value = self.text.last_value
|
||||
self.previous_value = self.text.last_value
|
||||
self.current_value = self.text.last_value
|
||||
self.marked_value = ""
|
||||
self.is_empty = true
|
||||
|
||||
self.text_width = 0
|
||||
self.market_text_width = 0
|
||||
self.total_width = 0
|
||||
|
||||
self.max_length = nil
|
||||
self.allowed_characters = nil
|
||||
|
||||
self.keyboard_type = keyboard_type or gui.KEYBOARD_TYPE_DEFAULT
|
||||
|
||||
self.button = self.druid:new_button(click_node, select)
|
||||
self.button:set_style(self.button_style)
|
||||
self.button.on_click_outside:subscribe(unselect)
|
||||
self.button.on_long_click:subscribe(clear_and_select)
|
||||
|
||||
self.on_input_select = Event()
|
||||
self.on_input_unselect = Event()
|
||||
self.on_input_text = Event()
|
||||
self.on_input_empty = Event()
|
||||
self.on_input_full = Event()
|
||||
self.on_input_wrong = Event()
|
||||
end
|
||||
|
||||
|
||||
function M.on_input(self, action_id, action)
|
||||
if self.selected then
|
||||
local input_text = nil
|
||||
if action_id == const.ACTION_TEXT then
|
||||
-- ignore return key
|
||||
if action.text == "\n" or action.text == "\r" then
|
||||
return true
|
||||
end
|
||||
|
||||
local hex = string.gsub(action.text,"(.)", function (c)
|
||||
return string.format("%02X%s",string.byte(c), "")
|
||||
end)
|
||||
|
||||
-- ignore arrow keys
|
||||
if not string.match(hex, "EF9C8[0-3]") then
|
||||
if not self.allowed_characters or action.text:match(self.allowed_characters) then
|
||||
input_text = self.value .. action.text
|
||||
if self.max_length then
|
||||
input_text = utf8.sub(input_text, 1, self.max_length)
|
||||
end
|
||||
else
|
||||
self.on_input_wrong:trigger(self:get_context(), action.text)
|
||||
self.style.on_input_wrong(self, self.button.node)
|
||||
end
|
||||
self.marked_value = ""
|
||||
end
|
||||
end
|
||||
|
||||
if action_id == const.ACTION_MARKED_TEXT then
|
||||
self.marked_value = action.text or ""
|
||||
if self.max_length then
|
||||
self.marked_value = utf8.sub(self.marked_value, 1, self.max_length)
|
||||
end
|
||||
end
|
||||
|
||||
if action_id == const.ACTION_BACKSPACE and (action.pressed or action.repeated) then
|
||||
input_text = utf8.sub(self.value, 1, -2)
|
||||
end
|
||||
|
||||
if action_id == const.ACTION_ENTER and action.released then
|
||||
unselect(self)
|
||||
return true
|
||||
end
|
||||
|
||||
if action_id == const.ACTION_BACK and action.released then
|
||||
unselect(self)
|
||||
return true
|
||||
end
|
||||
|
||||
if action_id == const.ACTION_ESC and action.released then
|
||||
unselect(self)
|
||||
return true
|
||||
end
|
||||
|
||||
if input_text or #self.marked_value > 0 then
|
||||
self:set_text(input_text)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return self.selected
|
||||
end
|
||||
|
||||
|
||||
function M.on_focus_lost(self)
|
||||
unselect(self)
|
||||
end
|
||||
|
||||
|
||||
function M.on_input_interrupt(self)
|
||||
-- unselect(self)
|
||||
end
|
||||
|
||||
|
||||
--- Set text for input field
|
||||
-- @function input:set_text
|
||||
-- @tparam string input_text The string to apply for input field
|
||||
function M.set_text(self, input_text)
|
||||
-- Case when update with marked text
|
||||
if input_text then
|
||||
self.value = input_text
|
||||
end
|
||||
|
||||
-- Only update the text if it has changed
|
||||
local current_value = self.value .. self.marked_value
|
||||
|
||||
if current_value ~= self.current_value then
|
||||
self.current_value = current_value
|
||||
|
||||
-- mask text if password field
|
||||
local masked_value, masked_marked_value
|
||||
if self.keyboard_type == gui.KEYBOARD_TYPE_PASSWORD then
|
||||
local mask_char = self.style.MASK_DEFAULT_CHAR or "*"
|
||||
masked_value = mask_text(self.value, mask_char)
|
||||
masked_marked_value = mask_text(self.marked_value, mask_char)
|
||||
end
|
||||
|
||||
-- text + marked text
|
||||
local value = masked_value or self.value
|
||||
local marked_value = masked_marked_value or self.marked_value
|
||||
self.is_empty = #value == 0 and #marked_value == 0
|
||||
|
||||
local final_text = value .. marked_value
|
||||
self.text:set_to(final_text)
|
||||
|
||||
-- measure it
|
||||
self.text_width = self.text:get_text_width(value)
|
||||
self.marked_text_width = self.text:get_text_width(marked_value)
|
||||
self.total_width = self.text_width + self.marked_text_width
|
||||
|
||||
self.on_input_text:trigger(self:get_context(), final_text)
|
||||
if #final_text == 0 then
|
||||
self.on_input_empty:trigger(self:get_context(), final_text)
|
||||
end
|
||||
if self.max_length and #final_text == self.max_length then
|
||||
self.on_input_full:trigger(self:get_context(), final_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Return current input field text
|
||||
-- @function input:get_text
|
||||
-- @treturn string The current input field text
|
||||
function M.get_text(self)
|
||||
return self.value .. self.marked_value
|
||||
end
|
||||
|
||||
|
||||
--- Set maximum length for input field.
|
||||
-- Pass nil to make input field unliminted (by default)
|
||||
-- @function input:set_max_length
|
||||
-- @tparam number max_length Maximum length for input text field
|
||||
-- @treturn druid.input Current input instance
|
||||
function M.set_max_length(self, max_length)
|
||||
self.max_length = max_length
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set allowed charaters for input field.
|
||||
-- See: https://defold.com/ref/stable/string/
|
||||
-- ex: [%a%d] for alpha and numeric
|
||||
-- @function input:set_allowerd_characters
|
||||
-- @tparam string characters Regulax exp. for validate user input
|
||||
-- @treturn druid.input Current input instance
|
||||
function M.set_allowed_characters(self, characters)
|
||||
self.allowed_characters = characters
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Reset current input selection and return previous value
|
||||
-- @function input:reset_changes
|
||||
function M.reset_changes(self)
|
||||
self:set_text(self.previous_value)
|
||||
unselect(self)
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,193 +0,0 @@
|
||||
--- Basic progress bar component.
|
||||
-- For correct progress bar init it should be in max size from gui
|
||||
-- @module druid.progress
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_change On progress bar change callback
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield node node Progress bar fill node
|
||||
-- @tfield string key The progress bar direction
|
||||
-- @tfield vector3 scale Current progress bar scale
|
||||
-- @tfield vector3 size Current progress bar size
|
||||
-- @tfield number max_size Maximum size of progress bar
|
||||
-- @tfield vector4 slice Progress bar slice9 settings
|
||||
|
||||
local Event = require("druid.event")
|
||||
local const = require("druid.const")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("progress", { const.ON_UPDATE, const.ON_LAYOUT_CHANGE })
|
||||
|
||||
|
||||
local function check_steps(self, from, to, exactly)
|
||||
if not self.steps then
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, #self.steps do
|
||||
local step = self.steps[i]
|
||||
local v1, v2 = from, to
|
||||
if v1 > v2 then
|
||||
v1, v2 = v2, v1
|
||||
end
|
||||
|
||||
if v1 < step and step < v2 then
|
||||
self.step_callback(self:get_context(), step)
|
||||
end
|
||||
if exactly and exactly == step then
|
||||
self.step_callback(self:get_context(), step)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function set_bar_to(self, set_to, is_silent)
|
||||
local prev_value = self.last_value
|
||||
self.last_value = set_to
|
||||
|
||||
local total_width = set_to * self.max_size
|
||||
|
||||
local scale = math.min(total_width / self.slice_size, 1)
|
||||
local size = math.max(total_width, self.slice_size)
|
||||
|
||||
self.scale[self.key] = scale
|
||||
gui.set_scale(self.node, self.scale)
|
||||
self.size[self.key] = size
|
||||
gui.set_size(self.node, self.size)
|
||||
|
||||
if not is_silent then
|
||||
check_steps(self, prev_value, set_to)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Component style params.
|
||||
-- You can override this component styles params in druid styles table
|
||||
-- or create your own style
|
||||
-- @table Style
|
||||
-- @tfield[opt=5] number SPEED Progress bas fill rate. More -> faster
|
||||
-- @tfield[opt=0.005] number MIN_DELTA Minimum step to fill progress bar
|
||||
function M.on_style_change(self, style)
|
||||
self.style = {}
|
||||
self.style.SPEED = style.SPEED or 5
|
||||
self.style.MIN_DELTA = style.MIN_DELTA or 0.005
|
||||
end
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function progress:init
|
||||
-- @tparam string|node node Progress bar fill node or node name
|
||||
-- @tparam string key Progress bar direction: const.SIDE.X or const.SIDE.Y
|
||||
-- @tparam[opt=1] number init_value Initial value of progress bar
|
||||
function M.init(self, node, key, init_value)
|
||||
assert(key == const.SIDE.X or const.SIDE.Y, "Progress bar key should be 'x' or 'y'")
|
||||
|
||||
self.prop = hash("scale."..key)
|
||||
self.key = key
|
||||
|
||||
self.node = self:get_node(node)
|
||||
self.scale = gui.get_scale(self.node)
|
||||
self.size = gui.get_size(self.node)
|
||||
self.max_size = self.size[self.key]
|
||||
self.slice = gui.get_slice9(self.node)
|
||||
if key == const.SIDE.X then
|
||||
self.slice_size = self.slice.x + self.slice.z
|
||||
else
|
||||
self.slice_size = self.slice.y + self.slice.w
|
||||
end
|
||||
|
||||
self.on_change = Event()
|
||||
|
||||
self:set_to(init_value or 1)
|
||||
end
|
||||
|
||||
|
||||
function M.on_layout_change(self)
|
||||
self:set_to(self.last_value)
|
||||
end
|
||||
|
||||
|
||||
function M.update(self, dt)
|
||||
if self.target then
|
||||
local prev_value = self.last_value
|
||||
local step = math.abs(self.last_value - self.target) * (self.style.SPEED*dt)
|
||||
step = math.max(step, self.style.MIN_DELTA)
|
||||
self:set_to(helper.step(self.last_value, self.target, step))
|
||||
|
||||
if self.last_value == self.target then
|
||||
check_steps(self, prev_value, self.target, self.target)
|
||||
|
||||
if self.target_callback then
|
||||
self.target_callback(self:get_context(), self.target)
|
||||
end
|
||||
|
||||
self.target = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Fill a progress bar and stop progress animation
|
||||
-- @function progress:fill
|
||||
function M.fill(self)
|
||||
set_bar_to(self, 1, true)
|
||||
end
|
||||
|
||||
|
||||
--- Empty a progress bar
|
||||
-- @function progress:empty
|
||||
function M.empty(self)
|
||||
set_bar_to(self, 0, true)
|
||||
end
|
||||
|
||||
|
||||
--- Instant fill progress bar to value
|
||||
-- @function progress:set_to
|
||||
-- @tparam number to Progress bar value, from 0 to 1
|
||||
function M.set_to(self, to)
|
||||
set_bar_to(self, to)
|
||||
end
|
||||
|
||||
|
||||
--- Return current progress bar value
|
||||
-- @function progress:get
|
||||
function M.get(self)
|
||||
return self.last_value
|
||||
end
|
||||
|
||||
|
||||
--- Set points on progress bar to fire the callback
|
||||
-- @function progress:set_steps
|
||||
-- @tparam number[] steps Array of progress bar values
|
||||
-- @tparam function callback Callback on intersect step value
|
||||
-- @usage progress:set_steps({0, 0.3, 0.6, 1}, function(self, step) end)
|
||||
function M.set_steps(self, steps, callback)
|
||||
self.steps = steps
|
||||
self.step_callback = callback
|
||||
end
|
||||
|
||||
|
||||
--- Start animation of a progress bar
|
||||
-- @function progress:to
|
||||
-- @tparam number to value between 0..1
|
||||
-- @tparam[opt] function callback Callback on animation ends
|
||||
function M.to(self, to, callback)
|
||||
to = helper.clamp(to, 0, 1)
|
||||
-- cause of float error
|
||||
local value = helper.round(to, 5)
|
||||
if value ~= self.last_value then
|
||||
self.target = value
|
||||
self.target_callback = callback
|
||||
else
|
||||
if callback then
|
||||
callback(self:get_context(), to)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,74 +0,0 @@
|
||||
--- Radio group module
|
||||
-- @module druid.radio_group
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_radio_click On any checkbox click
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield table checkboxes Array of checkbox components
|
||||
|
||||
local Event = require("druid.event")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("radio_group")
|
||||
|
||||
|
||||
local function on_checkbox_click(self, index)
|
||||
for i = 1, #self.checkboxes do
|
||||
self.checkboxes[i]:set_state(i == index, true)
|
||||
end
|
||||
|
||||
self.on_radio_click:trigger(self:get_context(), index)
|
||||
end
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function radio_group:init
|
||||
-- @tparam node[] node Array of gui node
|
||||
-- @tparam function callback Radio callback
|
||||
-- @tparam[opt=node] node[] click node Array of trigger nodes, by default equals to nodes
|
||||
function M.init(self, nodes, callback, click_nodes)
|
||||
self.druid = self:get_druid()
|
||||
self.checkboxes = {}
|
||||
|
||||
self.on_radio_click = Event(callback)
|
||||
|
||||
for i = 1, #nodes do
|
||||
local click_node = click_nodes and click_nodes[i] or nil
|
||||
local checkbox = self.druid:new_checkbox(nodes[i], function()
|
||||
on_checkbox_click(self, i)
|
||||
end, click_node)
|
||||
|
||||
table.insert(self.checkboxes, checkbox)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Set radio group state
|
||||
-- @function radio_group:set_state
|
||||
-- @tparam number index Index in radio group
|
||||
function M.set_state(self, index)
|
||||
on_checkbox_click(self, index)
|
||||
end
|
||||
|
||||
|
||||
--- Return radio group state
|
||||
-- @function radio_group:get_state
|
||||
-- @treturn number Index in radio group
|
||||
function M.get_state(self)
|
||||
local result = -1
|
||||
|
||||
for i = 1, #self.checkboxes do
|
||||
if self.checkboxes[i]:get_state() then
|
||||
result = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,156 +0,0 @@
|
||||
--- Druid slider component
|
||||
-- @module druid.slider
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_change_value On change value callback
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield node node Slider pin node
|
||||
-- @tfield vector3 start_pos Start pin node position
|
||||
-- @tfield vector3 pos Current pin node position
|
||||
-- @tfield vector3 target_pos Targer pin node position
|
||||
-- @tfield vector3 end_pos End pin node position
|
||||
-- @tfield number dist Length between start and end position
|
||||
-- @tfield bool is_drag Current drag state
|
||||
-- @tfield number value Current slider value
|
||||
|
||||
|
||||
local Event = require("druid.event")
|
||||
local helper = require("druid.helper")
|
||||
local const = require("druid.const")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("slider", { const.ON_INPUT_HIGH, const.ON_LAYOUT_CHANGE })
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function slider:init
|
||||
-- @tparam node node Gui pin node
|
||||
-- @tparam vector3 end_pos The end position of slider
|
||||
-- @tparam[opt] function callback On slider change callback
|
||||
function M.init(self, node, end_pos, callback)
|
||||
self.node = self:get_node(node)
|
||||
|
||||
self.start_pos = gui.get_position(self.node)
|
||||
self.pos = gui.get_position(self.node)
|
||||
self.target_pos = self.pos
|
||||
self.end_pos = end_pos
|
||||
|
||||
self.dist = self.end_pos - self.start_pos
|
||||
self.is_drag = false
|
||||
self.value = 0
|
||||
|
||||
self.on_change_value = Event(callback)
|
||||
|
||||
assert(self.dist.x == 0 or self.dist.y == 0, "Slider for now can be only vertical or horizontal")
|
||||
end
|
||||
|
||||
|
||||
function M.on_layout_change(self)
|
||||
self:set(self.value, true)
|
||||
end
|
||||
|
||||
|
||||
function M.on_input(self, action_id, action)
|
||||
if action_id ~= const.ACTION_TOUCH then
|
||||
return false
|
||||
end
|
||||
|
||||
if gui.pick_node(self.node, action.x, action.y) then
|
||||
if action.pressed then
|
||||
self.pos = gui.get_position(self.node)
|
||||
self.is_drag = true
|
||||
end
|
||||
end
|
||||
|
||||
if self.is_drag and not action.pressed then
|
||||
-- move
|
||||
self.pos.x = self.pos.x + action.dx
|
||||
self.pos.y = self.pos.y + action.dy
|
||||
|
||||
local prev_x = self.target_pos.x
|
||||
local prev_y = self.target_pos.y
|
||||
|
||||
self.target_pos.x = helper.clamp(self.pos.x, self.start_pos.x, self.end_pos.x)
|
||||
self.target_pos.y = helper.clamp(self.pos.y, self.start_pos.y, self.end_pos.y)
|
||||
|
||||
if prev_x ~= self.target_pos.x or prev_y ~= self.target_pos.y then
|
||||
local prev_value = self.value
|
||||
|
||||
if self.dist.x > 0 then
|
||||
self.value = (self.target_pos.x - self.start_pos.x) / self.dist.x
|
||||
end
|
||||
|
||||
if self.dist.y > 0 then
|
||||
self.value = (self.target_pos.y - self.start_pos.y) / self.dist.y
|
||||
end
|
||||
|
||||
if self.steps then
|
||||
local closest_dist = 1000
|
||||
local closest = nil
|
||||
for i = 1, #self.steps do
|
||||
local dist = math.abs(self.value - self.steps[i])
|
||||
if dist < closest_dist then
|
||||
closest = self.steps[i]
|
||||
closest_dist = dist
|
||||
end
|
||||
end
|
||||
if closest then
|
||||
self.value = closest
|
||||
end
|
||||
end
|
||||
|
||||
if prev_value ~= self.value then
|
||||
on_change_value(self)
|
||||
end
|
||||
end
|
||||
|
||||
set_position(self, self.value)
|
||||
end
|
||||
|
||||
if action.released then
|
||||
self.is_drag = false
|
||||
end
|
||||
|
||||
return self.is_drag
|
||||
end
|
||||
|
||||
|
||||
--- Set value for slider
|
||||
-- @function slider:set
|
||||
-- @tparam number value Value from 0 to 1
|
||||
-- @tparam[opt] bool is_silent Don't trigger event if true
|
||||
function M.set(self, value, is_silent)
|
||||
value = helper.clamp(value, 0, 1)
|
||||
set_position(self, value)
|
||||
self.value = value
|
||||
if not is_silent then
|
||||
on_change_value(self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Set slider steps. Pin node will
|
||||
-- apply closest step position
|
||||
-- @function slider:set_steps
|
||||
-- @tparam number[] steps Array of steps
|
||||
-- @usage slider:set_steps({0, 0.2, 0.6, 1})
|
||||
function M.set_steps(self, steps)
|
||||
self.steps = steps
|
||||
end
|
||||
|
||||
|
||||
return M
|
@@ -1,110 +0,0 @@
|
||||
--- Component to handle GUI timers.
|
||||
-- Timer updating by game delta time. If game is not focused -
|
||||
-- timer will be not updated.
|
||||
-- @module druid.timer
|
||||
|
||||
--- Component events
|
||||
-- @table Events
|
||||
-- @tfield druid_event on_tick On timer tick callback. Fire every second
|
||||
-- @tfield druid_event on_set_enabled On timer change enabled state callback
|
||||
-- @tfield druid_event on_timer_end On timer end callback
|
||||
|
||||
--- Component fields
|
||||
-- @table Fields
|
||||
-- @tfield node node Trigger node
|
||||
-- @tfield number from Initial timer value
|
||||
-- @tfield number target Target timer value
|
||||
-- @tfield number value Current timer value
|
||||
|
||||
local Event = require("druid.event")
|
||||
local const = require("druid.const")
|
||||
local formats = require("druid.helper.formats")
|
||||
local helper = require("druid.helper")
|
||||
local component = require("druid.component")
|
||||
|
||||
local M = component.create("timer", { const.ON_UPDATE })
|
||||
|
||||
|
||||
--- Component init function
|
||||
-- @function timer:init
|
||||
-- @tparam node node Gui text node
|
||||
-- @tparam number seconds_from Start timer value in seconds
|
||||
-- @tparam[opt=0] number seconds_to End timer value in seconds
|
||||
-- @tparam[opt] function callback Function on timer end
|
||||
function M.init(self, node, seconds_from, seconds_to, callback)
|
||||
self.node = self:get_node(node)
|
||||
seconds_from = math.max(seconds_from, 0)
|
||||
seconds_to = math.max(seconds_to or 0, 0)
|
||||
|
||||
self.on_tick = Event()
|
||||
self.on_set_enabled = Event()
|
||||
self.on_timer_end = Event(callback)
|
||||
|
||||
self:set_to(seconds_from)
|
||||
self:set_interval(seconds_from, seconds_to)
|
||||
|
||||
if seconds_to - seconds_from == 0 then
|
||||
self:set_state(false)
|
||||
self.on_timer_end:trigger(self:get_context(), self)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function M.update(self, dt)
|
||||
if not self.is_on then
|
||||
return
|
||||
end
|
||||
|
||||
self.temp = self.temp + dt
|
||||
local dist = math.min(1, math.abs(self.value - self.target))
|
||||
|
||||
if self.temp > dist then
|
||||
self.temp = self.temp - dist
|
||||
self.value = helper.step(self.value, self.target, 1)
|
||||
M.set_to(self, self.value)
|
||||
|
||||
self.on_tick:trigger(self:get_context(), self.value)
|
||||
|
||||
if self.value == self.target then
|
||||
self:set_state(false)
|
||||
self.on_timer_end:trigger(self:get_context(), self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Set text to text field
|
||||
-- @function timer:set_to
|
||||
-- @tparam number set_to Value in seconds
|
||||
function M.set_to(self, set_to)
|
||||
self.last_value = set_to
|
||||
gui.set_text(self.node, formats.second_string_min(set_to))
|
||||
end
|
||||
|
||||
|
||||
--- Called when update
|
||||
-- @function timer:set_state
|
||||
-- @tparam bool is_on Timer enable state
|
||||
function M.set_state(self, is_on)
|
||||
self.is_on = is_on
|
||||
|
||||
self.on_set_enabled:trigger(self:get_context(), is_on)
|
||||
end
|
||||
|
||||
|
||||
--- Set time interval
|
||||
-- @function timer:set_interval
|
||||
-- @tparam number from Start time in seconds
|
||||
-- @tparam number to Target time in seconds
|
||||
function M.set_interval(self, from, to)
|
||||
self.from = from
|
||||
self.value = from
|
||||
self.temp = 0
|
||||
self.target = to
|
||||
M.set_state(self, true)
|
||||
M.set_to(self, from)
|
||||
end
|
||||
|
||||
|
||||
return M
|
Reference in New Issue
Block a user