From 959f367dd79b03d9ca136b3af7c5cf7e0b90fe4f Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 22 Mar 2020 15:24:04 +0300 Subject: [PATCH 01/11] Remove done stuff from alpha todo --- alpha_todo.txt | 28 +--------------------------- druid/base/button.lua | 5 +++-- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/alpha_todo.txt b/alpha_todo.txt index 62342af..082801c 100644 --- a/alpha_todo.txt +++ b/alpha_todo.txt @@ -1,38 +1,12 @@ Simple to-do for Druid Alpha 0.2.0 - --- High -+ remove button event and match_event from druid -+ add hover component -+ add druid events/triggers? better callback system -+ better name for locale component? lang? lang_text? -+ better name for slider component? Slider is ok -+ Druid store assets - separate repository with rich components (progress_rich migrate) -+ refactor on_swipe. To on_scroll? Add input priority -+ separate custom data and predefined fields in components? Every component have their fields and events -+ How to set custom sprites for button states? -+ add druid settings (add auto_focus input and other stuff) (to game.project) - -+ 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 grid + scroll management - better default style, add template for custom style - compare with gooey -- add docs for all components -- add docs folder for every component with gifs? Solutions - remove component autoremove all children component - --- Low +- unify component api (get/set/to and other general stuff) - 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) - try use final druid in real project (FI uses custom druid) (use in 4321?) - ability to relocalize all locale text nodes - ability to control buttons via controller. Select it by cursor (d-pad) diff --git a/druid/base/button.lua b/druid/base/button.lua index 9c431f9..3ae4f72 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -7,6 +7,7 @@ -- @tfield druid_event on_repeated_click On repeated action button callback -- @tfield druid_event on_long_click On long tap button callback -- @tfield druid_event on_double_click On double tap button callback +-- @tfield druid_event on_hold_click On button hold before long_click callback --- Component fields -- @table Fields @@ -99,7 +100,7 @@ end local function on_button_hold(self, press_time) - self.on_hold_callback:trigger(self:get_context(), self.params, self, press_time) + self.on_hold_click:trigger(self:get_context(), self.params, self, press_time) end @@ -167,7 +168,7 @@ function M.init(self, node, callback, params, anim_node, event) self.on_repeated_click = Event() self.on_long_click = Event() self.on_double_click = Event() - self.on_hold_callback = Event() + self.on_hold_click = Event() end From 696622b42bfa3b190b513a76744ad704b03a70e5 Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 22 Mar 2020 15:24:47 +0300 Subject: [PATCH 02/11] Rename back hold_click -> hold_callback --- docs_md/01-components.md | 2 +- druid/base/button.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 513261c..59a88e8 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -13,7 +13,7 @@ Basic Druid input component - **on_click** - basic button callback - **on_repeated_click** - repeated click callback, while holding the button, don't trigger if callback is empty - **on_long_click** - callback on long button tap, don't trigger if callback is empty - - **on_hold_click** - hold callback, before long_click trigger, don't trigger if callback is empty + - **on_hold_callback** - hold callback, before long_click trigger, don't trigger if callback is empty - **on_double_click** - different callback, if tap button 2+ in row, don't trigger if callback is empty - If you have stencil on buttons and you don't want trigger them outside of stencil node, you can use `button:set_click_zone` to restrict button click zone - Button can have key trigger to use then by key: `button:set_key_trigger` diff --git a/druid/base/button.lua b/druid/base/button.lua index 3ae4f72..b42a3c9 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -7,7 +7,7 @@ -- @tfield druid_event on_repeated_click On repeated action button callback -- @tfield druid_event on_long_click On long tap button callback -- @tfield druid_event on_double_click On double tap button callback --- @tfield druid_event on_hold_click On button hold before long_click callback +-- @tfield druid_event on_hold_callback On button hold before long_click callback --- Component fields -- @table Fields @@ -100,7 +100,7 @@ end local function on_button_hold(self, press_time) - self.on_hold_click:trigger(self:get_context(), self.params, self, press_time) + self.on_hold_callback:trigger(self:get_context(), self.params, self, press_time) end @@ -168,7 +168,7 @@ function M.init(self, node, callback, params, anim_node, event) self.on_repeated_click = Event() self.on_long_click = Event() self.on_double_click = Event() - self.on_hold_click = Event() + self.on_hold_callback = Event() end From 7c22032004f01d4e82857c3a53dd5bf87df1b8dd Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 22 Mar 2020 15:32:00 +0300 Subject: [PATCH 03/11] Clean up todo, more docs --- docs/index.html | 2 +- docs/modules/component.html | 36 ++++++++++++++++++- docs/modules/druid.back_handler.html | 2 +- docs/modules/druid.blocker.html | 2 +- docs/modules/druid.button.html | 8 +++-- docs/modules/druid.checkbox.html | 2 +- docs/modules/druid.checkbox_group.html | 2 +- docs/modules/druid.grid.html | 2 +- docs/modules/druid.helper.html | 2 +- docs/modules/druid.hover.html | 2 +- docs/modules/druid.html | 2 +- docs/modules/druid.input.html | 2 +- docs/modules/druid.lang_text.html | 2 +- docs/modules/druid.progress.html | 2 +- docs/modules/druid.radio_group.html | 2 +- docs/modules/druid.scroll.html | 2 +- docs/modules/druid.slider.html | 2 +- docs/modules/druid.text.html | 2 +- docs/modules/druid.timer.html | 34 ++++++------------ docs/modules/druid_event.html | 2 +- docs/modules/druid_instance.html | 2 +- docs/topics/01-components.md.html | 4 +-- .../02-creating_custom_components.md.html | 2 +- docs/topics/03-styles.md.html | 2 +- docs/topics/04-druid_assets.md.html | 2 +- docs/topics/05-examples.md.html | 2 +- docs/topics/README.md.html | 2 +- druid/base/button.lua | 5 ++- druid/base/timer.lua | 9 ++--- druid/component.lua | 11 +++--- druid/druid.lua | 3 -- druid/styles/default/anims.lua | 2 +- druid/styles/default/style.lua | 6 ++-- 33 files changed, 92 insertions(+), 72 deletions(-) diff --git a/docs/index.html b/docs/index.html index 12e78fc..b5f8636 100644 --- a/docs/index.html +++ b/docs/index.html @@ -185,7 +185,7 @@
generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
diff --git a/docs/modules/component.html b/docs/modules/component.html index 2a20847..9c39094 100644 --- a/docs/modules/component.html +++ b/docs/modules/component.html @@ -117,6 +117,10 @@ Get current component interests + get_node(node_or_name) + Get node for component by name. + + get_druid() Return druid with context of calling component. @@ -320,6 +324,36 @@ + +
+ + get_node(node_or_name) +
+
+ Get node for component by name. + If component has nodes, nodeorname should be string + It auto pick node by template name or from nodes by clonetree + if they was setup via component:setnodes, component:set_template + + +

Parameters:

+
    +
  • node_or_name + string or node + Node name or node itself +
  • +
+ +

Returns:

+
    + + node + Gui node +
+ + + +
@@ -406,7 +440,7 @@
generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
diff --git a/docs/modules/druid.back_handler.html b/docs/modules/druid.back_handler.html index e325a78..3cf72b7 100644 --- a/docs/modules/druid.back_handler.html +++ b/docs/modules/druid.back_handler.html @@ -215,7 +215,7 @@
generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
diff --git a/docs/modules/druid.blocker.html b/docs/modules/druid.blocker.html index 561ad3b..efd7755 100644 --- a/docs/modules/druid.blocker.html +++ b/docs/modules/druid.blocker.html @@ -234,7 +234,7 @@
generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
diff --git a/docs/modules/druid.button.html b/docs/modules/druid.button.html index bbdf5fe..b9379cb 100644 --- a/docs/modules/druid.button.html +++ b/docs/modules/druid.button.html @@ -305,6 +305,10 @@ druid_event On double tap button callback +
  • on_hold_callback + druid_event + On button hold before long_click callback +
  • @@ -331,7 +335,7 @@ Animation node (default node) -
  • scale_from +
  • start_scale vector3 Initial scale of anim_node
  • @@ -405,7 +409,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.checkbox.html b/docs/modules/druid.checkbox.html index e342bba..a410199 100644 --- a/docs/modules/druid.checkbox.html +++ b/docs/modules/druid.checkbox.html @@ -277,7 +277,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.checkbox_group.html b/docs/modules/druid.checkbox_group.html index 2141614..197d339 100644 --- a/docs/modules/druid.checkbox_group.html +++ b/docs/modules/druid.checkbox_group.html @@ -239,7 +239,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.grid.html b/docs/modules/druid.grid.html index 6e08671..e390359 100644 --- a/docs/modules/druid.grid.html +++ b/docs/modules/druid.grid.html @@ -370,7 +370,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.helper.html b/docs/modules/druid.helper.html index d51cedf..137f7bb 100644 --- a/docs/modules/druid.helper.html +++ b/docs/modules/druid.helper.html @@ -236,7 +236,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.hover.html b/docs/modules/druid.hover.html index 7f092f2..771d8ff 100644 --- a/docs/modules/druid.hover.html +++ b/docs/modules/druid.hover.html @@ -211,7 +211,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.html b/docs/modules/druid.html index 890513e..5f52033 100644 --- a/docs/modules/druid.html +++ b/docs/modules/druid.html @@ -181,7 +181,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.input.html b/docs/modules/druid.input.html index eeed464..d5678b3 100644 --- a/docs/modules/druid.input.html +++ b/docs/modules/druid.input.html @@ -86,7 +86,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.lang_text.html b/docs/modules/druid.lang_text.html index 052acc8..ddcef2f 100644 --- a/docs/modules/druid.lang_text.html +++ b/docs/modules/druid.lang_text.html @@ -240,7 +240,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.progress.html b/docs/modules/druid.progress.html index 26fa713..b614a40 100644 --- a/docs/modules/druid.progress.html +++ b/docs/modules/druid.progress.html @@ -378,7 +378,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.radio_group.html b/docs/modules/druid.radio_group.html index 0391222..df89283 100644 --- a/docs/modules/druid.radio_group.html +++ b/docs/modules/druid.radio_group.html @@ -239,7 +239,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.scroll.html b/docs/modules/druid.scroll.html index 8d3c393..be05f0c 100644 --- a/docs/modules/druid.scroll.html +++ b/docs/modules/druid.scroll.html @@ -507,7 +507,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.slider.html b/docs/modules/druid.slider.html index 49068a6..dceaa2f 100644 --- a/docs/modules/druid.slider.html +++ b/docs/modules/druid.slider.html @@ -278,7 +278,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.text.html b/docs/modules/druid.text.html index b74e503..6889bab 100644 --- a/docs/modules/druid.text.html +++ b/docs/modules/druid.text.html @@ -352,7 +352,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid.timer.html b/docs/modules/druid.timer.html index f76d4c3..1116615 100644 --- a/docs/modules/druid.timer.html +++ b/docs/modules/druid.timer.html @@ -267,31 +267,17 @@ node Trigger node -
  • anim_node - node - Animation node - (default node) +
  • from + number + Initial timer value
  • -
  • scale_from - vector3 - Initial scale of anim_node +
  • target + number + Target timer value
  • -
  • pos - vector3 - Initial pos of anim_node -
  • -
  • params - any - Params to click callbacks -
  • -
  • hover - druid.hover - Druid hover logic component -
  • -
  • click_zone - node - Restriction zone - (optional) +
  • value + number + Current timer value
  • @@ -307,7 +293,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid_event.html b/docs/modules/druid_event.html index 7850ea7..7773bc4 100644 --- a/docs/modules/druid_event.html +++ b/docs/modules/druid_event.html @@ -239,7 +239,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/modules/druid_instance.html b/docs/modules/druid_instance.html index 6d30ad0..b8a6f6b 100644 --- a/docs/modules/druid_instance.html +++ b/docs/modules/druid_instance.html @@ -750,7 +750,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/topics/01-components.md.html b/docs/topics/01-components.md.html index a0875e0..2e0a3ef 100644 --- a/docs/topics/01-components.md.html +++ b/docs/topics/01-components.md.html @@ -111,7 +111,7 @@ - **on_click** - basic button callback - **on_repeated_click** - repeated click callback, while holding the button, don't trigger if callback is empty - **on_long_click** - callback on long button tap, don't trigger if callback is empty -- **on_hold_click** - hold callback, before long_click trigger, don't trigger if callback is empty +- **on_hold_callback** - hold callback, before long_click trigger, don't trigger if callback is empty - **on_double_click** - different callback, if tap button 2+ in row, don't trigger if callback is empty @@ -210,7 +210,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/topics/02-creating_custom_components.md.html b/docs/topics/02-creating_custom_components.md.html index cd684e7..e33e05d 100644 --- a/docs/topics/02-creating_custom_components.md.html +++ b/docs/topics/02-creating_custom_components.md.html @@ -202,7 +202,7 @@ There is next interests in druid:
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/topics/03-styles.md.html b/docs/topics/03-styles.md.html index f6bafcd..613a57f 100644 --- a/docs/topics/03-styles.md.html +++ b/docs/topics/03-styles.md.html @@ -138,7 +138,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/topics/04-druid_assets.md.html b/docs/topics/04-druid_assets.md.html index cab9b23..74a30f5 100644 --- a/docs/topics/04-druid_assets.md.html +++ b/docs/topics/04-druid_assets.md.html @@ -89,7 +89,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/topics/05-examples.md.html b/docs/topics/05-examples.md.html index 671c7ff..aae01a8 100644 --- a/docs/topics/05-examples.md.html +++ b/docs/topics/05-examples.md.html @@ -87,7 +87,7 @@
    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/docs/topics/README.md.html b/docs/topics/README.md.html index 742f109..c1b6857 100644 --- a/docs/topics/README.md.html +++ b/docs/topics/README.md.html @@ -291,7 +291,7 @@ https://insality.github.io/druid/

    generated by LDoc 1.4.6 -Last updated 2020-03-22 15:19:02 +Last updated 2020-03-22 15:31:43
    diff --git a/druid/base/button.lua b/druid/base/button.lua index b42a3c9..89e916c 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -13,7 +13,7 @@ -- @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 start_scale 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 @@ -152,8 +152,7 @@ function M.init(self, node, callback, params, anim_node, event) self.node = self:get_node(node) self.anim_node = anim_node and helper:get_node(anim_node) or self.node - -- TODO: rename to start_scale - self.scale_from = gui.get_scale(self.anim_node) + self.start_scale = gui.get_scale(self.anim_node) self.params = params self.hover = self.druid:new_hover(node, on_button_hover) self.click_zone = nil diff --git a/druid/base/timer.lua b/druid/base/timer.lua index 712dc93..cbf02df 100644 --- a/druid/base/timer.lua +++ b/druid/base/timer.lua @@ -12,12 +12,9 @@ --- 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 +-- @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") diff --git a/druid/component.lua b/druid/component.lua index 1e8be3a..47486b4 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -86,10 +86,13 @@ function Component.get_interests(self) end --- TODO: Определиться с get_node и node --- get_node - берет ноду по ноде или строке --- node - может брать ноду у компонента по схеме (если есть --- template или таблица нод после gui.clone_tree) +--- Get node for component by name. +-- If component has nodes, node_or_name should be string +-- It auto pick node by template name or from nodes by clone_tree +-- if they was setup via component:set_nodes, component:set_template +-- @function component:get_node +-- @tparam string|node node_or_name Node name or node itself +-- @treturn node Gui node function Component.get_node(self, node_or_name) local template_name = self:get_template() or const.EMPTY_STRING local nodes = self:get_nodes() diff --git a/druid/druid.lua b/druid/druid.lua index 458b2c5..3fb795d 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -31,13 +31,10 @@ local M = {} -- @tparam table module lua table with component function M.register(name, module) -- TODO: Find better solution to creating elements? - -- Possibly: druid.new(druid.BUTTON, etc?) -- Current way is very implicit druid_instance["new_" .. name] = function(self, ...) return druid_instance.create(self, module, ...) end - - -- print("Register component", name) end diff --git a/druid/styles/default/anims.lua b/druid/styles/default/anims.lua index ae56a40..d2d3d69 100644 --- a/druid/styles/default/anims.lua +++ b/druid/styles/default/anims.lua @@ -24,7 +24,7 @@ end function M.tap_scale_animation(self, node, target_scale) scale_to(self, node, target_scale, function() - M.back_scale_animation(self, node, self.scale_from) + M.back_scale_animation(self, node, self.start_scale) end ) end diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index f34558f..5e3e05b 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -18,14 +18,14 @@ M["button"] = { IS_HOVER = true, on_hover = function(self, node, state) - local scale_to = self.scale_from + M.button.HOVER_SCALE + local scale_to = self.start_scale + M.button.HOVER_SCALE - local target_scale = state and scale_to or self.scale_from + local target_scale = state and scale_to or self.start_scale anims.hover_scale(self, target_scale, M.button.HOVER_TIME) end, on_click = function(self, node) - local scale_to = self.scale_from + M.button.SCALE_CHANGE + local scale_to = self.start_scale + M.button.SCALE_CHANGE anims.tap_scale_animation(self, node, scale_to) settings.play_sound(M.button.BTN_SOUND) end, From 017138b5ff91ebbc1aa22d0b46216edc6eb0c3ed Mon Sep 17 00:00:00 2001 From: Insality Date: Sun, 22 Mar 2020 15:56:05 +0300 Subject: [PATCH 04/11] Update READMES --- README.md | 2 +- docs_md/02-creating_custom_components.md | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7f7c5c9..5b004db 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ Any events can handle several callbacks, if needed. ## Examples -See the [example folder](https://github.com/insality/druid/tree/develop/example/kenney) for examples of how to use **Druid** +See the [example folder](https://github.com/Insality/druid/tree/develop/example) for examples of how to use **Druid** See the [druid-assets repository](https://github.com/insality/druid-assets) for examples of how to create custom components and styles diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index d761462..bcebe7d 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -47,11 +47,23 @@ Add your custom component to druid via `druid.register` local druid = require("druid.druid") local my_component = require("my.amazing.component") -local function init(self) +function init(self) druid.register("my_component", my_component) end ``` +Registering make new function with "new_{component_name}". In our example it will be: `druid:new_my_component()` + +As component registered, you can create your component with next code: +```lua +local druid = require("druid.druid") + +function init(self) + self.druid = druid.new(self) + local my_component = self.druid:new_my_component(...) +end +``` + ### Interest Interest - is a way to indicate what events your component will respond to. There is next interests in druid: From 7821c031dda937bc85aba2f33c8962c155006eca Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 28 Mar 2020 16:46:50 +0300 Subject: [PATCH 05/11] Resolve #36: Get default druid text value from node --- druid/base/text.lua | 4 ++-- example/gui/main/main.gui | 6 +++--- example/page/texts.lua | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/druid/base/text.lua b/druid/base/text.lua index 436a4c7..e7701ee 100644 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -85,10 +85,10 @@ function M.init(self, node, value, 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.on_update_text_scale = Event() - self:set_to(value or 0) + self:set_to(value or gui.get_text(self.node)) return self end diff --git a/example/gui/main/main.gui b/example/gui/main/main.gui index e321240..be6d0fc 100644 --- a/example/gui/main/main.gui +++ b/example/gui/main/main.gui @@ -3518,7 +3518,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Inline:" + text: "Simple inline text" font: "game" id: "text_inline" xanchor: XANCHOR_NONE @@ -3581,7 +3581,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Multiline" + text: "Simple multiline text with smth" font: "game" id: "text_multiline" xanchor: XANCHOR_NONE @@ -3699,7 +3699,7 @@ nodes { } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA - text: "Anchoring:" + text: "Anchoring" font: "game" id: "text_anchoring" xanchor: XANCHOR_NONE diff --git a/example/page/texts.lua b/example/page/texts.lua index 0a91534..b77da1e 100644 --- a/example/page/texts.lua +++ b/example/page/texts.lua @@ -13,9 +13,9 @@ local pivots = { } local function setup_texts(self) - self.druid:new_text("text_inline", "Simple inline text") - self.druid:new_text("text_multiline", "Simple multiline text with smth") - local anchoring = self.druid:new_text("text_anchoring", "Anchoring") + self.druid:new_text("text_inline") + self.druid:new_text("text_multiline") + local anchoring = self.druid:new_text("text_anchoring") self.druid:new_text("text_no_adjust", "Without adjust size", true) self.druid:new_lang_text("text_locale", "ui_text_example") From d24107550a8a4cba96c5e8ac614b676e345ff53a Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 28 Mar 2020 16:48:30 +0300 Subject: [PATCH 06/11] Update docs --- README.md | 7 ++++--- docs_md/01-components.md | 10 ++++++++-- docs_md/02-creating_custom_components.md | 5 +++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5b004db..3a4bbb1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ + [![](media/druid_logo.png)](https://insality.github.io/druid/) **Druid** - powerful defold component UI library. Use basic **Druid** components or make your own game-specific components to make amazing GUI in your games. @@ -20,8 +21,8 @@ Or point to the ZIP file of a [specific release](https://github.com/Insality/dr For **Druid** to work requires next input bindings: - Mouse trigger - `Button 1` -> `touch` _For basic input components_ -- Key trigger - `Backspace` -> `backspace` _For back_handler component_ -- Key trigger - `Back` -> `text` _For back_handler component, Android back button_ +- Key trigger - `Backspace` -> `back` _For back_handler component_ +- Key trigger - `Back` -> `back` _For back_handler component, Android back button_ ![](media/input_binding.png) @@ -127,7 +128,7 @@ end ## Druid Events -Any **Druid** components as callbacks uses Druid Events. In component API ([button example](https://insality.github.io/druid/modules/druid.button.html#Events)) pointed list of component events. You can manually subscribe on this events by next API: +Any **Druid** components as callbacks uses [Druid Events](https://insality.github.io/druid/modules/druid_event.html). In component API ([button example](https://insality.github.io/druid/modules/druid.button.html#Events)) pointed list of component events. You can manually subscribe on this events by next API: - **event:subscribe**(callback) diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 59a88e8..4a5bc53 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -1,3 +1,4 @@ + # Druid components @@ -9,11 +10,12 @@ Basic Druid input component - **self** - Druid self context - **params** - Additional params, specified on button creating - **button_instance** - button itself +- You can set _params_ on button callback on button creating: `druid:new_button("node_name", callback, params)`. This _params_ will pass in callback as second argument - Button have next events: - **on_click** - basic button callback - **on_repeated_click** - repeated click callback, while holding the button, don't trigger if callback is empty - **on_long_click** - callback on long button tap, don't trigger if callback is empty - - **on_hold_callback** - hold callback, before long_click trigger, don't trigger if callback is empty + - **on_hold_click** - hold callback, before long_click trigger, don't trigger if callback is empty - **on_double_click** - different callback, if tap button 2+ in row, don't trigger if callback is empty - If you have stencil on buttons and you don't want trigger them outside of stencil node, you can use `button:set_click_zone` to restrict button click zone - Button can have key trigger to use then by key: `button:set_key_trigger` @@ -23,7 +25,7 @@ Basic Druid input component Basic Druid text component -- Text component by default have auto adjust text sizing. Text never will be more, than text size, which you can setup in gui scene. It can be disabled on component creating +- Text component by default have auto adjust text sizing. Text never will be bigger, than text node size, which you can setup in GUI scene. It can be disabled on component creating by settings argument `is_no_adjust` to _true_ ![](../media/text_autosize.png) @@ -53,8 +55,11 @@ Component to handle back button It works on Android back button and Backspace. Key triggers in `input.binding` should be setup +Setup callback on back button with `druid:new_back_handler(callback)` + ## Lang text Wrap on Text component to handle localization +- This is text druid component, using druid get_text_function to set text by it's id ## Scroll Basic Druid scroll component @@ -64,6 +69,7 @@ Basic Druid progress bar component ## Slider Basic Druid slider component +- You can setup points of interests on slider via `slider:set_steps`. If steps are exist, slider values will be only from this steps (notched slider) ## Input Basic Druid text input component (unimplemented) diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index bcebe7d..39afa70 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -38,6 +38,11 @@ end 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 + return M ``` From 9dd3a029ad792b1c3a33579f5a9cb26be2c6e713 Mon Sep 17 00:00:00 2001 From: Insality Date: Sat, 28 Mar 2020 23:10:30 +0300 Subject: [PATCH 07/11] Update documentation --- docs_md/01-components.md | 148 +++++++++++++++++++++++++++++++++++---- druid/base/button.lua | 13 ++-- druid/base/progress.lua | 2 +- druid/base/text.lua | 2 +- 4 files changed, 144 insertions(+), 21 deletions(-) diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 4a5bc53..3bfe65c 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -1,11 +1,19 @@ + # Druid components ## Button +[Button API here](https://insality.github.io/druid/modules/druid.button.html) -Basic Druid input component +### Overview +Basic Druid input component. Handle input on node and provide different callbacks on touch events. +### Setup +Create button with druid: `button = druid:new_button(node_name, callback, [params], [animation_node])` +Where node name is name of node from GUI scene. You can use `node_name` as input trigger zone and point another node for animation via `animation_node` + +### Notes - Button callback have next params: (self, params, button_instance) - **self** - Druid self context - **params** - Additional params, specified on button creating @@ -19,12 +27,19 @@ Basic Druid input component - **on_double_click** - different callback, if tap button 2+ in row, don't trigger if callback is empty - If you have stencil on buttons and you don't want trigger them outside of stencil node, you can use `button:set_click_zone` to restrict button click zone - Button can have key trigger to use then by key: `button:set_key_trigger` +- Animation node can be used for example to animate small icon on big panel. Node name of trigger zone will be `big panel` and animation node will be `small icon` ## Text +[Text API here](https://insality.github.io/druid/modules/druid.text.html) -Basic Druid text component +### Overview +Basic Druid text component. Text components by default have the text size adjusting. +### Setup +Create text node with druid: `text = druid:new_text(node_name, [initial_value])` + +### Notes - Text component by default have auto adjust text sizing. Text never will be bigger, than text node size, which you can setup in GUI scene. It can be disabled on component creating by settings argument `is_no_adjust` to _true_ ![](../media/text_autosize.png) @@ -35,13 +50,16 @@ Basic Druid text component ## Blocker +[Blocker API here](https://insality.github.io/druid/modules/druid.button.html) -Druid component for block input +### Overview +Druid component for block input. Use it to block input in special zone. -It can be used for block input in special zone. - -Example: +### Setup +Create blocker component with druid: `druid:new_blocker(node_name)` +### Notes +Explanation: ![](../media/blocker_scheme.png) Blue zone is **button** with close_window callback @@ -50,44 +68,150 @@ Yellow zone is blocker with window content So you can do the safe zones, when you have the big buttons + ## Back Handler -Component to handle back button +[Back handler API here](https://insality.github.io/druid/modules/druid.back_handler.html) -It works on Android back button and Backspace. Key triggers in `input.binding` should be setup +### Overview +Component to handle back button. It handle Android back button and Backspace key. Key triggers in `input.binding` should be setup for correct working. +### Setup Setup callback on back button with `druid:new_back_handler(callback)` +### Notes + + ## Lang text -Wrap on Text component to handle localization -- This is text druid component, using druid get_text_function to set text by it's id +[Lang text API here](https://insality.github.io/druid/modules/druid.lang_text.html) + +### Overview +Wrap on Text component to handle localization. It uses druid get_text_function to set text by it's id + +### Setup +Create lang text component with druid `text = druid:new_lang_text(node_name, locale_id)` + +### Notes + ## Scroll -Basic Druid scroll component +[Scroll API here](https://insality.github.io/druid/modules/druid.scroll.html) + +### Overview +Basic Druid scroll component. Handle all scrolling stuff in druid GUI + +### Setup +Create scroll component with druid: `scroll = druid:new_scroll(scroll_parent, scroll_input)`. +_Scroll parent_ - is dynamic part. This node will change position by scroll system +_Scroll input_ - is static part. It capturing user input and recognize scrolling touches + +Initial scroll size will be equal to _scroll parent_ node size. The initial view box will be equal to _scroll input_ node size + +### Notes + ## Progress +[Progress API here](https://insality.github.io/druid/modules/druid.progress.html) + +### Overview Basic Druid progress bar component +### Setup +Create progress bar component with druid: `progress = druid:new_progress(node_name, key, init_value)` + +Node name should have maximum node size, so in GUI scene, node_name should be fully filled. +Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or just "y") + +### Notes +- Progress correct working with 9slice nodes, it trying to set size by _set_size_ first, if it is not possible, it set up sizing via _set_scale_ +- Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene + ## Slider +[Slider API here](https://insality.github.io/druid/modules/druid.slider.html) + +### Overview Basic Druid slider component + +### Setup +Create slider component with druid: `slider = druid:new_slider(node_name, end_pos, callback)` + +Pin node (node_name in params) should be placed in zero position (initial). It will be available to mode Pin node between start pos and end pos. + +### Notes - You can setup points of interests on slider via `slider:set_steps`. If steps are exist, slider values will be only from this steps (notched slider) +- For now, start pos and end pos should be on vertical or horizontal line (their x or y value should be equal) ## Input +[Input API here](https://insality.github.io/druid/modules/druid.input.html) + +### Overview Basic Druid text input component (unimplemented) +### Setup + +### Notes + + ## Checkbox +[Checkbox API here](https://insality.github.io/druid/modules/druid.checkbox.html) + +### Overview Basic Druid checkbox component +### Setup + +### Notes + + ## Checkbox group +[Checkbox group API here](https://insality.github.io/druid/modules/druid.checkbox_group.html) + +### Overview Several checkboxes in one group +### Setup + +### Notes + + ## Radio group +[Radio group API here](https://insality.github.io/druid/modules/druid.radio_group.html) + +### Overview Several checkboxes in one group with single choice +### Setup + +### Notes + + ## Timer +[Timer API here](https://insality.github.io/druid/modules/druid.timer.html) + +### Overview Handle timer work on gui text node +### Setup + +### Notes + + ## Grid +[Grid API here](https://insality.github.io/druid/modules/druid.grid.html) + +### Overview Component for manage node positions +### Setup + +### Notes + + ## Hover -System Druid component, handle hover node state \ No newline at end of file +[Hover API here](https://insality.github.io/druid/modules/druid.hover.html) + +### Overview +System Druid component, handle hover node state + +### Setup + +### Notes \ No newline at end of file diff --git a/druid/base/button.lua b/druid/base/button.lua index 89e916c..2b2024d 100644 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -3,11 +3,11 @@ --- Component events -- @table Events --- @tfield druid_event on_click On release button callback --- @tfield druid_event on_repeated_click On repeated action button callback --- @tfield druid_event on_long_click On long tap button callback --- @tfield druid_event on_double_click On double tap button callback --- @tfield druid_event on_hold_callback On button hold before long_click callback +-- @tfield druid_event on_click (self, params, button_instance) On release button callback +-- @tfield druid_event on_repeated_click (self, params, button_instance, click_amount) On repeated action button callback +-- @tfield druid_event on_long_click (self, params, button_instance, time) On long tap button callback +-- @tfield druid_event on_double_click (self, params, button_instance, click_amount) On double tap button callback +-- @tfield druid_event on_hold_callback (self, params, button_instance, time) On button hold before long_click callback --- Component fields -- @table Fields @@ -146,8 +146,7 @@ end -- @tparam function callback Button callback -- @tparam[opt] table params Button callback params -- @tparam[opt] node anim_node Button anim node (node, if not provided) --- @tparam[opt] string event Button react event, const.ACTION_TOUCH by default -function M.init(self, node, callback, params, anim_node, event) +function M.init(self, node, callback, params, anim_node) self.druid = self:get_druid() self.node = self:get_node(node) diff --git a/druid/base/progress.lua b/druid/base/progress.lua index 2aa21e8..4b3d58b 100644 --- a/druid/base/progress.lua +++ b/druid/base/progress.lua @@ -74,7 +74,7 @@ end -- @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 +-- @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'") diff --git a/druid/base/text.lua b/druid/base/text.lua index e7701ee..e6ccf07 100644 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -67,7 +67,7 @@ end --- Component init function -- @function text:init -- @tparam node node Gui text node --- @tparam[opt] string value Initial text +-- @tparam[opt] string value Initial text. Default value is node text from GUI scene. -- @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) From 48bd0da429a4fc80e6e4430ec6e035c2d195b627 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 9 Apr 2020 22:07:56 +0300 Subject: [PATCH 08/11] Update annotations --- druid/base/checkbox_group.lua | 2 +- druid/base/radio_group.lua | 4 ++-- druid/base/scroll.lua | 2 +- druid/system/druid_instance.lua | 23 ++++++++++++++++++++--- media/scroll_outline.png | Bin 0 -> 11545 bytes media/scroll_scheme.png | Bin 0 -> 21643 bytes 6 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 media/scroll_outline.png create mode 100644 media/scroll_scheme.png diff --git a/druid/base/checkbox_group.lua b/druid/base/checkbox_group.lua index dd9a94a..85bb211 100644 --- a/druid/base/checkbox_group.lua +++ b/druid/base/checkbox_group.lua @@ -39,7 +39,7 @@ end --- Set checkbox group state -- @function checkbox_group:set_state --- @tparam bool[] state Array of checkbox state +-- @tparam bool[] indexes Array of checkbox state function M.set_state(self, indexes) for i = 1, #indexes do if self.checkboxes[i] then diff --git a/druid/base/radio_group.lua b/druid/base/radio_group.lua index a446d02..8701ad0 100644 --- a/druid/base/radio_group.lua +++ b/druid/base/radio_group.lua @@ -48,7 +48,7 @@ end --- Set radio group state -- @function radio_group:set_state --- @tparam bool[] state Array of checkbox state +-- @tparam number index Index in radio group function M.set_state(self, index) on_checkbox_click(self, index) end @@ -56,7 +56,7 @@ end --- Return radio group state -- @function radio_group:get_state --- @treturn bool[] Array if checkboxes state +-- @treturn number Index in radio group function M.get_state(self) local result = -1 diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 4a437c2..56a50aa 100644 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -11,7 +11,7 @@ -- @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 +-- @tfield druid_event on_point_scroll On scroll_to_index function callback --- Component fields -- @table Fields diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 4f0ec68..9739803 100644 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -128,12 +128,27 @@ function Druid.create(self, component, ...) end +--- Call on final function on gui_script. It will call on_remove +-- on all druid components +-- @function druid:final +function Druid.final(self) + local components = self.components[const.ALL] + + for i = #components, 1, -1 do + if components[i].on_remove then + components[i]:on_remove() + end + end +end + + --- Remove component from druid instance. -- Component `on_remove` function will be invoked, if exist. -- @function druid:remove -- @tparam Component component Component instance function Druid.remove(self, component) local all_components = self.components[const.ALL] + for i = #all_components, 1, -1 do if all_components[i] == component then if component.on_remove then @@ -204,9 +219,11 @@ function Druid.on_message(self, message_id, message, sender) end end else - local components = self.components[const.ON_MESSAGE] or const.EMPTY_TABLE - for i = 1, #components do - components[i]:on_message(message_id, message, sender) + local components = self.components[const.ON_MESSAGE] + if components then + for i = 1, #components do + components[i]:on_message(message_id, message, sender) + end end end end diff --git a/media/scroll_outline.png b/media/scroll_outline.png new file mode 100644 index 0000000000000000000000000000000000000000..888d9f4141f7150fb28207a04d7e660f2f086b12 GIT binary patch literal 11545 zcmZXZb97`)x9~ff*qqqO#GKf+ZQC7N6Wg{Xnm7~NHYT=h-OTg6-@Wfz-}$3govO|1 z)4P7XPnf){7(5I%3;+Otmk<|L1OPztKF3^8Up_x)h*^~Y04zoeAt8AQAt6F}M>|ss zYZCxKJvd1NQW;IE?tFP!dY$YbQ^0Y8;{cBMS0S0i7Z4F7g#hAGzueMLVRUo|WpDvF zN=bQnWMtuha8M5cvLT#+^_Pv0%!i2+Cy)J%$LHx)UjfaDUL+*F@{xcbu|83* zRP4*v-=3E{>tIj}BuTIgPl|@bcW0*+07ajTk2)Fz;!JUO@;bVc&ee~_o?QYYArL^V z(61a{I5OPsMF4-fJaK^$NY@x4FfV9H9NY+*7Q~4qpD-YJ(P4^QRcp{EW63gbaJU<( zn-{QY;q6@z2*}l2jNr>g2^z|q6j>2RexHL1x`PXFrtI!`2iQjwbI)vTaUqY1MCdzo z`VK)qBc}QI8b3dOdF#$-v_@+~W+i7Db6xzH#rtrDMvQpj`GKTp5m+#eyI`aHpmiua z>Ku89z!P~{S0lmz-91_Mj`Mor#>74`<{t3@Nj89V^;I7NAaZhHWgMn&3l1w9w5)D3 z?F?E*z7Hkp72}vckj`auFY+XI0bGiYk%S9nba{>PE?^tbJQ$9Kbzazr*TBHlf7jX{ zFVv@4l;Kfmzf#7;0iPvtV<(@Rc8oYMQv8)SZkK(?9^#x8#}Oi+Umw;>j!1)xf3r%b zPLgVATNhku7??Ho{iSCeZ3BL72^kj!X~*M~8Fr*F^Li-** z#L!CX(@aJ<2F#)h-7I0eitc=w=qHY_nbl-rrAz)HSKez{NZo?m$(_!6W;s-sqbr=wN|E(mK8sqqw2<<3tXciuf`5HN=w^|tlG>5DQ}yU5QLd=zo;{rXZ6 z8cnXX@boszSx-r<^3}#~L3Ed-cDlk`mM~CNP;^G@gxH9hWX|^(`(bdq)B87B1fdu| z@)DE>_?52}KfOfttJp|O$@@`+O#AD*+vug-Xy+NjYsklITcb4)6L_Q15@7FCG z?JEu-B~1LV?mdHiJIb1X1~8wH*nIdXgYEGa03zJwcZ!D4712lM&_@iB3(De;&+rAK z3xgfRbu;Rb152Z1nh>PWk0ln`u?yKAH_>l)6SwpWX1B@|xF$bWGa`PVE(1W9#L5KJ z3)D#;nMMdHDDaSwsSo5zfH)Sd5Ktz-8Ovx4!NGqXi--m;!tWptQ;#^}50i^>NTUp< z<8RA*&Z;Ei#Vlb4h>OYt}sT4pGawmBMDy=Q!C7o*H{oBuTV;={NiAUo@&s&COUK@PgL^Cqz;!$ z62iXqDH~Q9ofCPQf!2lg8*0=Ts;d}Z{5BH$HN2#K`puf>9-$GDD_W;(%O02gTjuu( zjDv`Xev@t4O}fn$`?qH3KZxA$*@)GCY~7xlB$r2zf?l*8=o>LPJ@lwp(8S>I0kqvY zzanDAN(ujv-Xf7hjS7?JV<}`D3d0cNr?<28v!qzy z&qPkY7LrX%&S1}YOb<-s7gy%D3%!KjQMYmD6Z?}3_P;kU>&v5H-5^%wA@NhhE%#q-t3Zg=ydILO>MUiY+dJJ?7acR40 z)@eOyj%k)@Evdy4?D3Stsk?F`gjpnOWKjtQwMfgc(nJ>|YOxn_6sa|1hGY9oL)wsn!UJr(&C`xOQi?iFepkQymVZcDezpi8w&bTxN%-ew1e zi$;k0lcv>X1p0d0n+FX0P#FOBUdFt5yi^;E9p5`*UTI#R zUkzUSU$b7FK>vW6f;xbjL1e?wz=lI}!WP3Wz;+-L!<0coz~G@CBc-G6qc&p5B3Gf} zqY#CbhJi<*g>fT2(NU2fQ+e>$O8_+^b;h)5Br0UB)iY(a)wm_wv|oRNs|v~xD{m(X zSCdLAYA~tSD%Xm^kQEV&Byp0>Q$)q7rbNfmrT7pDQ5Vpo(koFglaEqak!8@WlD?Q^ zTz-$Sd0NG{ejzKN!6a8BdeF=!wIj-*^Hq8;4=4l`$y46?O`MewN+3RUXoWvmh#g6|Yg3~-P$pfbp{ z^sQ_?=kBAjQgss7Xgw?1v%JgR3Ip4O!h6BQYIhI@H3vl~z)HAF7ALkR947GS;OKPe zSm`!&qO@VP#nu{spSgIRP8`WP+ue7$H@hi&(70iH;y+|wD&CLWV*jCQ zeK^B|PaBsq4Q)2=rGn!use@f33;f8{WC9Sj>hi@}Ll45N?wh}(>xiXBSCid$-z za#UNWDkDuOycs?;mUI*g=a@|2*C0Num zE7F(WoIh+{tcS$Dp;lgAO<-PmYd zu^G;&$SCZj!DN3eVcc-GI4r)8vO7^qn zb)HTe@DVt8Y^-*=on)TnKSgqjZoiM7wW%6fiJoX`DX#Wp4RJA_37qZVadGNyIJdsE z&34=z@r-&RUS#~~eBu8PSQR=8q1D0GVZ$%uvGl08Zm!Y#{ql^uN3odmliTK0;mqP( z<)VGLWPWj_dUfM{>~Q(*V1JSTaS84go)fXdYwOPNw&-K@NX?*nKV&;3S?>aG0M4w_ zz)Oj}hez>Ub=&5xbmZ`iv7qMMHTps~MrnYrJ;uG0DUMNsO@qCkO@+CVVePtmSLi}) zG6pq=n2&bS*vItQ>pJ2w#j4JuZq3Qo3H4_B#!Anr)4{9!S?Z`d8lp8guK%)s?_!yc z-ADOD`Q=G}*xAC8!vLa5v5l(6<0fUVdaL2Gp+S7Zd?Ts=5UH%JPYBQ}2jn_I`u%|g zOgk~Ntx_>KKJpW}Vv1ut2aWKrm+~A+M?zx^@D8BwkU*&lLu2EP!`blZpn9VVks0wQ zF_#6trv6UZBRkP*w78eUy~&i)F6XAy#U+T#k@X`LM=?Y<#WX-Q!Q8<(h}%rrO+iV- zNJdUVUnQrdpr|g*%`eR>EVr&Otg@^!&9}`r$hRmhs;(?5$SW_TD5tmVG8(cLX3=DR zH)XPT9;sMu>(5`gE>-#I92%8TS(8=Uo(h&iQh>Vt)x}?1!PeY00J4B0B<0fOt6dmg z53g58rVkBTE#Egk+#&2fbQ)lQsPq;Bj<2#fe$ln&Nsk)u6(j!qd>Hg?PgwK@00ty*!eCZIt{K7C!LbH z0-Ac;g|NnO)XaOrg&b|>K-LyJwMLcmL}Sl|m-XKJ&z|Gsbex8m;~#WhZI5;MzG-LS zk1A_l9;_4=>#*fm=h>Rp4qKL;%A5AC&Y~BnZHinKS6zYTf5_IdPTL%+@85?ZIS^4> zU-8rUlFy1SvfUjoj)t>`bOU)EH{3qv%`7I*Acen72NLK4J1cxu7|>o;Ow`Zd4>FSC z;+oD14hC!2&v0FRs#%F5D{A}84rUj5(Y&SK(7p>jNk5@*WH7sW``l-&>zQE=Z$$V? z((>p?ycN|n-p4$t`ISsVU`f%y-osacoYq}fONuXC0S16=hrp76yEQKkJn_HOcG>5Ztv0$}KIoUlXKYTjW!lJ}-#LkQ4 z#o}ZAZJln1VRUYsXE<#7+xl+dxk{$erbDOJJ2$YPpd+EJ&JT7O{h(#{e%O1dVD+X^ z?d_g|%`*@T7KQdWubfC^qIo#?i<>)NTv z3|YU&;HZMyb=3kZP#34;y#ac4%t7e7cz`wnqiNN@vc{&&b!O$k`Lr`**?n`p`(+u? zkpTag^Y(CRM`-Q0oMX1>9q!@yq14I78_m1>T-QYR5M~X1g5DVc=W~l!^VaxVoSGe9 zjK6E4L-)fqDrdsJlFzIeuh)Aacf#xMyU}Wn@u$b?l#X^ieZBhE?B{~5gE^*$@LtRN z>WRuHHqoQr)lK?CmobnE5?Nffm`;HqQqC#+*~qEv0@xBYGk(T;W>W@@SS<1OU6Qdz z8aNs`^}1#0C8B%NXee2ti4<*)Kb(JZ+$G(|-9EOdci475i0!52h3wVMn;1In%R`%n z!p&<^m%ONpa=9M!RyawvoV1W^(%i{TU~ot4`**Gfz0L#7DG1AyKD6wL(ix{8gevSQ)M3 zd9w+=36aUwdhOUqZ~FXmnv8#CAl|a=)O%21Q^Bttu@dSD3A%wQxGEvrq;p36FWL3k zfx0D4ke<|T^cT$s2^S}O6kAQ=N4I>~n>eLdK?vAzRYk==*n=fQ40_goY(!G7ry(6- z7a@=11V*QY;e}eoRLfCHjjbjnC&uEYZ+CjW;5R9kv?EyDAKky;GG*Skn%VLp*)y8Wtz;`cI-eCEB$_Sn_45g)biX z-r%fxbpHg{zXAX!8y2{hfT4DP-x3{QDfZ87Gy;Ia*$;&QVoDIwkEZ^kjgOG@iWHP- z6C|D=K9%Un1S?(%!{1{HVxXI<58<0ov^*RT*Yd|YAx93&2t?A4pJGv6aKAt@0eV3c zaWvzwI^jN1#)iD9H>s2A=+@Zx-=ZNgqpf-qu9UsF{1cGG4k@TmB0{NI(9$XDkL%}w zr@-I0l+VV`7jO=65s?zoNJ`(sl9UBhNgkL&er>8x)M3}j*5Vnb7+&m!?(J?`?_D1h zZ*`39bi>~0?%oJ91@QWF3uqCM=b8105NGFu<|i0p_8F0~kP;2km3djn89Pr5-`iQm zl_%26FBOQZI4Up5Zz%;Ui_L4!#aINHTUt$9!CNgJ_ICDMF`vDp8LhRkMaDCh=dPW&Da8}<5y|`RE&kj1 z`v%y2Kz!h;P-xzS0s0m!*EsQLzNt~Yq0_b~N+L?kX}X+?%w4-q??@E?f6fgE-0UvC_UmGTZdFyyeeDKP;5E6+yym^k>Hs)kEo;;E=B)mE+Z9 z)%vAvd2yl>4MP$m#b@b*yOX6ezb5_pWJ2_HDbp8)=>vryJr$sa1bXjhl#2iiK)wVc z7IKV*M+3q0$Iexw^o!@OeFe^;&vB8)GzBnkes}v?8MPjAKJd#3lrc&jbOC2I)Tl3b z3xB8R%KZ@{0CS61Az57*Y*u(Wa+-6NH=nuCs%SC4Gs?II@$1=Fu~=^BC}1Rwlur+? zzj5|>MTa$u_4uhjZUrtPyQ_nQQu*RUSG@7KL`$oepOU9jo7MPF)8$EjbG=ta$pI;d!gv zYnukk^a*6gTCrG4_#V+6!pc>?KH2NB$U2s%+rT~%0XPJl+-tGW+*_(Xi2 zhhnr@Mqon4Cq^*XFlMGUJm_buroTrgd0ld=OYlTRcH=uyV3TP000+5|spft#hF;}q z1^vp*O7JqDVngAR`DwU@)>fiDEx=<57`hckvXwi zVKUK}0qlMqNqxCLbtg)-IJI&risduxGl*un4<*JvJcn`4WS+E(NAmMqMI_NrDbXk~ z3Nah>@l+E$j9SMY*Dh&?M_#1&FF7Z?)fyTq0in(S(qdj)jham=}hSkdWKa*pyRISoA;Y zpLaaO=0Ko5Cq2EZt1F!=Go78I89gHh2M0X^6Fn0X?WY8-le;a@z>U_{iR51+|Id!F ziIb6|g+0*1&X(}6T?0cqXCMzT@n1*(d;J@yiJQg$d9ro-PgKTTGS|5p63h5smW)BlbC zzw-Hav;LX=+$~-hZuP7R0OdtOSU}kg<0hyYAb zwC~jN+IJVh5W&-Wz8?o~<8TZU{UC7)92YkXZ7Da|PV19g?-Om9nWj9Rcdd}J(tgkk zAmm-(r~LeJH`gD-rrwi{4T0|8hrv?;sQREXY5X_E+-~?>pW{!_r4#@p(aW{j$zL^p zav8rs`GjmAeD1%iT^-=;P|GQNT4sMGSu8+tgVJwrZ#L8Z+PNp|5*X@uUFQ5NnJa<1 zNjO(nk^?#U*UK+@kYMj|KD-69AklpH8`JNITaS=$j(lxdJw{e^~{1jdKRO;I%54!j1YWC zA}gamMJV87wq)3&*oNzMVs`bo{_R8?-&VKNRAs-$Hj%K}?R-S`7}mAIvx27+R)9G= z|9HgtBmi;t=dC~a7&I~kjD6If?LP2S{#oKKfzbWd$beD1Kb$)p4;$%OZxQ``Brk^s zbvE!?N09;o%t)-mDRaq$Chpt|zIxyi%lL1_?#^o@R&$H5*Yx<5ePlo;s5U{kon8culz( zWr+7)bQ51H)ysD?4Z_Q6s331;eFM+f#xHNl+dB^E>{<$8Ba&k5y6RDg9h5yfQbyz- zdayZuD2D8A29&xObk$)4m|9N8e7V40zs=uMk9WDrxP_u#k$nM7_B4qlL3*kD1xTA` z>^(FtgB=@ncu7sta$>?+=2nq-^$Yj~-vAsW=UGT&T5X7xzBh0@NJ*DaGQ!e+B(ikT z{Cy)d=BwqyMr4^hkUe&`?4o9L{rS!mvDK$Peu2Zk#`+&VVCau`dLuUwgSKZLKj|uR z?iBHQZ&je>sNCN7uwbR3Muj#zvmdj8CGZ3}>a1SI{ywZT1KAg;?pfbb%1ir$c@}hp zaejDS84x%WQAjVO6mFDdzxndA9tfZ7a{@y<$%tARFtt?2x`}Q@x;77NYHX>D>Pe?C z<4G>N*Kv2vZ2ODr_#f!bth_WZ{X4yLB6>1)9*Oe+kJb2Y6S;TqkFt9UiqI3dTrsfC zkqKhaB&}U5;W9l9H)%sdW4-VV>OU%b+6omh7+yqyz`|J5?Iy?3r4AFvLz-ItQ_uyM#;%n&UB`g zgKcnuKx@3)L7Q7z7+Ij(WL{w0e3<)o#m;kCE>xr-JETGpZ0lY4Yg$BParu$75PWzV z*c&_Wl*9WbEc3HCnRA0a`({O% zT{<+8PWbda#fnEcAt+~ve`Si_W^i%xgv($D+hTO8Av319K16LXgM?6wh)O1($Ad?F zx5B)!u(;;tl$Waca~x@QW>Du{I6SSfB?JDK-aFv4Z{!)WgXuO*0T)W+{BD*Z2o#$vd z)lNyCm=u zHUJ9;eZk0Tf)1Ghyk}Wkr;MNp#fpS{j$bfM?(!XwzT6_ccZLtCTb5V2Z>zG#Hd-UH+gI1_LNzJ?WYIAU4eMEvX!)_*tRdb?jQ_Z3A0Dt=n5rNSFW%FjM3(QT zzy%HDK_QWNY4UV3o=$C2*~!2jY63rHfxGwQed@gM=H0D@f*Vf37@wV6GmIIvHRG_ z3$g@L?W*Qh9frpAv^pv(*tq5zJWrVVc2t*HeX3~^NuvPv{uQd+7=9O*mCM01$~d~!}< zp0hO-^L`PFylMy^l^Kw?2rBUwKEjz3Mfnr5*I1n(E5TcT3Fzvgj4OkEZs`@xAS#D_ zL0;_N^tMwR)R!l;Ez_od_*aH8i%?edk`CEQDU@BKAo^;ii~d-n={9Xg7BTWoxz?WV zf)o4w)LMD*YRqGf_@swR`Oj1LR{jx~mBCuQT2(A)z~0YjrY+b{yA$$DRx%*@xRU#a zRbm*w2p_pb72DkLt^b4>r>9FuFJ6m-JavQhGR90WvGE~7ie*FU=<$YVCE9gA_^@^C zTz;NVAeF(6yQ5oNul$nRfcz78-`x;?DG&26i3UljdDKRAj?QrpYH< zTtQt*mV&6eo=hjyFTMK?>d?`4`;ORt_uCs32}U{J31r;AcJY$&?@=su*KRZ6`}~o+ zc|qADd3fyy@EH8VE*zlFt74XpZf;$FIp;G$%FpubkqFda`wJO<(CU9_h6>--`0ova zznFwy;8a23Xv;sSBi%&>f*`1RWl!?2Ft;RVc!wCg!=XhB(<^0MjqN9G{Vgn%pg*AI zXXG-Srirq|HZiPsGAq4wO>_wVI~Uf z?L=o+GWwTfe8yek=|f-(yiM9L>@RppRx0S}J*rf)L;uld!7wylBik+=j3XISW?J?6 zZREaxW-_0%W;8PkQ4MYt>qDC5^Ibo=GsU(j{}?LAl}|LjgV&`V^Qqj=^Act3fgt!B zG-(b4dV87b9xv9-4%;D+)ci6$UA_WMnW5&0gum{0U=6!vYhj#9U`IH~H9$3w^nI-aAM~5wE7-$m==%A?nO_3P?18 z%Co&o>3D-?o2)<@jDaWt)g^1;YF@Yxjp~HXB+5rRh?j3oz89i2kH$EM<}g$j!Q$bb z$b9q}{<%lg_RN<`eNhx4C#4~C=`u-bFtN=H$a=m>0VD5kTW2!VJ(7WIHC^5IZBG+s z%`BG4D42Hz@)E^5Z4Aa0UuukMk$ANN=@Dc4wS4cAS81ND7C6aXD%#c(`O@Wns4u4jftFbUvrA$EgBh~Agrf3gS8)*d{|?SI1#vf~a_{ONS(4l87j zo0m@SkdA*jI5E!Oq!0#$yXAk%<50RyJQu{qV*TnNlJTQgAuo%@(NR- zaR$D|+-U@`0SOWTLvW7~SxRC%Ayybo%A83ZaOs9RvbLu&ju*? zRXQhbqCErCo|{_Vn<>an9}}>D(}+O~TtCIpEWgvT*gC@K`u$TZrDJ`x2;i z#ch{84EU;S7yzheDYAF6_>;iLHan0~)25fh;gKX>Ir5cTKeOC`T0+g{q`dXOUSs2} zn7~*p^YIU(wtMa`%l`}l%T;X?qq;M#ZC8DzM{1S6=V7z=CX_Ivs^J7p|-is4Ev!pVOVb5m6Dz(fMG zIsB}IWqOj(q@uUkxZ-_)Z06uB_(f*bv_v%JReKS$|9POSWt&`*PDw-($!o_VOc+Ee z{uaN?W1e#A;AgACvU*HdsX~7&8%uq@l)%)n(eraTWuC~|7$&FU6NQeBmRi2He{X|= ziWRbe1S$3VG5BNB-#?jN%`ULV5wemMKZz1BUWQst7sL z*baqIx0lW>(PwTi3ZwLkn_rfL@k~NIv^?aUub$1N^YY)q<1(&bk+1@CiK^^@K!HUc zAW?3)z|x2v2~YB#wuhYPX(HVcdK2Pa72ekQIRfT9Sthrz%b+On(jvO$%5^3RXK-TS z<`l;Ir$q62QpW8EZAoPr@bnRgabF!;ayP0{I2qHEa?C&W zVan!Gp%K&sCk0(2rOdU){^Ro3WNvmNlvc-@e^K2J!?m8WB{fNci_vQ0jDY1ilXv?( znbLBKLn3aQZ?DcNYnE1J!+JacrJrd)if$1U(mPzyus7u2g|c$ZX<2v9lSR5~7n`Lb%KiY!&sDL#cu<1UxYtlapXFPn*w4GPQlNJ?mAs1J*)yH}FZ__zPzTfDWlq!(R{3e3g|;T`mCjs9AAzIGE425n zNhad3r5-Dk=DGkG=82Avo^*A|CX9l3SKbxdgVdhc1!va4rvAc@NG5lBOnGf7y7&HR zs)w<1fqdDaZB930pakoa^r|)a&i7+WWh4($!>!|;2;OLvHPVVCT=QH^IU?qZpI*<( z<^7c9@?~3x_Lxa~Dg$p(g=1)F&JT-`7*&R#a_Atv#UDznr4$AX<68Bl2^lbuZ|kYc zx+o)~7S+R~5~cYb$f)?Kg;X;JqKb2Bd}YDBR8zh6uxnZ_QC2&d}< YjH=nG)e68c2Kc-rL}Z1l1oZ>{2Q&Wr6951J literal 0 HcmV?d00001 diff --git a/media/scroll_scheme.png b/media/scroll_scheme.png new file mode 100644 index 0000000000000000000000000000000000000000..64dbc7e2950d358b33e502b66499ff4f3d26b0e7 GIT binary patch literal 21643 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 DvbDqM literal 0 HcmV?d00001 From 179ac5c068bc8992121a5ff10c647abf9fb5fbe8 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 9 Apr 2020 22:11:51 +0300 Subject: [PATCH 09/11] Update docs md --- README.md | 47 ++++++++++++++++++++---- docs_md/01-components.md | 47 ++++++++++++++++++++---- docs_md/02-creating_custom_components.md | 4 ++ docs_md/04-druid_assets.md | 2 +- 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3a4bbb1..eff4aae 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![](media/druid_logo.png)](https://insality.github.io/druid/) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/insality/druid)](https://github.com/Insality/druid/releases) + **Druid** - powerful defold component UI library. Use basic **Druid** components or make your own game-specific components to make amazing GUI in your games. @@ -113,14 +115,6 @@ local function init(self) self.druid:new_button("button_node_name", button_callback) end -function update(self, dt) - self.druid:update(dt) -end - -function on_message(self, message_id, message, sender) - self.druid:on_message(message_id, message, sender) -end - function on_input(self, action_id, action) return self.druid:on_input(action_id, action) end @@ -138,11 +132,48 @@ Any **Druid** components as callbacks uses [Druid Events](https://insality.githu Any events can handle several callbacks, if needed. + +## Druid lifecycle + +Here is full druid lifecycle setup in your ***.gui_script** file: +```lua +local druid = require("druid.druid") + +function init(self) + self.druid = druid.new(self) +end + +function final(self) + self.druid:final() +end + +function update(self, dt) + self.druid:update(dt) +end + +function on_input(self, action_id, action) + return self.druid:on_input(action_id, action) +end + +function on_message(self, message_id, message, sender) + self.druid:on_message(message_id, message, sender) +end +``` + +- *on_input* used for almost all basic druid components +- *update* used for progress bar, scroll and timer base components +- *on_message* used for specific druid events, like language change or layout change (TODO: in future) +- *final* used for custom components, what have to do several action before destroy + +Recommended is fully integrate al druid lifecycles functions + + ## Features - Druid input goes as stack. Last created button will checked first. So create your GUI from back - Don't forget about `return` in `on_input`: `return self.druid:on_input()`. It need, if you have more than 1 acquire inputs (several druid, other input system, etc) + ## Examples See the [example folder](https://github.com/Insality/druid/tree/develop/example) for examples of how to use **Druid** diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 3bfe65c..28e427e 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -76,7 +76,7 @@ So you can do the safe zones, when you have the big buttons Component to handle back button. It handle Android back button and Backspace key. Key triggers in `input.binding` should be setup for correct working. ### Setup -Setup callback on back button with `druid:new_back_handler(callback)` +Setup callback with `druid:new_back_handler(callback)` ### Notes @@ -101,12 +101,27 @@ Basic Druid scroll component. Handle all scrolling stuff in druid GUI ### Setup Create scroll component with druid: `scroll = druid:new_scroll(scroll_parent, scroll_input)`. + _Scroll parent_ - is dynamic part. This node will change position by scroll system + _Scroll input_ - is static part. It capturing user input and recognize scrolling touches Initial scroll size will be equal to _scroll parent_ node size. The initial view box will be equal to _scroll input_ node size +Usually, Place static input zone part, and as children add scroll parent part: +![](../media/scroll_scheme.png) +![](../media/scroll_outline.png) + +*Here scroll_content_zone below input zone, in game content zone be able to scroll left until end* + ### Notes +- Scroll by default style have inertion and "back moving". It can be adjust via scroll [style settings](https://insality.github.io/druid/modules/druid.scroll.html#Style) +- You can setup "points of interest". Scroll always will be centered on closes point of interest. It is able to create slider without inertion and points of interest on each scroll element. +- Scroll have next events: + - *on_scroll* On scroll move callback + - *on_scroll_to* On scroll_to function callback + - *on_point_scroll* On scroll_to_index function callback +- You can adjust scroll content size by `scroll:set_border(node_size)`. It will setup new size to content node. ## Progress @@ -124,6 +139,7 @@ Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or ju ### Notes - Progress correct working with 9slice nodes, it trying to set size by _set_size_ first, if it is not possible, it set up sizing via _set_scale_ - Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene +- If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles ## Slider [Slider API here](https://insality.github.io/druid/modules/druid.slider.html) @@ -155,12 +171,14 @@ Basic Druid text input component (unimplemented) [Checkbox API here](https://insality.github.io/druid/modules/druid.checkbox.html) ### Overview -Basic Druid checkbox component +Basic Druid checkbox component. ### Setup +Create checkbox component with druid: `checkbox = druid:new_checkbox(node, callback)` ### Notes - +- Checkbox uses button to handle click +- You can setup another node to handle input with click_node arg in component init: `druid:new_checkbox(node, callback, [click_node])` ## Checkbox group [Checkbox group API here](https://insality.github.io/druid/modules/druid.checkbox_group.html) @@ -169,8 +187,11 @@ Basic Druid checkbox component Several checkboxes in one group ### Setup +Create checkbox_group component with druid: `group = druid:new_checkbox_group(nodes[], callback)` ### Notes +- Callback arguments: `function(self, checkbox_index)`. Index is equals in _nodes[]_ array in component constructor +- You can get/set checkbox_group state with `group:set_state()` and `group:get_state()` ## Radio group @@ -180,9 +201,12 @@ Several checkboxes in one group Several checkboxes in one group with single choice ### Setup +Create radio_group component with druid: `group = druid:new_radio_group(nodes[], callback)` ### Notes - +- Callback arguments: `function(self, checkbox_index)`. Index is equals in _nodes[]_ array in component constructor +- You can get/set radio_group state with `group:set_state()` and `group:get_state()` +- Only different from checkbox_group: on click another checkboxes in this group will be unchecked ## Timer [Timer API here](https://insality.github.io/druid/modules/druid.timer.html) @@ -191,20 +215,28 @@ Several checkboxes in one group with single choice Handle timer work on gui text node ### Setup +Create timer component with druid: `timer = druid:new_timer(text_node, from_seconds, to_seconds, callback)` ### Notes - +- Timer fires callback, when timer value equals to _to_seconds_ +- Timer will setup text node with current timer value +- Timer uses update function to handle time ## Grid [Grid API here](https://insality.github.io/druid/modules/druid.grid.html) ### Overview -Component for manage node positions +Component for manage node positions. Very simple implementation for nodes with equal size ### Setup +Create grid component with druid: `grid = druid:new_grid(parent_node, prefab_node, max_in_row_elements)` ### Notes - +- Grid on _adding elements_ will setup parent to _parent_node_ +- You can get array of position of every element for setup points of interest in scroll component +- You can get size of all elements for setup size in scroll component +- You can adjust anchor and border between elements +- _Prefab node_ in component init used to get grid item size ## Hover [Hover API here](https://insality.github.io/druid/modules/druid.hover.html) @@ -213,5 +245,6 @@ Component for manage node positions System Druid component, handle hover node state ### Setup +Create grid component with druid: `hover = druid:new_hover(node, callback)` ### Notes \ No newline at end of file diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index 39afa70..07fd051 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -43,6 +43,10 @@ end function M.on_input_interrupt(self) end +-- Call on component remove or on druid:final +function M.on_remove(self) +end + return M ``` diff --git a/docs_md/04-druid_assets.md b/docs_md/04-druid_assets.md index 8a2c992..1e5ae11 100644 --- a/docs_md/04-druid_assets.md +++ b/docs_md/04-druid_assets.md @@ -3,6 +3,6 @@ ## Overview I've created [druid-assets repository](https://github.com/Insality/druid-assets) to make a _marketplace_ with custom styles and components. -Any of druid users can push their own components and styles to share it with the other users +Any of Druid users can push their own components and styles to share it with the other users Also, this marketplace is great example to how you can create your custom components \ No newline at end of file From 4cd5c551559c037b67c01f0e0d859e39cdfd2299 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 9 Apr 2020 22:11:59 +0300 Subject: [PATCH 10/11] Update docs --- docs/index.html | 4 +- docs/modules/component.html | 4 +- docs/modules/druid.back_handler.html | 4 +- docs/modules/druid.blocker.html | 4 +- docs/modules/druid.button.html | 23 +- docs/modules/druid.checkbox.html | 4 +- docs/modules/druid.checkbox_group.html | 10 +- docs/modules/druid.grid.html | 4 +- docs/modules/druid.helper.html | 4 +- docs/modules/druid.hover.html | 4 +- docs/modules/druid.html | 4 +- docs/modules/druid.input.html | 4 +- docs/modules/druid.lang_text.html | 4 +- docs/modules/druid.progress.html | 9 +- docs/modules/druid.radio_group.html | 18 +- docs/modules/druid.scroll.html | 6 +- docs/modules/druid.slider.html | 4 +- docs/modules/druid.text.html | 6 +- docs/modules/druid.timer.html | 4 +- docs/modules/druid_event.html | 4 +- docs/modules/druid_instance.html | 23 +- docs/topics/01-components.md.html | 217 +++++++++++++++--- .../02-creating_custom_components.md.html | 29 ++- docs/topics/03-styles.md.html | 4 +- docs/topics/04-druid_assets.md.html | 6 +- docs/topics/05-examples.md.html | 4 +- docs/topics/README.md.html | 65 ++++-- 27 files changed, 357 insertions(+), 119 deletions(-) diff --git a/docs/index.html b/docs/index.html index b5f8636..f70f2e4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -54,7 +54,7 @@

    Topics

    Topics

      -
    • Druid components
    • +
    • 01-components
    • Creating custom components
    • Styles
    • Druid assets
    • @@ -440,7 +440,7 @@
      generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
      diff --git a/docs/modules/druid.back_handler.html b/docs/modules/druid.back_handler.html index 3cf72b7..c80f183 100644 --- a/docs/modules/druid.back_handler.html +++ b/docs/modules/druid.back_handler.html @@ -62,7 +62,7 @@

    Topics

    Topics

    Topics

      -
    • Druid components
    • +
    • 01-components
    • Creating custom components
    • Styles
    • Druid assets
    • @@ -84,7 +84,7 @@

      Functions

      - + @@ -133,7 +133,7 @@
      - init(node, callback[, params[, anim_node[, event]]]) + init(node, callback[, params[, anim_node]])
      Component init function @@ -159,11 +159,6 @@ Button anim node (node, if not provided) (optional) -
    • event - string - Button react event, const.ACTION_TOUCH by default - (optional) -
    • @@ -291,23 +286,23 @@
      • on_click druid_event - On release button callback + (self, params, button_instance) On release button callback
      • on_repeated_click druid_event - On repeated action button callback + (self, params, buttoninstance, clickamount) On repeated action button callback
      • on_long_click druid_event - On long tap button callback + (self, params, button_instance, time) On long tap button callback
      • on_double_click druid_event - On double tap button callback + (self, params, buttoninstance, clickamount) On double tap button callback
      • on_hold_callback druid_event - On button hold before long_click callback + (self, params, buttoninstance, time) On button hold before longclick callback
      @@ -409,7 +404,7 @@
      generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
      diff --git a/docs/modules/druid.checkbox.html b/docs/modules/druid.checkbox.html index a410199..8364f00 100644 --- a/docs/modules/druid.checkbox.html +++ b/docs/modules/druid.checkbox.html @@ -62,7 +62,7 @@

      Topics

        -
      • Druid components
      • +
      • 01-components
      • Creating custom components
      • Styles
      • Druid assets
      • @@ -277,7 +277,7 @@
        generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
        diff --git a/docs/modules/druid.checkbox_group.html b/docs/modules/druid.checkbox_group.html index 197d339..2c63f9a 100644 --- a/docs/modules/druid.checkbox_group.html +++ b/docs/modules/druid.checkbox_group.html @@ -62,7 +62,7 @@

      Topics

      - + @@ -147,7 +147,7 @@
      - set_state(state) + set_state(indexes)
      Set checkbox group state @@ -155,7 +155,7 @@

      Parameters:

        -
      • state +
      • indexes bool[] Array of checkbox state
      • @@ -239,7 +239,7 @@
        generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
        diff --git a/docs/modules/druid.grid.html b/docs/modules/druid.grid.html index e390359..b5564b9 100644 --- a/docs/modules/druid.grid.html +++ b/docs/modules/druid.grid.html @@ -62,7 +62,7 @@

      Topics

      Topics

      Topics

      Topics

      Topics

      Topics

      Topics

      init(node, callback[, params[, anim_node[, event]]])init(node, callback[, params[, anim_node]]) Component init function
      Component init function
      set_state(state)set_state(indexes) Set checkbox group state
      - + @@ -135,7 +135,7 @@
      - init(node, key, init_value) + init(node, key[, init_value=1])
      Component init function @@ -154,6 +154,7 @@
    • init_value number Initial value of progress bar + (default 1)
    • @@ -378,7 +379,7 @@
      generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
      diff --git a/docs/modules/druid.radio_group.html b/docs/modules/druid.radio_group.html index df89283..fd5cb47 100644 --- a/docs/modules/druid.radio_group.html +++ b/docs/modules/druid.radio_group.html @@ -62,7 +62,7 @@

      Topics

      - + @@ -147,7 +147,7 @@
      - set_state(state) + set_state(index)
      Set radio group state @@ -155,9 +155,9 @@

      Parameters:

        -
      • state - bool[] - Array of checkbox state +
      • index + number + Index in radio group
      @@ -178,8 +178,8 @@

      Returns:

        - bool[] - Array if checkboxes state + number + Index in radio group
      @@ -239,7 +239,7 @@
      generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
      diff --git a/docs/modules/druid.scroll.html b/docs/modules/druid.scroll.html index be05f0c..1d7045d 100644 --- a/docs/modules/druid.scroll.html +++ b/docs/modules/druid.scroll.html @@ -62,7 +62,7 @@

      Topics

      @@ -507,7 +507,7 @@
      generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
      diff --git a/docs/modules/druid.slider.html b/docs/modules/druid.slider.html index dceaa2f..89ccf5b 100644 --- a/docs/modules/druid.slider.html +++ b/docs/modules/druid.slider.html @@ -62,7 +62,7 @@

      Topics

      Topics

        -
      • Druid components
      • +
      • 01-components
      • Creating custom components
      • Styles
      • Druid assets
      • @@ -142,7 +142,7 @@
      • value string - Initial text + Initial text. Default value is node text from GUI scene. (optional)
      • no_adjust @@ -352,7 +352,7 @@
        generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
        diff --git a/docs/modules/druid.timer.html b/docs/modules/druid.timer.html index 1116615..d89517a 100644 --- a/docs/modules/druid.timer.html +++ b/docs/modules/druid.timer.html @@ -62,7 +62,7 @@

      Topics

      Topics

      Topics

      + + + + @@ -240,6 +244,21 @@ + +
      + + druid:final() +
      +
      + Call on final function on guiscript. It will call onremove + on all druid components + + + + + + +
      @@ -750,7 +769,7 @@
      generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
      diff --git a/docs/topics/01-components.md.html b/docs/topics/01-components.md.html index 2e0a3ef..2a2afb2 100644 --- a/docs/topics/01-components.md.html +++ b/docs/topics/01-components.md.html @@ -52,7 +52,7 @@

      Topics

        -
      • Druid components
      • +
      • 01-components
      • Creating custom components
      • Styles
      • Druid assets
      • @@ -88,46 +88,59 @@
        + +

        Druid components

        Button

        +

        Button API here

        -

        Basic Druid input component

        +

        Overview

        +

        Basic Druid input component. Handle input on node and provide different callbacks on touch events.

        -
          -
        • Button callback have next params: (self, params, button_instance) +

          Setup

          +

          Create button with druid: button = druid:new_button(node_name, callback, [params], [animation_node]) +Where node name is name of node from GUI scene. You can use node_name as input trigger zone and point another node for animation via animation_node

          + +

          Notes

          +

          - Button callback have next params: (self, params, button_instance)

           - **self** - Druid self context
           - **params** - Additional params, specified on button creating
           - **button_instance** - button itself
           
          -
        • -
        • Button have next events: + +

          - You can set params on button callback on button creating: druid:new_button("node_name", callback, params). This params will pass in callback as second argument +- Button have next events:

           - **on_click** - basic button callback
           - **on_repeated_click** - repeated click callback, while holding the button, don't trigger if callback is empty
           - **on_long_click** - callback on long button tap, don't trigger if callback is empty
          -- **on_hold_callback** - hold callback, before long_click trigger, don't trigger if callback is empty
          +- **on_hold_click** - hold callback, before long_click trigger, don't trigger if callback is empty
           - **on_double_click** - different callback, if tap button 2+ in row, don't trigger if callback is empty
           
          -
        • -
        • If you have stencil on buttons and you don't want trigger them outside of stencil node, you can use button:set_click_zone to restrict button click zone
        • -
        • Button can have key trigger to use then by key: button:set_key_trigger
        • -
        + +

        - If you have stencil on buttons and you don't want trigger them outside of stencil node, you can use button:set_click_zone to restrict button click zone +- Button can have key trigger to use then by key: button:set_key_trigger +- Animation node can be used for example to animate small icon on big panel. Node name of trigger zone will be big panel and animation node will be small icon

        Text

        +

        Text API here

        -

        Basic Druid text component

        +

        Overview

        +

        Basic Druid text component. Text components by default have the text size adjusting.

        -
          -
        • Text component by default have auto adjust text sizing. Text never will be more, than text size, which you can setup in gui scene. It can be disabled on component creating
        • -
        +

        Setup

        +

        Create text node with druid: text = druid:new_text(node_name, [initial_value])

        + +

        Notes

        +

        - Text component by default have auto adjust text sizing. Text never will be bigger, than text node size, which you can setup in GUI scene. It can be disabled on component creating by settings argument is_no_adjust to true

        @@ -140,14 +153,17 @@

        Blocker

        +

        Blocker API here

        -

        Druid component for block input

        +

        Overview

        +

        Druid component for block input. Use it to block input in special zone.

        -

        It can be used for block input in special zone.

        +

        Setup

        +

        Create blocker component with druid: druid:new_blocker(node_name)

        -

        Example:

        - -

        +

        Notes

        +

        Explanation: +

        Blue zone is button with close_window callback

        @@ -155,62 +171,209 @@

        So you can do the safe zones, when you have the big buttons

        +

        Back Handler

        -

        Component to handle back button

        +

        Back handler API here

        + +

        Overview

        +

        Component to handle back button. It handle Android back button and Backspace key. Key triggers in input.binding should be setup for correct working.

        + +

        Setup

        +

        Setup callback with druid:new_back_handler(callback)

        + +

        Notes

        -

        It works on Android back button and Backspace. Key triggers in input.binding should be setup

        Lang text

        -

        Wrap on Text component to handle localization

        +

        Lang text API here

        + +

        Overview

        +

        Wrap on Text component to handle localization. It uses druid gettextfunction to set text by it's id

        + +

        Setup

        +

        Create lang text component with druid text = druid:new_lang_text(node_name, locale_id)

        + +

        Notes

        +

        Scroll

        -

        Basic Druid scroll component

        +

        Scroll API here

        + +

        Overview

        +

        Basic Druid scroll component. Handle all scrolling stuff in druid GUI

        + +

        Setup

        +

        Create scroll component with druid: scroll = druid:new_scroll(scroll_parent, scroll_input).

        + +

        Scroll parent - is dynamic part. This node will change position by scroll system

        + +

        Scroll input - is static part. It capturing user input and recognize scrolling touches

        + +

        Initial scroll size will be equal to scroll parent node size. The initial view box will be equal to scroll input node size

        + +

        Usually, Place static input zone part, and as children add scroll parent part: + +

        + +

        *Here scrollcontentzone below input zone, in game content zone be able to scroll left until end*

        + +

        Notes

        +

        - Scroll by default style have inertion and "back moving". It can be adjust via scroll style settings +- You can setup "points of interest". Scroll always will be centered on closes point of interest. It is able to create slider without inertion and points of interest on each scroll element. +- Scroll have next events:

        + +
        +- *on_scroll* On scroll move callback
        +- *on_scroll_to* On scroll_to function callback
        +- *on_point_scroll* On scroll_to_index function callback
        +
        + +

        - You can adjust scroll content size by scroll:set_border(node_size). It will setup new size to content node.

        +

        Progress

        +

        Progress API here

        + +

        Overview

        Basic Druid progress bar component

        +

        Setup

        +

        Create progress bar component with druid: progress = druid:new_progress(node_name, key, init_value)

        + +

        Node name should have maximum node size, so in GUI scene, node_name should be fully filled. +Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or just "y")

        + +

        Notes

        +

        - Progress correct working with 9slice nodes, it trying to set size by setsize_ first, if it is not possible, it set up sizing via setscale_ +- Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene +- If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles

        +

        Slider

        +

        Slider API here

        + +

        Overview

        Basic Druid slider component

        +

        Setup

        +

        Create slider component with druid: slider = druid:new_slider(node_name, end_pos, callback)

        + +

        Pin node (node_name in params) should be placed in zero position (initial). It will be available to mode Pin node between start pos and end pos.

        + +

        Notes

        +

        - You can setup points of interests on slider via slider:set_steps. If steps are exist, slider values will be only from this steps (notched slider) +- For now, start pos and end pos should be on vertical or horizontal line (their x or y value should be equal)

        +

        Input

        +

        Input API here

        + +

        Overview

        Basic Druid text input component (unimplemented)

        +

        Setup

        + +

        Notes

        + +

        Checkbox

        -

        Basic Druid checkbox component

        +

        Checkbox API here

        + +

        Overview

        +

        Basic Druid checkbox component.

        + +

        Setup

        +

        Create checkbox component with druid: checkbox = druid:new_checkbox(node, callback)

        + +

        Notes

        +

        - Checkbox uses button to handle click +- You can setup another node to handle input with click_node arg in component init: druid:new_checkbox(node, callback, [click_node])

        Checkbox group

        +

        Checkbox group API here

        + +

        Overview

        Several checkboxes in one group

        +

        Setup

        +

        Create checkbox_group component with druid: group = druid:new_checkbox_group(nodes[], callback)

        + +

        Notes

        +

        - Callback arguments: function(self, checkbox_index). Index is equals in nodes[] array in component constructor +- You can get/set checkbox_group state with group:set_state() and group:get_state()

        + +

        Radio group

        +

        Radio group API here

        + +

        Overview

        Several checkboxes in one group with single choice

        +

        Setup

        +

        Create radio_group component with druid: group = druid:new_radio_group(nodes[], callback)

        + +

        Notes

        +

        - Callback arguments: function(self, checkbox_index). Index is equals in nodes[] array in component constructor +- You can get/set radio_group state with group:set_state() and group:get_state() +- Only different from checkbox_group: on click another checkboxes in this group will be unchecked

        +

        Timer

        +

        Timer API here

        + +

        Overview

        Handle timer work on gui text node

        +

        Setup

        +

        Create timer component with druid: timer = druid:new_timer(text_node, from_seconds, to_seconds, callback)

        + +

        Notes

        +

        - Timer fires callback, when timer value equals to toseconds_ +- Timer will setup text node with current timer value +- Timer uses update function to handle time

        +

        Grid

        -

        Component for manage node positions

        +

        Grid API here

        + +

        Overview

        +

        Component for manage node positions. Very simple implementation for nodes with equal size

        + +

        Setup

        +

        Create grid component with druid: grid = druid:new_grid(parent_node, prefab_node, max_in_row_elements)

        + +

        Notes

        +

        - Grid on adding elements will setup parent to parentnode_ +- You can get array of position of every element for setup points of interest in scroll component +- You can get size of all elements for setup size in scroll component +- You can adjust anchor and border between elements +- Prefab node in component init used to get grid item size

        Hover

        +

        Hover API here

        + +

        Overview

        System Druid component, handle hover node state

        +

        Setup

        +

        Create grid component with druid: hover = druid:new_hover(node, callback)

        + +

        Notes

        +
        generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
        diff --git a/docs/topics/02-creating_custom_components.md.html b/docs/topics/02-creating_custom_components.md.html index e33e05d..30efb0f 100644 --- a/docs/topics/02-creating_custom_components.md.html +++ b/docs/topics/02-creating_custom_components.md.html @@ -41,7 +41,7 @@

        Topics

          -
        • Druid components
        • +
        • 01-components
        • Creating custom components
        • Styles
        • Druid assets
        • @@ -120,6 +120,15 @@ 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 on component remove or on druid:final +function M.on_remove(self) +end + return M @@ -131,12 +140,26 @@ local druid = require("druid.druid") local my_component = require("my.amazing.component") -local function init(self) +function init(self) druid.register("my_component", my_component) end +

          Registering make new function with "new{componentname}". In our example it will be: druid:new_my_component()

          + +

          As component registered, you can create your component with next code:

          + +
          +local druid = require("druid.druid")
          +
          +function init(self)
          +    self.druid = druid.new(self)
          +    local my_component = self.druid:new_my_component(...)
          +end
          +
          + +

          Interest

          Interest - is a way to indicate what events your component will respond to. There is next interests in druid: @@ -202,7 +225,7 @@ There is next interests in druid:

          generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
          diff --git a/docs/topics/03-styles.md.html b/docs/topics/03-styles.md.html index 613a57f..259f54d 100644 --- a/docs/topics/03-styles.md.html +++ b/docs/topics/03-styles.md.html @@ -40,7 +40,7 @@

          Topics

            -
          • Druid components
          • +
          • 01-components
          • Creating custom components
          • Styles
          • Druid assets
          • @@ -138,7 +138,7 @@
            generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
            diff --git a/docs/topics/04-druid_assets.md.html b/docs/topics/04-druid_assets.md.html index 74a30f5..85d8667 100644 --- a/docs/topics/04-druid_assets.md.html +++ b/docs/topics/04-druid_assets.md.html @@ -38,7 +38,7 @@

            Topics

              -
            • Druid components
            • +
            • 01-components
            • Creating custom components
            • Styles
            • Druid assets
            • @@ -80,7 +80,7 @@

              Overview

              I've created druid-assets repository to make a marketplace with custom styles and components.

              -

              Any of druid users can push their own components and styles to share it with the other users

              +

              Any of Druid users can push their own components and styles to share it with the other users

              Also, this marketplace is great example to how you can create your custom components

              @@ -89,7 +89,7 @@
              generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
              diff --git a/docs/topics/05-examples.md.html b/docs/topics/05-examples.md.html index aae01a8..ba040e2 100644 --- a/docs/topics/05-examples.md.html +++ b/docs/topics/05-examples.md.html @@ -38,7 +38,7 @@

              Topics

                -
              • Druid components
              • +
              • 01-components
              • Creating custom components
              • Styles
              • Druid assets
              • @@ -87,7 +87,7 @@
                generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
                diff --git a/docs/topics/README.md.html b/docs/topics/README.md.html index c1b6857..02732fa 100644 --- a/docs/topics/README.md.html +++ b/docs/topics/README.md.html @@ -36,6 +36,7 @@
              • Components
              • Basic usage
              • Druid Events
              • +
              • Druid lifecycle
              • Features
              • Examples
              • Documentation
              • @@ -48,7 +49,7 @@

                Topics

                  -
                • Druid components
                • +
                • 01-components
                • Creating custom components
                • Styles
                • Druid assets
                • @@ -85,6 +86,8 @@

                  +

                  GitHub release (latest by date)

                  +

                  Druid - powerful defold component UI library. Use basic Druid components or make your own game-specific components to make amazing GUI in your games.

                  @@ -107,8 +110,8 @@
                  • Mouse trigger - Button 1 -> touch For basic input components
                  • -
                  • Key trigger - Backspace -> backspace For backhandler component_
                  • -
                  • Key trigger - Back -> text For backhandler component, Android back button_
                  • +
                  • Key trigger - Backspace -> back For backhandler component_
                  • +
                  • Key trigger - Back -> back For backhandler component, Android back button_

                  @@ -193,14 +196,6 @@ self.druid:new_button("button_node_name", button_callback) end -function update(self, dt) - self.druid:update(dt) -end - -function on_message(self, message_id, message, sender) - self.druid:on_message(message_id, message, sender) -end - function on_input(self, action_id, action) return self.druid:on_input(action_id, action) end @@ -210,7 +205,7 @@

                  Druid Events

                  -

                  Any Druid components as callbacks uses Druid Events. In component API (button example) pointed list of component events. You can manually subscribe on this events by next API:

                  +

                  Any Druid components as callbacks uses Druid Events. In component API (button example) pointed list of component events. You can manually subscribe on this events by next API:

                  • event:subscribe(callback)

                  • @@ -220,6 +215,47 @@

                    Any events can handle several callbacks, if needed.

                    + +

                    +

                    Druid lifecycle

                    + +

                    Here is full druid lifecycle setup in your *.gui_script file:

                    + +
                    +local druid = require("druid.druid")
                    +
                    +function init(self)
                    +    self.druid = druid.new(self)
                    +end
                    +
                    +function final(self)
                    +    self.druid:final()
                    +end
                    +
                    +function update(self, dt)
                    +    self.druid:update(dt)
                    +end
                    +
                    +function on_input(self, action_id, action)
                    +    return self.druid:on_input(action_id, action)
                    +end
                    +
                    +function on_message(self, message_id, message, sender)
                    +    self.druid:on_message(message_id, message, sender)
                    +end
                    +
                    + + +
                      +
                    • *on_input* used for almost all basic druid components
                    • +
                    • update used for progress bar, scroll and timer base components
                    • +
                    • *on_message* used for specific druid events, like language change or layout change (TODO: in future)
                    • +
                    • final used for custom components, what have to do several action before destroy
                    • +
                    + +

                    Recommended is fully integrate al druid lifecycles functions

                    + +

                    Features

                    @@ -228,10 +264,11 @@
                  • Don't forget about return in on_input: return self.druid:on_input(). It need, if you have more than 1 acquire inputs (several druid, other input system, etc)
                  +

                  Examples

                  -

                  See the example folder for examples of how to use Druid

                  +

                  See the example folder for examples of how to use Druid

                  See the druid-assets repository for examples of how to create custom components and styles

                  @@ -291,7 +328,7 @@ https://insality.github.io/druid/

                  generated by LDoc 1.4.6 -Last updated 2020-03-22 15:31:43 +Last updated 2020-04-09 22:11:32
                  From 0ab794f86cb1925e4b53f310f76ec6927285fa00 Mon Sep 17 00:00:00 2001 From: Insality Date: Thu, 9 Apr 2020 22:15:08 +0300 Subject: [PATCH 11/11] Update README --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index eff4aae..e43e429 100644 --- a/README.md +++ b/README.md @@ -66,31 +66,31 @@ druid.set_default_style(your_style) - **[Text](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#text)** - Basic Druid text component -- **Lang text** - Wrap on Text component to handle localization +- **[Lang text](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#lang-text)** - Wrap on Text component to handle localization -- **Scroll** - Basic Druid scroll component +- **[Scroll](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#scroll)** - Basic Druid scroll component -- **Progress** - Basic Druid progress bar component +- **[Progress](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#progress)** - Basic Druid progress bar component -- **Slider** - Basic Druid slider component +- **[Slider](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#slider)** - Basic Druid slider component -- **Input** - Basic Druid text input component (unimplemented) +- **[Input](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#input)** - Basic Druid text input component (unimplemented) -- **Checkbox** - Basic Druid checkbox component +- **[Checkbox](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox)** - Basic Druid checkbox component -- **Checkbox group** - Several checkboxes in one group +- **[Checkbox group](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#checkbox-group)** - Several checkboxes in one group -- **Radio group** - Several checkboxes in one group with single choice +- **[Radio group](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#radio-group)** - Several checkboxes in one group with single choice - **[Blocker](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#blocker)** - Block input in node zone component -- **Back Handler** - Handle back button (Android back, backspace) +- **[Back Handler](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#back-handler)** - Handle back button (Android back, backspace) -- **Timer** - Handle timer work on gui text node +- **[Timer](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#timer)** - Handle timer work on gui text node -- **Grid** - Component for manage node positions +- **[Grid](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#grid)** - Component for manage node positions -- **Hover** - System Druid component, handle hover node state +- **[Hover](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#hover)** - System Druid component, handle hover node state Full info see on _[components.md](https://github.com/Insality/druid/blob/master/docs_md/01-components.md)_
      init(node, key, init_value)init(node, key[, init_value=1]) Component init function
      Component init function
      set_state(state)set_state(index) Set radio group state
      Create new druid component
      druid:final()Call on final function on gui_script.
      druid:remove(component) Remove component from druid instance.