diff --git a/alpha_todo.txt b/alpha_todo.txt index bf7cbc8..62342af 100644 --- a/alpha_todo.txt +++ b/alpha_todo.txt @@ -15,21 +15,21 @@ Simple to-do for Druid Alpha 0.2.0 + button add key trigger + button and hover click restriction zone? ++ button polish, actions ++ better scroll size management, check different cases. So implicit now ++ better callbacks for every components - unify component api (get/set/to and other general stuff) -- better callbacks for every components -- better scroll size management, check different cases. So implicit now - better grid + scroll management - better default style, add template for custom style -- add input_text component for alpha release - compare with gooey - add docs for all components - add docs folder for every component with gifs? Solutions - remove component autoremove all children component -- button polish, actions -- Low +- add input_text component for alpha release - add code template and example for user components - custom input settings (name of touch, text, etc) - add good examples with template and/or nodes (basic component no use any of them) diff --git a/docs/index.html b/docs/index.html index 8e850b0..aa797fc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -145,7 +145,7 @@
generated by LDoc 1.4.6 -Last updated 2020-02-24 00:03:02 +Last updated 2020-03-21 20:02:23
diff --git a/druid/base/back_handler.lua b/druid/base/back_handler.lua index 2431f80..00414c8 100644 --- a/druid/base/back_handler.lua +++ b/druid/base/back_handler.lua @@ -1,6 +1,14 @@ --- Component to handle back key (android, backspace) -- @module druid.back_handler +--- Component events +-- @table Events +-- @tfield druid_event on_back On back handler callback + +--- Component fields +-- @table Fields +-- @tfield any params Params to click callbacks + local Event = require("druid.event") local const = require("druid.const") local component = require("druid.component") @@ -10,11 +18,9 @@ local M = component.create("back_handler", { const.ON_INPUT }) --- Component init function -- @function back_handler:init --- @tparam table self Component instance -- @tparam callback callback On back button -- @tparam[opt] params Callback argument function M.init(self, callback, params) - self.callback = callback self.params = params self.on_back = Event(callback) diff --git a/druid/base/blocker.lua b/druid/base/blocker.lua index 303d703..e32239e 100644 --- a/druid/base/blocker.lua +++ b/druid/base/blocker.lua @@ -1,9 +1,17 @@ ---- Component to block input on specify zone (node) +--- Component to block input on specify zone by node -- @module druid.blocker +--- Component events +-- @table Events +-- @tfield druid_event on_click On release button callback +-- @tfield druid_event on_enable_change On enable/disable callback + +--- Component fields +-- @table Fields +-- @tfield node node Trigger node + local Event = require("druid.event") local const = require("druid.const") -local helper = require("druid.helper") local component = require("druid.component") local M = component.create("blocker", { const.ON_INPUT_HIGH }) @@ -22,7 +30,7 @@ function M.on_input(self, action_id, action) return false end - if not helper.is_enabled(self.node) then + if not self:is_enabled(self.node) then return false end @@ -34,13 +42,19 @@ function M.on_input(self, action_id, action) end +--- Set enabled blocker component state +-- @function blocker:set_enabled +-- @tparam bool state Enabled state function M.set_enabled(self, state) - + gui.set_enabled(self.node, state) end +--- Return blocked enabled state +-- @function blocker:is_enabled +-- @treturn bool True, if blocker is enabled function M.is_enabled(self, state) - + return gui.is_enabled(self.node) end diff --git a/druid/base/button.lua b/druid/base/button.lua index 7b940d9..9c431f9 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -1,9 +1,6 @@ --- Component to handle basic GUI button -- @module druid.button ---- Button gui component ---@class druid - --- Component events -- @table Events -- @tfield druid_event on_click On release button callback @@ -144,7 +141,6 @@ end --- Component init function -- @function button:init --- @tparam table self Component instance -- @tparam node node Gui node -- @tparam function callback Button callback -- @tparam[opt] table params Button callback params @@ -246,6 +242,9 @@ function M.on_input_interrupt(self) end +--- Set enabled button component state +-- @function button:set_enabled +-- @tparam bool state Enabled state function M.set_enabled(self, state) self.disabled = not state if self._style.on_set_enabled then @@ -254,7 +253,10 @@ function M.set_enabled(self, state) end -function M.get_enabled(self) +--- Return button enabled state +-- @function button:is_enabled +-- @treturn bool True, if button is enabled +function M.is_enabled(self) return not self.disabled end @@ -262,7 +264,6 @@ end --- Strict button click area. Useful for -- no click events outside stencil node -- @function button:set_click_zone --- @tparam table self Component instance -- @tparam node zone Gui node function M.set_click_zone(self, zone) self.click_zone = self:get_node(zone) diff --git a/druid/base/checkbox.lua b/druid/base/checkbox.lua index 723decd..7770be9 100644 --- a/druid/base/checkbox.lua +++ b/druid/base/checkbox.lua @@ -1,13 +1,54 @@ --- 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 + +--- Component style params +-- @table Style +-- @tfield function on_change_state (self, node, state) + local Event = require("druid.event") local component = require("druid.component") local M = component.create("checkbox") -function M.set_state(self, state, is_silence) +local function on_click(self) + M.set_state(self, not self.state) +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.style = self:get_style() + 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 + + +--- 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) if self.state == state then return end @@ -17,34 +58,18 @@ function M.set_state(self, state, is_silence) self.style.on_change_state(self, self.node, state) end - if not is_silence and self.callback then + 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 -local function on_click(self) - M.set_state(self, not self.state) -end - - -function M.init(self, node, callback, click_node) - self.style = self:get_style() - self.druid = self:get_druid() - self.node = self:get_node(node) - self.click_node = self:get_node(click_node) - self.callback = callback - - 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 - - return M diff --git a/druid/base/checkbox_group.lua b/druid/base/checkbox_group.lua index 3f5ed11..dd9a94a 100644 --- a/druid/base/checkbox_group.lua +++ b/druid/base/checkbox_group.lua @@ -1,32 +1,25 @@ ---- Checkboux group module +--- 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") -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 - - -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 - - +--- 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 = {} @@ -44,4 +37,30 @@ function M.init(self, nodes, callback, click_nodes) end +--- Set checkbox group state +-- @function checkbox_group:set_state +-- @tparam bool[] state 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 diff --git a/druid/base/grid.lua b/druid/base/grid.lua index 6dad84d..86e0444 100644 --- a/druid/base/grid.lua +++ b/druid/base/grid.lua @@ -2,12 +2,34 @@ -- Grid can anchor your elements, get content size and other -- @module druid.grid +--- Component events +-- @table Events +-- @tfield druid_event on_add_item On item add callback +-- @tfield druid_event on_remove_item On item remove callback +-- @tfield druid_event on_clear On grid clear callback +-- @tfield druid_event on_update_positions On update item positions callback + +--- Component fields +-- @table Fields +-- @tfield node parent Parent gui node +-- @tfield node[] nodes List of all grid nodes +-- @tfield vector3 offset Item distance between each other items +-- @tfield vector3 anchor Item anchor +-- @tfield vector3 node_size Item size +-- @tfield vector4 border The size of item content +-- @tfield vector3 border_offer The border offset for correct anchor calculations + local Event = require("druid.event") local component = require("druid.component") local M = component.create("grid") +--- Component init function +-- @function grid:init +-- @tparam node parent The gui node parent, where items will be placed +-- @tparam node element Element prefab. Need to get it size +-- @tparam[opt=1] number in_row How many nodes in row can be placed function M.init(self, parent, element, in_row) self.parent = self:get_node(parent) self.nodes = {} @@ -55,6 +77,7 @@ local function get_pos(self, index) temp_pos.x = col * (self.node_size.x + self.offset.x) - self.border_offset.x temp_pos.y = -row * (self.node_size.y + self.offset.y) - self.border_offset.y + temp_pos.z = 0 return temp_pos end @@ -70,18 +93,29 @@ local function update_pos(self) end + +--- Set grid items offset, the distance between items +-- @function grid:set_offset +-- @tparam vector3 offset Offset function M.set_offset(self, offset) self.offset = offset update_pos(self) end +--- Set grid anchor +-- @function grid:set_anchor +-- @tparam vector3 acnhor Anchor function M.set_anchor(self, anchor) self.anchor = anchor update_pos(self) end +--- Add new item to the grid +-- @function grid:add +-- @tparam node item Gui node +-- @tparam[opt] number index The item position. By default add as last item function M.add(self, item, index) index = index or (#self.nodes + 1) table.insert(self.nodes, index, item) @@ -95,6 +129,9 @@ function M.add(self, item, index) end +--- Return grid content size +-- @function grid:get_size +-- @treturn vector3 The grid content size function M.get_size(self) return vmath.vector3( self.border.z - self.border.x, @@ -103,6 +140,9 @@ function M.get_size(self) end +--- Return array of all node positions +-- @function grid:get_all_pos +-- @treturn vector3[] All grid node positions function M.get_all_pos(self) local result = {} for i = 1, #self.nodes do @@ -113,6 +153,8 @@ function M.get_all_pos(self) end +--- Clear all items from the grid +-- @function grid:clear function M.clear(self) for i = 1, #self.nodes do gui.delete_node(self.nodes[i]) diff --git a/druid/base/hover.lua b/druid/base/hover.lua index a535af9..a38cda0 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -1,5 +1,9 @@ --- Component to handle hover node interaction --- @module druid.input +-- @module druid.hover + +--- Component events +-- @table Events +-- @tfield druid_event on_hover On hover callback local Event = require("druid.event") local const = require("druid.const") @@ -11,7 +15,6 @@ local M = component.create("hover", { const.ON_INPUT }) --- Component init function -- @function hover:init --- @tparam table self Component instance -- @tparam node node Gui node -- @tparam function on_hover_callback Hover callback function M.init(self, node, on_hover_callback) @@ -24,14 +27,6 @@ function M.init(self, node, on_hover_callback) end -function M.set_hover(self, state) - if self._is_hovered ~= state then - self._is_hovered = state - self.on_hover:trigger(self:get_context(), state) - end -end - - function M.on_input(self, action_id, action) if action_id ~= const.ACTION_TOUCH then return @@ -64,10 +59,20 @@ function M.on_input_interrupt(self) end +--- Set hover state +-- @function hover:set_hover +-- @tparam bool state The hover state +function M.set_hover(self, state) + if self._is_hovered ~= state then + self._is_hovered = state + self.on_hover:trigger(self:get_context(), state) + end +end + + --- Strict button click area. Useful for -- no click events outside stencil node -- @function button:set_click_zone --- @tparam table self Component instance -- @tparam node zone Gui node function M.set_click_zone(self, zone) self.click_zone = self:get_node(zone) diff --git a/druid/base/input.lua b/druid/base/input.lua index 3b05fb8..21079a2 100644 --- a/druid/base/input.lua +++ b/druid/base/input.lua @@ -1,4 +1,5 @@ ---- Druid input text component +--- Druid input text component. +-- Carry on user text input -- @local unimplemented -- @module druid.input diff --git a/druid/base/lang_text.lua b/druid/base/lang_text.lua index 760190e..5c81c03 100644 --- a/druid/base/lang_text.lua +++ b/druid/base/lang_text.lua @@ -2,6 +2,15 @@ -- Good working with localization system -- @module druid.lang_text +--- Component events +-- @table Events +-- @tfield druid_event on_change On change text callback + +--- Component fields +-- @table Fields +-- @tfield druid.text text The text component + +local Event = require("druid.event") local const = require("druid.const") local settings = require("druid.system.settings") local component = require("druid.component") @@ -9,31 +18,23 @@ local component = require("druid.component") local M = component.create("lang_text", { const.ON_CHANGE_LANGUAGE }) -function M.init(self, node, lang_id, no_adjust) +--- Component init function +-- @function lang_text:init +-- @tparam node node The text node +-- @tparam string locale_id Default locale id +-- @tparam bool no_adjust If true, will not correct text size +function M.init(self, node, locale_id, no_adjust) self.druid = self:get_druid() - self.text = self.druid:new_text(node, lang_id, no_adjust) - self:translate(lang_id) + self.text = self.druid:new_text(node, locale_id, no_adjust) + + self.on_change = Event() + + self:translate(locale_id) return self end -function M.set_to(self, text) - self.last_locale = false - self.text:set_to(text) -end - - ---- Translate the text by locale_id --- @function text:translate --- @tparam table self Component instance --- @tparam string locale_id Locale id -function M.translate(self, locale_id) - self.last_locale = locale_id or self.last_locale - self.text:set_to(settings.get_text(self.last_locale)) -end - - function M.on_change_language(self) if self.last_locale then M.translate(self) @@ -41,4 +42,23 @@ function M.on_change_language(self) end +--- Setup raw text to lang_text component +-- @function lang_text:set_to +-- @tparam string text Text for text node +function M.set_to(self, text) + self.last_locale = false + self.text:set_to(text) + self.on_change:trigger() +end + + +--- Translate the text by locale_id +-- @function lang_text:translate +-- @tparam string locale_id Locale id +function M.translate(self, locale_id) + self.last_locale = locale_id or self.last_locale + self.text:set_to(settings.get_text(self.last_locale)) +end + + return M diff --git a/druid/base/progress.lua b/druid/base/progress.lua index 251c38f..2aa21e8 100644 --- a/druid/base/progress.lua +++ b/druid/base/progress.lua @@ -1,6 +1,26 @@ ---- Basic progress bar component +--- 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 + +--- Component style params +-- @table Style +-- @tfield number SPEED Progress bas fill rate. More -> faster +-- @tfield number MIN_DELTA Minimum step to fill progress bar + +local Event = require("druid.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") @@ -8,34 +28,6 @@ local component = require("druid.component") local M = component.create("progress", { const.ON_UPDATE }) ---- Component init function --- @function progress:init --- @tparam table self Component instance --- @tparam string|node node Progress bar fill node or node name --- @tparam string key Progress bar direction (x or y) --- @tparam 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.style = self:get_style() - 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:set_to(init_value or 1) -end - - local function check_steps(self, from, to, exactly) if not self.steps then return @@ -58,7 +50,7 @@ local function check_steps(self, from, to, exactly) end -local function set_bar_to(self, set_to, is_silence) +local function set_bar_to(self, set_to, is_silent) local prev_value = self.last_value self.last_value = set_to @@ -72,73 +64,38 @@ local function set_bar_to(self, set_to, is_silence) self.size[self.key] = size gui.set_size(self.node, self.size) - if not is_silence then + if not is_silent then check_steps(self, prev_value, set_to) end end ---- Fill a progress bar and stop progress animation --- @function progress:empty --- @tparam table self Component instance -function M.fill(self) - set_bar_to(self, 1, true) -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 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 ---- Empty a progress bar --- @function progress:empty --- @tparam table self Component instance -function M.empty(self) - set_bar_to(self, 0, true) -end - - ---- Instant fill progress bar to value --- @function progress:set_to --- @tparam table self Component instance --- @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 --- @tparam table self Component instance -function M.get(self) - return self.last_value -end - - ---- Set points on progress bar to fire the callback --- @function progress:set_steps --- @tparam table self Component instance --- @tparam table steps Array of progress bar values --- @tparam function callback Callback on intersect step value -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 table self Component instance --- @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 + self.style = self:get_style() + 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 - if callback then - callback(self:get_context(), to) - end + self.slice_size = self.slice.y + self.slice.w end + + self.on_change = Event() + + self:set_to(init_value or 1) end @@ -162,4 +119,63 @@ function M.update(self, dt) 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 diff --git a/druid/base/radio_group.lua b/druid/base/radio_group.lua index b5e2f97..a446d02 100644 --- a/druid/base/radio_group.lua +++ b/druid/base/radio_group.lua @@ -1,6 +1,15 @@ --- 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") @@ -11,17 +20,43 @@ local function on_checkbox_click(self, index) self.checkboxes[i]:set_state(i == index, true) end - if self.callback then - self.callback(self:get_context(), index) + 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 bool[] state Array of checkbox state function M.set_state(self, index) on_checkbox_click(self, index) end +--- Return radio group state +-- @function radio_group:get_state +-- @treturn bool[] Array if checkboxes state function M.get_state(self) local result = -1 @@ -36,20 +71,4 @@ function M.get_state(self) end -function M.init(self, nodes, callback, click_nodes) - self.druid = self:get_druid() - self.checkboxes = {} - self.callback = 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 - - return M diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index f95cdd9..4a437c2 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -1,6 +1,41 @@ ---- Component to handle scroll content +--- Component to handle scroll content. +-- Scroll consist from two nodes: scroll parent and scroll input +-- Scroll input the user input zone, it's static +-- Scroll parent the scroll moving part, it will change position. +-- Setup initial scroll size by changing scroll parent size. If scroll parent +-- size will be less than scroll_input size, no scroll is available. For scroll +-- parent size should be more than input size -- @module druid.scroll +--- Component events +-- @table Events +-- @tfield druid_event on_scroll On scroll move callback +-- @tfield druid_event on_scroll_to On scroll_to function callback +-- @tfield druid_event on_point_scroll On scroll_to_index function callbck + +--- Component fields +-- @table Fields +-- @tfield node node Scroll parent node +-- @tfield node input_zone Scroll input node +-- @tfield vector3 zone_size Current scroll content size +-- @tfield number soft_size Soft zone size from style table +-- @tfield vector3 center_offset Distance from node to node's center +-- @tfield bool is_inert Flag, if scroll now moving by inertion +-- @tfield vector3 inert Current inert speed +-- @tfield vector3 pos Current scroll posisition +-- @tfield vector3 target Current scroll target position + +--- Component style params +-- @table Style +-- @tfield number FRICT_HOLD Multiplier for inertion, while touching +-- @tfield number FRICT Multiplier for free inertion +-- @tfield number INERT_THRESHOLD Scroll speed to stop inertion +-- @tfield number INERT_SPEED Multiplier for inertion speed +-- @tfield number DEADZONE Deadzone for start scrol in pixels +-- @tfield number SOFT_ZONE_SIZE Size of outside zone in pixels (for scroll back moving) +-- @tfield number BACK_SPEED Scroll back returning lerp speed +-- @tfield number ANIM_SPEED Scroll gui.animation speed for scroll_to function + local Event = require("druid.event") local helper = require("druid.helper") local const = require("druid.const") @@ -46,39 +81,6 @@ local function update_border(self) end -function M.init(self, scroll_parent, input_zone, border) - self.style = self:get_style() - self.node = self:get_node(scroll_parent) - self.input_zone = self:get_node(input_zone) - - self.zone_size = gui.get_size(self.input_zone) - self.soft_size = self.style.SOFT_ZONE_SIZE - - -- Distance from node to node's center - local offset = helper.get_pivot_offset(gui.get_pivot(self.input_zone)) - self.center_offset = vmath.vector3(self.zone_size) - self.center_offset.x = self.center_offset.x * offset.x - self.center_offset.y = self.center_offset.y * offset.y - - self.is_inert = true - self.inert = vmath.vector3(0) - self.pos = gui.get_position(self.node) - self.target = vmath.vector3(self.pos) - - self.input = { - touch = false, - start_x = 0, - start_y = 0, - side = false, - } - - update_border(self) - - self.on_scroll = Event() - self.on_scroll_to = Event() - self.on_point_scroll = Event() -end - local function set_pos(self, pos) if self.pos.x ~= pos.x or self.pos.y ~= pos.y then @@ -146,6 +148,7 @@ end --- Find closer point of interest -- if no inert, scroll to next point by scroll direction -- if inert, find next point by scroll director +-- @local local function check_points(self) if not self.points then return @@ -236,17 +239,6 @@ local function cancel_animate(self) end -function M.update(self, dt) - if self.input.touch then - if M.current_scroll == self then - update_hand_scroll(self, dt) - end - else - update_free_inert(self, dt) - end -end - - local function add_delta(self, dx, dy) local t = self.target local b = self.border @@ -295,6 +287,55 @@ local function add_delta(self, dx, dy) end +--- Component init function +-- @function scroll:init +-- @tparam node scroll_parent Gui node where placed scroll content. This node will change position +-- @tparam node input_zone Gui node where input is catched +function M.init(self, scroll_parent, input_zone) + self.style = self:get_style() + self.node = self:get_node(scroll_parent) + self.input_zone = self:get_node(input_zone) + + self.zone_size = gui.get_size(self.input_zone) + self.soft_size = self.style.SOFT_ZONE_SIZE + + -- Distance from node to node's center + local offset = helper.get_pivot_offset(gui.get_pivot(self.input_zone)) + self.center_offset = vmath.vector3(self.zone_size) + self.center_offset.x = self.center_offset.x * offset.x + self.center_offset.y = self.center_offset.y * offset.y + + self.is_inert = true + self.inert = vmath.vector3(0) + self.pos = gui.get_position(self.node) + self.target = vmath.vector3(self.pos) + + self.input = { + touch = false, + start_x = 0, + start_y = 0, + side = false, + } + + update_border(self) + + self.on_scroll = Event() + self.on_scroll_to = Event() + self.on_point_scroll = Event() +end + + +function M.update(self, dt) + if self.input.touch then + if M.current_scroll == self then + update_hand_scroll(self, dt) + end + else + update_free_inert(self, dt) + end +end + + function M.on_input(self, action_id, action) if action_id ~= const.ACTION_TOUCH then return false @@ -377,9 +418,10 @@ function M.scroll_to(self, point, is_instant) end) end - self.on_scroll_to:trigger(self:get_context(), point, is_instant) + self.on_scroll_to:trigger(self:get_context(), target, is_instant) end + --- Start scroll to target scroll percent -- @function scroll:scroll_to_percent -- @tparam point vector3 target percent @@ -404,11 +446,11 @@ function M.scroll_to_percent(self, percent, is_instant) M.scroll_to(self, pos, is_instant) end + --- Scroll to item in scroll by point index -- @function scroll:init --- @tparam table self Component instance -- @tparam number index Point index --- @tparam[opt] boolean skip_cb If true, skip the point callback +-- @tparam[opt] bool skip_cb If true, skip the point callback function M.scroll_to_index(self, index, skip_cb) index = helper.clamp(index, 1, #self.points) @@ -427,7 +469,6 @@ end --- Set points of interest. -- Scroll will always centered on closer points -- @function scroll:set_points --- @tparam table self Component instance -- @tparam table points Array of vector3 points function M.set_points(self, points) self.points = points @@ -447,8 +488,7 @@ end -- If disabled, scroll through points (if exist) -- If no points, just simple drag without inertion -- @function scroll:set_inert --- @tparam table self Component instance --- @tparam boolean state Inert scroll state +-- @tparam bool state Inert scroll state function M.set_inert(self, state) self.is_inert = state end @@ -456,7 +496,6 @@ end --- Set the callback on scrolling to point (if exist) -- @function scroll:on_point_move --- @tparam table self Component instance -- @tparam function callback Callback on scroll to point of interest function M.on_point_move(self, callback) self.on_point_scroll:subscribe(callback) @@ -465,8 +504,7 @@ end --- Set the scroll possibly area -- @function scroll:set_border --- @tparam table self Component instance --- @tparam vmath.vector3 border Size of scrolling area +-- @tparam vector3 border Size of scrolling area function M.set_border(self, content_size) gui.set_size(self.node, content_size) update_border(self) @@ -475,8 +513,7 @@ end --- Return current scroll progress -- @function scroll:get_scroll_percent --- @tparam table self Component instance --- @return vmath.vector3 Scroll progress +-- @treturn vector3 Scroll progress function M.get_scroll_percent(self) local border = self.border local size_x = math.abs(border.z - border.x) diff --git a/druid/base/slider.lua b/druid/base/slider.lua index 945c4e3..f5b8f13 100644 --- a/druid/base/slider.lua +++ b/druid/base/slider.lua @@ -1,6 +1,22 @@ --- 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") @@ -14,6 +30,11 @@ local function on_change_value(self) 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) @@ -79,6 +100,10 @@ function M.on_input(self, action_id, action) 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) diff --git a/druid/base/text.lua b/druid/base/text.lua index 1c19c2f..436a4c7 100644 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -1,7 +1,25 @@ ---- Component to handle all GUI texts --- Good working with localization system +--- Component to handle all GUI texts. +-- Druid text can adjust itself for text node size +-- Text will never will be outside of his text size (even multiline) -- @module druid.text +--- Component events +-- @table Events +-- @tfield druid_event on_set_text On set text callback +-- @tfield druid_event on_update_text_scale On adjust text size callback +-- @tfield druid_event on_set_pivot On change pivot callback + +--- Component fields +-- @table Fields +-- @tfield node node Text node +-- @tfield vector3 pos Current text position +-- @tfield vector3 start_scale Initial text node scale +-- @tfield vector3 scale Current text node scale +-- @tfield vector3 start_size Initial text node size +-- @tfield vector3 text_area Current text node available are +-- @tfield bool is_no_adjust Current text size adjust settings +-- @tfield vector3 color Current text color + local Event = require("druid.event") local const = require("druid.const") local component = require("druid.component") @@ -19,33 +37,6 @@ local function update_text_size(self) end -function M.init(self, node, value, no_adjust) - self.node = self:get_node(node) - self.start_pivot = gui.get_pivot(self.node) - - self.start_pos = gui.get_position(self.node) - self.pos = gui.get_position(self.node) - - self.start_scale = gui.get_scale(self.node) - self.scale = gui.get_scale(self.node) - - self.start_size = gui.get_size(self.node) - self.text_area = gui.get_size(self.node) - self.text_area.x = self.text_area.x * self.start_scale.x - self.text_area.y = self.text_area.y * self.start_scale.y - - self.is_no_adjust = no_adjust - self.last_color = gui.get_color(self.node) - - self.on_set_text = Event() - self.on_update_text_scale = Event() - self.on_set_pivot = Event() - - self:set_to(value or 0) - return self -end - - --- Setup scale x, but can only be smaller, than start text scale local function update_text_area_size(self) gui.set_scale(self.node, self.start_scale) @@ -73,9 +64,37 @@ local function update_text_area_size(self) end +--- Component init function +-- @function text:init +-- @tparam node node Gui text node +-- @tparam[opt] string value Initial text +-- @tparam[opt] bool no_adjust If true, text will be not auto-adjust size +function M.init(self, node, value, no_adjust) + self.node = self:get_node(node) + self.pos = gui.get_position(self.node) + + self.start_scale = gui.get_scale(self.node) + self.scale = gui.get_scale(self.node) + + self.start_size = gui.get_size(self.node) + self.text_area = gui.get_size(self.node) + self.text_area.x = self.text_area.x * self.start_scale.x + self.text_area.y = self.text_area.y * self.start_scale.y + + self.is_no_adjust = no_adjust + self.color = gui.get_color(self.node) + + self.on_set_text = Event() + self.on_update_text_scale = Event() + self.on_set_pivot = Event() + + self:set_to(value or 0) + return self +end + + --- Set text to text field -- @function text:set_to --- @tparam table self Component instance -- @tparam string set_to Text for node function M.set_to(self, set_to) self.last_value = set_to @@ -91,28 +110,25 @@ end --- Set color -- @function text:set_color --- @tparam table self Component instance --- @tparam vmath.vector4 color Color for node +-- @tparam vector4 color Color for node function M.set_color(self, color) - self.last_color = color + self.color = color gui.set_color(self.node, color) end --- Set alpha -- @function text:set_alpha --- @tparam table self Component instance -- @tparam number alpha Alpha for node function M.set_alpha(self, alpha) - self.last_color.w = alpha - gui.set_color(self.node, self.last_color) + self.color.w = alpha + gui.set_color(self.node, self.color) end --- Set scale -- @function text:set_scale --- @tparam table self Component instance --- @tparam vmath.vector3 scale Scale for node +-- @tparam vector3 scale Scale for node function M.set_scale(self, scale) self.last_scale = scale gui.set_scale(self.node, scale) @@ -122,7 +138,6 @@ end --- Set text pivot. Text will re-anchor inside -- his text area -- @function text:set_pivot --- @tparam table self Component instance -- @tparam gui.pivot pivot Gui pivot constant function M.set_pivot(self, pivot) local prev_pivot = gui.get_pivot(self.node) diff --git a/druid/base/timer.lua b/druid/base/timer.lua index 8fecf86..712dc93 100644 --- a/druid/base/timer.lua +++ b/druid/base/timer.lua @@ -1,6 +1,24 @@ ---- Component to handle GUI timers +--- 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[opt=node] node anim_node Animation node +-- @tfield vector3 scale_from Initial scale of anim_node +-- @tfield vector3 pos Initial pos of anim_node +-- @tfield any params Params to click callbacks +-- @tfield druid.hover hover Druid hover logic component +-- @tfield[opt] node click_zone Restriction zone + local Event = require("druid.event") local const = require("druid.const") local formats = require("druid.helper.formats") @@ -10,6 +28,12 @@ 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) @@ -31,42 +55,6 @@ function M.init(self, node, seconds_from, seconds_to, callback) end ---- Set text to text field --- @function timer:set_to --- @tparam table self Component instance --- @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 table self Component instance --- @tparam boolean 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 table self Component instance --- @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 - - function M.update(self, dt) if not self.is_on then return @@ -89,5 +77,37 @@ function M.update(self, dt) 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 \ No newline at end of file diff --git a/druid/event.lua b/druid/event.lua index 1d6c289..b4bc110 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -45,7 +45,7 @@ end --- Return true, if event have at lease one handler -- @function event:is_exist --- @treturn boolean True if event have handlers +-- @treturn bool True if event have handlers function M.is_exist(self) return #self._callbacks > 0 end diff --git a/example/kenney/page/main.lua b/example/kenney/page/main.lua index 70e5539..834593c 100644 --- a/example/kenney/page/main.lua +++ b/example/kenney/page/main.lua @@ -19,8 +19,8 @@ end local function setup_button(self) local b = self.druid:new_button("button_simple", lang.toggle_locale, "button_param") self.druid:new_button("button_template/button", function() - print(b:get_enabled()) - b:set_enabled(not b:get_enabled()) + print(b:is_enabled()) + b:set_enabled(not b:is_enabled()) end, "button_param") end diff --git a/example/kenney/page/scroll.lua b/example/kenney/page/scroll.lua index 71fe04d..4fb112c 100644 --- a/example/kenney/page/scroll.lua +++ b/example/kenney/page/scroll.lua @@ -4,6 +4,7 @@ local M = {} local function init_grid(self) local prefab = gui.get_node("grid_prefab") + local grid_scroll = self.druid:new_scroll("grid_content", "scroll_with_grid_size") local grid = self.druid:new_grid("grid_content", "grid_prefab", 20) grid:set_anchor(vmath.vector3(0, 0.5, 0)) @@ -13,12 +14,15 @@ local function init_grid(self) grid:add(clone_prefab["grid_prefab"]) gui.set_text(clone_prefab["grid_prefab_text"], "Node " .. i) - self.druid:new_button(clone_prefab["grid_button"]) + self.druid:new_button(clone_prefab["grid_button"], function() + local position = gui.get_position(clone_prefab["grid_prefab"]) + position.x = -position.x + grid_scroll:scroll_to(position) + end) end gui.set_enabled(prefab, false) - local grid_scroll = self.druid:new_scroll("grid_content", "scroll_with_grid_size") grid_scroll:set_border(grid:get_size()) local scroll_slider = self.druid:new_slider("grid_scroll_pin", vmath.vector3(300, 0, 0), function(_, value)