From c85d66fdca64979780cd93d8cc02054c24f2abe9 Mon Sep 17 00:00:00 2001 From: Insality Date: Tue, 29 Oct 2024 20:31:45 +0200 Subject: [PATCH] Update annotations P.1 --- README.md | 48 +- docs_md/01-components.md | 27 - docs_md/02-creating_custom_components.md | 1 - docs_md/advanced-setup.md | 2 +- druid/annotations.lua | 1902 ----------------- druid/base/back_handler.lua | 69 +- druid/base/blocker.lua | 67 +- druid/base/button.lua | 104 +- druid/base/drag.lua | 90 +- druid/base/hover.lua | 63 +- druid/base/scroll.lua | 131 +- druid/base/static_grid.lua | 134 +- druid/base/text.lua | 77 +- druid/component.lua | 425 ++-- druid/const.lua | 13 +- druid/custom/rich_input/rich_input.gui | 146 +- druid/custom/rich_input/rich_input.lua | 77 +- druid/custom/rich_text/rich_text.lua | 47 +- druid/druid.lua | 107 +- .../editor_scripts/create_druid_component.py | 4 - druid/event.lua | 27 +- druid/extended/data_list.lua | 96 +- druid/extended/dynamic_grid.lua | 427 ---- druid/extended/hotkey.lua | 36 +- druid/extended/input.lua | 94 +- druid/extended/lang_text.lua | 34 +- druid/extended/layout.lua | 160 +- druid/extended/progress.lua | 56 +- druid/extended/slider.lua | 56 +- druid/extended/swipe.lua | 48 +- druid/extended/timer.lua | 96 +- druid/helper.lua | 237 +- druid/styles/default/style.lua | 2 - druid/system/druid_instance.lua | 407 ++-- druid/system/settings.lua | 16 +- druid/templates/component.template.lua | 17 +- druid/templates/component_full.template.lua | 28 +- example/components/container/container.lua | 14 +- .../examples/basic/blocker/basic_blocker.lua | 2 +- utils/annotations_manual.lua | 12 +- 40 files changed, 1458 insertions(+), 3941 deletions(-) delete mode 100644 druid/annotations.lua delete mode 100644 druid/extended/dynamic_grid.lua diff --git a/README.md b/README.md index 143999f..c0ba53a 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,15 @@ In this example you can inspect a variety of **Druid** components and see how th ## Setup -### Dependency +### [Dependency](https://www.defold.com/manuals/libraries/) -To integrate the **Druid** extension into your own project, add this project as a [dependency](https://www.defold.com/manuals/libraries/) in your **Defold** game. Open your `game.project` file and add the following line to the dependencies field under the project section: +Open your `game.project` file and add the following line to the dependencies field under the project section: -**Druid v1.0** +**[Druid](https://github.com/Insality/druid/archive/refs/tags/1.0.zip)** -> [https://github.com/Insality/druid/archive/refs/tags/1.0.zip](https://github.com/Insality/druid/archive/refs/tags/1.0.zip) +``` +https://github.com/Insality/druid/archive/refs/tags/1.0.zip +``` Here is a list of [all releases](https://github.com/Insality/druid/releases). @@ -119,15 +121,15 @@ Here is full **Druid** components list. | Name | Description | Example |
Preview
| |------|-------------|---------|---------| -| **[Button](https://insality.github.io/druid/modules/Button.html)** | Logic over GUI Node. Handle the user click interactions: click, long click, double click, etc. | [Button Example](https://insality.github.io/druid/druid/?example=general_buttons) | | -| **[Text](https://insality.github.io/druid/modules/Text.html)** | Logic over GUI Text. By default Text component fit the text inside text node size area with different adjust modes. | [Text Example](https://insality.github.io/druid/druid/?example=texts_general) | | -| **[Scroll](https://insality.github.io/druid/modules/Scroll.html)** | Logic over two GUI Nodes: input and content. Provides basic behaviour for scrollable content. | [Scroll Example](https://insality.github.io/druid/druid/?example=general_scroll) | | -| **[Blocker](https://insality.github.io/druid/modules/Blocker.html)** | Logic over GUI Node. Don't pass any user input below node area size. | [Blocker Example](https://insality.github.io/druid/druid/?example=timer) | | -| **[Back Handler](https://insality.github.io/druid/modules/BackHandler.html)** | Call callback on user "Back" action. It's a Android back button or keyboard backspace key | [Back Handler Example](https://insality.github.io/druid/druid/?example=timer) | | -| **[Static Grid](https://insality.github.io/druid/modules/StaticGrid.html)** | Logic over GUI Node. Component to manage node positions with all equal node sizes. | [Static Gid Example](https://insality.github.io/druid/druid/?example=general_grid) | | -| **[Hover](https://insality.github.io/druid/modules/Hover.html)** | Logic over GUI Node. Handle hover action over node. For both: mobile touch and mouse cursor. | [Hover Example](https://insality.github.io/druid/druid/?example=timer) | | -| **[Swipe](https://insality.github.io/druid/modules/Swipe.html)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/druid/?example=general_swipe) | | -| **[Drag](https://insality.github.io/druid/modules/Drag.html)** | Logic over GUI Node. Handle drag input actions. Can be useful to make on screen controlls. | [Drag Example](https://insality.github.io/druid/druid/?example=general_drag) | | +| **[Button](https://insality.github.io/druid/modules/Button.html)** | Logic over GUI Node. Handle the user click interactions: click, long click, double click, etc. | [Button Example](https://insality.github.io/druid/druid/?example=ui_example_basic_button) | | +| **[Text](https://insality.github.io/druid/modules/Text.html)** | Logic over GUI Text. By default Text component fit the text inside text node size area with different adjust modes. | [Text Example](https://insality.github.io/druid/druid/?example=ui_example_basic_text) | | +| **[Scroll](https://insality.github.io/druid/modules/Scroll.html)** | Logic over two GUI Nodes: input and content. Provides basic behaviour for scrollable content. | [Scroll Example](https://insality.github.io/druid/druid/?example=ui_example_basic_scroll) | | +| **[Blocker](https://insality.github.io/druid/modules/Blocker.html)** | Logic over GUI Node. Don't pass any user input below node area size. | [Blocker Example](https://insality.github.io/druid/druid/?example=ui_example_basic_blocker) | | +| **[Back Handler](https://insality.github.io/druid/modules/BackHandler.html)** | Call callback on user "Back" action. It's a Android back button or keyboard backspace key | [Back Handler Example](https://insality.github.io/druid/druid/?example=ui_example_basic_back_handler) | | +| **[Static Grid](https://insality.github.io/druid/modules/StaticGrid.html)** | Logic over GUI Node. Component to manage node positions with all equal node sizes. | [Static Gid Example](https://insality.github.io/druid/druid/?example=ui_example_basic_grid) | | +| **[Hover](https://insality.github.io/druid/modules/Hover.html)** | Logic over GUI Node. Handle hover action over node. For both: mobile touch and mouse cursor. | [Hover Example](https://insality.github.io/druid/druid/?example=ui_example_basic_hover) | | +| **[Swipe](https://insality.github.io/druid/modules/Swipe.html)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/druid/?example=ui_example_basic_swipe) | | +| **[Drag](https://insality.github.io/druid/modules/Drag.html)** | Logic over GUI Node. Handle drag input actions. Can be useful to make on screen controlls. | [Drag Example](https://insality.github.io/druid/druid/?example=ui_example_basic_drag) | | ### Extended components @@ -141,16 +143,16 @@ druid.register("data_list", data_list) | Name | Description | Example |
Preview
| |------|-------------|---------|---------| -| **[Data List](https://insality.github.io/druid/modules/DataList.html)** | Logic over Scroll and Grid components. Create only visible GUI nodes or components to make "infinity" scroll befaviour | [Data List Example](https://insality.github.io/druid/druid/?example=general_data_list) | | -| **[Input](https://insality.github.io/druid/modules/Input.html)** | Logic over GUI Node and GUI Text (or Text component). Provides basic user text input. | [Input Example](https://insality.github.io/druid/druid/?example=general_input) | | -| **[Lang text](https://insality.github.io/druid/modules/LangText.html)** | Logic over Text component to handle localization. Can be translated in real-time with `druid.on_language_change` | [Lang Text Example](https://insality.github.io/druid/druid/?example=timer) | | -| **[Progress](https://insality.github.io/druid/modules/Progress.html)** | Logic over GUI Node. Handle node size and scale to handle progress node size. | [Progress Example](https://insality.github.io/druid/druid/?example=general_progress_bar) | | -| **[Slider](https://insality.github.io/druid/modules/Slider.html)** | Logic over GUI Node. Handle draggable node with position restrictions. | [Slider Example](https://insality.github.io/druid/druid/?example=general_sliders) | | -| **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Logic over GUI Text. Handle basic timer functions. | [Timer Example](https://insality.github.io/druid/druid/?example=timer) | | -| **[Hotkey](https://insality.github.io/druid/modules/Hotkey.html)** | Allow to set callbacks for keyboard hotkeys with key modificators. | [Hotkey Example](https://insality.github.io/druid/druid/?example=general_hotkey) | | -| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Logic over GUI Node. Arrange nodes inside layout node with margin/paddings settings. | [Layout Example](https://insality.github.io/druid/druid/?example=general_layout) | | -| **[Rich Input](https://insality.github.io/druid/modules/RichInput.html)** | Logic over GUI Node and GUI Text (or Text component). Provides rich text input with different styles and text formatting. | [Rich Input Example](https://insality.github.io/druid/druid/?example=general_rich_input) | | -| **[Rich Text](https://insality.github.io/druid/modules/RichText.html)** | Logic over GUI Text. Provides rich text formatting with different styles and text formatting. | [Rich Text Example](https://insality.github.io/druid/druid/?example=general_rich_text) | | +| **[Data List](https://insality.github.io/druid/modules/DataList.html)** | Logic over Scroll and Grid components. Create only visible GUI nodes or components to make "infinity" scroll befaviour | [Data List Example](https://insality.github.io/druid/druid/?example=ui_example_data_list_basic) | | +| **[Input](https://insality.github.io/druid/modules/Input.html)** | Logic over GUI Node and GUI Text (or Text component). Provides basic user text input. | [Input Example](https://insality.github.io/druid/druid/?example=ui_example_basic_input) | | +| **[Lang text](https://insality.github.io/druid/modules/LangText.html)** | Logic over Text component to handle localization. Can be translated in real-time with `druid.on_language_change` | [Lang Text Example](https://insality.github.io/druid/druid/?example=ui_example_window_language) | | +| **[Progress](https://insality.github.io/druid/modules/Progress.html)** | Logic over GUI Node. Handle node size and scale to handle progress node size. | [Progress Example](https://insality.github.io/druid/druid/?example=ui_example_basic_progress_bar) | | +| **[Slider](https://insality.github.io/druid/modules/Slider.html)** | Logic over GUI Node. Handle draggable node with position restrictions. | [Slider Example](https://insality.github.io/druid/druid/?example=ui_example_basic_slider) | | +| **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Logic over GUI Text. Handle basic timer functions. | [Timer Example](https://insality.github.io/druid/druid/?example=ui_example_basic_timer) | | +| **[Hotkey](https://insality.github.io/druid/modules/Hotkey.html)** | Allow to set callbacks for keyboard hotkeys with key modificators. | [Hotkey Example](https://insality.github.io/druid/druid/?example=ui_example_basic_hotkey) | | +| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Logic over GUI Node. Arrange nodes inside layout node with margin/paddings settings. | [Layout Example](https://insality.github.io/druid/druid/?example=ui_example_layout_basic) | | +| **[Rich Input](https://insality.github.io/druid/modules/RichInput.html)** | Logic over GUI Node and GUI Text (or Text component). Provides rich text input with different styles and text formatting. | [Rich Input Example](https://insality.github.io/druid/druid/?example=ui_example_basic_rich_input) | | +| **[Rich Text](https://insality.github.io/druid/modules/RichText.html)** | Logic over GUI Text. Provides rich text formatting with different styles and text formatting. | [Rich Text Example](https://insality.github.io/druid/druid/?example=ui_example_basic_rich_text) | | For a complete overview, see: **_[components.md](docs_md/01-components.md)_**. diff --git a/docs_md/01-components.md b/docs_md/01-components.md index 6aa0735..edb1fa3 100644 --- a/docs_md/01-components.md +++ b/docs_md/01-components.md @@ -227,33 +227,6 @@ Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_ - _Prefab node_ used to get node size and anchor - You can point *position_function* for animations with _static_grid:set_position_function(node, pos)_ callback. Default - *gui.set_position()* - -## Dynamic Grid -[Dynamic Grid API here](https://insality.github.io/druid/modules/DynamicGrid.html) - -### Overview -Component for manage node positions with different node sizes. -Unlike Static Grid, Dynamic Grid can place nodes only in one row or in one column. -Dynamic Grid can't have gaps between elements -- you will get error, if try spawn element far away from others. -Dynamic Grid should have __West__, __East__, __South__ or __North__ pivot (vertical or horizontal element placement) - -### Setup -Create component with druid: `grid = druid:new_dynamic_grid(parent_node)` - -Check the _parent_node_ have correct pivot point. You will get the error otherwise. - -### Notes -- On _add node_ grid will set node 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 also bind the grid to the scroll component for auto resize scroll content size -- Pivot of parent_node matter for node placement -- You can point *position_function* for animations with _static_grid:set_position_function(node, pos)_ callback. Default - *gui.set_position()* -- First node placed at Grid pivot point. Other nodes placed nearby of other nodes. -- On *add/remove* nodes always shifted. You can point the shift side in this functions (*is_shift_left* boolean argumentp - - ## Data List [Data List API here](https://insality.github.io/druid/modules/DataList.html) diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index 45e5a6b..bdb1ea9 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -148,7 +148,6 @@ Available keywords: - `text`: Adds a [Druid Text](01-components.md#text) component. - `lang_text`: Adds a [Druid Lang Text](01-components.md#lang-text) component. - `grid` or `static_grid`: Adds a [Druid Static Grid](01-components.md#static-grid) component. You should set up the Grid prefab for this component after generating the file. -- `dynamic_grid`: Adds a [Druid Dynamic Grid](01-components.md#dynamic-grid) component. - `scroll_view`: Adds a [Druid Scroll](01-components.md#scroll) component. It also adds a `scroll_content` node with the same postfix. Ensure that it's the correct node. - `blocker`: Adds a [Druid Blocker](01-components.md#blocker) component. - `slider`: Adds a [Druid Slider](01-components.md#slider) component. You should adjust the end position of the Slider after generating the file. diff --git a/docs_md/advanced-setup.md b/docs_md/advanced-setup.md index 5e047a7..ef95336 100644 --- a/docs_md/advanced-setup.md +++ b/docs_md/advanced-setup.md @@ -121,7 +121,7 @@ window.set_listener(on_window_callback) ``` -## EmmyLua Annotations +## Lua Annotations [EmmyLua](https://emmylua.github.io/annotation.html) is a Lua annotation library. It is a useful tool for enabling Lua code autocompletion in editors such as [VSCode](https://github.com/EmmyLua/VSCode-EmmyLua) and [IntelliJ IDEA](https://github.com/EmmyLua/IntelliJ-EmmyLua). diff --git a/druid/annotations.lua b/druid/annotations.lua deleted file mode 100644 index 9ccff3c..0000000 --- a/druid/annotations.lua +++ /dev/null @@ -1,1902 +0,0 @@ --- luacheck: ignore ----@meta - ----@class druid -local druid = {} - ---- Create a new Druid instance for creating GUI components. ----@param context table The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks. ----@param style table|nil The Druid style table to override style parameters for this Druid instance. ----@return druid_instance The Druid instance @{DruidInstance}. -function druid.new(context, style) end - ---- Call this function when the game language changes. ---- This function will translate all current LangText components. -function druid.on_language_change() end - ---- Set the window callback to enable on_focus_gain and on_focus_lost functions. ---- This is used to trigger the on_focus_lost and on_focus_gain functions in Druid components. ----@param event string Event param from window listener -function druid.on_window_callback(event) end - ---- Register a new external Druid component. ---- You can register your own components to make new alias: the druid:new_{name} function. For example, if you want to register a component called "my_component", you can create it using druid:new_my_component(...). This can be useful if you have your own "basic" components that you don't want to re-create each time. ----@param name string module name ----@param module table lua table with component -function druid.register(name, module) end - ---- Set your own default style for all Druid instances. ---- To create your own style file, copy the default style file and make changes to it. Register the new style before creating your Druid instances. ----@param style table Druid style module -function druid.set_default_style(style) end - ---- Set the Druid sound function to play UI sounds if used. ---- Set a function to play a sound given a sound_id. This function is used for button clicks to play the "click" sound. It can also be used to play sounds in your custom components (see the default Druid style file for an example). ----@param callback function Sound play callback -function druid.set_sound_function(callback) end - ---- Set the text function for the LangText component. ---- The Druid locale component will call this function to get translated text. After setting the text function, all existing locale components will be updated. ----@param callback function Get localized text function -function druid.set_text_function(callback) end - - ----@class druid.back_handler : druid.base_component ----@field on_back druid.event The @{DruidEvent} Event on back handler action. ----@field params any|nil Custom args to pass in the callback -local druid__back_handler = {} - - ----@class druid.base_component -local druid__base_component = {} - ---- Return all children components, recursive ----@param self druid.base_component @{BaseComponent} ----@return table Array of childrens if the Druid component instance -function druid__base_component.get_childrens(self) end - ---- Context used as first arg in all Druid events ---- Context is usually self of gui_script. ----@param self druid.base_component @{BaseComponent} ----@return table BaseComponent context -function druid__base_component.get_context(self) end - ---- Get Druid instance for inner component creation. ----@param self druid.base_component @{BaseComponent} ----@param template string|nil The template name ----@param nodes table|nil The nodes table ----@return druid_instance Druid instance with component context -function druid__base_component.get_druid(self, template, nodes) end - ---- Return component input priority ----@param self druid.base_component @{BaseComponent} ----@return number The component input priority -function druid__base_component.get_input_priority(self) end - ---- Return component name ----@param self druid.base_component @{BaseComponent} ----@return string The component name -function druid__base_component.get_name(self) end - ---- Get component node by name. ---- If component has nodes, node_or_name should be string It autopick node by template name or from nodes by gui.clone_tree if they was setup via component:set_nodes, component:set_template. If node is not found, the exception will fired ----@param self druid.base_component @{BaseComponent} ----@param node_or_name string|node Node name or node itself ----@return node Gui node -function druid__base_component.get_node(self, node_or_name) end - ---- Return the parent component if exist ----@param self druid.base_component @{BaseComponent} ----@return druid.base_component|nil The druid component instance or nil -function druid__base_component.get_parent_component(self) end - ---- Return parent component name ----@param self druid.base_component @{BaseComponent} ----@return string|nil The parent component name if exist or bil -function druid__base_component.get_parent_name(self) end - ---- Get current component template name. ----@param self druid.base_component @{BaseComponent} ----@return string Component full template name -function druid__base_component.get_template(self) end - ---- Return component UID. ---- UID generated in component creation order. ----@param self druid.base_component @{BaseComponent} ----@return number The component uid -function druid__base_component.get_uid(self) end - ---- Reset component input priority to default value ----@param self druid.base_component @{BaseComponent} ----@return number The component input priority -function druid__base_component.reset_input_priority(self) end - ---- Set component input state. ---- By default it enabled If input is disabled, the component will not receive input events ----@param self druid.base_component @{BaseComponent} ----@param state boolean|nil The component input state ----@return druid.base_component BaseComponent itself -function druid__base_component.set_input_enabled(self, state) end - ---- Set component input priority ---- Default value: 10 ----@param self druid.base_component @{BaseComponent} ----@param value number The new input priority value ----@param is_temporary boolean|nil If true, the reset input priority will return to previous value ----@return number The component input priority -function druid__base_component.set_input_priority(self, value, is_temporary) end - - ----@class druid.blocker : druid.base_component ----@field node node Blocker node -local druid__blocker = {} - ---- The @{Blocker} constructor ----@param self druid.blocker @{Blocker} ----@param node node Gui node -function druid__blocker.init(self, node) end - ---- Return blocker enabled state ----@param self druid.blocker @{Blocker} ----@return boolean @True, if blocker is enabled -function druid__blocker.is_enabled(self) end - ---- Set enabled blocker component state. ---- Don't change node enabled state itself. ----@param self druid.blocker @{Blocker} ----@param state boolean|nil Enabled state -function druid__blocker.set_enabled(self, state) end - - ----@class druid.button : druid.base_component ----@field anim_node node|nil Button animation node. ----@field click_zone node|nil Additional button click area, defined by another GUI node ----@field hover druid.hover The @{Hover}: Button Hover component ----@field node node Button trigger node ----@field node_id hash The GUI node id from button node ----@field on_click druid.event The @{DruidEvent}: Event on successful release action over button. ----@field on_click_outside druid.event The @{DruidEvent}: Event calls if click event was outside of button. ----@field on_double_click druid.event The @{DruidEvent}: Event on double tap action over button. ----@field on_hold_callback druid.event The @{DruidEvent}: Event calls every frame before on_long_click event. ----@field on_long_click druid.event The @{DruidEvent}: Event on long tap action over button. ----@field on_pressed druid.event The @{DruidEvent}: Event triggered if button was pressed by user. ----@field on_repeated_click druid.event The @{DruidEvent}: Event on repeated action over button. ----@field params any Custom args for any Button event. ----@field style druid.button.style Component style params. -local druid__button = {} - ---- Get current key name to trigger this button. ----@param self druid.button ----@return hash The action_id of the input key -function druid__button.get_key_trigger(self) end - ---- The @{Button} constructor ----@param self druid.button @{Button} ----@param node string|node The node_id or gui.get_node(node_id) ----@param callback function On click button callback ----@param custom_args any|nil Button events custom arguments ----@param anim_node string|node|nil Node to animate instead of trigger node. -function druid__button.init(self, node, callback, custom_args, anim_node) end - ---- Get button enabled state. ---- By default all Buttons is enabled on creating. ----@param self druid.button @{Button} ----@return boolean @True, if button is enabled now, False overwise -function druid__button.is_enabled(self) end - ---- Set function for additional check for button click availability ----@param self druid.button ----@param check_function function|nil Should return true or false. If true - button can be pressed. ----@param failure_callback function|nil Function will be called on button click, if check function return false ----@return druid.button Current button instance -function druid__button.set_check_function(self, check_function, failure_callback) end - ---- Set additional button click area. ---- Useful to restrict click outside out stencil node or scrollable content. This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check ----@param self druid.button @{Button} ----@param zone node|string|nil Gui node ----@return druid.button Current button instance -function druid__button.set_click_zone(self, zone) end - ---- Set button enabled state. ---- The style.on_set_enabled will be triggered. Disabled button is not clickable. ----@param self druid.button @{Button} ----@param state boolean|nil Enabled state ----@return druid.button Current button instance -function druid__button.set_enabled(self, state) end - ---- Set key name to trigger this button by keyboard. ----@param self druid.button @{Button} ----@param key hash|string The action_id of the input key ----@return druid.button Current button instance -function druid__button.set_key_trigger(self, key) end - ---- Set Button mode to work inside user HTML5 interaction event. ---- It's required to make protected things like copy & paste text, show mobile keyboard, etc The HTML5 button's doesn't call any events except on_click event. If the game is not HTML, html mode will be not enabled ----@param self druid.button ----@param is_web_mode boolean|nil If true - button will be called inside html5 callback ----@return druid.button Current button instance -function druid__button.set_web_user_interaction(self, is_web_mode) end - - ----@class druid.button.style ----@field AUTOHOLD_TRIGGER number|nil Maximum hold time to trigger button release while holding. Default: 0.8 ----@field DOUBLETAP_TIME number|nil Time between double taps. Default: 0.4 ----@field LONGTAP_TIME number|nil Minimum time to trigger on_hold_callback. Default: 0.4 ----@field on_click function function(self, node) ----@field on_click_disabled function function(self, node) ----@field on_hover function function(self, node, hover_state) ----@field on_mouse_hover function function(self, node, hover_state) ----@field on_set_enabled function function(self, node, enabled_state) -local druid__button__style = {} - - ----@class druid.data_list : druid.base_component ----@field grid druid.static_grid The Druid Grid component ----@field last_index number The current last index of visual elements ----@field on_element_add druid.event On DataList visual element created Event callback(self, index, node, instance) ----@field on_element_remove druid.event On DataList visual element created Event callback(self, index) ----@field on_scroll_progress_change druid.event Event triggered when scroll progress is changed; event(self, progress_value) ----@field scroll druid.scroll The Druid scroll component ----@field scroll_progress number The current progress of scroll posititon ----@field top_index number The current top index of visual elements -local druid__data_list = {} - ---- Add element to DataList. ---- Currenly untested ----@param self druid.data_list @{DataList} ----@param data table ----@param index number|nil ----@param shift_policy number|nil The constant from const.SHIFT.* -function druid__data_list.add(self, data, index, shift_policy) end - ---- Clear the DataList and refresh visuals ----@param self druid.data_list @{DataList} -function druid__data_list.clear(self) end - ---- Return all currenly created components in DataList ----@param self druid.data_list @{DataList} ----@return druid.base_component[] List of created nodes -function druid__data_list.get_created_components(self) end - ---- Return all currenly created nodes in DataList ----@param self druid.data_list @{DataList} ----@return node[] List of created nodes -function druid__data_list.get_created_nodes(self) end - ---- Return current data from DataList component ----@param self druid.data_list @{DataList} ----@return table The current data array -function druid__data_list.get_data(self) end - ---- Return index for data value ----@param self druid.data_list @{DataList} ----@param data table -function druid__data_list.get_index(self, data) end - ---- The @{DataList} constructor ----@param self druid.data_list @{DataList} ----@param scroll druid.scroll The @{Scroll} instance for Data List component ----@param grid druid.static_grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component ----@param create_function function The create function callback(self, data, index, data_list). Function should return (node, [component]) -function druid__data_list.init(self, scroll, grid, create_function) end - ---- Druid System on_remove function ----@param self druid.data_list @{DataList} -function druid__data_list.on_remove(self) end - ---- Remove element from DataList. ---- Currenly untested ----@param self druid.data_list @{DataList} ----@param index number|nil ----@param shift_policy number|nil The constant from const.SHIFT.* -function druid__data_list.remove(self, index, shift_policy) end - ---- Remove element from DataList by data value. ---- Currenly untested ----@param self druid.data_list @{DataList} ----@param data table ----@param shift_policy number|nil The constant from const.SHIFT.* -function druid__data_list.remove_by_data(self, data, shift_policy) end - ---- Instant scroll to element with passed index ----@param self druid.data_list @{DataList} ----@param index number -function druid__data_list.scroll_to_index(self, index) end - ---- Set new data set for DataList component ----@param self druid.data_list @{DataList} ----@param data table The new data array ----@return druid.data_list Current DataList instance -function druid__data_list.set_data(self, data) end - ---- Set refresh function for DataList component ----@param self druid.data_list @{DataList} ----@param is_use_cache boolean Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove ----@return druid.data_list Current DataList instance -function druid__data_list.set_use_cache(self, is_use_cache) end - - ----@class druid.drag : druid.base_component ----@field can_x boolean Is drag component process vertical dragging. ----@field can_y boolean Is drag component process horizontal. ----@field is_drag boolean Is component now dragging ----@field is_touch boolean Is component now touching ----@field node node Drag node ----@field on_drag druid.event on drag progress callback(self, dx, dy, total_x, total_y, touch) ----@field on_drag_end druid.event Event on drag end callback(self, total_x, total_y, touch) ----@field on_drag_start druid.event Event on drag start callback(self, touch) ----@field on_touch_end druid.event Event on touch end callback(self) ----@field on_touch_start druid.event Event on touch start callback(self) ----@field screen_x number Current touch x screen position ----@field screen_y number Current touch y screen position ----@field style druid.drag.style Component style params. ----@field touch_start_pos vector3 Touch start position ----@field x number Current touch x position ----@field y number Current touch y position -local druid__drag = {} - ---- The @{Drag} constructor ----@param self druid.drag @{Drag} ----@param node node GUI node to detect dragging ----@param on_drag_callback function Callback for on_drag_event(self, dx, dy) -function druid__drag.init(self, node, on_drag_callback) end - ---- Check if Drag component is enabled ----@param self druid.drag @{Drag} ----@return boolean -function druid__drag.is_enabled(self) end - ---- Strict drag click area. ---- Useful for restrict events outside stencil node ----@param self druid.drag @{Drag} ----@param node node|string|nil Gui node -function druid__drag.set_click_zone(self, node) end - ---- Set Drag input enabled or disabled ----@param self druid.drag @{Drag} ----@param is_enabled boolean|nil -function druid__drag.set_enabled(self, is_enabled) end - - ----@class druid.drag.style ----@field DRAG_DEADZONE number|nil Distance in pixels to start dragging. Default: 10 ----@field NO_USE_SCREEN_KOEF boolean|nil If screen aspect ratio affects on drag values. Default: false -local druid__drag__style = {} - - ----@class druid.dynamic_grid : druid.base_component ----@field border vector4 The size of item content ----@field first_index number The first index of node in grid ----@field last_index number The last index of node in grid ----@field node_size vector3 Item size ----@field nodes node[] List of all grid elements. ----@field on_add_item druid.event On item add callback(self, node, index) ----@field on_change_items druid.event On item add or remove callback(self, index) ----@field on_clear druid.event On grid clear callback(self) ----@field on_remove_item druid.event On item remove callback(self, index) ----@field on_update_positions druid.event On update item positions callback(self) ----@field parent node Parent gui node -local druid__dynamic_grid = {} - ---- Return side vector to correct node shifting ----@param self unknown ----@param side unknown ----@param is_forward unknown -function druid__dynamic_grid._get_side_vector(self, side, is_forward) end - ---- Add new node to the grid ----@param self druid.dynamic_grid @{DynamicGrid} ----@param node node Gui node ----@param index number|nil The node position. By default add as last node ----@param shift_policy number|nil How shift nodes, if required. Default: const.SHIFT.RIGHT ----@param is_instant boolean|nil If true, update node positions instantly -function druid__dynamic_grid.add(self, node, index, shift_policy, is_instant) end - ---- Clear grid nodes array. ---- GUI nodes will be not deleted! If you want to delete GUI nodes, use dynamic_grid.nodes array before grid:clear ----@param self druid.dynamic_grid @{DynamicGrid} ----@return druid.dynamic_grid Current grid instance -function druid__dynamic_grid.clear(self) end - ---- Return array of all node positions ----@param self druid.dynamic_grid @{DynamicGrid} ----@return vector3[] All grid node positions -function druid__dynamic_grid.get_all_pos(self) end - ---- Return grid content borders ----@param self druid.dynamic_grid @{DynamicGrid} ----@return vector3 The grid content borders -function druid__dynamic_grid.get_borders(self) end - ---- Return grid index by node ----@param self druid.dynamic_grid @{DynamicGrid} ----@param node node The gui node in the grid ----@return number The node index -function druid__dynamic_grid.get_index_by_node(self, node) end - ---- Return DynamicGrid offset, where DynamicGrid content starts. ----@param self druid.dynamic_grid @{DynamicGrid} The DynamicGrid instance ----@return vector3 The DynamicGrid offset -function druid__dynamic_grid.get_offset(self) end - ---- Return pos for grid node index ----@param self druid.dynamic_grid @{DynamicGrid} ----@param index number The grid element index ----@param node node The node to be placed ----@param origin_index number|nil Index of nearby node ----@return vector3 node position -function druid__dynamic_grid.get_pos(self, index, node, origin_index) end - ---- Return grid content size ----@param self druid.dynamic_grid @{DynamicGrid} ----@param border vector3 ----@return vector3 The grid content size -function druid__dynamic_grid.get_size(self, border) end - ---- The @{DynamicGrid} constructor ----@param self druid.dynamic_grid @{DynamicGrid} ----@param parent node The gui node parent, where items will be placed -function druid__dynamic_grid.init(self, parent) end - ---- Remove the item from the grid. ---- Note that gui node will be not deleted ----@param self druid.dynamic_grid @{DynamicGrid} ----@param index number The grid node index to remove ----@param shift_policy number|nil How shift nodes, if required. Default: const.SHIFT.RIGHT ----@param is_instant boolean|nil If true, update node positions instantly ----@return node The deleted gui node from grid -function druid__dynamic_grid.remove(self, index, shift_policy, is_instant) end - ---- Change set position function for grid nodes. ---- It will call on update poses on grid elements. Default: gui.set_position ----@param self druid.dynamic_grid @{DynamicGrid} ----@param callback function Function on node set position ----@return druid.dynamic_grid Current grid instance -function druid__dynamic_grid.set_position_function(self, callback) end - - ----@class druid.event -local druid__event = {} - ---- Clear the all event handlers ----@param self druid.event @{DruidEvent} -function druid__event.clear(self) end - ---- DruidEvent constructor ----@param callback function|nil Subscribe the callback on new event, if callback exist ----@param callback_context any|nil Additional context as first param to callback call -function druid__event.create(callback, callback_context) end - ---- Return true, if event not have handler ----@param self druid.event @{DruidEvent} ----@return boolean True if event not have handlers -function druid__event.is_empty(self) end - ---- Return true, if event have at lease one handler ----@param self druid.event @{DruidEvent} ----@return boolean True if event have handlers -function druid__event.is_exist(self) end - ---- Check is event subscribed. ----@param self druid.event @{DruidEvent} ----@param callback function Callback itself ----@param callback_context any|nil Additional context as first param to callback call ----@return boolean, number|nil @Is event subscribed, return index of callback in event as second param -function druid__event.is_subscribed(self, callback, callback_context) end - ---- Subscribe callback on event ----@param self druid.event @{DruidEvent} ----@param callback function Callback itself ----@param callback_context any|nil Additional context as first param to callback call, usually it's self ----@return boolean True if callback was subscribed -function druid__event.subscribe(self, callback, callback_context) end - ---- Trigger the event and call all subscribed callbacks ----@param self druid.event @{DruidEvent} ----@param ... any All event params -function druid__event.trigger(self, ...) end - ---- Unsubscribe callback on event ----@param self druid.event @{DruidEvent} ----@param callback function Callback itself ----@param callback_context any|nil Additional context as first param to callback call -function druid__event.unsubscribe(self, callback, callback_context) end - - ----@class druid.hotkey : druid.base_component ----@field button druid.button Button component from click_node ----@field click_node node|nil Button trigger node ----@field node node Visual node ----@field on_hotkey_pressed druid.event On hotkey released callback(self, argument) ----@field on_hotkey_released druid.event On hotkey released callback(self, argument) ----@field style druid.hotkey.style Component style params. -local druid__hotkey = {} - ---- Add hotkey for component callback ----@param self druid.hotkey @{Hotkey} ----@param keys string[]|hash[]|string|hash that have to be pressed before key pressed to activate ----@param callback_argument any|nil The argument to pass into the callback function ----@return druid.hotkey Current instance -function druid__hotkey.add_hotkey(self, keys, callback_argument) end - ---- The @{Hotkey} constructor ----@param self druid.hotkey @{Hotkey} ----@param keys string[]|string The keys to be pressed for trigger callback. Should contains one key and any modificator keys ----@param callback function The callback function ----@param callback_argument any|nil The argument to pass into the callback function -function druid__hotkey.init(self, keys, callback, callback_argument) end - ---- If true, the callback will be triggered on action.repeated ----@param self druid.hotkey @{Hotkey} ----@param is_enabled_repeated bool The flag value ----@return druid.hotkey -function druid__hotkey.set_repeat(self, is_enabled_repeated) end - - ----@class druid.hotkey.style ----@field MODIFICATORS string[] The list of action_id as hotkey modificators -local druid__hotkey__style = {} - - ----@class druid.hover : druid.base_component ----@field node node Hover node ----@field on_hover druid.event On hover callback(self, state, hover_instance) ----@field on_mouse_hover druid.event On mouse hover callback(self, state, hover_instance) ----@field style druid.hover.style Component style params. -local druid__hover = {} - ---- The @{Hover} constructor ----@param self druid.hover @{Hover} ----@param node node Gui node ----@param on_hover_callback function Hover callback ----@param on_mouse_hover function On mouse hover callback -function druid__hover.init(self, node, on_hover_callback, on_mouse_hover) end - ---- Return current hover enabled state ----@param self druid.hover @{Hover} ----@return boolean The hover enabled state -function druid__hover.is_enabled(self) end - ---- Return current hover state. ---- True if touch action was on the node at current time ----@param self druid.hover @{Hover} ----@return boolean The current hovered state -function druid__hover.is_hovered(self) end - ---- Return current hover state. ---- True if nil action_id (usually desktop mouse) was on the node at current time ----@param self druid.hover @{Hover} ----@return boolean The current hovered state -function druid__hover.is_mouse_hovered(self) end - ---- Strict hover click area. ---- Useful for no click events outside stencil node ----@param self druid.hover @{Hover} ----@param zone node|string|nil Gui node -function druid__hover.set_click_zone(self, zone) end - ---- Set enable state of hover component. ---- If hover is not enabled, it will not generate any hover events ----@param self druid.hover @{Hover} ----@param state boolean|nil The hover enabled state -function druid__hover.set_enabled(self, state) end - ---- Set hover state ----@param self druid.hover @{Hover} ----@param state boolean|nil The hover state -function druid__hover.set_hover(self, state) end - ---- Set mouse hover state ----@param self druid.hover @{Hover} ----@param state boolean|nil The mouse hover state -function druid__hover.set_mouse_hover(self, state) end - - ----@class druid.hover.style ----@field ON_HOVER_CURSOR string Mouse hover style on node hover ----@field ON_MOUSE_HOVER_CURSOR string Mouse hover style on node mouse hover -local druid__hover__style = {} - - ----@class druid.input : druid.base_component ----@field allowerd_characters string|nil Pattern matching for user input ----@field button druid.button Button component ----@field current_value string Current input value with marked text ----@field cursor_index number The cursor index. ----@field end_index number Theselection end index. ----@field is_empty boolean Is current input is empty now ----@field is_selected boolean Is current input selected now ----@field keyboard_type number Gui keyboard type for input field ----@field marked_text_width number Marked text width ----@field marked_value string Marked text for input field. ----@field max_length number|nil Max length for input text ----@field on_input_empty druid.event On input field text change to empty string callback(self, input_text) ----@field on_input_full druid.event On input field text change to max length string callback(self, input_text) ----@field on_input_select druid.event On input field select callback(self, input_instance) ----@field on_input_text druid.event On input field text change callback(self, input_text) ----@field on_input_unselect druid.event On input field unselect callback(self, input_text, input_instance) ----@field on_input_wrong druid.event On trying user input with not allowed character callback(self, params, input_text) ----@field on_select_cursor_change druid.event On cursor position change callback(self, cursor_index, start_index, end_index) ----@field previous_value string Previous input value ----@field start_index number The selection start index. ----@field style druid.input.style Component style params. ----@field text druid.text Text component ----@field text_width number Text width ----@field value string Current input value -local druid__input = {} - ---- Return current input field text ----@param self druid.input @{Input} ----@return string The current input field text -function druid__input.get_text(self) end - ---- Replace selected text with new text ----@param self druid.input @{Input} ----@param text string The text to replace selected text ----@return string New input text -function druid__input.get_text_selected_replaced(self, text) end - ---- The @{Input} constructor ----@param self druid.input @{Input} ----@param click_node node Node to enabled input component ----@param text_node node|druid.text Text node what will be changed on user input. You can pass text component instead of text node name @{Text} ----@param keyboard_type number|nil Gui keyboard type for input field -function druid__input.init(self, click_node, text_node, keyboard_type) end - ---- Change cursor position by delta ----@param self druid.input @{Input} ----@param delta number side for cursor position, -1 for left, 1 for right ----@param is_add_to_selection boolean (Shift key) ----@param is_move_to_end boolean (Ctrl key) -function druid__input.move_selection(self, delta, is_add_to_selection, is_move_to_end) end - ---- Reset current input selection and return previous value ----@param self druid.input @{Input} ----@return druid.input Current input instance -function druid__input.reset_changes(self) end - ---- Select input field. ---- It will show the keyboard and trigger on_select events ----@param self druid.input @{Input} -function druid__input.select(self) end - ---- Set cursor position in input field ----@param self druid.input @{Input} ----@param cursor_index number|nil Cursor index for cursor position, if nil - will be set to the end of the text ----@param start_index number|nil Start index for cursor position, if nil - will be set to the end of the text ----@param end_index number|nil End index for cursor position, if nil - will be set to the start_index ----@return druid.input Current input instance -function druid__input.select_cursor(self, cursor_index, start_index, end_index) end - ---- Set allowed charaters for input field. ---- See: https://defold.com/ref/stable/string/ ex: [%a%d] for alpha and numeric ----@param self druid.input @{Input} ----@param characters string Regulax exp. for validate user input ----@return druid.input Current input instance -function druid__input.set_allowed_characters(self, characters) end - ---- Set maximum length for input field. ---- Pass nil to make input field unliminted (by default) ----@param self druid.input @{Input} ----@param max_length number Maximum length for input text field ----@return druid.input Current input instance -function druid__input.set_max_length(self, max_length) end - ---- Set text for input field ----@param self druid.input @{Input} ----@param input_text string The string to apply for input field -function druid__input.set_text(self, input_text) end - ---- Remove selection from input. ---- It will hide the keyboard and trigger on_unselect events ----@param self druid.input @{Input} -function druid__input.unselect(self) end - - ----@class druid.input.style ----@field IS_LONGTAP_ERASE boolean Is long tap will erase current input data. Default: false ----@field IS_UNSELECT_ON_RESELECT boolean If true, call unselect on select selected input. Default: false ----@field MASK_DEFAULT_CHAR string Default character mask for password input. Default: *] ----@field on_input_wrong function (self, button_node) Callback on wrong user input ----@field on_select function (self, button_node) Callback on input field selecting ----@field on_unselect function (self, button_node) Callback on input field unselecting -local druid__input__style = {} - - ----@class druid.lang_text : druid.base_component ----@field node node Text node ----@field on_change druid.event On change text callback ----@field text druid.text The text component -local druid__lang_text = {} - ---- Format string with new text params on localized text ----@param self druid.lang_text @{LangText} ----@param a string|nil Optional param to string.format ----@param b string|nil Optional param to string.format ----@param c string|nil Optional param to string.format ----@param d string|nil Optional param to string.format ----@param e string|nil Optional param to string.format ----@param f string|nil Optional param to string.format ----@param g string|nil Optional param to string.format ----@return druid.lang_text Current instance -function druid__lang_text.format(self, a, b, c, d, e, f, g) end - ---- The @{LangText} constructor ----@param self druid.lang_text @{LangText} ----@param node string|node The node_id or gui.get_node(node_id) ----@param locale_id string|nil Default locale id or text from node as default ----@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference -function druid__lang_text.init(self, node, locale_id, adjust_type) end - ---- Setup raw text to lang_text component ----@param self druid.lang_text @{LangText} ----@param text string Text for text node ----@return druid.lang_text Current instance -function druid__lang_text.set_to(self, text) end - ---- Translate the text by locale_id ----@param self druid.lang_text @{LangText} ----@param locale_id string Locale id ----@param a string|nil Optional param to string.format ----@param b string|nil Optional param to string.format ----@param c string|nil Optional param to string.format ----@param d string|nil Optional param to string.format ----@param e string|nil Optional param to string.format ----@param f string|nil Optional param to string.format ----@param g string|nil Optional param to string.format ----@return druid.lang_text Current instance -function druid__lang_text.translate(self, locale_id, a, b, c, d, e, f, g) end - - ----@class druid.layout : druid.base_component ----@field mode string Current layout mode ----@field node node Layout node -local druid__layout = {} - - ----@class druid.progress : druid.base_component ----@field key string The progress bar direction. ----@field max_size number Maximum size of progress bar ----@field node node Progress bar fill node ----@field on_change druid.event On progress bar change callback(self, new_value) ----@field scale vector3 Current progress bar scale ----@field size vector3 Current progress bar size ----@field slice vector4 Progress bar slice9 settings ----@field style druid.progress.style Component style params. -local druid__progress = {} - ---- Empty a progress bar ----@param self druid.progress @{Progress} -function druid__progress.empty(self) end - ---- Fill a progress bar and stop progress animation ----@param self druid.progress @{Progress} -function druid__progress.fill(self) end - ---- Return current progress bar value ----@param self druid.progress @{Progress} -function druid__progress.get(self) end - ---- The @{Progress} constructor ----@param self druid.progress @{Progress} ----@param node string|node Node name or GUI Node itself. ----@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y ----@param init_value number|nil Initial value of progress bar. Default: 1 -function druid__progress.init(self, node, key, init_value) end - ---- Set progress bar max node size ----@param self druid.progress @{Progress} ----@param max_size vector3 The new node maximum (full) size ----@return druid.progress @{Progress} -function druid__progress.set_max_size(self, max_size) end - ---- Set points on progress bar to fire the callback ----@param self druid.progress @{Progress} ----@param steps number[] Array of progress bar values ----@param callback function Callback on intersect step value -function druid__progress.set_steps(self, steps, callback) end - ---- Instant fill progress bar to value ----@param self druid.progress @{Progress} ----@param to number Progress bar value, from 0 to 1 -function druid__progress.set_to(self, to) end - ---- Start animation of a progress bar ----@param self druid.progress @{Progress} ----@param to number value between 0..1 ----@param callback function|nil Callback on animation ends -function druid__progress.to(self, to, callback) end - - ----@class druid.progress.style ----@field MIN_DELTA number|nil Minimum step to fill progress bar. Default: 0.005 ----@field SPEED number|nil Progress bas fill rate. More -> faster. Default: 5 -local druid__progress__style = {} - - ----@class druid.rich_input ----@field cursor node On input field text change to empty string callback(self, input_text) ----@field cursor_position vector3 On input field text change to empty string callback(self, input_text) ----@field cursor_text node On input field text change to empty string callback(self, input_text) ----@field drag druid.drag On input field text change to empty string callback(self, input_text) ----@field druid druid_instance The component druid instance ----@field input druid.input On input field text change callback(self, input_text) ----@field input_text druid.text On input field text change to empty string callback(self, input_text) ----@field placeholder druid.text On input field text change to empty string callback(self, input_text) ----@field root node Root node ----@field text_position vector3 On input field text change to empty string callback(self, input_text) -local druid__rich_input = {} - ---- Set input field text ----@param self druid.rich_input @{RichInput} -function druid__rich_input.get_text(self) end - ---- The @{RichInput} constructor ----@param self druid.rich_input @{RichInput} ----@param template string The template string name ----@param nodes table Nodes table from gui.clone_tree -function druid__rich_input.init(self, template, nodes) end - ---- Select input field ----@param self druid.rich_input @{RichInput} -function druid__rich_input.select(self) end - ---- Set allowed charaters for input field. ---- See: https://defold.com/ref/stable/string/ ex: [%a%d] for alpha and numeric ----@param self druid.rich_input @{RichInput} ----@param characters string Regulax exp. for validate user input ----@return druid.rich_input Current instance -function druid__rich_input.set_allowed_characters(self, characters) end - ---- Set input field font ----@param self druid.rich_input @{RichInput} ----@param font hash The font hash ----@return druid.input Current input instance -function druid__rich_input.set_font(self, font) end - ---- Set placeholder text ----@param self druid.rich_input @{RichInput} ----@param placeholder_text string The placeholder text -function druid__rich_input.set_placeholder(self, placeholder_text) end - ---- Set input field text ----@param self druid.rich_input @{RichInput} ----@param text string The input text ----@return druid.input Current input instance -function druid__rich_input.set_text(self, text) end - - ----@class druid.rich_text : druid.base_component ----@field druid druid_instance The component druid instance ----@field root node The root node of the Rich Text ----@field style druid.rich_text.style Component style params. ----@field text_prefab node The text prefab node -local druid__rich_text = {} - ---- Split a word into it's characters ----@param self druid.rich_text @{RichText} ----@param word druid.rich_text.word ----@return druid.rich_text.word[] characters -function druid__rich_text.characters(self, word) end - ---- Clear all created words. -function druid__rich_text.clear() end - ---- Get current line metrics ----@return druid.rich_text.lines_metrics -function druid__rich_text.get_line_metric() end - ---- Get current text ----@param self druid.rich_text @{RichText} ----@return string text -function druid__rich_text.get_text(self) end - ---- Get all current words. ----@return table druid.rich_text.word[] -function druid__rich_text.get_words() end - ---- The @{RichText} constructor ----@param self druid.rich_text @{RichText} ----@param text_node node|string The text node to make Rich Text ----@param value string|nil The initial text value. Default will be gui.get_text(text_node) -function druid__rich_text.init(self, text_node, value) end - ---- Set text for Rich Text ----@param self druid.rich_text @{RichText} ----@param text string|nil The text to set ----@return druid.rich_text.word[] words ----@return druid.rich_text.lines_metrics line_metrics -function druid__rich_text.set_text(self, text) end - ---- Get all words, which has a passed tag. ----@param self druid.rich_text @{RichText} ----@param tag string ----@return druid.rich_text.word[] words -function druid__rich_text.tagged(self, tag) end - - ----@class druid.rich_text.style ----@field ADJUST_SCALE_DELTA number|nil Scale step on each height adjust step. Default: 0.02 ----@field ADJUST_STEPS number|nil Amount steps of attemps text adjust by height. Default: 20 ----@field COLORS table|nil Rich Text color aliases. Default: {} -local druid__rich_text__style = {} - - ----@class druid.scroll : druid.base_component ----@field _is_inert boolean Flag, if scroll now moving by inertion ----@field available_pos vector4 Available position for content node: (min_x, max_y, max_x, min_y) ----@field available_size vector3 Size of available positions: (width, height, 0) ----@field content_node node Scroll content node ----@field drag druid.drag Drag Druid component ----@field inertion vector3 Current inert speed ----@field is_animate boolean Flag, if scroll now animating by gui.animate ----@field on_point_scroll druid.event On scroll_to_index function callback(self, index, point) ----@field on_scroll druid.event On scroll move callback(self, position) ----@field on_scroll_to druid.event On scroll_to function callback(self, target, is_instant) ----@field position vector3 Current scroll posisition ----@field selected number|nil Current index of points of interests ----@field style druid.scroll.style Component style params. ----@field target_position vector3 Current scroll target position ----@field view_node node Scroll view node ----@field view_size vector3 Scroll view size -local druid__scroll = {} - ---- Bind the grid component (Static or Dynamic) to recalculate scroll size on grid changes ----@param self druid.scroll @{Scroll} ----@param grid druid.static_grid Druid grid component ----@return druid.scroll Current scroll instance -function druid__scroll.bind_grid(self, grid) end - ---- Return current scroll progress status. ---- Values will be in [0..1] interval ----@param self druid.scroll @{Scroll} ----@return vector3 New vector with scroll progress values -function druid__scroll.get_percent(self) end - ---- Return vector of scroll size with width and height. ----@param self druid.scroll @{Scroll} ----@return vector3 Available scroll size -function druid__scroll.get_scroll_size(self) end - ---- The @{Scroll} constructor ----@param self druid.scroll @{Scroll} ----@param view_node string|node GUI view scroll node ----@param content_node string|node GUI content scroll node -function druid__scroll.init(self, view_node, content_node) end - ---- Return if scroll have inertion. ----@param self druid.scroll @{Scroll} ----@return boolean @If scroll have inertion -function druid__scroll.is_inert(self) end - ---- Check node if it visible now on scroll. ---- Extra border is not affected. Return true for elements in extra scroll zone ----@param self druid.scroll @{Scroll} ----@param node node The node to check ----@return boolean True if node in visible scroll area -function druid__scroll.is_node_in_view(self, node) end - ---- Start scroll to target point. ----@param self druid.scroll @{Scroll} ----@param point vector3 Target point ----@param is_instant boolean|nil Instant scroll flag -function druid__scroll.scroll_to(self, point, is_instant) end - ---- Scroll to item in scroll by point index. ----@param self druid.scroll @{Scroll} ----@param index number Point index ----@param skip_cb boolean|nil If true, skip the point callback -function druid__scroll.scroll_to_index(self, index, skip_cb) end - ---- Start scroll to target scroll percent ----@param self druid.scroll @{Scroll} ----@param percent vector3 target percent ----@param is_instant boolean|nil instant scroll flag -function druid__scroll.scroll_to_percent(self, percent, is_instant) end - ---- Strict drag scroll area. ---- Useful for restrict events outside stencil node ----@param self druid.drag ----@param node node|string Gui node -function druid__scroll.set_click_zone(self, node) end - ---- Set extra size for scroll stretching. ---- Set 0 to disable stretching effect ----@param self druid.scroll @{Scroll} ----@param stretch_size number|nil Size in pixels of additional scroll area ----@return druid.scroll Current scroll instance -function druid__scroll.set_extra_stretch_size(self, stretch_size) end - ---- Lock or unlock horizontal scroll ----@param self druid.scroll @{Scroll} ----@param state boolean|nil True, if horizontal scroll is enabled ----@return druid.scroll Current scroll instance -function druid__scroll.set_horizontal_scroll(self, state) end - ---- Enable or disable scroll inert. ---- If disabled, scroll through points (if exist) If no points, just simple drag without inertion ----@param self druid.scroll @{Scroll} ----@param state boolean|nil Inert scroll state ----@return druid.scroll Current scroll instance -function druid__scroll.set_inert(self, state) end - ---- Set points of interest. ---- Scroll will always centered on closer points ----@param self druid.scroll @{Scroll} ----@param points table Array of vector3 points ----@return druid.scroll Current scroll instance -function druid__scroll.set_points(self, points) end - ---- Set scroll content size. ---- It will change content gui node size ----@param self druid.scroll @{Scroll} ----@param size vector3 The new size for content node ----@param offset vector3|nil Offset value to set, where content is starts ----@return druid.scroll Current scroll instance -function druid__scroll.set_size(self, size, offset) end - ---- Lock or unlock vertical scroll ----@param self druid.scroll @{Scroll} ----@param state boolean|nil True, if vertical scroll is enabled ----@return druid.scroll Current scroll instance -function druid__scroll.set_vertical_scroll(self, state) end - ---- Set new scroll view size in case the node size was changed. ----@param self druid.scroll @{Scroll} ----@param size vector3 The new size for view node ----@return druid.scroll Current scroll instance -function druid__scroll.set_view_size(self, size) end - ---- Refresh scroll view size ----@param self druid.scroll @{Scroll} -function druid__scroll.update_view_size(self) end - - ----@class druid.scroll.style ----@field ANIM_SPEED number|nil Scroll gui.animation speed for scroll_to function. Default: 2 ----@field BACK_SPEED number|nil Scroll back returning lerp speed. Default: 35 ----@field EXTRA_STRETCH_SIZE number|nil extra size in pixels outside of scroll (stretch effect). Default: 0 ----@field FRICT number|nil Multiplier for free inertion. Default: 0 ----@field FRICT_HOLD number|nil Multiplier for inertion, while touching. Default: 0 ----@field INERT_SPEED number|nil Multiplier for inertion speed. Default: 30 ----@field INERT_THRESHOLD number|nil Scroll speed to stop inertion. Default: 3 ----@field POINTS_DEADZONE number|nil Speed to check points of interests in no_inertion mode. Default: 20 ----@field SMALL_CONTENT_SCROLL boolean|nil If true, content node with size less than view node size can be scrolled. Default: false ----@field WHEEL_SCROLL_BY_INERTION boolean|nil If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false ----@field WHEEL_SCROLL_INVERTED boolean|nil If true, invert direction for touchpad and mouse wheel scroll. Default: false ----@field WHEEL_SCROLL_SPEED boolean|nil The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 -local druid__scroll__style = {} - - ----@class druid.slider : druid.base_component ----@field dist vector3 Length between start and end position ----@field end_pos vector3 End pin node position ----@field is_drag boolean Current drag state ----@field node node Slider pin node ----@field on_change_value druid.event On change value callback(self, value) ----@field pos vector3 Current pin node position ----@field start_pos vector3 Start pin node position ----@field target_pos vector3 Targer pin node position ----@field value number Current slider value -local druid__slider = {} - ---- The @{Slider} constructor ----@param self druid.slider @{Slider} ----@param node node Gui pin node ----@param end_pos vector3 The end position of slider ----@param callback function|nil On slider change callback -function druid__slider.init(self, node, end_pos, callback) end - ---- Check if Slider component is enabled ----@param self druid.slider @{Slider} ----@return boolean -function druid__slider.is_enabled(self) end - ---- Set value for slider ----@param self druid.slider @{Slider} ----@param value number Value from 0 to 1 ----@param is_silent boolean|nil Don't trigger event if true -function druid__slider.set(self, value, is_silent) end - ---- Set Slider input enabled or disabled ----@param self druid.slider @{Slider} ----@param is_enabled boolean -function druid__slider.set_enabled(self, is_enabled) end - ---- Set input zone for slider. ---- User can touch any place of node, pin instantly will move at this position and node drag will start. This function require the Defold version 1.3.0+ ----@param self druid.slider @{Slider} ----@param input_node node|string|nil ----@return druid.slider @{Slider} -function druid__slider.set_input_node(self, input_node) end - ---- Set slider steps. ---- Pin node will apply closest step position ----@param self druid.slider @{Slider} ----@param steps number[] Array of steps ----@return druid.slider @{Slider} -function druid__slider.set_steps(self, steps) end - - ----@class druid.static_grid : druid.base_component ----@field anchor vector3 Item anchor [0..1] ----@field border vector4 The size of item content ----@field first_index number The first index of node in grid ----@field last_index number The last index of node in grid ----@field node_size vector3 Item size ----@field nodes node[] List of all grid nodes ----@field on_add_item druid.event On item add callback(self, node, index) ----@field on_change_items druid.event On item add, remove or change in_row callback(self, index|nil) ----@field on_clear druid.event On grid clear callback(self) ----@field on_remove_item druid.event On item remove callback(self, index) ----@field on_update_positions druid.event On update item positions callback(self) ----@field parent node Parent gui node ----@field pivot vector3 Item pivot [-0.5..0.5] ----@field style druid.static_grid.style Component style params. -local druid__static_grid = {} - ---- Add new item to the grid ----@param self druid.static_grid @{StaticGrid} ----@param item node GUI node ----@param index number|nil The item position. By default add as last item ----@param shift_policy number|nil How shift nodes, if required. Default: const.SHIFT.RIGHT ----@param is_instant boolean|nil If true, update node positions instantly -function druid__static_grid.add(self, item, index, shift_policy, is_instant) end - ---- Clear grid nodes array. ---- GUI nodes will be not deleted! If you want to delete GUI nodes, use static_grid.nodes array before grid:clear ----@param self druid.static_grid @{StaticGrid} ----@return druid.static_grid Current grid instance -function druid__static_grid.clear(self) end - ---- Return array of all node positions ----@param self druid.static_grid @{StaticGrid} ----@return vector3[] All grid node positions -function druid__static_grid.get_all_pos(self) end - ---- Return grid content borders ----@param self druid.static_grid @{StaticGrid} ----@return vector3 The grid content borders -function druid__static_grid.get_borders(self) end - ---- Return index for grid pos ----@param self druid.static_grid @{StaticGrid} ----@param pos vector3 The node position in the grid ----@return number The node index -function druid__static_grid.get_index(self, pos) end - ---- Return grid index by node ----@param self druid.static_grid @{StaticGrid} ----@param node node The gui node in the grid ----@return number The node index -function druid__static_grid.get_index_by_node(self, node) end - ---- Return StaticGrid offset, where StaticGrid content starts. ----@param self druid.static_grid @{StaticGrid} The StaticGrid instance ----@return vector3 The StaticGrid offset -function druid__static_grid.get_offset(self) end - ---- Return pos for grid node index ----@param self druid.static_grid @{StaticGrid} ----@param index number The grid element index ----@return vector3 @Node position -function druid__static_grid.get_pos(self, index) end - ---- Return grid content size ----@param self druid.static_grid @{StaticGrid} ----@return vector3 The grid content size -function druid__static_grid.get_size(self) end - ---- The @{StaticGrid} constructor ----@param self druid.static_grid @{StaticGrid} ----@param parent string|node The GUI Node container, where grid's items will be placed ----@param element node Element prefab. Need to get it size ----@param in_row number|nil How many nodes in row can be placed. By default 1 -function druid__static_grid.init(self, parent, element, in_row) end - ---- Update grid content ----@param self druid.static_grid @{StaticGrid} -function druid__static_grid.refresh(self) end - ---- Remove the item from the grid. ---- Note that gui node will be not deleted ----@param self druid.static_grid @{StaticGrid} ----@param index number The grid node index to remove ----@param shift_policy number|nil How shift nodes, if required. Default: const.SHIFT.RIGHT ----@param is_instant boolean|nil If true, update node positions instantly ----@return node The deleted gui node from grid -function druid__static_grid.remove(self, index, shift_policy, is_instant) end - ---- Set grid anchor. ---- Default anchor is equal to anchor of grid parent node ----@param self druid.static_grid @{StaticGrid} ----@param anchor vector3 Anchor -function druid__static_grid.set_anchor(self, anchor) end - ---- Set new in_row elements for grid ----@param self druid.static_grid @{StaticGrid} ----@param in_row number The new in_row value ----@return druid.static_grid Current grid instance -function druid__static_grid.set_in_row(self, in_row) end - ---- Set new node size for grid ----@param self druid.static_grid @{StaticGrid} ----@param width number The new node width ----@param height number The new node height ----@return druid.static_grid Current grid instance -function druid__static_grid.set_item_size(self, width, height) end - ---- Set new items to the grid. ---- All previous items will be removed ----@param self druid.static_grid @{StaticGrid} ----@param nodes node[] The new grid nodes ----@param is_instant boolean If true, update node positions instantly -function druid__static_grid.set_items(self, nodes, is_instant) end - ---- Change set position function for grid nodes. ---- It will call on update poses on grid elements. Default: gui.set_position ----@param self druid.static_grid @{StaticGrid} ----@param callback function Function on node set position ----@return druid.static_grid Current grid instance -function druid__static_grid.set_position_function(self, callback) end - ---- Sort grid nodes by custom comparator function ----@param self druid.static_grid @{StaticGrid} ----@param comparator function The comparator function. (a, b) -> boolean ----@return druid.static_grid Current grid instance -function druid__static_grid.sort_nodes(self, comparator) end - - ----@class druid.static_grid.style ----@field IS_ALIGN_LAST_ROW boolean|nil If true, always align last row of the grid as grid pivot sets. Default: false ----@field IS_DYNAMIC_NODE_POSES boolean|nil If true, always center grid content as grid pivot sets. Default: false -local druid__static_grid__style = {} - - ----@class druid.swipe : druid.base_component ----@field click_zone node|nil Restriction zone ----@field node node Swipe node ----@field on_swipe druid.event Trigger on swipe event(self, swipe_side, dist, delta_time) ----@field style druid.swipe.style Component style params. -local druid__swipe = {} - ---- The @{Swipe} constructor ----@param self druid.swipe @{Swipe} ----@param node node Gui node ----@param on_swipe_callback function Swipe callback for on_swipe_end event -function druid__swipe.init(self, node, on_swipe_callback) end - ---- Strict swipe click area. ---- Useful for restrict events outside stencil node ----@param self druid.swipe @{Swipe} ----@param zone node|string|nil Gui node -function druid__swipe.set_click_zone(self, zone) end - - ----@class druid.swipe.style ----@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50 ----@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4 ----@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false -local druid__swipe__style = {} - - ----@class druid.text : druid.base_component ----@field adjust_type number Current text size adjust settings ----@field color vector3 Current text color ----@field last_value string The last text value ----@field node node Text node ----@field node_id hash The node id of text node ----@field on_set_pivot druid.event On change pivot callback(self, pivot) ----@field on_set_text druid.event On set text callback(self, text) ----@field on_update_text_scale druid.event On adjust text size callback(self, new_scale, text_metrics) ----@field pos vector3 Current text position ----@field scale vector3 Current text node scale ----@field start_scale vector3 Initial text node scale ----@field start_size vector3 Initial text node size ----@field style druid.text.style Component style params. ----@field text_area vector3 Current text node available are -local druid__text = {} - ---- Return current text adjust type ----@param self unknown ----@param adjust_type unknown ----@return number The current text adjust type -function druid__text.get_text_adjust(self, adjust_type) end - ---- Get chars count by width ----@param self druid.text @{Text} ----@param width number ----@return number Chars count -function druid__text.get_text_index_by_width(self, width) end - ---- Calculate text width with font with respect to trailing space ----@param self druid.text @{Text} ----@param text string |nil ----@return number Width ----@return number Height -function druid__text.get_text_size(self, text) end - ---- The @{Text} constructor ----@param self druid.text @{Text} ----@param node string|node Node name or GUI Text Node itself ----@param value string|nil Initial text. Default value is node text from GUI scene. Default: nil ----@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE -function druid__text.init(self, node, value, adjust_type) end - ---- Return true, if text with line break ----@param self druid.text @{Text} ----@return boolean Is text node with line break -function druid__text.is_multiline(self) end - ---- Set alpha ----@param self druid.text @{Text} ----@param alpha number Alpha for node ----@return druid.text Current text instance -function druid__text.set_alpha(self, alpha) end - ---- Set color ----@param self druid.text @{Text} ----@param color vector4 Color for node ----@return druid.text Current text instance -function druid__text.set_color(self, color) end - ---- Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types ----@param self druid.text @{Text} ----@param minimal_scale number If pass nil - not use minimal scale ----@return druid.text Current text instance -function druid__text.set_minimal_scale(self, minimal_scale) end - ---- Set text pivot. ---- Text will re-anchor inside text area ----@param self druid.text @{Text} ----@param pivot number The gui.PIVOT_* constant ----@return druid.text Current text instance -function druid__text.set_pivot(self, pivot) end - ---- Set scale ----@param self druid.text @{Text} ----@param scale vector3 Scale for node ----@return druid.text Current text instance -function druid__text.set_scale(self, scale) end - ---- Set text area size ----@param self druid.text @{Text} ----@param size vector3 The new text area size ----@return druid.text Current text instance -function druid__text.set_size(self, size) end - ---- Set text adjust, refresh the current text visuals, if needed ----@param self druid.text @{Text} ----@param adjust_type string|nil See const.TEXT_ADJUST. If pass nil - use current adjust type ----@param minimal_scale number|nil If pass nil - not use minimal scale ----@return druid.text Current text instance -function druid__text.set_text_adjust(self, adjust_type, minimal_scale) end - ---- Set text to text field ----@param self druid.text @{Text} ----@param set_to string Text for node ----@return druid.text Current text instance -function druid__text.set_to(self, set_to) end - - ----@class druid.text.style ----@field ADJUST_SCALE_DELTA string|nil Scale step on each height adjust step. Default: 0.02 ----@field ADJUST_STEPS string|nil Amount of iterations for text adjust by height. Default: 20 ----@field DEFAULT_ADJUST string|nil The default adjust type for any text component. Default: DOWNSCALE ----@field TRIM_POSTFIX string|nil The postfix for TRIM adjust type. Default: ... -local druid__text__style = {} - - ----@class druid.timer : druid.base_component ----@field from number Initial timer value ----@field node node Trigger node ----@field on_set_enabled druid.event On timer change enabled state callback(self, is_enabled) ----@field on_tick druid.event On timer tick. ----@field on_timer_end druid.event On timer end callback ----@field target number Target timer value ----@field value number Current timer value -local druid__timer = {} - ---- The @{Timer} constructor ----@param self druid.timer @{Timer} ----@param node node Gui text node ----@param seconds_from number|nil Start timer value in seconds ----@param seconds_to number|nil End timer value in seconds ----@param callback function|nil Function on timer end -function druid__timer.init(self, node, seconds_from, seconds_to, callback) end - ---- Set time interval ----@param self druid.timer @{Timer} ----@param from number Start time in seconds ----@param to number Target time in seconds -function druid__timer.set_interval(self, from, to) end - ---- Called when update ----@param self druid.timer @{Timer} ----@param is_on boolean|nil Timer enable state -function druid__timer.set_state(self, is_on) end - ---- Set text to text field ----@param self druid.timer @{Timer} ----@param set_to number Value in seconds -function druid__timer.set_to(self, set_to) end - - ----@class druid_instance -local druid_instance = {} - ---- Call this in gui_script final function. ----@param self druid_instance -function druid_instance.final(self) end - ---- Create @{BackHandler} component ----@param self druid_instance ----@param callback function|nil @The callback(self, custom_args) to call on back event ----@param params any|nil Callback argument ----@return druid.back_handler @{BackHandler} component -function druid_instance.new_back_handler(self, callback, params) end - ---- Create @{Blocker} component ----@param self druid_instance ----@param node string|node The node_id or gui.get_node(node_id) ----@return druid.blocker @{Blocker} component -function druid_instance.new_blocker(self, node) end - ---- Create @{Button} component ----@param self druid_instance ----@param node string|node The node_id or gui.get_node(node_id) ----@param callback function|nil Button callback ----@param params any|nil Button callback params ----@param anim_node node|string|nil Button anim node (node, if not provided) ----@return druid.button @{Button} component -function druid_instance.new_button(self, node, callback, params, anim_node) end - ---- Create @{DataList} component ----@param self druid_instance ----@param druid_scroll druid.scroll The Scroll instance for Data List component ----@param druid_grid druid.static_grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component ----@param create_function function The create function callback(self, data, index, data_list). Function should return (node, [component]) ----@return druid.data_list @{DataList} component -function druid_instance.new_data_list(self, druid_scroll, druid_grid, create_function) end - ---- Create @{Drag} component ----@param self druid_instance ----@param node string|node The node_id or gui.get_node(node_id). Will used as user input node. ----@param on_drag_callback function|nil Callback for on_drag_event(self, dx, dy) ----@return druid.drag @{Drag} component -function druid_instance.new_drag(self, node, on_drag_callback) end - ---- Create @{DynamicGrid} component Deprecated ----@param self druid_instance ----@param parent_node string|node The node_id or gui.get_node(node_id). Parent of all Grid items. ----@return druid.dynamic_grid @{DynamicGrid} component -function druid_instance.new_dynamic_grid(self, parent_node) end - ---- Create @{Hotkey} component ----@param self druid_instance ----@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys ----@param callback function The callback function ----@param callback_argument any|nil The argument to pass into the callback function ----@return druid.hotkey @{Hotkey} component -function druid_instance.new_hotkey(self, keys_array, callback, callback_argument) end - ---- Create @{Hover} component ----@param self druid_instance ----@param node string|node The node_id or gui.get_node(node_id) ----@param on_hover_callback function|nil Hover callback ----@param on_mouse_hover_callback function|nil Mouse hover callback ----@return druid.hover @{Hover} component -function druid_instance.new_hover(self, node, on_hover_callback, on_mouse_hover_callback) end - ---- Create @{Input} component ----@param self druid_instance ----@param click_node string|node Button node to enabled input component ----@param text_node string|node|druid.text Text node what will be changed on user input ----@param keyboard_type number|nil Gui keyboard type for input field ----@return druid.input @{Input} component -function druid_instance.new_input(self, click_node, text_node, keyboard_type) end - ---- Create @{LangText} component ----@param self druid_instance ----@param node string|node The_node id or gui.get_node(node_id) ----@param locale_id string|nil Default locale id or text from node as default ----@param adjust_type string|nil Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE ----@return druid.lang_text @{LangText} component -function druid_instance.new_lang_text(self, node, locale_id, adjust_type) end - ---- Create @{Layout} component ----@param self druid_instance ----@param node string|node The_node id or gui.get_node(node_id). ----@param mode string The layout mode ----@return druid.layout @{Layout} component -function druid_instance.new_layout(self, node, mode) end - ---- Create @{Progress} component ----@param self druid_instance ----@param node string|node Progress bar fill node or node name ----@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y ----@param init_value number|nil Initial value of progress bar. Default: 1 ----@return druid.progress @{Progress} component -function druid_instance.new_progress(self, node, key, init_value) end - ---- Create @{RichInput} component. ---- As a template please check rich_input.gui layout. ----@param self druid_instance ----@param template string The template string name ----@param nodes table Nodes table from gui.clone_tree ----@return druid.rich_input @{RichInput} component -function druid_instance.new_rich_input(self, template, nodes) end - ---- Create @{RichText} component. ----@param self druid_instance ----@param text_node string|node The text node to make Rich Text ----@param value string|nil The initial text value. Default will be gui.get_text(text_node) ----@return druid.rich_text @{RichText} component -function druid_instance.new_rich_text(self, text_node, value) end - ---- Create @{Scroll} component ----@param self druid_instance ----@param view_node string|node The node_id or gui.get_node(node_id). Will used as user input node. ----@param content_node string|node The node_id or gui.get_node(node_id). Will used as scrollable node inside view_node. ----@return druid.scroll @{Scroll} component -function druid_instance.new_scroll(self, view_node, content_node) end - ---- Create @{Slider} component ----@param self druid_instance ----@param pin_node string|node The_node id or gui.get_node(node_id). ----@param end_pos vector3 The end position of slider ----@param callback function|nil On slider change callback ----@return druid.slider @{Slider} component -function druid_instance.new_slider(self, pin_node, end_pos, callback) end - ---- Create @{StaticGrid} component ----@param self druid_instance ----@param parent_node string|node The node_id or gui.get_node(node_id). Parent of all Grid items. ----@param item string|node Item prefab. Required to get grid's item size. Can be adjusted separately. ----@param in_row number|nil How many nodes in row can be placed ----@return druid.static_grid @{StaticGrid} component -function druid_instance.new_static_grid(self, parent_node, item, in_row) end - ---- Create @{Swipe} component ----@param self druid_instance ----@param node string|node The node_id or gui.get_node(node_id). Will used as user input node. ----@param on_swipe_callback function|nil Swipe callback for on_swipe_end event ----@return druid.swipe @{Swipe} component -function druid_instance.new_swipe(self, node, on_swipe_callback) end - ---- Create @{Text} component ----@param self druid_instance ----@param node string|node The node_id or gui.get_node(node_id) ----@param value string|nil Initial text. Default value is node text from GUI scene. ----@param no_adjust boolean|nil If true, text will be not auto-adjust size ----@return druid.text @{Text} component -function druid_instance.new_text(self, node, value, no_adjust) end - ---- Create @{Timer} component ----@param self druid_instance ----@param node string|node Gui text node ----@param seconds_from number Start timer value in seconds ----@param seconds_to number|nil End timer value in seconds ----@param callback function|nil Function on timer end ----@return druid.timer @{Timer} component -function druid_instance.new_timer(self, node, seconds_from, seconds_to, callback) end - ---- Call this in gui_script on_input function. ---- Used for almost all components ----@param self druid_instance ----@param action_id hash Action_id from on_input ----@param action table Action from on_input ----@return boolean The boolean value is input was consumed -function druid_instance.on_input(self, action_id, action) end - ---- Call this in gui_script on_message function. ---- Used for special actions. See SPECIFIC_UI_MESSAGES table ----@param self druid_instance ----@param message_id hash Message_id from on_message ----@param message table Message from on_message ----@param sender url Sender from on_message -function druid_instance.on_message(self, message_id, message, sender) end - ---- Remove created component from Druid instance. ---- Component `on_remove` function will be invoked, if exist. ----@param self druid_instance ----@param component druid.base_component Component instance ----@return boolean True if component was removed -function druid_instance.remove(self, component) end - ---- Set blacklist components for input processing. ---- If blacklist is not empty and component contains in this list, component will be not processed on input step ----@param self druid_instance @{DruidInstance} ----@param blacklist_components table|druid.base_component|nil The array of component to blacklist ----@return self @{DruidInstance} -function druid_instance.set_blacklist(self, blacklist_components) end - ---- Set whitelist components for input processing. ---- If whitelist is not empty and component not contains in this list, component will be not processed on input step ----@param self druid_instance ----@param whitelist_components table|druid.base_component|nil The array of component to whitelist ----@return self @{DruidInstance} -function druid_instance.set_whitelist(self, whitelist_components) end - ---- Call this in gui_script update function. ---- Used for: scroll, progress, timer components ----@param self druid_instance ----@param dt number Delta time -function druid_instance.update(self, dt) end - - ----@class helper -local helper = {} - ---- Add all elements from source array to the target array ----@param target any[] Array to put elements from source ----@param source any[]|nil The source array to get elements from ----@return any[] The target array -function helper.add_array(target, source) end - ---- Centerate nodes by x position with margin. ---- This functions calculate total width of nodes and set position for each node. The centrate will be around 0 x position. ----@param margin number|nil Offset between nodes ----@param ... unknown Gui nodes -function helper.centrate_nodes(margin, ...) end - ---- Clamp value between min and max ----@param a number Value ----@param min number Min value ----@param max number Max value ----@return number Clamped value -function helper.clamp(a, min, max) end - ---- Check if value is in array and return index of it ----@param t table Array ----@param value unknown Value ----@return number|nil Index of value or nil -function helper.contains(t, value) end - ---- Make a copy table with all nested tables ----@param orig_table table Original table ----@return table Copy of original table -function helper.deepcopy(orig_table) end - ---- Calculate distance between two points ----@param x1 number First point x ----@param y1 number First point y ----@param x2 number Second point x ----@param y2 number Second point y ----@return number Distance -function helper.distance(x1, y1, x2, y2) end - ---- Distance from node position to his borders ----@param node node GUI node ----@param offset vector3|nil Offset from node position. Pass current node position to get non relative border values ----@return vector4 Vector4 with border values (left, top, right, down) -function helper.get_border(node, offset) end - ---- Return closest non inverted clipping parent node for given node ----@param node node GUI node ----@return node|nil The closest stencil node or nil -function helper.get_closest_stencil_node(node) end - ---- Get current GUI scale for each side ----@return number scale_x ----@return number scale_y -function helper.get_gui_scale() end - ---- Get node offset for given GUI pivot. ---- Offset shown in [-0.5 .. 0.5] range, where -0.5 is left or bottom, 0.5 is right or top. ----@param pivot number The gui.PIVOT_* constant ----@return vector3 Vector offset with [-0.5..0.5] values -function helper.get_pivot_offset(pivot) end - ---- Get node size adjusted by scale ----@param node node GUI node ----@return vector3 Scaled size -function helper.get_scaled_size(node) end - ---- Get cumulative parent's node scale ----@param node node Gui node ----@param include_passed_node_scale boolean|nil True if add current node scale to result ----@return vector3 The scene node scale -function helper.get_scene_scale(node, include_passed_node_scale) end - ---- Get current screen stretch multiplier for each side ----@return number stretch_x ----@return number stretch_y -function helper.get_screen_aspect_koef() end - ---- Get text metric from GUI node. ----@param text_node node ----@return GUITextMetrics -function helper.get_text_metrics_from_node(text_node) end - ---- Add value to array with shift policy ---- Shift policy can be: left, right, no_shift ----@param array table Array ----@param any unknown Item to insert ----@param index number|nil Index to insert. If nil, item will be inserted at the end of array ----@param shift_policy number|nil The druid_const.SHIFT.* constant ----@return any Inserted item -function helper.insert_with_shift(array, any, index, shift_policy) end - ---- Check if device is native mobile (Android or iOS) ----@return boolean Is mobile -function helper.is_mobile() end - ---- Check if device is mobile and can support multitouch ----@return boolean Is multitouch supported -function helper.is_multitouch_supported() end - ---- Check if device is HTML5 ----@return boolean Is web -function helper.is_web() end - ---- Check if device is HTML5 mobile ----@return boolean Is web mobile -function helper.is_web_mobile() end - ---- Lerp between two values ----@param a number First value ----@param b number Second value ----@param t number Lerp amount ----@return number Lerped value -function helper.lerp(a, b, t) end - ---- Remove value from array with shift policy ---- Shift policy can be: left, right, no_shift ----@param array table Array ----@param index number|nil Index to remove. If nil, item will be removed from the end of array ----@param shift_policy number|nil The druid_const.SHIFT.* constant ----@return any Removed item -function helper.remove_with_shift(array, index, shift_policy) end - ---- Round number to specified decimal places ----@param num number Number ----@param num_decimal_places number|nil Decimal places ----@return number Rounded number -function helper.round(num, num_decimal_places) end - ---- Return sign of value (-1, 0, 1) ----@param val number Value ----@return number Sign -function helper.sign(val) end - ---- Move value from current to target value with step amount ----@param current number Current value ----@param target number Target value ----@param step number Step amount ----@return number New value -function helper.step(current, target, step) end - ---- Simple table to one-line string converter ----@param t table ----@return string -function helper.table_to_string(t) end - - --- Manual Annotations -- - ----@class druid.component: druid.base_component - ----@class druid.rich_text.metrics ----@field width number ----@field height number ----@field offset_x number|nil ----@field offset_y number|nil ----@field max_ascent number ----@field max_descent number ----@field node_size vector3|nil @For images only - ----@class druid.rich_text.lines_metrics ----@field text_width number ----@field text_height number ----@field lines table - ----@class druid.rich_text.word ----@field node node ----@field relative_scale number ----@field color vector4 ----@field position vector3 ----@field offset vector3 ----@field scale vector3 ----@field size vector3 ----@field metrics druid.rich_text.metrics ----@field pivot userdata @ The gui.PIVOT_* constant ----@field text string ----@field shadow vector4 ----@field outline vector4 ----@field font string ----@field image druid.rich_text.image ----@field default_animation string ----@field anchor number ----@field br boolean ----@field nobr boolean ----@field source_text string ----@field image_color vector4 ----@field text_color vector4 - ----@class druid.rich_text.image ----@field texture string ----@field anim string ----@field width number ----@field height number - ----@class druid.rich_text.settings ----@field parent node ----@field size number ----@field fonts table ----@field scale vector3 ----@field color vector4 ----@field shadow vector4 ----@field outline vector4 ----@field position vector3 ----@field image_pixel_grid_snap boolean ----@field combine_words boolean ----@field default_animation string ----@field text_prefab node ----@field adjust_scale number ----@field default_texture string ----@field is_multiline boolean ----@field text_leading number ----@field font hash ----@field width number ----@field height number - ----@class GUITextMetrics ----@field width number ----@field height number ----@field max_ascent number ----@field max_descent number - ----@class utf8 ----@field len fun(s: string):number ----@field sub fun(s: string, start_index: number, length: number) ----@field reverse fun() ----@field char fun() ----@field unicode fun() ----@field gensub fun() ----@field byte fun() ----@field find fun() ----@field match fun(s: string, m: string) ----@field gmatch fun(s: string, m: string) ----@field gsub fun() ----@field dump fun() ----@field format fun() ----@field lower fun() ----@field upper fun() ----@field rep fun() - - ----Add generics to some functions. - ----Create new component. ----@generic T: druid.base_component ----@param self druid_instance ----@param component T Component module ----@param ... any Other component params to pass it to component:init function ----@return T Component instance -function druid_instance.new(self, component, ...) end - ---- Set current component style table. ---- Invoke `on_style_change` on component, if exist. Component should handle their style changing and store all style params ----@generic T: druid.base_component ----@param self T @{BaseComponent} ----@param druid_style table|nil Druid style module ----@return T @{BaseComponent} -function druid__base_component.set_style(self, druid_style) end - ---- Set component template name. ---- Use on all your custom components with GUI layouts used as templates. It will check parent template name to build full template name in self:get_node() ----@generic T: druid.base_component ----@param self T @{BaseComponent} ----@param template string BaseComponent template name ----@return T @{BaseComponent} -function druid__base_component.set_template(self, template) end - ---- Set current component nodes. ---- Use if your component nodes was cloned with `gui.clone_tree` and you got the node tree. ----@generic T: druid.base_component ----@param self T @{BaseComponent} ----@param nodes table BaseComponent nodes table ----@return T @{BaseComponent} -function druid__base_component.set_nodes(self, nodes) end diff --git a/druid/base/back_handler.lua b/druid/base/back_handler.lua index 899e12e..56e0c0c 100644 --- a/druid/base/back_handler.lua +++ b/druid/base/back_handler.lua @@ -1,65 +1,24 @@ --- Copyright (c) 2023 Maksim Tuprikov . This code is licensed under MIT license - ---- Component with event on back and backspace button. --- # Overview # --- --- Back Handler is recommended to put in every game window to close it --- or in main screen to call settings window. --- --- # Notes # --- --- • Back Handler inheritance @{BaseComponent}, you can use all of its methods in addition to those described here. --- --- • Back Handler react on release action ACTION_BACK or ACTION_BACKSPACE --- @usage --- local callback = function(self, params) ... end --- --- local params = {} --- local back_handler = self.druid:new_back_handler(callback, [params]) --- @module BackHandler --- @within BaseComponent --- @alias druid.back_handler - ---- The @{DruidEvent} Event on back handler action. --- --- Trigger on input action ACTION_BACK or ACTION_BACKSPACE --- @usage --- -- Subscribe additional callbacks: --- back_handler.on_back:subscribe(callback) --- @tfield DruidEvent on_back @{DruidEvent} - ---- Custom args to pass in the callback --- @usage --- -- Replace params on runtime: --- back_handler.params = { ... } --- @tfield any|nil params - ---- - -local Event = require("druid.event") +local event = require("druid.event") local const = require("druid.const") local component = require("druid.component") -local BackHandler = component.create("back_handler") +---@class druid.back_handler: druid.base_component +---@field on_back druid.event Trigger on back handler action, fun(self, params) +---@field params any|nil Custom args to pass in the callback +local M = component.create("back_handler") ---- The @{BackHandler} constructor --- @tparam BackHandler self @{BackHandler} --- @tparam function callback @The callback(self, custom_args) to call on back event --- @tparam any|nil custom_args Button events custom arguments --- @local -function BackHandler.init(self, callback, custom_args) - self.params = custom_args - self.on_back = Event(callback) +---@param callback function|nil +---@param params any|nil +function M:init(callback, params) + self.params = params + self.on_back = event.create(callback) end ---- Component input handler --- @tparam BackHandler self @{BackHandler} --- @tparam string action_id on_input action id --- @tparam table action on_input action --- @local -function BackHandler.on_input(self, action_id, action) +---@param action_id string +---@param action table +function M:on_input(action_id, action) if not action.released then return false end @@ -73,4 +32,4 @@ function BackHandler.on_input(self, action_id, action) end -return BackHandler +return M diff --git a/druid/base/blocker.lua b/druid/base/blocker.lua index 92fc414..bbd1890 100644 --- a/druid/base/blocker.lua +++ b/druid/base/blocker.lua @@ -1,50 +1,22 @@ --- Copyright (c) 2023 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to consume input in special zone defined by GUI node. --- # Overview # --- --- # Notes # --- --- Blocker consume input if `gui.pick_node` works on it. --- --- • Blocker inheritance @{BaseComponent}, you can use all of its methods in addition to those described here. --- --- • Blocker initial enabled state is `gui.is_enabled(node, true)` --- --- • The Blocker node should be enabled to capture the input --- @usage --- local node = gui.get_node("blocker_node") --- local blocker = self.druid:new_blocker(node) --- @module Blocker --- @within BaseComponent --- @alias druid.blocker - ----Blocker node --- @tfield node node - ---- - local const = require("druid.const") local component = require("druid.component") -local Blocker = component.create("blocker") +---@class druid.blocker: druid.base_component +---@field node node +---@field private _is_enabled boolean +local M = component.create("blocker") ---- The @{Blocker} constructor --- @tparam Blocker self @{Blocker} --- @tparam node node Gui node -function Blocker.init(self, node) +---@param node node +function M:init(node) self.node = self:get_node(node) self._is_enabled = gui.is_enabled(self.node, true) end ---- Component input handler --- @tparam Blocker self @{Blocker} --- @tparam string action_id on_input action id --- @tparam table action on_input action --- @local -function Blocker.on_input(self, action_id, action) +---@param action_id string +---@param action table +function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH and action_id ~= nil then @@ -67,22 +39,21 @@ function Blocker.on_input(self, action_id, action) end ---- Set enabled blocker component state. --- --- Don't change node enabled state itself. --- @tparam Blocker self @{Blocker} --- @tparam boolean|nil state Enabled state -function Blocker.set_enabled(self, state) +---Set blocker enabled state +---@param state boolean +---@return druid.blocker self +function M:set_enabled(state) self._is_enabled = state + + return self end ---- Return blocker enabled state --- @tparam Blocker self @{Blocker} --- @treturn boolean @True, if blocker is enabled -function Blocker.is_enabled(self) +---Get blocker enabled state +---@return boolean +function M:is_enabled() return self._is_enabled end -return Blocker +return M diff --git a/druid/base/button.lua b/druid/base/button.lua index 9b09c48..7684380 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -35,16 +35,16 @@ -- @alias druid.button ---- The @{DruidEvent}: Event on successful release action over button. +--- The DruidEvent: Event on successful release action over button. -- @usage -- -- Custom args passed in Button constructor -- button.on_click:subscribe(function(self, custom_args, button_instance) -- print("On button click!") -- end) --- @tfield DruidEvent on_click @{DruidEvent} +-- @tfield DruidEvent on_click DruidEvent ---- The @{DruidEvent}: Event on repeated action over button. +--- The DruidEvent: Event on repeated action over button. -- -- This callback will be triggered if user hold the button. The repeat rate pick from `input.repeat_interval` in game.project -- @usage @@ -52,10 +52,10 @@ -- button.on_repeated_click:subscribe(function(self, custom_args, button_instance, click_count) -- print("On repeated Button click!") -- end) --- @tfield DruidEvent on_repeated_click @{DruidEvent} +-- @tfield DruidEvent on_repeated_click DruidEvent ---- The @{DruidEvent}: Event on long tap action over button. +--- The DruidEvent: Event on long tap action over button. -- -- This callback will be triggered if user pressed the button and hold the some amount of time. -- The amount of time picked from button style param: LONGTAP_TIME @@ -64,10 +64,10 @@ -- button.on_long_click:subscribe(function(self, custom_args, button_instance, hold_time) -- print("On long Button click!") -- end) --- @tfield DruidEvent on_long_click @{DruidEvent} +-- @tfield DruidEvent on_long_click DruidEvent ---- The @{DruidEvent}: Event on double tap action over button. +--- The DruidEvent: Event on double tap action over button. -- -- If secondary click was too fast after previous one, the double -- click will be called instead usual click (if on_double_click subscriber exists) @@ -76,10 +76,10 @@ -- button.on_double_click:subscribe(function(self, custom_args, button_instance, click_amount) -- print("On double Button click!") -- end) --- @tfield DruidEvent on_double_click @{DruidEvent} +-- @tfield DruidEvent on_double_click DruidEvent ---- The @{DruidEvent}: Event calls every frame before on_long_click event. +--- The DruidEvent: Event calls every frame before on_long_click event. -- -- If long_click subscriber exists, the on_hold_callback will be called before long_click trigger. -- @@ -89,10 +89,10 @@ -- button.on_double_click:subscribe(function(self, custom_args, button_instance, time) -- print("On hold Button callback!") -- end) --- @tfield DruidEvent on_hold_callback @{DruidEvent} +-- @tfield DruidEvent on_hold_callback DruidEvent ---- The @{DruidEvent}: Event calls if click event was outside of button. +--- The DruidEvent: Event calls if click event was outside of button. -- -- This event will be triggered for each button what was not clicked on user click action -- @@ -102,16 +102,16 @@ -- button.on_click_outside:subscribe(function(self, custom_args, button_instance) -- print("On click Button outside!") -- end) --- @tfield DruidEvent on_click_outside @{DruidEvent} +-- @tfield DruidEvent on_click_outside DruidEvent ---- The @{DruidEvent}: Event triggered if button was pressed by user. +--- The DruidEvent: Event triggered if button was pressed by user. -- @usage -- -- Custom args passed in Button constructor -- button.on_pressed:subscribe(function(self, custom_args, button_instance) -- print("On Button pressed!") -- end) --- @tfield DruidEvent on_pressed @{DruidEvent} +-- @tfield DruidEvent on_pressed DruidEvent --- Button trigger node -- @tfield node node @@ -128,8 +128,8 @@ ---Custom args for any Button event. Setup in Button constructor -- @tfield any params ---- The @{Hover}: Button Hover component --- @tfield Hover hover @{Hover} +--- The Hover: Button Hover component +-- @tfield Hover hover Hover --- Additional button click area, defined by another GUI node -- @tfield node|nil click_zone @@ -141,7 +141,26 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Button = component.create("button") +---@class druid.button: druid.base_component +---@field on_click druid.event +---@field on_pressed druid.event +---@field on_repeated_click druid.event +---@field on_long_click druid.event +---@field on_double_click druid.event +---@field on_hold_callback druid.event +---@field on_click_outside druid.event +---@field node node +---@field node_id hash +---@field anim_node node +---@field params any +---@field hover druid.hover +---@field click_zone node +---@field start_scale vector3 +---@field start_pos vector3 +---@field disabled boolean +---@field key_trigger hash +---@field style table +local M = component.create("button") local function is_input_match(self, action_id) @@ -271,7 +290,7 @@ end -- @tfield function on_hover function(self, node, hover_state) -- @tfield function on_mouse_hover function(self, node, hover_state) -- @tfield function on_set_enabled function(self, node, enabled_state) -function Button.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.LONGTAP_TIME = style.LONGTAP_TIME or 0.4 self.style.AUTOHOLD_TRIGGER = style.AUTOHOLD_TRIGGER or 0.8 @@ -285,22 +304,21 @@ function Button.on_style_change(self, style) end ---- The @{Button} constructor --- @tparam Button self @{Button} --- @tparam string|node node The node_id or gui.get_node(node_id) --- @tparam function callback On click button callback --- @tparam any|nil custom_args Button events custom arguments --- @tparam string|node|nil anim_node Node to animate instead of trigger node. -function Button.init(self, node, callback, custom_args, anim_node) +---Button constructor +---@param node_or_node_id node|string Node name or GUI Node itself. +---@param callback fun()|nil Callback on button click +---@param custom_args any|nil Custom args for any Button event +---@param anim_node node|string|nil Node to animate instead of trigger node. +function M:init(node_or_node_id, callback, custom_args, anim_node) self.druid = self:get_druid() - self.node = self:get_node(node) + self.node = self:get_node(node_or_node_id) self.node_id = gui.get_id(self.node) self.anim_node = anim_node and self:get_node(anim_node) or self.node self.start_scale = gui.get_scale(self.anim_node) self.start_pos = gui.get_position(self.anim_node) self.params = custom_args - self.hover = self.druid:new_hover(node, on_button_hover) + self.hover = self.druid:new_hover(node_or_node_id, on_button_hover) self.hover.on_mouse_hover:subscribe(on_button_mouse_hover) self.click_zone = nil self.is_repeated_started = false @@ -325,7 +343,7 @@ function Button.init(self, node, callback, custom_args, anim_node) end -function Button.on_late_init(self) +function M:on_late_init() if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) if stencil_node then @@ -335,7 +353,7 @@ function Button.on_late_init(self) end -function Button.on_input(self, action_id, action) +function M:on_input(action_id, action) if not is_input_match(self, action_id) then return false end @@ -416,14 +434,14 @@ function Button.on_input(self, action_id, action) end -function Button.on_input_interrupt(self) +function M:on_input_interrupt() self.can_action = false self.hover:set_hover(false) self.hover:set_mouse_hover(false) end -function Button.on_message_input(self, node_id, message) +function M:on_message_input(node_id, message) if node_id ~= self.node_id or self.disabled or not gui.is_enabled(self.node) then return false end @@ -451,13 +469,13 @@ end --- Set button enabled state. -- The style.on_set_enabled will be triggered. -- Disabled button is not clickable. --- @tparam Button self @{Button} +-- @tparam Button self Button -- @tparam boolean|nil state Enabled state -- @treturn Button Current button instance -- @usage -- button:set_enabled(false) -- button:set_enabled(true) -function Button.set_enabled(self, state) +function M:set_enabled(state) self.disabled = not state self.hover:set_enabled(state) self.style.on_set_enabled(self, self.node, state) @@ -469,11 +487,11 @@ end --- Get button enabled state. -- -- By default all Buttons is enabled on creating. --- @tparam Button self @{Button} +-- @tparam Button self Button -- @treturn boolean @True, if button is enabled now, False overwise -- @usage -- local is_enabled = button:is_enabled() -function Button.is_enabled(self) +function M:is_enabled() return not self.disabled end @@ -482,12 +500,12 @@ end -- Useful to restrict click outside out stencil node or scrollable content. -- -- This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check --- @tparam Button self @{Button} +-- @tparam Button self Button -- @tparam node|string|nil zone Gui node -- @treturn Button Current button instance -- @usage -- button:set_click_zone("stencil_node") -function Button.set_click_zone(self, zone) +function M:set_click_zone(zone) self.click_zone = self:get_node(zone) self.hover:set_click_zone(zone) @@ -496,12 +514,12 @@ end --- Set key name to trigger this button by keyboard. --- @tparam Button self @{Button} +-- @tparam Button self Button -- @tparam hash|string key The action_id of the input key -- @treturn Button Current button instance -- @usage -- button:set_key_trigger("key_space") -function Button.set_key_trigger(self, key) +function M:set_key_trigger(key) self.key_trigger = hash(key) return self @@ -513,7 +531,7 @@ end -- @treturn hash The action_id of the input key -- @usage -- local key_hash = button:get_key_trigger() -function Button.get_key_trigger(self) +function M:get_key_trigger() return self.key_trigger end @@ -523,7 +541,7 @@ end -- @tparam function|nil check_function Should return true or false. If true - button can be pressed. -- @tparam function|nil failure_callback Function will be called on button click, if check function return false -- @treturn Button Current button instance -function Button.set_check_function(self, check_function, failure_callback) +function M:set_check_function(check_function, failure_callback) self._check_function = check_function self._failure_callback = failure_callback end @@ -540,10 +558,10 @@ end -- @treturn Button Current button instance -- @usage -- button:set_web_user_interaction(true) -function Button.set_web_user_interaction(self, is_web_mode) +function M:set_web_user_interaction(is_web_mode) self._is_html5_mode = not not (is_web_mode and html5) return self end -return Button +return M diff --git a/druid/base/drag.lua b/druid/base/drag.lua index fd79105..3218ae6 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -14,19 +14,19 @@ -- @tfield node node --- Event on touch start callback(self) --- @tfield DruidEvent on_touch_start @{DruidEvent} +-- @tfield DruidEvent on_touch_start DruidEvent --- Event on touch end callback(self) --- @tfield DruidEvent on_touch_end @{DruidEvent} +-- @tfield DruidEvent on_touch_end DruidEvent --- Event on drag start callback(self, touch) --- @tfield DruidEvent on_drag_start @{DruidEvent} +-- @tfield DruidEvent on_drag_start DruidEvent --- on drag progress callback(self, dx, dy, total_x, total_y, touch) --- @tfield DruidEvent on_drag Event @{DruidEvent} +-- @tfield DruidEvent on_drag Event DruidEvent --- Event on drag end callback(self, total_x, total_y, touch) --- @tfield DruidEvent on_drag_end @{DruidEvent} +-- @tfield DruidEvent on_drag_end DruidEvent --- Is component now touching -- @tfield boolean is_touch @@ -62,7 +62,31 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Drag = component.create("drag", const.PRIORITY_INPUT_HIGH) +---@class druid.drag: druid.base_component +---@field node node +---@field on_touch_start druid.event +---@field on_touch_end druid.event +---@field on_drag_start druid.event +---@field on_drag druid.event +---@field on_drag_end druid.event +---@field style table +---@field click_zone node +---@field is_touch boolean +---@field is_drag boolean +---@field can_x boolean +---@field can_y boolean +---@field dx number +---@field dy number +---@field touch_id number +---@field x number +---@field y number +---@field screen_x number +---@field screen_y number +---@field touch_start_pos vector3 +---@field private _is_enabled boolean +---@field private _x_koef number +---@field private _y_koef number +local M = component.create("drag", const.PRIORITY_INPUT_HIGH) local function start_touch(self, touch) @@ -177,19 +201,18 @@ end -- @table style -- @tfield number|nil DRAG_DEADZONE Distance in pixels to start dragging. Default: 10 -- @tfield boolean|nil NO_USE_SCREEN_KOEF If screen aspect ratio affects on drag values. Default: false -function Drag.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.DRAG_DEADZONE = style.DRAG_DEADZONE or 10 self.style.NO_USE_SCREEN_KOEF = style.NO_USE_SCREEN_KOEF or false end ---- The @{Drag} constructor --- @tparam Drag self @{Drag} --- @tparam node node GUI node to detect dragging --- @tparam function on_drag_callback Callback for on_drag_event(self, dx, dy) -function Drag.init(self, node, on_drag_callback) - self.node = self:get_node(node) +---Drag constructor +---@param node_or_node_id node|string +---@param on_drag_callback function +function M:init(node_or_node_id, on_drag_callback) + self.node = self:get_node(node_or_node_id) self.dx = 0 self.dy = 0 @@ -219,7 +242,7 @@ function Drag.init(self, node, on_drag_callback) end -function Drag.on_late_init(self) +function M:on_late_init() if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) if stencil_node then @@ -229,7 +252,7 @@ function Drag.on_late_init(self) end -function Drag.on_window_resized(self) +function M:on_window_resized() local x_koef, y_koef = helper.get_screen_aspect_koef() self._x_koef = x_koef self._y_koef = y_koef @@ -237,14 +260,17 @@ function Drag.on_window_resized(self) end -function Drag.on_input_interrupt(self) +function M:on_input_interrupt() if self.is_drag or self.is_touch then end_touch(self) end end -function Drag.on_input(self, action_id, action) +---@local +---@param action_id string +---@param action table +function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH then return false end @@ -321,29 +347,31 @@ function Drag.on_input(self, action_id, action) end ---- Strict drag click area. Useful for --- restrict events outside stencil node --- @tparam Drag self @{Drag} --- @tparam node|string|nil node Gui node -function Drag.set_click_zone(self, node) +---Set Drag click zone +---@param node node|string|nil +---@return druid.drag self +function M:set_click_zone(node) self.click_zone = self:get_node(node) + + return self end ---- Set Drag input enabled or disabled --- @tparam Drag self @{Drag} --- @tparam boolean|nil is_enabled -function Drag.set_enabled(self, is_enabled) +---Set Drag component enabled state. +---@param is_enabled boolean +---@return druid.drag self +function M:set_enabled(is_enabled) self._is_enabled = is_enabled + + return self end ---- Check if Drag component is enabled --- @tparam Drag self @{Drag} --- @treturn boolean -function Drag.is_enabled(self) +---Check if Drag component is enabled +---@return boolean +function M:is_enabled() return self._is_enabled end -return Drag +return M diff --git a/druid/base/hover.lua b/druid/base/hover.lua index f178cf2..d5e1700 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -9,10 +9,10 @@ -- @tfield node node --- On hover callback(self, state, hover_instance) --- @tfield DruidEvent on_hover @{DruidEvent} +-- @tfield DruidEvent on_hover DruidEvent --- On mouse hover callback(self, state, hover_instance) --- @tfield DruidEvent on_mouse_hover @{DruidEvent} +-- @tfield DruidEvent on_mouse_hover DruidEvent --- @@ -21,15 +21,25 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Hover = component.create("hover") +---@class druid.hover: druid.base_component +---@field node node +---@field on_hover druid.event +---@field on_mouse_hover druid.event +---@field style table +---@field click_zone node +---@field private _is_hovered boolean +---@field private _is_mouse_hovered boolean +---@field private _is_enabled boolean +---@field private _is_mobile boolean +local M = component.create("hover") ---- The @{Hover} constructor --- @tparam Hover self @{Hover} +--- The Hover constructor +-- @tparam Hover self Hover -- @tparam node node Gui node -- @tparam function on_hover_callback Hover callback -- @tparam function on_mouse_hover On mouse hover callback -function Hover.init(self, node, on_hover_callback, on_mouse_hover) +function M:init(node, on_hover_callback, on_mouse_hover) self.node = self:get_node(node) self._is_hovered = false @@ -42,7 +52,7 @@ function Hover.init(self, node, on_hover_callback, on_mouse_hover) end -function Hover.on_late_init(self) +function M:on_late_init() if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) if stencil_node then @@ -58,14 +68,14 @@ end -- @table style -- @tfield[opt] string ON_HOVER_CURSOR Mouse hover style on node hover -- @tfield[opt] string ON_MOUSE_HOVER_CURSOR Mouse hover style on node mouse hover -function Hover.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.ON_HOVER_CURSOR = style.ON_HOVER_CURSOR or nil self.style.ON_MOUSE_HOVER_CURSOR = style.ON_MOUSE_HOVER_CURSOR or nil end -function Hover.on_input(self, action_id, action) +function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= nil then return false end @@ -99,15 +109,15 @@ function Hover.on_input(self, action_id, action) end -function Hover.on_input_interrupt(self) +function M:on_input_interrupt() self:set_hover(false) end --- Set hover state --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @tparam boolean|nil state The hover state -function Hover.set_hover(self, state) +function M:set_hover(state) if self._is_hovered == state then return end @@ -122,17 +132,17 @@ end --- Return current hover state. True if touch action was on the node at current time --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @treturn boolean The current hovered state -function Hover.is_hovered(self) +function M:is_hovered() return self._is_hovered end --- Set mouse hover state --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @tparam boolean|nil state The mouse hover state -function Hover.set_mouse_hover(self, state) +function M:set_mouse_hover(state) if self._is_mouse_hovered == state then return end @@ -147,18 +157,18 @@ end --- Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @treturn boolean The current hovered state -function Hover.is_mouse_hovered(self) +function M:is_mouse_hovered() return self._is_mouse_hovered end --- Strict hover click area. Useful for -- no click events outside stencil node --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @tparam node|string|nil zone Gui node -function Hover.set_click_zone(self, zone) +function M:set_click_zone(zone) self.click_zone = self:get_node(zone) end @@ -166,9 +176,9 @@ end --- Set enable state of hover component. -- If hover is not enabled, it will not generate -- any hover events --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @tparam boolean|nil state The hover enabled state -function Hover.set_enabled(self, state) +function M:set_enabled(state) self._is_enabled = state if not state then @@ -183,16 +193,17 @@ end --- Return current hover enabled state --- @tparam Hover self @{Hover} +-- @tparam Hover self Hover -- @treturn boolean The hover enabled state -function Hover.is_enabled(self) +function M:is_enabled() return self._is_enabled end -- Internal cursor stack local cursor_stack = {} -function Hover:_set_cursor(priority, cursor) +---@local +function M:_set_cursor(priority, cursor) if not defos then return end @@ -217,4 +228,4 @@ function Hover:_set_cursor(priority, cursor) end -return Hover +return M diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 3aa9f77..f8bc2c6 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -39,13 +39,13 @@ --- On scroll move callback(self, position) --- @tfield DruidEvent on_scroll @{DruidEvent} +-- @tfield DruidEvent on_scroll DruidEvent --- On scroll_to function callback(self, target, is_instant) --- @tfield DruidEvent on_scroll_to @{DruidEvent} +-- @tfield DruidEvent on_scroll_to DruidEvent --- On scroll_to_index function callback(self, index, point) --- @tfield DruidEvent on_point_scroll @{DruidEvent} +-- @tfield DruidEvent on_point_scroll DruidEvent --- Scroll view node -- @tfield node view_node @@ -75,7 +75,7 @@ -- @tfield vector3 available_size --- Drag Druid component --- @tfield Drag drag @{Drag} +-- @tfield Drag drag Drag --- Current index of points of interests -- @tfield number|nil selected @@ -90,7 +90,16 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Scroll = component.create("scroll") +---@class druid.scroll: druid.base_component +---@field on_scroll druid.event +---@field on_scroll_to druid.event +---@field on_point_scroll druid.event +---@field view_node node +---@field view_border vector4 +---@field content_node node +---@field view_size vector3 +---@field position vector3 +local M = component.create("scroll") local function inverse_lerp(min, max, current) @@ -138,7 +147,7 @@ end -- @tfield boolean|nil WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 -- @tfield boolean|nil WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll. Default: false -- @tfield boolean|nil WHEEL_SCROLL_BY_INERTION If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false -function Scroll.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0 self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2 @@ -161,11 +170,11 @@ function Scroll.on_style_change(self, style) end ---- The @{Scroll} constructor --- @tparam Scroll self @{Scroll} +--- The Scroll constructor +-- @tparam Scroll self Scroll -- @tparam string|node view_node GUI view scroll node -- @tparam string|node content_node GUI content scroll node -function Scroll.init(self, view_node, content_node) +function M:init(view_node, content_node) self.druid = self:get_druid() self.view_node = self:get_node(view_node) @@ -203,7 +212,7 @@ function Scroll.init(self, view_node, content_node) end -function Scroll.on_late_init(self) +function M:on_late_init() if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) if stencil_node then @@ -213,12 +222,12 @@ function Scroll.on_late_init(self) end -function Scroll.on_layout_change(self) +function M:on_layout_change() gui.set_position(self.content_node, self.position) end -function Scroll.update(self, dt) +function M:update(dt) if self.is_animate then self.position.x = gui.get(self.content_node, "position.x") self.position.y = gui.get(self.content_node, "position.y") @@ -233,23 +242,23 @@ function Scroll.update(self, dt) end -function Scroll.on_input(self, action_id, action) +function M:on_input(action_id, action) return self:_process_scroll_wheel(action_id, action) end -function Scroll.on_remove(self) +function M:on_remove() self:bind_grid(nil) end --- Start scroll to target point. --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam vector3 point Target point -- @tparam boolean|nil is_instant Instant scroll flag -- @usage scroll:scroll_to(vmath.vector3(0, 50, 0)) -- @usage scroll:scroll_to(vmath.vector3(0), true) -function Scroll.scroll_to(self, point, is_instant) +function M:scroll_to(point, is_instant) local b = self.available_pos local target = vmath.vector3( self._is_horizontal_scroll and -point.x or self.target_position.x, @@ -278,10 +287,10 @@ end --- Scroll to item in scroll by point index. --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam number index Point index -- @tparam boolean|nil skip_cb If true, skip the point callback -function Scroll.scroll_to_index(self, index, skip_cb) +function M:scroll_to_index(index, skip_cb) if not self.points then return end @@ -301,11 +310,11 @@ end --- Start scroll to target scroll percent --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam vector3 percent target percent -- @tparam boolean|nil is_instant instant scroll flag -- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0)) -function Scroll.scroll_to_percent(self, percent, is_instant) +function M:scroll_to_percent(percent, is_instant) local border = self.available_pos local pos = vmath.vector3( @@ -327,9 +336,9 @@ end --- Return current scroll progress status. -- Values will be in [0..1] interval --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @treturn vector3 New vector with scroll progress values -function Scroll.get_percent(self) +function M:get_percent() local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x) local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y) @@ -339,11 +348,11 @@ end --- Set scroll content size. -- It will change content gui node size --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam vector3 size The new size for content node -- @tparam vector3|nil offset Offset value to set, where content is starts -- @treturn druid.scroll Current scroll instance -function Scroll.set_size(self, size, offset) +function M:set_size(size, offset) if offset then self._offset = offset end @@ -355,10 +364,10 @@ end --- Set new scroll view size in case the node size was changed. --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam vector3 size The new size for view node -- @treturn druid.scroll Current scroll instance -function Scroll.set_view_size(self, size) +function M:set_view_size(size) gui.set_size(self.view_node, size) self.view_size = size self.view_border = helper.get_border(self.view_node) @@ -369,8 +378,8 @@ end --- Refresh scroll view size --- @tparam Scroll self @{Scroll} -function Scroll.update_view_size(self) +-- @tparam Scroll self Scroll +function M:update_view_size() self.view_size = helper.get_scaled_size(self.view_node) self.view_border = helper.get_border(self.view_node) self:_update_size() @@ -382,10 +391,10 @@ end --- Enable or disable scroll inert. -- If disabled, scroll through points (if exist) -- If no points, just simple drag without inertion --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam boolean|nil state Inert scroll state -- @treturn druid.scroll Current scroll instance -function Scroll.set_inert(self, state) +function M:set_inert(state) self._is_inert = state return self @@ -393,19 +402,19 @@ end --- Return if scroll have inertion. --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @treturn boolean @If scroll have inertion -function Scroll.is_inert(self) +function M:is_inert() return self._is_inert end --- Set extra size for scroll stretching. -- Set 0 to disable stretching effect --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam number|nil stretch_size Size in pixels of additional scroll area -- @treturn druid.scroll Current scroll instance -function Scroll.set_extra_stretch_size(self, stretch_size) +function M:set_extra_stretch_size(stretch_size) self.style.EXTRA_STRETCH_SIZE = stretch_size or 0 self:_update_size() @@ -414,19 +423,19 @@ end --- Return vector of scroll size with width and height. --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @treturn vector3 Available scroll size -function Scroll.get_scroll_size(self) +function M:get_scroll_size() return self.available_size end --- Set points of interest. -- Scroll will always centered on closer points --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam table points Array of vector3 points -- @treturn druid.scroll Current scroll instance -function Scroll.set_points(self, points) +function M:set_points(points) self.points = points table.sort(self.points, function(a, b) @@ -440,10 +449,10 @@ end --- Lock or unlock horizontal scroll --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam boolean|nil state True, if horizontal scroll is enabled -- @treturn druid.scroll Current scroll instance -function Scroll.set_horizontal_scroll(self, state) +function M:set_horizontal_scroll(state) self._is_horizontal_scroll = state self.drag.can_x = self.available_size.x > 0 and state return self @@ -451,10 +460,10 @@ end --- Lock or unlock vertical scroll --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam boolean|nil state True, if vertical scroll is enabled -- @treturn druid.scroll Current scroll instance -function Scroll.set_vertical_scroll(self, state) +function M:set_vertical_scroll(state) self._is_vertical_scroll = state self.drag.can_y = self.available_size.y > 0 and state return self @@ -463,10 +472,10 @@ end --- Check node if it visible now on scroll. -- Extra border is not affected. Return true for elements in extra scroll zone --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam node node The node to check -- @treturn boolean True if node in visible scroll area -function Scroll.is_node_in_view(self, node) +function M:is_node_in_view(node) local node_offset_for_view = gui.get_position(node) local parent = gui.get_parent(node) local is_parent_of_view = false @@ -504,10 +513,10 @@ end --- Bind the grid component (Static or Dynamic) to recalculate -- scroll size on grid changes --- @tparam Scroll self @{Scroll} +-- @tparam Scroll self Scroll -- @tparam StaticGrid grid Druid grid component -- @treturn druid.scroll Current scroll instance -function Scroll.bind_grid(self, grid) +function M:bind_grid(grid) if self._grid_on_change then self._grid_on_change:unsubscribe(self._grid_on_change_callback) @@ -535,12 +544,12 @@ end -- restrict events outside stencil node -- @tparam Drag self -- @tparam node|string node Gui node -function Scroll.set_click_zone(self, node) +function M:set_click_zone(node) self.drag:set_click_zone(node) end -function Scroll._on_scroll_drag(self, dx, dy) +function M:_on_scroll_drag(dx, dy) local t = self.target_position local b = self.available_pos local eb = self.available_pos_extra @@ -581,7 +590,7 @@ function Scroll._on_scroll_drag(self, dx, dy) end -function Scroll._check_soft_zone(self) +function M:_check_soft_zone() local target = self.target_position local border = self.available_pos local speed = self.style.BACK_SPEED @@ -610,7 +619,7 @@ end -- Cancel animation on other animation or input touch -function Scroll._cancel_animate(self) +function M:_cancel_animate() self.inertion.x = 0 self.inertion.y = 0 @@ -624,7 +633,7 @@ function Scroll._cancel_animate(self) end -function Scroll._set_scroll_position(self, position_x, position_y) +function M:_set_scroll_position(position_x, position_y) local available_extra = self.available_pos_extra position_x = helper.clamp(position_x, available_extra.x, available_extra.z) position_y = helper.clamp(position_y, available_extra.w, available_extra.y) @@ -643,7 +652,7 @@ end -- if no inert, scroll to next point by scroll direction -- if inert, find next point by scroll director -- @local -function Scroll._check_points(self) +function M:_check_points() if not self.points then return end @@ -699,7 +708,7 @@ function Scroll._check_points(self) end -function Scroll._check_threshold(self) +function M:_check_threshold() local is_stopped = false if self.drag.can_x and math.abs(self.inertion.x) < self.style.INERT_THRESHOLD then @@ -717,7 +726,7 @@ function Scroll._check_threshold(self) end -function Scroll._update_free_scroll(self, dt) +function M:_update_free_scroll(dt) if self.is_animate then return end @@ -742,7 +751,7 @@ function Scroll._update_free_scroll(self, dt) end -function Scroll._update_hand_scroll(self, dt) +function M:_update_hand_scroll(dt) if self.is_animate then self:_cancel_animate() end @@ -757,7 +766,7 @@ function Scroll._update_hand_scroll(self, dt) end -function Scroll._on_touch_start(self) +function M:_on_touch_start() self.inertion.x = 0 self.inertion.y = 0 self.target_position.x = self.position.x @@ -765,12 +774,12 @@ function Scroll._on_touch_start(self) end -function Scroll._on_touch_end(self) +function M:_on_touch_end() self:_check_threshold() end -function Scroll._update_size(self) +function M:_update_size() local content_border = helper.get_border(self.content_node) local content_size = helper.get_scaled_size(self.content_node) @@ -808,7 +817,7 @@ function Scroll._update_size(self) end -function Scroll._process_scroll_wheel(self, action_id, action) +function M:_process_scroll_wheel(action_id, action) if not self._is_mouse_hover or self.style.WHEEL_SCROLL_SPEED == 0 then return false end @@ -845,9 +854,9 @@ function Scroll._process_scroll_wheel(self, action_id, action) end -function Scroll._on_mouse_hover(self, state) +function M:_on_mouse_hover(state) self._is_mouse_hover = state end -return Scroll +return M diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index c602ce0..c78d7ec 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -37,19 +37,19 @@ -- @alias druid.static_grid --- On item add callback(self, node, index) --- @tfield DruidEvent on_add_item @{DruidEvent} +-- @tfield DruidEvent on_add_item DruidEvent --- On item remove callback(self, index) --- @tfield DruidEvent on_remove_item @{DruidEvent} +-- @tfield DruidEvent on_remove_item DruidEvent --- On item add, remove or change in_row callback(self, index|nil) --- @tfield DruidEvent on_change_items @{DruidEvent} +-- @tfield DruidEvent on_change_items DruidEvent --- On grid clear callback(self) --- @tfield DruidEvent on_clear @{DruidEvent} +-- @tfield DruidEvent on_clear DruidEvent --- On update item positions callback(self) --- @tfield DruidEvent on_update_positions @{DruidEvent} +-- @tfield DruidEvent on_update_positions DruidEvent --- Parent gui node -- @tfield node parent @@ -82,7 +82,23 @@ local Event = require("druid.event") local helper = require("druid.helper") local component = require("druid.component") -local StaticGrid = component.create("static_grid") +---@class druid.grid: druid.base_component +---@field on_add_item druid.event +---@field on_remove_item druid.event +---@field on_change_items druid.event +---@field on_clear druid.event +---@field on_update_positions druid.event +---@field parent node +---@field nodes node[] +---@field first_index number +---@field last_index number +---@field anchor vector3 +---@field pivot vector3 +---@field node_size vector3 +---@field border vector4 +---@field in_row number +---@field style table +local M = component.create("static_grid") local function _extend_border(border, pos, size, pivot) @@ -104,23 +120,23 @@ end -- @table style -- @tfield boolean|nil IS_DYNAMIC_NODE_POSES If true, always center grid content as grid pivot sets. Default: false -- @tfield boolean|nil IS_ALIGN_LAST_ROW If true, always align last row of the grid as grid pivot sets. Default: false -function StaticGrid.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.IS_DYNAMIC_NODE_POSES = style.IS_DYNAMIC_NODE_POSES or false self.style.IS_ALIGN_LAST_ROW = style.IS_ALIGN_LAST_ROW or false end ---- The @{StaticGrid} constructor --- @tparam StaticGrid self @{StaticGrid} +--- The StaticGrid constructor +-- @tparam StaticGrid self StaticGrid -- @tparam string|node parent The GUI Node container, where grid's items will be placed -- @tparam node element Element prefab. Need to get it size -- @tparam number|nil in_row How many nodes in row can be placed. By default 1 -function StaticGrid.init(self, parent, element, in_row) +function M:init(parent, element, in_row) self.parent = self:get_node(parent) self.nodes = {} - self.pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) + self.pivot = helper.get_pivot_offset(self.parent) self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0) self.in_row = in_row or 1 @@ -149,10 +165,10 @@ end local _temp_pos = vmath.vector3(0) --- Return pos for grid node index --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam number index The grid element index -- @treturn vector3 @Node position -function StaticGrid.get_pos(self, index) +function M:get_pos(index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 @@ -167,10 +183,10 @@ end --- Return index for grid pos --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam vector3 pos The node position in the grid -- @treturn number The node index -function StaticGrid.get_index(self, pos) +function M:get_index(pos) -- Offset to left-top corner from node pivot local node_offset_x = self.node_size.x * (-0.5 + self.node_pivot.x) local node_offset_y = self.node_size.y * (0.5 - self.node_pivot.y) @@ -187,10 +203,10 @@ end --- Return grid index by node --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam node node The gui node in the grid -- @treturn number The node index -function StaticGrid.get_index_by_node(self, node) +function M:get_index_by_node(node) for index, grid_node in pairs(self.nodes) do if node == grid_node then return index @@ -201,28 +217,28 @@ function StaticGrid.get_index_by_node(self, node) end -function StaticGrid.on_layout_change(self) +function M:on_layout_change() self:_update(true) end --- Set grid anchor. Default anchor is equal to anchor of grid parent node --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam vector3 anchor Anchor -function StaticGrid.set_anchor(self, anchor) +function M:set_anchor(anchor) self.anchor = anchor self:_update() end --- Update grid content --- @tparam StaticGrid self @{StaticGrid} -function StaticGrid.refresh(self) +-- @tparam StaticGrid self StaticGrid +function M:refresh() self:_update(true) end -function StaticGrid.set_pivot(self, pivot) +function M:set_pivot(pivot) local prev_pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.pivot = helper.get_pivot_offset(pivot) @@ -254,12 +270,12 @@ end --- Add new item to the grid --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam node item GUI node -- @tparam number|nil index The item position. By default add as last item -- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT -- @tparam boolean|nil is_instant If true, update node positions instantly -function StaticGrid.add(self, item, index, shift_policy, is_instant) +function M:add(item, index, shift_policy, is_instant) index = index or ((self.last_index or 0) + 1) helper.insert_with_shift(self.nodes, item, index, shift_policy) @@ -279,10 +295,10 @@ end --- Set new items to the grid. All previous items will be removed --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam node[] nodes The new grid nodes -- @tparam[opt=false] boolean is_instant If true, update node positions instantly -function StaticGrid.set_items(self, nodes, is_instant) +function M:set_items(nodes, is_instant) self.nodes = nodes for index = 1, #nodes do local item = nodes[index] @@ -296,12 +312,12 @@ end --- Remove the item from the grid. Note that gui node will be not deleted --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam number index The grid node index to remove -- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT -- @tparam boolean|nil is_instant If true, update node positions instantly -- @treturn node The deleted gui node from grid -function StaticGrid.remove(self, index, shift_policy, is_instant) +function M:remove(index, shift_policy, is_instant) assert(self.nodes[index], "No grid item at given index " .. index) local remove_node = self.nodes[index] @@ -317,9 +333,9 @@ end --- Return grid content size --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @treturn vector3 The grid content size -function StaticGrid.get_size(self) +function M:get_size() return vmath.vector3( self.border.z - self.border.x, self.border.y - self.border.w, @@ -327,7 +343,7 @@ function StaticGrid.get_size(self) end -function StaticGrid.get_size_for(self, count) +function M:get_size_for(count) if not count or count == 0 then return vmath.vector3(0) end @@ -350,17 +366,17 @@ end --- Return grid content borders --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @treturn vector3 The grid content borders -function StaticGrid.get_borders(self) +function M:get_borders() return self.border end --- Return array of all node positions --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @treturn vector3[] All grid node positions -function StaticGrid.get_all_pos(self) +function M:get_all_pos() local result = {} for i, node in pairs(self.nodes) do table.insert(result, gui.get_position(node)) @@ -372,10 +388,10 @@ end --- Change set position function for grid nodes. It will call on -- update poses on grid elements. Default: gui.set_position --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam function callback Function on node set position -- @treturn druid.static_grid Current grid instance -function StaticGrid.set_position_function(self, callback) +function M:set_position_function(callback) self._set_position_function = callback or gui.set_position return self @@ -384,9 +400,9 @@ end --- Clear grid nodes array. GUI nodes will be not deleted! -- If you want to delete GUI nodes, use static_grid.nodes array before grid:clear --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @treturn druid.static_grid Current grid instance -function StaticGrid.clear(self) +function M:clear() self.border.x = 0 self.border.y = 0 self.border.w = 0 @@ -403,9 +419,9 @@ end --- Return StaticGrid offset, where StaticGrid content starts. --- @tparam StaticGrid self @{StaticGrid} The StaticGrid instance +-- @tparam StaticGrid self StaticGrid The StaticGrid instance -- @treturn vector3 The StaticGrid offset -function StaticGrid:get_offset() +function M:get_offset() local borders = self:get_borders() local size = self:get_size() @@ -419,10 +435,10 @@ end --- Set new in_row elements for grid --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam number in_row The new in_row value -- @treturn druid.static_grid Current grid instance -function StaticGrid.set_in_row(self, in_row) +function M:set_in_row(in_row) self.in_row = in_row self._grid_horizonal_offset = self.node_size.x * (self.in_row - 1) * self.anchor.x self._zero_offset = vmath.vector3( @@ -438,11 +454,11 @@ end --- Set new node size for grid --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam[opt] number width The new node width -- @tparam[opt] number height The new node height -- @treturn druid.static_grid Current grid instance -function StaticGrid.set_item_size(self, width, height) +function M:set_item_size(width, height) if width then self.node_size.x = width end @@ -463,20 +479,20 @@ end --- Sort grid nodes by custom comparator function --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam function comparator The comparator function. (a, b) -> boolean -- @treturn druid.static_grid Current grid instance -function StaticGrid.sort_nodes(self, comparator) +function M:sort_nodes(comparator) table.sort(self.nodes, comparator) self:_update(true) end --- Update grid inner state --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback -- @local -function StaticGrid._update(self, is_instant) +function M:_update(is_instant) self:_update_indexes() self:_update_borders() self:_update_pos(is_instant) @@ -484,9 +500,9 @@ end --- Update first and last indexes of grid nodes --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @local -function StaticGrid._update_indexes(self) +function M:_update_indexes() self.first_index = nil self.last_index = nil for index in pairs(self.nodes) do @@ -500,9 +516,9 @@ end --- Update grid content borders, recalculate min and max values --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @local -function StaticGrid._update_borders(self) +function M:_update_borders() if not self.first_index then self.border = vmath.vector4(0) return @@ -519,10 +535,10 @@ end --- Update grid nodes position --- @tparam StaticGrid self @{StaticGrid} +-- @tparam StaticGrid self StaticGrid -- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback -- @local -function StaticGrid._update_pos(self, is_instant) +function M:_update_pos(is_instant) local zero_offset = self:_get_zero_offset() for i, node in pairs(self.nodes) do @@ -545,7 +561,7 @@ end -- parent pivot node (0:0) with adjusting of node sizes and anchoring -- @treturn vector3 The offset vector -- @local -function StaticGrid:_get_zero_offset() +function M:_get_zero_offset() if not self.style.IS_DYNAMIC_NODE_POSES then return const.VECTOR_ZERO end @@ -562,7 +578,7 @@ end --- Return offset x for last row in grid. Used to align this row accorting to grid's anchor -- @treturn number The offset x value -- @local -function StaticGrid:_get_zero_offset_x(row_index) +function M:_get_zero_offset_x(row_index) if not self.style.IS_DYNAMIC_NODE_POSES or not self.style.IS_ALIGN_LAST_ROW then return self._zero_offset.x end @@ -580,4 +596,4 @@ function StaticGrid:_get_zero_offset_x(row_index) end -return StaticGrid +return M diff --git a/druid/base/text.lua b/druid/base/text.lua index 39188f4..66b11ac 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -36,13 +36,13 @@ -- @alias druid.text --- On set text callback(self, text) --- @tfield DruidEvent on_set_text @{DruidEvent} +-- @tfield DruidEvent on_set_text DruidEvent --- On adjust text size callback(self, new_scale, text_metrics) --- @tfield DruidEvent on_update_text_scale @{DruidEvent} +-- @tfield DruidEvent on_update_text_scale DruidEvent --- On change pivot callback(self, pivot) --- @tfield DruidEvent on_set_pivot @{DruidEvent} +-- @tfield DruidEvent on_set_pivot DruidEvent --- Text node -- @tfield node node @@ -83,7 +83,16 @@ local utf8_lua = require("druid.system.utf8") local component = require("druid.component") local utf8 = utf8 or utf8_lua --[[@as utf8]] -local Text = component.create("text") +---@class druid.text: druid.base_component +---@field node node +---@field on_set_text druid.event +---@field on_update_text_scale druid.event +---@field on_set_pivot druid.event +---@field style table +---@field private start_pivot number +---@field private start_scale vector3 +---@field private scale vector3 +local M = component.create("text") local function update_text_size(self) if self.scale.x == 0 or self.scale.y == 0 then @@ -269,7 +278,7 @@ end -- @tfield string|nil DEFAULT_ADJUST The default adjust type for any text component. Default: DOWNSCALE -- @tfield string|nil ADJUST_STEPS Amount of iterations for text adjust by height. Default: 20 -- @tfield string|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02 -function Text.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.TRIM_POSTFIX = style.TRIM_POSTFIX or "..." self.style.DEFAULT_ADJUST = style.DEFAULT_ADJUST or const.TEXT_ADJUST.DOWNSCALE @@ -278,12 +287,12 @@ function Text.on_style_change(self, style) end ---- The @{Text} constructor --- @tparam Text self @{Text} +--- The Text constructor +-- @tparam Text self Text -- @tparam string|node node Node name or GUI Text Node itself -- @tparam string|nil value Initial text. Default value is node text from GUI scene. Default: nil -- @tparam string|nil adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE -function Text.init(self, node, value, adjust_type) +function M:init(node, value, adjust_type) self.node = self:get_node(node) self.pos = gui.get_position(self.node) self.node_id = gui.get_id(self.node) @@ -309,12 +318,12 @@ function Text.init(self, node, value, adjust_type) end -function Text.on_layout_change(self) +function M:on_layout_change() self:set_to(self.last_value) end -function Text.on_message_input(self, node_id, message) +function M:on_message_input(node_id, message) if node_id ~= self.node_id then return false end @@ -326,11 +335,11 @@ end --- Calculate text width with font with respect to trailing space --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam string text|nil -- @treturn number Width -- @treturn number Height -function Text.get_text_size(self, text) +function M:get_text_size(text) text = text or self.last_value local font_name = gui.get_font(self.node) local font = gui.get_font_resource(font_name) @@ -351,10 +360,10 @@ end --- Get chars count by width --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam number width -- @treturn number Chars count -function Text.get_text_index_by_width(self, width) +function M:get_text_index_by_width(width) local text = self.last_value local font_name = gui.get_font(self.node) local font = gui.get_font_resource(font_name) @@ -385,10 +394,10 @@ end --- Set text to text field --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam string set_to Text for node -- @treturn Text Current text instance -function Text.set_to(self, set_to) +function M:set_to(set_to) set_to = set_to or "" self.last_value = set_to @@ -403,10 +412,10 @@ end --- Set text area size --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam vector3 size The new text area size -- @treturn Text Current text instance -function Text.set_size(self, size) +function M:set_size(size) self.start_size = size self.text_area = vmath.vector3(size) self.text_area.x = self.text_area.x * self.start_scale.x @@ -416,10 +425,10 @@ end --- Set color --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam vector4 color Color for node -- @treturn Text Current text instance -function Text.set_color(self, color) +function M:set_color(color) self.color = color gui.set_color(self.node, color) @@ -428,10 +437,10 @@ end --- Set alpha --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam number alpha Alpha for node -- @treturn Text Current text instance -function Text.set_alpha(self, alpha) +function M:set_alpha(alpha) self.color.w = alpha gui.set_color(self.node, self.color) @@ -440,10 +449,10 @@ end --- Set scale --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam vector3 scale Scale for node -- @treturn Text Current text instance -function Text.set_scale(self, scale) +function M:set_scale(scale) self.last_scale = scale gui.set_scale(self.node, scale) @@ -452,10 +461,10 @@ end --- Set text pivot. Text will re-anchor inside text area --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam number pivot The gui.PIVOT_* constant -- @treturn Text Current text instance -function Text.set_pivot(self, pivot) +function M:set_pivot(pivot) local prev_pivot = gui.get_pivot(self.node) local prev_offset = const.PIVOTS[prev_pivot] @@ -478,19 +487,19 @@ end --- Return true, if text with line break --- @tparam Text self @{Text} +-- @tparam Text self Text -- @treturn boolean Is text node with line break -function Text.is_multiline(self) +function M:is_multiline() return gui.get_line_break(self.node) end --- Set text adjust, refresh the current text visuals, if needed --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam string|nil adjust_type See const.TEXT_ADJUST. If pass nil - use current adjust type -- @tparam number|nil minimal_scale If pass nil - not use minimal scale -- @treturn Text Current text instance -function Text.set_text_adjust(self, adjust_type, minimal_scale) +function M:set_text_adjust(adjust_type, minimal_scale) self.adjust_type = adjust_type self._minimal_scale = minimal_scale self:set_to(self.last_value) @@ -500,10 +509,10 @@ end --- Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types --- @tparam Text self @{Text} +-- @tparam Text self Text -- @tparam number minimal_scale If pass nil - not use minimal scale -- @treturn Text Current text instance -function Text.set_minimal_scale(self, minimal_scale) +function M:set_minimal_scale(minimal_scale) self._minimal_scale = minimal_scale return self @@ -512,9 +521,9 @@ end --- Return current text adjust type -- @treturn number The current text adjust type -function Text.get_text_adjust(self, adjust_type) +function M:get_text_adjust(adjust_type) return self.adjust_type end -return Text +return M diff --git a/druid/component.lua b/druid/component.lua index 0672303..9ce4138 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -1,83 +1,99 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Basic class for all Druid components. --- To create you custom component, use static function `component.create` --- @usage --- -- Create your component: --- local component = require("druid.component") --- --- local AwesomeComponent = component.create("awesome_component") --- --- function AwesomeComponent:init(template, nodes) --- self:set_template(template) --- self:set_nodes(nodes) --- self.druid = self:get_druid() --- end --- --- return AwesomeComponent --- @module BaseComponent --- @alias druid.base_component +---Base component class for all Druid components. local const = require("druid.const") local helper = require("druid.helper") -local BaseComponent = {} +---@class druid.base_component.meta +---@field template string +---@field context table +---@field nodes table +---@field style table +---@field druid druid_instance +---@field input_enabled boolean +---@field children table +---@field parent druid.base_component +---@field instance_class table + +---@class druid.base_component.component +---@field name string +---@field input_priority number +---@field default_input_priority number +---@field _is_input_priority_changed boolean +---@field _uid number + +---@class druid.base_component +---@field druid druid_instance Druid instance to create inner components +---@field protected init fun(self:druid.base_component, ...)|nil +---@field protected update fun(self:druid.base_component, dt:number)|nil +---@field protected on_remove fun(self:druid.base_component)|nil +---@field protected on_input fun(self:druid.base_component, action_id:number, action:table)|nil +---@field protected on_message fun(self:druid.base_component, message_id:hash, message:table, sender:userdata)|nil +---@field protected on_late_init fun(self:druid.base_component)|nil +---@field protected on_focus_lost fun(self:druid.base_component)|nil +---@field protected on_focus_gained fun(self:druid.base_component)|nil +---@field protected on_style_change fun(self:druid.base_component, style: table)|nil +---@field protected on_layout_change fun(self:druid.base_component)|nil +---@field protected on_window_resized fun(self:druid.base_component, width:number, height:number)|nil +---@field protected on_language_change fun(self:druid.base_component, language:string)|nil +---@field private _component druid.base_component.component +---@field private _meta druid.base_component.meta +local M = {} local INTERESTS = {} -- Cache interests per component class in runtime local IS_AUTO_TEMPLATE = not (sys.get_config_int("druid.no_auto_template", 0) == 1) -- Component Interests -BaseComponent.ON_INPUT = const.ON_INPUT -BaseComponent.ON_UPDATE = const.ON_UPDATE -BaseComponent.ON_MESSAGE = const.ON_MESSAGE -BaseComponent.ON_LATE_INIT = const.ON_LATE_INIT -BaseComponent.ON_FOCUS_LOST = const.ON_FOCUS_LOST -BaseComponent.ON_FOCUS_GAINED = const.ON_FOCUS_GAINED -BaseComponent.ON_LAYOUT_CHANGE = const.ON_LAYOUT_CHANGE -BaseComponent.ON_MESSAGE_INPUT = const.ON_MESSAGE_INPUT -BaseComponent.ON_WINDOW_RESIZED = const.ON_WINDOW_RESIZED -BaseComponent.ON_LANGUAGE_CHANGE = const.ON_LANGUAGE_CHANGE +M.ON_INPUT = const.ON_INPUT +M.ON_UPDATE = const.ON_UPDATE +M.ON_MESSAGE = const.ON_MESSAGE +M.ON_LATE_INIT = const.ON_LATE_INIT +M.ON_FOCUS_LOST = const.ON_FOCUS_LOST +M.ON_FOCUS_GAINED = const.ON_FOCUS_GAINED +M.ON_LAYOUT_CHANGE = const.ON_LAYOUT_CHANGE +M.ON_MESSAGE_INPUT = const.ON_MESSAGE_INPUT +M.ON_WINDOW_RESIZED = const.ON_WINDOW_RESIZED +M.ON_LANGUAGE_CHANGE = const.ON_LANGUAGE_CHANGE -BaseComponent.ALL_INTERESTS = { - BaseComponent.ON_INPUT, - BaseComponent.ON_UPDATE, - BaseComponent.ON_MESSAGE, - BaseComponent.ON_LATE_INIT, - BaseComponent.ON_FOCUS_LOST, - BaseComponent.ON_FOCUS_GAINED, - BaseComponent.ON_LAYOUT_CHANGE, - BaseComponent.ON_MESSAGE_INPUT, - BaseComponent.ON_WINDOW_RESIZED, - BaseComponent.ON_LANGUAGE_CHANGE, +M.ALL_INTERESTS = { + M.ON_INPUT, + M.ON_UPDATE, + M.ON_MESSAGE, + M.ON_LATE_INIT, + M.ON_FOCUS_LOST, + M.ON_FOCUS_GAINED, + M.ON_LAYOUT_CHANGE, + M.ON_MESSAGE_INPUT, + M.ON_WINDOW_RESIZED, + M.ON_LANGUAGE_CHANGE, } -- Mapping from on_message method to specific method name -BaseComponent.SPECIFIC_UI_MESSAGES = { - [hash("layout_changed")] = BaseComponent.ON_LAYOUT_CHANGE, -- The message_id from Defold - [hash(BaseComponent.ON_FOCUS_LOST)] = BaseComponent.ON_FOCUS_LOST, - [hash(BaseComponent.ON_FOCUS_GAINED)] = BaseComponent.ON_FOCUS_GAINED, - [hash(BaseComponent.ON_WINDOW_RESIZED)] = BaseComponent.ON_WINDOW_RESIZED, - [hash(BaseComponent.ON_MESSAGE_INPUT)] = BaseComponent.ON_MESSAGE_INPUT, - [hash(BaseComponent.ON_LANGUAGE_CHANGE)] = BaseComponent.ON_LANGUAGE_CHANGE, +M.SPECIFIC_UI_MESSAGES = { + [hash("layout_changed")] = M.ON_LAYOUT_CHANGE, -- The message_id from Defold + [hash(M.ON_FOCUS_LOST)] = M.ON_FOCUS_LOST, + [hash(M.ON_FOCUS_GAINED)] = M.ON_FOCUS_GAINED, + [hash(M.ON_WINDOW_RESIZED)] = M.ON_WINDOW_RESIZED, + [hash(M.ON_MESSAGE_INPUT)] = M.ON_MESSAGE_INPUT, + [hash(M.ON_LANGUAGE_CHANGE)] = M.ON_LANGUAGE_CHANGE, } local uid = 0 -function BaseComponent.create_uid() +---@private +function M.create_uid() uid = uid + 1 return uid end ---- Set current component style table. --- --- Invoke `on_style_change` on component, if exist. Component should handle --- their style changing and store all style params --- @tparam BaseComponent self @{BaseComponent} --- @tparam table|nil druid_style Druid style module --- @treturn BaseComponent @{BaseComponent} --- @local -function BaseComponent.set_style(self, druid_style) +---Set component style. Pass nil to clear style +---@generic T +---@param self T +---@param druid_style table|nil +---@return T self The component itself for chaining +function M.set_style(self, druid_style) + ---@cast self druid.base_component + self._meta.style = druid_style or {} local component_style = self._meta.style[self._component.name] or {} @@ -89,15 +105,16 @@ function BaseComponent.set_style(self, druid_style) end ---- Set component template name. --- --- Use on all your custom components with GUI layouts used as templates. --- It will check parent template name to build full template name in self:get_node() --- @tparam BaseComponent self @{BaseComponent} --- @tparam string template BaseComponent template name --- @treturn BaseComponent @{BaseComponent} --- @local -function BaseComponent.set_template(self, template) +---Set component template name. Pass nil to clear template. +---This template id used to access nodes inside the template on GUI scene. +---Parent template will be added automatically if exist. +---@generic T +---@param self T +---@param template string|nil +---@return T self The component itself for chaining +function M.set_template(self, template) + ---@cast self druid.base_component + template = template or "" local parent = self:get_parent_component() @@ -116,101 +133,49 @@ function BaseComponent.set_template(self, template) end ---- Get current component template name. --- @tparam BaseComponent self @{BaseComponent} --- @treturn string Component full template name -function BaseComponent.get_template(self) +---Get full template name. +---@return string +function M:get_template() return self._meta.template end ---- Set current component nodes. --- Use if your component nodes was cloned with `gui.clone_tree` and you got the node tree. --- @tparam BaseComponent self @{BaseComponent} --- @tparam table nodes BaseComponent nodes table --- @treturn BaseComponent @{BaseComponent} --- @usage --- local nodes = gui.clone_tree(self.prefab) --- ... In your component: --- self:set_nodes(nodes) --- @local -function BaseComponent.set_nodes(self, nodes) +---Set current component nodes, returned from `gui.clone_tree` function. +---@param nodes table +---@return druid.base_component +function M.set_nodes(self, nodes) self._meta.nodes = nodes - - -- When we use gui.clone_tree in inner template (template inside other template) - -- this nodes have no id. We have table: hash(correct_id) : hash("") - -- It's wrong and we use this hack to fix this - if nodes then - for id, node in pairs(nodes) do - gui.set_id(node, id) - end - end - return self end ---- Context used as first arg in all Druid events --- --- Context is usually self of gui_script. --- @tparam BaseComponent self @{BaseComponent} --- @treturn table BaseComponent context -function BaseComponent.get_context(self) +---Return current component context +---@return any context Usually it's self of script but can be any other Druid component +function M.get_context(self) return self._meta.context end ---- Increase input priority in input stack --- @tparam BaseComponent self @{BaseComponent} --- @local -function BaseComponent.increase_input_priority(self) - helper.deprecated("The component:increase_input_priority is deprecated. Please use component:set_input_priority(druid_const.PRIORITY_INPUT_MAX) instead") -end - - ---- Get component node by name. --- --- If component has nodes, node_or_name should be string --- It autopick node by template name or from nodes by gui.clone_tree --- if they was setup via component:set_nodes, component:set_template. --- If node is not found, the exception will fired --- @tparam BaseComponent self @{BaseComponent} --- @tparam string|node node_or_name Node name or node itself --- @treturn node Gui node -function BaseComponent.get_node(self, node_or_name) - if type(node_or_name) ~= "string" then +---Get component node by node_id. Respect to current template and nodes. +---@param node_id string|node +---@return node +function M.get_node(self, node_id) + if type(node_id) ~= "string" then -- Assume it's already node from gui.get_node - return node_or_name + return node_id end local template_name = self:get_template() - local nodes = self:__get_nodes() - - if #template_name > 0 then - template_name = template_name .. "/" - end - - local node - if nodes then - node = nodes[template_name .. node_or_name] - else - node = gui.get_node(template_name .. node_or_name) - end - - if not node then - assert(node, "No component with name: " .. (template_name or "") .. (node_or_name or "")) - end - - return node + local nodes = self:get_nodes() + return helper.get_node(node_id, template_name, nodes) end ---- Get Druid instance for inner component creation. --- @tparam BaseComponent self @{BaseComponent} --- @tparam string|nil template The template name --- @tparam table|nil nodes The nodes table --- @treturn DruidInstance Druid instance with component context -function BaseComponent.get_druid(self, template, nodes) +---Get Druid instance for inner component creation. +---@param template string|nil +---@param nodes table|nil +---@return druid_instance +function M:get_druid(template, nodes) local context = { _context = self } local druid_instance = setmetatable(context, { __index = self._meta.druid }) @@ -226,39 +191,33 @@ function BaseComponent.get_druid(self, template, nodes) end ---- Return component name --- @tparam BaseComponent self @{BaseComponent} --- @treturn string The component name -function BaseComponent.get_name(self) - return self._component.name .. BaseComponent.create_uid() +---Get component name +---@return string name The component name + uid +function M.get_name(self) + return self._component.name .. M.create_uid() end ---- Return parent component name --- @tparam BaseComponent self @{BaseComponent} --- @treturn string|nil The parent component name if exist or bil -function BaseComponent.get_parent_name(self) +---Get parent component name +---@return string|nil parent_name The parent component name if exist or nil +function M.get_parent_name(self) local parent = self:get_parent_component() return parent and parent:get_name() end ---- Return component input priority --- @tparam BaseComponent self @{BaseComponent} --- @treturn number The component input priority -function BaseComponent.get_input_priority(self) +---Get component input priority, the bigger number processed first. Default value: 10 +---@return number +function M.get_input_priority(self) return self._component.input_priority end ---- Set component input priority --- --- Default value: 10 --- @tparam BaseComponent self @{BaseComponent} --- @tparam number value The new input priority value --- @tparam boolean|nil is_temporary If true, the reset input priority will return to previous value --- @treturn number The component input priority -function BaseComponent.set_input_priority(self, value, is_temporary) +---Set component input priority, the bigger number processed first. Default value: 10 +---@param value number +---@param is_temporary boolean|nil If true, the reset input priority will return to previous value +---@return druid.base_component self The component itself for chaining +function M.set_input_priority(self, value, is_temporary) assert(value) if self._component.input_priority == value then @@ -281,32 +240,27 @@ function BaseComponent.set_input_priority(self, value, is_temporary) end ---- Reset component input priority to default value --- @tparam BaseComponent self @{BaseComponent} --- @treturn number The component input priority -function BaseComponent.reset_input_priority(self) +---Reset component input priority to it's default value, that was set in `create` function or `set_input_priority` +---@return druid.base_component self The component itself for chaining +function M.reset_input_priority(self) self:set_input_priority(self._component.default_input_priority) return self end ---- Return component UID. --- --- UID generated in component creation order. --- @tparam BaseComponent self @{BaseComponent} --- @treturn number The component uid -function BaseComponent.get_uid(self) +---Get component UID, unique identifier created in component creation order. +---@return number uid The component uid +function M.get_uid(self) return self._component._uid end ---- Set component input state. By default it enabled --- --- If input is disabled, the component will not receive input events --- @tparam BaseComponent self @{BaseComponent} --- @tparam boolean|nil state The component input state --- @treturn BaseComponent BaseComponent itself -function BaseComponent.set_input_enabled(self, state) +---Set component input state. By default it's enabled. +---If input is disabled, the component will not receive input events. +---Recursive for all children components. +---@param state boolean +---@return druid.base_component self The component itself for chaining +function M.set_input_enabled(self, state) self._meta.input_enabled = state for index = 1, #self._meta.children do @@ -317,23 +271,22 @@ function BaseComponent.set_input_enabled(self, state) end ---- Return the parent component if exist --- @tparam BaseComponent self @{BaseComponent} --- @treturn BaseComponent|nil The druid component instance or nil -function BaseComponent.get_parent_component(self) +---Get parent component +---@return druid.base_component|nil parent The parent component if exist or nil +function M.get_parent_component(self) return self._meta.parent end --- Setup component context and his style table --- @tparam BaseComponent self @{BaseComponent} +-- @tparam BaseComponent self BaseComponent -- @tparam table druid_instance The parent druid instance -- @tparam table context Druid context. Usually it is self of script -- @tparam table style Druid style module -- @tparam table instance_class The component instance class -- @treturn component BaseComponent itself --- @local -function BaseComponent.setup_component(self, druid_instance, context, style, instance_class) +---@private +function M:setup_component(druid_instance, context, style, instance_class) self._meta = { template = "", context = context, @@ -357,62 +310,35 @@ function BaseComponent.setup_component(self, druid_instance, context, style, ins end ---- Print log information if debug mode is enabled --- @tparam BaseComponent self @{BaseComponent} --- @tparam string message --- @tparam table context --- @local -function BaseComponent.log_message(self, message, context) - if not self._component.is_debug then - return - end - print("[" .. self:get_name() .. "]:", message, helper.table_to_string(context)) -end - - ---- Set debug logs for component enabled or disabled --- @tparam BaseComponent self @{BaseComponent} --- @tparam boolean|nil is_debug --- @local -function BaseComponent.set_debug(self, is_debug) - self._component.is_debug = is_debug -end - - --- Return true, if input priority was changed --- @tparam BaseComponent self @{BaseComponent} --- @local -function BaseComponent._is_input_priority_changed(self) +-- @tparam BaseComponent self BaseComponent +---@private +function M._is_input_priority_changed(self) return self._component._is_input_priority_changed end --- Reset is_input_priority_changed field --- @tparam BaseComponent self @{BaseComponent} --- @local -function BaseComponent._reset_input_priority_changed(self) +-- @tparam BaseComponent self BaseComponent +---@private +function M._reset_input_priority_changed(self) self._component._is_input_priority_changed = false end -function BaseComponent.__tostring(self) - return self._component.name -end - - --- Get current component interests --- @tparam BaseComponent self @{BaseComponent} +-- @tparam BaseComponent self BaseComponent -- @treturn table List of component interests --- @local -function BaseComponent.__get_interests(self) +---@private +function M.__get_interests(self) local instance_class = self._meta.instance_class if INTERESTS[instance_class] then return INTERESTS[instance_class] end local interests = {} - for index = 1, #BaseComponent.ALL_INTERESTS do - local interest = BaseComponent.ALL_INTERESTS[index] + for index = 1, #M.ALL_INTERESTS do + local interest = M.ALL_INTERESTS[index] if self[interest] and type(self[interest]) == "function" then table.insert(interests, interest) end @@ -423,34 +349,31 @@ function BaseComponent.__get_interests(self) end ---- Get current component nodes --- @tparam BaseComponent self @{BaseComponent} --- @treturn table BaseComponent nodes table --- @local -function BaseComponent.__get_nodes(self) +---Get current component nodes +---@return table +function M.get_nodes(self) local nodes = self._meta.nodes local parent = self:get_parent_component() if parent then - nodes = nodes or parent:__get_nodes() + nodes = nodes or parent:get_nodes() end return nodes end ---- Add child to component children list --- @tparam BaseComponent self @{BaseComponent} --- @tparam component child The druid component instance --- @local -function BaseComponent.__add_child(self, child) +---Add child to component children list +---@param child druid.base_component The druid component instance +---@private +function M:__add_child(child) table.insert(self._meta.children, child) end --- Remove child from component children list --- @tparam BaseComponent self @{BaseComponent} +-- @tparam BaseComponent self BaseComponent -- @tparam component child The druid component instance --- @local -function BaseComponent.__remove_child(self, child) +---@private +function M.__remove_child(self, child) for i = #self._meta.children, 1, -1 do if self._meta.children[i] == child then table.remove(self._meta.children, i) @@ -461,9 +384,9 @@ end --- Return all children components, recursive --- @tparam BaseComponent self @{BaseComponent} +-- @tparam BaseComponent self BaseComponent -- @treturn table Array of childrens if the Druid component instance -function BaseComponent.get_childrens(self) +function M.get_childrens(self) local childrens = {} for i = 1, #self._meta.children do @@ -477,23 +400,21 @@ function BaseComponent.get_childrens(self) end ---- Create new component. It will inheritance from basic Druid component. --- @function BaseComponent.create --- @tparam string name BaseComponent name --- @tparam number|nil input_priority The input priority. The bigger number processed first --- @local -function BaseComponent.create(name, input_priority) +---Сreate a new component class, which will inherit from the base Druid component. +---@param name string|nil The name of the component +---@param input_priority number|nil The input priority. The bigger number processed first. Default value: 10 +---@return druid.base_component +function M.create(name, input_priority) local new_class = setmetatable({}, { - __index = BaseComponent, + __index = M, __call = function(cls, ...) local self = setmetatable({ _component = { - name = name, + name = name or "Druid Component", input_priority = input_priority or const.PRIORITY_INPUT, default_input_priority = input_priority or const.PRIORITY_INPUT, - is_debug = false, _is_input_priority_changed = true, -- Default true for sort once time after GUI init - _uid = BaseComponent.create_uid() + _uid = M.create_uid() } }, { __index = cls @@ -506,4 +427,4 @@ function BaseComponent.create(name, input_priority) end -return BaseComponent +return M diff --git a/druid/const.lua b/druid/const.lua index 70667de..639585f 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -1,10 +1,4 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid constants --- @local --- @module DruidConst --- @alias druid_const - +---@class druid.system.const local M = {} M.ACTION_TEXT = hash(sys.get_config_string("druid.input_text", "text")) @@ -25,7 +19,6 @@ M.ACTION_LCMD = hash(sys.get_config_string("druid.input_key_lsuper", "key_lsuper M.IS_STENCIL_CHECK = not (sys.get_config_int("druid.no_stencil_check", 0) == 1) - M.ON_INPUT = "on_input" M.ON_UPDATE = "update" M.ON_MESSAGE = "on_message" @@ -123,10 +116,6 @@ M.SWIPE = { RIGHT = "right", } -M.ERRORS = { - GRID_DYNAMIC_ANCHOR = "The pivot of dynamic grid node should be West, East, South or North" -} - M.EMPTY_FUNCTION = function() end return M diff --git a/druid/custom/rich_input/rich_input.gui b/druid/custom/rich_input/rich_input.gui index b511cec..5467ee9 100644 --- a/druid/custom/rich_input/rich_input.gui +++ b/druid/custom/rich_input/rich_input.gui @@ -1,11 +1,11 @@ script: "" fonts { - name: "game" - font: "/example/assets/fonts/game.font" + name: "text_bold" + font: "/example/assets/fonts/text_bold.font" } textures { - name: "kenney" - texture: "/example/assets/images/kenney.atlas" + name: "druid" + texture: "/example/assets/druid.atlas" } background_color { x: 0.0 @@ -33,8 +33,8 @@ nodes { w: 1.0 } size { - x: 1.0 - y: 1.0 + x: 500.0 + y: 80.0 z: 0.0 w: 1.0 } @@ -46,7 +46,7 @@ nodes { } type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" + texture: "" id: "root" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -65,7 +65,11 @@ nodes { clipping_inverted: false alpha: 1.0 template_node_child: false - size_mode: SIZE_MODE_AUTO + size_mode: SIZE_MODE_MANUAL + custom_type: 0 + enabled: true + visible: false + material: "" } nodes { position { @@ -87,8 +91,8 @@ nodes { w: 1.0 } size { - x: 190.0 - y: 45.0 + x: 500.0 + y: 80.0 z: 0.0 w: 1.0 } @@ -100,7 +104,7 @@ nodes { } type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA - texture: "kenney/progress_back" + texture: "druid/rect_round2_width1" id: "button" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -110,17 +114,21 @@ nodes { layer: "" inherit_alpha: true slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 + x: 4.0 + y: 4.0 + z: 4.0 + w: 4.0 } clipping_mode: CLIPPING_MODE_NONE clipping_visible: true clipping_inverted: false alpha: 1.0 template_node_child: false - size_mode: SIZE_MODE_AUTO + size_mode: SIZE_MODE_MANUAL + custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -136,27 +144,27 @@ nodes { w: 1.0 } scale { - x: 0.5 - y: 0.5 + x: 1.0 + y: 1.0 z: 1.0 w: 1.0 } size { - x: 300.0 + x: 480.0 y: 60.0 z: 0.0 w: 1.0 } color { - x: 0.9490196 - y: 0.9490196 - z: 0.9490196 + x: 0.31 + y: 0.318 + z: 0.322 w: 1.0 } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA text: "Placeholder" - font: "game" + font: "text_bold" id: "placeholder_text" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -179,11 +187,15 @@ nodes { layer: "" inherit_alpha: true alpha: 1.0 - outline_alpha: 1.0 + outline_alpha: 0.0 shadow_alpha: 0.0 template_node_child: false text_leading: 1.0 text_tracking: 0.0 + custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { @@ -199,27 +211,27 @@ nodes { w: 1.0 } scale { - x: 0.6 - y: 0.6 - z: 1.0 - w: 1.0 - } - size { - x: 300.0 - y: 60.0 - z: 0.0 - w: 1.0 - } - color { x: 1.0 y: 1.0 z: 1.0 w: 1.0 } + size { + x: 480.0 + y: 60.0 + z: 0.0 + w: 1.0 + } + color { + x: 0.722 + y: 0.741 + z: 0.761 + w: 1.0 + } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA text: "User input" - font: "game" + font: "text_bold" id: "input_text" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -242,15 +254,19 @@ nodes { layer: "" inherit_alpha: true alpha: 1.0 - outline_alpha: 1.0 + outline_alpha: 0.0 shadow_alpha: 0.0 template_node_child: false text_leading: 1.0 text_tracking: 0.0 + custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { - x: 67.0 + x: 118.0 y: 0.0 z: 0.0 w: 1.0 @@ -262,26 +278,26 @@ nodes { w: 1.0 } scale { - x: 0.6 - y: 0.6 + x: 1.0 + y: 1.0 z: 1.0 w: 1.0 } size { - x: 1.0 - y: 1.0 + x: 16.0 + y: 50.0 z: 0.0 w: 1.0 } color { - x: 1.0 - y: 1.0 - z: 1.0 + x: 0.631 + y: 0.843 + z: 0.961 w: 1.0 } type: TYPE_BOX blend_mode: BLEND_MODE_ALPHA - texture: "kenney/empty" + texture: "druid/ui_circle_16" id: "cursor_node" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -291,22 +307,26 @@ nodes { layer: "" inherit_alpha: true slice9 { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 + x: 8.0 + y: 8.0 + z: 8.0 + w: 8.0 } clipping_mode: CLIPPING_MODE_NONE clipping_visible: true clipping_inverted: false - alpha: 1.0 + alpha: 0.5 template_node_child: false - size_mode: SIZE_MODE_AUTO + size_mode: SIZE_MODE_MANUAL + custom_type: 0 + enabled: true + visible: true + material: "" } nodes { position { x: 0.0 - y: 2.0 + y: 4.0 z: 0.0 w: 1.0 } @@ -317,8 +337,8 @@ nodes { w: 1.0 } scale { - x: 1.0 - y: 1.0 + x: 1.2 + y: 1.2 z: 1.0 w: 1.0 } @@ -329,15 +349,15 @@ nodes { w: 1.0 } color { - x: 0.2 - y: 0.2 - z: 0.2 + x: 0.722 + y: 0.741 + z: 0.761 w: 1.0 } type: TYPE_TEXT blend_mode: BLEND_MODE_ALPHA text: "|" - font: "game" + font: "text_bold" id: "cursor_text" xanchor: XANCHOR_NONE yanchor: YANCHOR_NONE @@ -358,13 +378,17 @@ nodes { line_break: false parent: "cursor_node" layer: "" - inherit_alpha: true + inherit_alpha: false alpha: 1.0 outline_alpha: 0.0 shadow_alpha: 0.0 template_node_child: false text_leading: 1.0 text_tracking: 0.0 + custom_type: 0 + enabled: true + visible: true + material: "" } material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/druid/custom/rich_input/rich_input.lua b/druid/custom/rich_input/rich_input.lua index c42b637..a1f18ab 100644 --- a/druid/custom/rich_input/rich_input.lua +++ b/druid/custom/rich_input/rich_input.lua @@ -6,13 +6,13 @@ -- @alias druid.rich_input --- The component druid instance --- @tfield DruidInstance druid @{DruidInstance} +-- @tfield DruidInstance druid DruidInstance --- Root node -- @tfield node root --- On input field text change callback(self, input_text) --- @tfield Input input @{Input} +-- @tfield Input input Input --- On input field text change to empty string callback(self, input_text) -- @tfield node cursor @@ -44,16 +44,23 @@ local utf8_lua = require("druid.system.utf8") local utf8 = utf8 or utf8_lua local input = require("druid.extended.input") -local RichInput = component.create("druid.rich_input") -local SCHEME = { - ROOT = "root", - BUTTON = "button", - PLACEHOLDER = "placeholder_text", - INPUT = "input_text", - CURSOR = "cursor_node", - CURSOR_TEXT = "cursor_text", -} +---@class druid.rich_input: druid.base_component +---@field root node +---@field input druid.input +---@field cursor node +---@field cursor_text node +---@field cursor_position vector3 +local M = component.create("druid.rich_input") + +--local SCHEME = { +-- ROOT = "root", +-- BUTTON = "button", +-- PLACEHOLDER = "placeholder_text", +-- INPUT = "input_text", +-- CURSOR = "cursor_node", +-- CURSOR_TEXT = "cursor_text", +--} local DOUBLE_CLICK_TIME = 0.35 @@ -189,13 +196,11 @@ local function on_drag_callback(self, dx, dy, x, y, touch) end ---- The @{RichInput} constructor --- @tparam RichInput self @{RichInput} --- @tparam string template The template string name --- @tparam table nodes Nodes table from gui.clone_tree -function RichInput.init(self, template, nodes) +---@param template string The template string name +---@param nodes table Nodes table from gui.clone_tree +function M:init(template, nodes) self.druid = self:get_druid(template, nodes) - self.root = self:get_node(SCHEME.ROOT) + self.root = self:get_node("root") self._last_touch_info = { cursor_index = nil, @@ -204,20 +209,20 @@ function RichInput.init(self, template, nodes) self.is_lshift = false self.is_lctrl = false - self.input = self.druid:new(input, self:get_node(SCHEME.BUTTON), self:get_node(SCHEME.INPUT)) + self.input = self.druid:new(input, "button", "input_text") self.is_button_input_enabled = gui.is_enabled(self.input.button.node) - self.cursor = self:get_node(SCHEME.CURSOR) + self.cursor = self:get_node("cursor_node") self.cursor_position = gui.get_position(self.cursor) - self.cursor_text = self:get_node(SCHEME.CURSOR_TEXT) + self.cursor_text = self:get_node("cursor_text") - self.drag = self.druid:new_drag(self:get_node(SCHEME.BUTTON), on_drag_callback) + self.drag = self.druid:new_drag("button", on_drag_callback) self.drag.on_touch_start:subscribe(on_touch_start_callback) self.drag:set_input_priority(const.PRIORITY_INPUT_MAX + 1) self.drag:set_enabled(false) self.input:set_text("") - self.placeholder = self.druid:new_text(self:get_node(SCHEME.PLACEHOLDER)) + self.placeholder = self.druid:new_text("placeholder_text") self.text_position = gui.get_position(self.input.text.node) self.input.on_input_text:subscribe(update_text) @@ -230,7 +235,7 @@ function RichInput.init(self, template, nodes) end -function RichInput.on_input(self, action_id, action) +function M:on_input(action_id, action) if action_id == const.ACTION_LSHIFT then if action.pressed then self.is_lshift = true @@ -258,26 +263,26 @@ end --- Set placeholder text --- @tparam RichInput self @{RichInput} +-- @tparam RichInput self RichInput -- @tparam string placeholder_text The placeholder text -function RichInput.set_placeholder(self, placeholder_text) +function M:set_placeholder(placeholder_text) self.placeholder:set_to(placeholder_text) return self end --- Select input field --- @tparam RichInput self @{RichInput} -function RichInput.select(self) +-- @tparam RichInput self RichInput +function M:select() self.input:select() end --- Set input field text --- @tparam RichInput self @{RichInput} +-- @tparam RichInput self RichInput -- @treturn druid.input Current input instance -- @tparam string text The input text -function RichInput.set_text(self, text) +function M:set_text(text) self.input:set_text(text) gui.set_enabled(self.placeholder.node, true and #self.input:get_text() == 0) @@ -286,10 +291,10 @@ end --- Set input field font --- @tparam RichInput self @{RichInput} +-- @tparam RichInput self RichInput -- @tparam hash font The font hash -- @treturn druid.input Current input instance -function RichInput.set_font(self, font) +function M:set_font(font) gui.set_font(self.input.text.node, font) gui.set_font(self.placeholder.node, font) @@ -298,8 +303,8 @@ end --- Set input field text --- @tparam RichInput self @{RichInput} -function RichInput.get_text(self) +-- @tparam RichInput self RichInput +function M:get_text() return self.input:get_text() end @@ -307,14 +312,14 @@ end --- Set allowed charaters for input field. -- See: https://defold.com/ref/stable/string/ -- ex: [%a%d] for alpha and numeric --- @tparam RichInput self @{RichInput} +-- @tparam RichInput self RichInput -- @tparam string characters Regulax exp. for validate user input -- @treturn RichInput Current instance -function RichInput.set_allowed_characters(self, characters) +function M:set_allowed_characters(characters) self.input:set_allowed_characters(characters) return self end -return RichInput +return M diff --git a/druid/custom/rich_text/rich_text.lua b/druid/custom/rich_text/rich_text.lua index 4ed7198..e2a2d5c 100644 --- a/druid/custom/rich_text/rich_text.lua +++ b/druid/custom/rich_text/rich_text.lua @@ -63,7 +63,7 @@ -- @alias druid.rich_text --- The component druid instance --- @tfield DruidInstance druid @{DruidInstance} +-- @tfield DruidInstance druid DruidInstance --- The root node of the Rich Text -- @tfield node root @@ -76,14 +76,19 @@ local component = require("druid.component") local rich_text = require("druid.custom.rich_text.module.rt") -local RichText = component.create("rich_text") +---@class druid.rich_text: druid.base_component +---@field root node +---@field text_prefab node +---@field private _last_value string +---@field private _settings table +local M = component.create("rich_text") ---- The @{RichText} constructor --- @tparam RichText self @{RichText} +--- The RichText constructor +-- @tparam RichText self RichText -- @tparam node|string text_node The text node to make Rich Text -- @tparam string|nil value The initial text value. Default will be gui.get_text(text_node) -function RichText.init(self, text_node, value) +function M:init(text_node, value) self.root = self:get_node(text_node) self.text_prefab = self.root @@ -98,7 +103,7 @@ function RichText.init(self, text_node, value) end -function RichText.on_layout_change(self) +function M:on_layout_change() if self._last_value then self:set_text(self._last_value) end @@ -112,7 +117,7 @@ end -- @tfield table|nil COLORS Rich Text color aliases. Default: {} -- @tfield number|nil ADJUST_STEPS Amount steps of attemps text adjust by height. Default: 20 -- @tfield number|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02 -function RichText.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.COLORS = style.COLORS or {} self.style.ADJUST_STEPS = style.ADJUST_STEPS or 20 @@ -121,7 +126,7 @@ end --- Set text for Rich Text --- @tparam RichText self @{RichText} +-- @tparam RichText self RichText -- @tparam string|nil text The text to set -- @treturn druid.rich_text.word[] words -- @treturn druid.rich_text.lines_metrics line_metrics @@ -168,7 +173,7 @@ end -- -- -- -function RichText.set_text(self, text) +function M:set_text(text) text = text or "" self:clear() self._last_value = text @@ -184,14 +189,14 @@ end --- Get current text --- @tparam RichText self @{RichText} +-- @tparam RichText self RichText -- @treturn string text -function RichText.get_text(self) +function M:get_text() return self._last_value end -function RichText:on_remove() +function M:on_remove() gui.set_scale(self.root, self._default_scale) gui.set_size(self.root, self._default_size) self:clear() @@ -199,7 +204,7 @@ end --- Clear all created words. -function RichText:clear() +function M:clear() if self._words then rich_text.remove(self._words) self._words = nil @@ -209,10 +214,10 @@ end --- Get all words, which has a passed tag. --- @tparam RichText self @{RichText} +-- @tparam RichText self RichText -- @tparam string tag -- @treturn druid.rich_text.word[] words -function RichText.tagged(self, tag) +function M:tagged(tag) if not self._words then return end @@ -222,29 +227,29 @@ end ---Split a word into it's characters --- @tparam RichText self @{RichText} +-- @tparam RichText self RichText -- @tparam druid.rich_text.word word -- @treturn druid.rich_text.word[] characters -function RichText.characters(self, word) +function M:characters(word) return rich_text.characters(word) end --- Get all current words. -- @treturn table druid.rich_text.word[] -function RichText:get_words() +function M:get_words() return self._words end --- Get current line metrics --- @treturn druid.rich_text.lines_metrics -function RichText:get_line_metric() +function M:get_line_metric() return self._line_metrics end -function RichText:_create_settings() +function M:_create_settings() local root_size = gui.get_size(self.root) local scale = gui.get_scale(self.root) @@ -280,4 +285,4 @@ function RichText:_create_settings() end -return RichText +return M diff --git a/druid/druid.lua b/druid/druid.lua index 37997d4..b198728 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -13,7 +13,7 @@ -- -- • Each Druid instance maintains the self context from the constructor and passes it to each Druid callback. -- --- See next: @{DruidInstance} +-- See next: DruidInstance -- -- @usage -- local druid = require("druid.druid") @@ -52,15 +52,15 @@ local druid_instance = require("druid.system.druid_instance") local default_style = require("druid.styles.default.style") +---@class druid local M = {} - -local _instances = {} +local druid_instances = {} local function clean_deleted_druid_instances() - for i = #_instances, 1, -1 do - if _instances[i]._deleted then - table.remove(_instances, i) + for i = #druid_instances, 1, -1 do + if druid_instances[i]._deleted then + table.remove(druid_instances, i) end end end @@ -68,45 +68,27 @@ end local function get_druid_instances() clean_deleted_druid_instances() - return _instances + return druid_instances end ---- Register a new external Druid component. --- --- You can register your own components to make new alias: the druid:new_{name} function. --- For example, if you want to register a component called "my_component", you can create it using druid:new_my_component(...). --- This can be useful if you have your own "basic" components that you don't want to re-create each time. --- @function druid.register --- @tparam string name module name --- @tparam table module lua table with component --- @usage --- local my_component = require("path.to.my.component") --- druid.register("my_component", my_component) --- ... --- local druid = druid.new(self) --- local component_instance = self.druid:new_my_component(...) +---Register a new external Druid component. +---You can register your own components to make new alias: the druid:new_{name} function. +---For example, if you want to register a component called "my_component", you can create it using druid:new_my_component(...). +---This can be useful if you have your own "basic" components that you don't want to re-create each time. +---@param name string Module name +---@param module table Lua table with component function M.register(name, module) druid_instance["new_" .. name] = function(self, ...) return druid_instance.new(self, module, ...) end - - return druid_instance["new_" .. name] end ---- Create a new Druid instance for creating GUI components. --- --- @function druid.new --- @tparam table context The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks. --- @tparam table|nil style The Druid style table to override style parameters for this Druid instance. --- @treturn druid_instance The Druid instance @{DruidInstance}. --- @usage --- local druid = require("druid.druid") --- --- function init(self) --- self.druid = druid.new(self) --- end +---Create a new Druid instance for creating GUI components. +---@param context table The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks. +---@param style table|nil The Druid style table to override style parameters for this Druid instance. +---@return druid_instance druid_instance The new Druid instance function M.new(context, style) clean_deleted_druid_instances() @@ -117,65 +99,35 @@ function M.new(context, style) local new_instance = setmetatable({}, { __index = druid_instance }) new_instance:initialize(context, style) - table.insert(_instances, new_instance) + table.insert(druid_instances, new_instance) return new_instance end ---- Set your own default style for all Druid instances. --- --- To create your own style file, copy the default style file and make changes to it. --- Register the new style before creating your Druid instances. --- @function druid.set_default_style --- @tparam table style Druid style module --- @usage --- local my_style = require("path.to.my.style") --- druid.set_default_style(my_style) +---Set the default style for all Druid instances. +---@param style table Default style function M.set_default_style(style) settings.default_style = style or {} end ---- Set the text function for the LangText component. --- --- The Druid locale component will call this function to get translated text. --- After setting the text function, all existing locale components will be updated. --- @function druid.set_text_function --- @tparam function callback Get localized text function --- @usage --- druid.set_text_function(function(text_id) --- return lang_data[text_id] -- Replace with your real function --- end) +---Set the text function for the LangText component. +---@param callback fun(text_id: string): string Get localized text function function M.set_text_function(callback) settings.get_text = callback or const.EMPTY_FUNCTION M.on_language_change() end ---- Set the Druid sound function to play UI sounds if used. --- --- Set a function to play a sound given a sound_id. This function is used for button clicks to play the "click" sound. --- It can also be used to play sounds in your custom components (see the default Druid style file for an example). --- @function druid.set_sound_function --- @tparam function callback Sound play callback --- @usage --- druid.set_sound_function(function(sound_id) --- sound.play(sound_id) -- Replace with your real function --- end) +---Set the sound function to able components to play sounds. +---@param callback fun(sound_id: string) Sound play callback function M.set_sound_function(callback) settings.play_sound = callback or const.EMPTY_FUNCTION end ---- Set the window callback to enable on_focus_gain and on_focus_lost functions. --- --- This is used to trigger the on_focus_lost and on_focus_gain functions in Druid components. --- @function druid.on_window_callback --- @tparam string event Event param from window listener --- @usage --- window.set_listener(function(_, event) --- druid.on_window_callback(event) --- end) +---Set the window callback to enable Druid window events. +---@param event constant Event param from window listener function M.on_window_callback(event) local instances = get_druid_instances() @@ -195,12 +147,7 @@ function M.on_window_callback(event) end ---- Call this function when the game language changes. --- --- This function will translate all current LangText components. --- @function druid.on_language_change --- @usage --- druid.on_language_change() +---Call this function when the game language changes. function M.on_language_change() local instances = get_druid_instances() diff --git a/druid/editor_scripts/create_druid_component.py b/druid/editor_scripts/create_druid_component.py index 24d1203..195429a 100644 --- a/druid/editor_scripts/create_druid_component.py +++ b/druid/editor_scripts/create_druid_component.py @@ -48,10 +48,6 @@ def process_component(node_name, component_name): component_define += "\n--TODO: Replace prefab_name with grid element prefab" component_define += "\n\tself.{0} = self.druid:new_static_grid(\"{1}\", \"prefab_name\", 1)".format(node_name, node_name) - if node_name.startswith("dynamic_grid"): - component_annotations += "\n---@field {0} druid.dynamic_grid".format(node_name) - component_define += "\n\tself.{0} = self.druid:new_dynamic_grid(\"{1}\")".format(node_name, node_name) - if node_name.startswith("scroll_view"): field_name = node_name.replace("_view", "") content_name = node_name.replace("_view", "_content") diff --git a/druid/event.lua b/druid/event.lua index ef79c86..395172b 100644 --- a/druid/event.lua +++ b/druid/event.lua @@ -8,6 +8,7 @@ -- @module DruidEvent -- @alias druid.event +---@class druid.event local M = {} M.COUNTER = 0 @@ -39,11 +40,11 @@ end --- Check is event subscribed. --- @tparam DruidEvent self @{DruidEvent} +-- @tparam DruidEvent self DruidEvent -- @tparam function callback Callback itself -- @tparam any|nil callback_context Additional context as first param to callback call -- @treturn boolean, number|nil @Is event subscribed, return index of callback in event as second param -function M.is_subscribed(self, callback, callback_context) +function M:is_subscribed(callback, callback_context) if #self == 0 then return false, nil end @@ -60,7 +61,7 @@ end --- Subscribe callback on event --- @tparam DruidEvent self @{DruidEvent} +-- @tparam DruidEvent self DruidEvent -- @tparam function callback Callback itself -- @tparam any|nil callback_context Additional context as first param to callback call, usually it's self -- @treturn boolean True if callback was subscribed @@ -71,7 +72,7 @@ end -- ... -- local button = self.druid:new_button("button", callback) -- button.on_long_click:subscribe(on_long_callback, self) -function M.subscribe(self, callback, callback_context) +function M:subscribe(callback, callback_context) assert(type(self) == "table", "You should subscribe to event with : syntax") assert(callback, "A function must be passed to subscribe to an event") @@ -85,7 +86,7 @@ end --- Unsubscribe callback on event --- @tparam DruidEvent self @{DruidEvent} +-- @tparam DruidEvent self DruidEvent -- @tparam function callback Callback itself -- @tparam any|nil callback_context Additional context as first param to callback call -- @usage @@ -94,7 +95,7 @@ end -- end -- ... -- button.on_long_click:unsubscribe(on_long_callback, self) -function M.unsubscribe(self, callback, callback_context) +function M:unsubscribe(callback, callback_context) assert(callback, "A function must be passed to subscribe to an event") local _, event_index = self:is_subscribed(callback, callback_context) @@ -108,17 +109,17 @@ end --- Return true, if event have at lease one handler --- @tparam DruidEvent self @{DruidEvent} +-- @tparam DruidEvent self DruidEvent -- @treturn boolean True if event have handlers -- @usage -- local is_long_click_handler_exists = button.on_long_click:is_exist() -function M.is_exist(self) +function M:is_exist() return #self > 0 end --- Return true, if event not have handler ---- @tparam DruidEvent self @{DruidEvent} +--- @tparam DruidEvent self DruidEvent --- @treturn boolean True if event not have handlers --- @usage --- local is_long_click_handler_not_exists = button.on_long_click:is_empty() @@ -128,10 +129,10 @@ end --- Clear the all event handlers --- @tparam DruidEvent self @{DruidEvent} +-- @tparam DruidEvent self DruidEvent -- @usage -- button.on_long_click:clear() -function M.clear(self) +function M:clear() for index = #self, 1, -1 do self[index] = nil end @@ -139,14 +140,14 @@ end --- Trigger the event and call all subscribed callbacks --- @tparam DruidEvent self @{DruidEvent} +-- @tparam DruidEvent self DruidEvent -- @tparam any ... All event params -- @usage -- local Event = require("druid.event") -- ... -- local event = Event() -- event:trigger("Param1", "Param2") -function M.trigger(self, ...) +function M:trigger(...) if #self == 0 then return end diff --git a/druid/extended/data_list.lua b/druid/extended/data_list.lua index 81bf959..9fadb6a 100644 --- a/druid/extended/data_list.lua +++ b/druid/extended/data_list.lua @@ -10,10 +10,10 @@ --- The Druid scroll component --- @tfield Scroll scroll @{Scroll} +-- @tfield Scroll scroll Scroll --- The Druid Grid component --- @tfield StaticGrid grid @{StaticGrid}, @{DynamicGrid} +-- @tfield StaticGrid grid StaticGrid}, @{DynamicGrid --- The current progress of scroll posititon -- @tfield number scroll_progress @@ -25,13 +25,13 @@ -- @tfield number last_index --- Event triggered when scroll progress is changed; event(self, progress_value) --- @tfield DruidEvent on_scroll_progress_change @{DruidEvent} +-- @tfield DruidEvent on_scroll_progress_change DruidEvent ---On DataList visual element created Event callback(self, index, node, instance) --- @tfield DruidEvent on_element_add @{DruidEvent} +-- @tfield DruidEvent on_element_add DruidEvent ---On DataList visual element created Event callback(self, index) --- @tfield DruidEvent on_element_remove @{DruidEvent} +-- @tfield DruidEvent on_element_remove DruidEvent --- @@ -40,15 +40,27 @@ local helper = require("druid.helper") local component = require("druid.component") local Event = require("druid.event") -local DataList = component.create("data_list") +---@class druid.data_list: druid.base_component +---@field scroll druid.scroll +---@field grid druid.grid +---@field on_scroll_progress_change druid.event +---@field on_element_add druid.event +---@field on_element_remove druid.event +---@field private _create_function function +---@field private _is_use_cache boolean +---@field private _cache table +---@field private _data table +---@field private _data_visual table +---@field private top_index number +local M = component.create("data_list") ---- The @{DataList} constructor --- @tparam DataList self @{DataList} --- @tparam Scroll scroll The @{Scroll} instance for Data List component --- @tparam StaticGrid grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component +--- The DataList constructor +-- @tparam DataList self DataList +-- @tparam Scroll scroll The Scroll instance for Data List component +-- @tparam StaticGrid grid The StaticGrid} or @{DynamicGrid instance for Data List component -- @tparam function create_function The create function callback(self, data, index, data_list). Function should return (node, [component]) -function DataList.init(self, scroll, grid, create_function) +function M:init(scroll, grid, create_function) self.scroll = scroll self.grid = grid if self.grid.style then @@ -75,28 +87,28 @@ end --- Druid System on_remove function --- @tparam DataList self @{DataList} -function DataList.on_remove(self) +-- @tparam DataList self DataList +function M:on_remove() self:clear() self.scroll.on_scroll:unsubscribe(self._refresh, self) end --- Set refresh function for DataList component --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam boolean is_use_cache Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove -- @treturn druid.data_list Current DataList instance -function DataList.set_use_cache(self, is_use_cache) +function M:set_use_cache(is_use_cache) self._is_use_cache = is_use_cache return self end --- Set new data set for DataList component --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam table data The new data array -- @treturn druid.data_list Current DataList instance -function DataList.set_data(self, data) +function M:set_data(data) self._data = data or {} self:_refresh() @@ -105,19 +117,19 @@ end --- Return current data from DataList component --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @treturn table The current data array -function DataList.get_data(self) +function M:get_data() return self._data end --- Add element to DataList. Currenly untested --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam table data -- @tparam number|nil index -- @tparam number|nil shift_policy The constant from const.SHIFT.* -function DataList.add(self, data, index, shift_policy) +function M:add(data, index, shift_policy) index = index or #self._data + 1 shift_policy = shift_policy or const.SHIFT.RIGHT @@ -127,20 +139,20 @@ end --- Remove element from DataList. Currenly untested --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam number|nil index -- @tparam number|nil shift_policy The constant from const.SHIFT.* -function DataList.remove(self, index, shift_policy) +function M:remove(index, shift_policy) helper.remove_with_shift(self._data, index, shift_policy) self:_refresh() end --- Remove element from DataList by data value. Currenly untested --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam table data -- @tparam number|nil shift_policy The constant from const.SHIFT.* -function DataList.remove_by_data(self, data, shift_policy) +function M:remove_by_data(data, shift_policy) local index = helper.contains(self._data, data) if index then helper.remove_with_shift(self._data, index, shift_policy) @@ -150,17 +162,17 @@ end --- Clear the DataList and refresh visuals --- @tparam DataList self @{DataList} -function DataList.clear(self) +-- @tparam DataList self DataList +function M:clear() self._data = {} self:_refresh() end --- Return index for data value --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam table data -function DataList.get_index(self, data) +function M:get_index(data) for index, value in pairs(self._data) do if value == data then return index @@ -172,9 +184,9 @@ end --- Return all currenly created nodes in DataList --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @treturn node[] List of created nodes -function DataList.get_created_nodes(self) +function M:get_created_nodes() local nodes = {} for index, data in pairs(self._data_visual) do @@ -186,9 +198,9 @@ end --- Return all currenly created components in DataList --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @treturn druid.base_component[] List of created nodes -function DataList.get_created_components(self) +function M:get_created_components() local components = {} for index, data in pairs(self._data_visual) do @@ -200,19 +212,19 @@ end --- Instant scroll to element with passed index --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam number index -function DataList.scroll_to_index(self, index) +function M:scroll_to_index(index) local pos = self.grid:get_pos(index) self.scroll:scroll_to(pos) end --- Add element at passed index using cache or create new --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam number index -- @local -function DataList._add_at(self, index) +function M:_add_at(index) if self._data_visual[index] then self:_remove_at(index) end @@ -243,10 +255,10 @@ end --- Remove element from passed index and add it to cache if applicable --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @tparam number index -- @local -function DataList._remove_at(self, index) +function M:_remove_at(index) self.grid:remove(index, const.SHIFT.NO_SHIFT) local visual_data = self._data_visual[index] @@ -274,9 +286,9 @@ end --- Refresh all elements in DataList --- @tparam DataList self @{DataList} +-- @tparam DataList self DataList -- @local -function DataList._refresh(self) +function M:_refresh() self.scroll:set_size(self.grid:get_size_for(#self._data)) local start_pos = -self.scroll.position --[[@as vector3]] @@ -313,4 +325,4 @@ function DataList._refresh(self) end -return DataList +return M diff --git a/druid/extended/dynamic_grid.lua b/druid/extended/dynamic_grid.lua deleted file mode 100644 index c4f0c76..0000000 --- a/druid/extended/dynamic_grid.lua +++ /dev/null @@ -1,427 +0,0 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle placing components in row --- --- Example Link --- @module DynamicGrid --- @within BaseComponent --- @alias druid.dynamic_grid - ---- On item add callback(self, node, index) --- @tfield DruidEvent on_add_item @{DruidEvent} - ---- On item remove callback(self, index) --- @tfield DruidEvent on_remove_item @{DruidEvent} - ---- On item add or remove callback(self, index) --- @tfield DruidEvent on_change_items @{DruidEvent} - ---- On grid clear callback(self) --- @tfield DruidEvent on_clear @{DruidEvent} - ---- On update item positions callback(self) --- @tfield DruidEvent on_update_positions @{DruidEvent} - ---- Parent gui node --- @tfield node parent - ---- List of all grid elements. Contains from node, pos, size, pivot --- @tfield node[] nodes - ---- The first index of node in grid --- @tfield number first_index - ---- The last index of node in grid --- @tfield number last_index - ---- Item size --- @tfield vector3 node_size - ---- The size of item content --- @tfield vector4 border - ---- - -local const = require("druid.const") -local Event = require("druid.event") -local helper = require("druid.helper") -local component = require("druid.component") - -local DynamicGrid = component.create("dynamic_grid") - - -local SIDE_VECTORS = { - LEFT = vmath.vector3(-1, 0, 0), - RIGHT = vmath.vector3(1, 0, 0), - TOP = vmath.vector3(0, -1, 0), - BOT = vmath.vector3(0, 1, 0), -} - -local AVAILABLE_PIVOTS = { - gui.PIVOT_N, - gui.PIVOT_S, - gui.PIVOT_W, - gui.PIVOT_E, -} - - ---- The @{DynamicGrid} constructor --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam node parent The gui node parent, where items will be placed -function DynamicGrid.init(self, parent) - self.parent = self:get_node(parent) - - local parent_pivot = gui.get_pivot(self.parent) - self.pivot = helper.get_pivot_offset(parent_pivot) - - assert(helper.contains(AVAILABLE_PIVOTS, parent_pivot), const.ERRORS.GRID_DYNAMIC_ANCHOR) - self.side = ((parent_pivot == gui.PIVOT_W or parent_pivot == gui.PIVOT_E) - and const.SIDE.X or const.SIDE.Y) - - self.nodes = {} - self.border = vmath.vector4(0) -- Current grid content size - - self.on_add_item = Event() - self.on_remove_item = Event() - self.on_change_items = Event() - self.on_clear = Event() - self.on_update_positions = Event() - - self._set_position_function = gui.set_position -end - - -function DynamicGrid.on_layout_change(self) - self:_update(true) -end - - ---- Return pos for grid node index --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam number index The grid element index --- @tparam node node The node to be placed --- @tparam number|nil origin_index Index of nearby node --- @treturn vector3 node position -function DynamicGrid.get_pos(self, index, node, origin_index) - local origin_node = self.nodes[origin_index] - - -- If anchor node is not exist, check around nodes - if not origin_node then - if self.nodes[index + 1] then - origin_index = index + 1 - end - if self.nodes[index - 1] then - origin_index = index - 1 - end - origin_node = self.nodes[origin_index] - end - - if not origin_node then - assert(not self.first_index, "Dynamic Grid can't have gaps between nodes. Error on grid:add") - - -- If not origin node, so it should be first element in the grid - local size = helper.get_scaled_size(node) - local pivot = const.PIVOTS[gui.get_pivot(node)] - return vmath.vector3( - size.x * pivot.x - size.x * self.pivot.x, - size.y * pivot.y - size.y * self.pivot.y, - 0) - end - - if origin_node then - -- Other nodes spawn from other side of the origin node - local is_forward = origin_index < index - local delta = is_forward and 1 or -1 - return self:_get_next_node_pos(index - delta, node, self:_get_side_vector(self.side, is_forward)) - end -end - - ---- Add new node to the grid --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam node node Gui node --- @tparam number|nil index The node position. By default add as last node --- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT --- @tparam boolean|nil is_instant If true, update node positions instantly -function DynamicGrid.add(self, node, index, shift_policy, is_instant) - shift_policy = shift_policy or const.SHIFT.RIGHT - local delta = shift_policy -- -1 or 1 or 0 - - -- By default add node at end - index = index or ((self.last_index or 0) + 1) - - -- If node exist at index place, shifting them - local is_shift = self.nodes[index] and shift_policy ~= const.SHIFT.NO_SHIFT - if is_shift then - -- We need to iterate from index to start or end grid, depends of shift side - local start_index = shift_policy == const.SHIFT.LEFT and self.first_index or self.last_index - for i = start_index, index, -delta do - self.nodes[i + delta] = self.nodes[i] - end - end - - self:_add_node(node, index, index - delta) - - -- After shifting we should recalc node poses - if is_shift then - -- We need to iterate from placed node to start or end grid, depends of shift side - local target_index = shift_policy == const.SHIFT.LEFT and self.first_index or self.last_index - for i = index + delta, target_index + delta, delta do - local move_node = self.nodes[i] - move_node.pos = self:get_pos(i, move_node.node, i - delta) - end - end - - -- Sync grid data - self:_update(is_instant) - - self.on_add_item:trigger(self:get_context(), node, index) - self.on_change_items:trigger(self:get_context(), index) -end - - ---- Remove the item from the grid. Note that gui node will be not deleted --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam number index The grid node index to remove --- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT --- @tparam boolean|nil is_instant If true, update node positions instantly --- @treturn node The deleted gui node from grid -function DynamicGrid.remove(self, index, shift_policy, is_instant) - shift_policy = shift_policy or const.SHIFT.RIGHT - local delta = shift_policy -- -1 or 1 or 0 - - assert(self.nodes[index], "No grid item at given index " .. index) - - -- Just set nil for delete node data - local removed_node = self.nodes[index].node - self.nodes[index] = nil - - -- After delete node, we should shift nodes and recalc their poses, depends from is_shift_left - if shift_policy ~= const.SHIFT.NO_SHIFT then - local target_index = shift_policy == const.SHIFT.LEFT and self.first_index or self.last_index - for i = index, target_index, delta do - self.nodes[i] = self.nodes[i + delta] - if self.nodes[i] then - self.nodes[i].pos = self:get_pos(i, self.nodes[i].node, i - delta) - end - end - end - - -- Sync grid data - self:_update(is_instant) - - self.on_remove_item:trigger(self:get_context(), index) - self.on_change_items:trigger(self:get_context(), index) - - return removed_node -end - - ---- Return grid content size --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam vector3 border --- @treturn vector3 The grid content size -function DynamicGrid.get_size(self, border) - border = border or self.border - return vmath.vector3( - border.z - border.x, - border.y - border.w, - 0) -end - - ---- Return DynamicGrid offset, where DynamicGrid content starts. --- @tparam DynamicGrid self @{DynamicGrid} The DynamicGrid instance --- @treturn vector3 The DynamicGrid offset -function DynamicGrid.get_offset(self) - local size = self:get_size() - local borders = self:get_borders() - local offset = vmath.vector3( - (borders.z + borders.x)/2 + size.x * self.pivot.x, - (borders.y + borders.w)/2 + size.y * self.pivot.y, - 0) - - return offset -end - - ---- Return grid content borders --- @tparam DynamicGrid self @{DynamicGrid} --- @treturn vector3 The grid content borders -function DynamicGrid.get_borders(self) - return self.border -end - - ---- Return grid index by node --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam node node The gui node in the grid --- @treturn number The node index -function DynamicGrid.get_index_by_node(self, node) - for index, node_info in pairs(self.nodes) do - if node == node_info.node then - return index - end - end - - return nil -end - - ---- Return array of all node positions --- @tparam DynamicGrid self @{DynamicGrid} --- @treturn vector3[] All grid node positions -function DynamicGrid.get_all_pos(self) - local result = {} - for i, node in pairs(self.nodes) do - table.insert(result, gui.get_position(node.node)) - end - - return result -end - - ---- Change set position function for grid nodes. It will call on --- update poses on grid elements. Default: gui.set_position --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam function callback Function on node set position --- @treturn druid.dynamic_grid Current grid instance -function DynamicGrid.set_position_function(self, callback) - self._set_position_function = callback or gui.set_position - return self -end - - ---- Clear grid nodes array. GUI nodes will be not deleted! --- If you want to delete GUI nodes, use dynamic_grid.nodes array before grid:clear --- @tparam DynamicGrid self @{DynamicGrid} --- @treturn druid.dynamic_grid Current grid instance -function DynamicGrid.clear(self) - self.nodes = {} - self:_update() - - self.on_clear:trigger(self:get_context()) - - return self -end - - -function DynamicGrid._add_node(self, node, index, origin_index) - self.nodes[index] = { - node = node, - pos = self:get_pos(index, node, origin_index), - size = helper.get_scaled_size(node), - pivot = const.PIVOTS[gui.get_pivot(node)] - } - - -- Add new item instantly in new pos - gui.set_parent(node, self.parent) - gui.set_position(node, self.nodes[index].pos) -end - - ---- Update grid inner state --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback --- @local -function DynamicGrid._update(self, is_instant) - self:_update_indexes() - self:_update_borders() - self:_update_pos(is_instant) -end - - ---- Update first and last indexes of grid nodes --- @tparam DynamicGrid self @{DynamicGrid} --- @local -function DynamicGrid._update_indexes(self) - self.first_index = nil - self.last_index = nil - for index in pairs(self.nodes) do - self.first_index = self.first_index or index - self.last_index = self.last_index or index - - self.first_index = math.min(self.first_index, index) - self.last_index = math.max(self.last_index, index) - end -end - - ---- Update grid content borders, recalculate min and max values --- @tparam DynamicGrid self @{DynamicGrid} --- @local -function DynamicGrid._update_borders(self) - if not self.first_index then - self.border = vmath.vector4(0) - return - end - - self.border = vmath.vector4(math.huge, -math.huge, -math.huge, math.huge) - - for index, node in pairs(self.nodes) do - local pos = node.pos - local size = node.size - local pivot = node.pivot - - local left = pos.x - size.x/2 - (size.x * pivot.x) - local right = pos.x + size.x/2 - (size.x * pivot.x) - local top = pos.y + size.y/2 - (size.y * pivot.y) - local bottom = pos.y - size.y/2 - (size.y * pivot.y) - - self.border.x = math.min(self.border.x, left) - self.border.y = math.max(self.border.y, top) - self.border.z = math.max(self.border.z, right) - self.border.w = math.min(self.border.w, bottom) - end -end - - ---- Update grid nodes position --- @tparam DynamicGrid self @{DynamicGrid} --- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback --- @local -function DynamicGrid._update_pos(self, is_instant) - for index, node in pairs(self.nodes) do - if is_instant then - gui.set_position(node.node, node.pos) - else - self._set_position_function(node.node, node.pos) - end - end - - self.on_update_positions:trigger(self:get_context()) -end - - -function DynamicGrid._get_next_node_pos(self, origin_node_index, new_node, place_side) - local node = self.nodes[origin_node_index] - - local new_node_size = helper.get_scaled_size(new_node) - local new_pivot = const.PIVOTS[gui.get_pivot(new_node)] - - local dist_x = (node.size.x/2 + new_node_size.x/2) * place_side.x - local dist_y = (node.size.y/2 + new_node_size.y/2) * place_side.y - local node_center_x = node.pos.x - node.size.x * node.pivot.x - local node_center_y = node.pos.y - node.size.y * node.pivot.y - - return vmath.vector3( - node_center_x + dist_x + new_node_size.x * new_pivot.x, - node_center_y - dist_y + new_node_size.y * new_pivot.y, - 0 - ) -end - - ---- Return side vector to correct node shifting -function DynamicGrid._get_side_vector(self, side, is_forward) - if side == const.SIDE.X then - return is_forward and SIDE_VECTORS.RIGHT or SIDE_VECTORS.LEFT - end - - if side == const.SIDE.Y then - return is_forward and SIDE_VECTORS.BOT or SIDE_VECTORS.TOP - end -end - - -return DynamicGrid diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua index 41507bd..b5db756 100644 --- a/druid/extended/hotkey.lua +++ b/druid/extended/hotkey.lua @@ -8,10 +8,10 @@ -- @alias druid.hotkey --- On hotkey released callback(self, argument) --- @tfield DruidEvent on_hotkey_pressed @{DruidEvent} +-- @tfield DruidEvent on_hotkey_pressed DruidEvent --- On hotkey released callback(self, argument) --- @tfield DruidEvent on_hotkey_released @{DruidEvent} +-- @tfield DruidEvent on_hotkey_released DruidEvent --- Visual node -- @tfield node node @@ -20,7 +20,7 @@ -- @tfield node|nil click_node --- Button component from click_node --- @tfield Button button @{Button} +-- @tfield Button button Button --- @@ -28,15 +28,21 @@ local helper = require("druid.helper") local component = require("druid.component") local Event = require("druid.event") -local Hotkey = component.create("hotkey") +---@class druid.hotkey: druid.base_component +---@field on_hotkey_pressed druid.event +---@field on_hotkey_released druid.event +---@field style table +---@field private _hotkeys table +---@field private _modificators table +local M = component.create("hotkey") ---- The @{Hotkey} constructor --- @tparam Hotkey self @{Hotkey} +--- The Hotkey constructor +-- @tparam Hotkey self Hotkey -- @tparam string[]|string keys The keys to be pressed for trigger callback. Should contains one key and any modificator keys -- @tparam function callback The callback function -- @tparam any|nil callback_argument The argument to pass into the callback function -function Hotkey.init(self, keys, callback, callback_argument) +function M:init(keys, callback, callback_argument) self.druid = self:get_druid() self._hotkeys = {} @@ -56,7 +62,7 @@ end -- or create your own style -- @table style -- @tfield string[] MODIFICATORS The list of action_id as hotkey modificators -function Hotkey.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.MODIFICATORS = style.MODIFICATORS or {} @@ -67,11 +73,11 @@ end --- Add hotkey for component callback --- @tparam Hotkey self @{Hotkey} +-- @tparam Hotkey self Hotkey -- @tparam string[]|hash[]|string|hash keys that have to be pressed before key pressed to activate -- @tparam any|nil callback_argument The argument to pass into the callback function -- @treturn Hotkey Current instance -function Hotkey.add_hotkey(self, keys, callback_argument) +function M:add_hotkey(keys, callback_argument) keys = keys or {} if type(keys) == "string" then keys = { keys } @@ -110,14 +116,14 @@ function Hotkey.add_hotkey(self, keys, callback_argument) end -function Hotkey.on_focus_gained(self) +function M:on_focus_gained() for k, v in pairs(self._modificators) do self._modificators[k] = false end end -function Hotkey.on_input(self, action_id, action) +function M:on_input(action_id, action) if not action_id or #self._hotkeys == 0 then return false end @@ -168,13 +174,13 @@ end --- If true, the callback will be triggered on action.repeated --- @tparam Hotkey self @{Hotkey} +-- @tparam Hotkey self Hotkey -- @tparam bool is_enabled_repeated The flag value -- @treturn Hotkey -function Hotkey.set_repeat(self, is_enabled_repeated) +function M:set_repeat(is_enabled_repeated) self._is_process_repeated = is_enabled_repeated return self end -return Hotkey +return M diff --git a/druid/extended/input.lua b/druid/extended/input.lua index db608e1..b4f29dd 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -10,25 +10,25 @@ -- @alias druid.input --- On input field select callback(self, input_instance) --- @tfield DruidEvent on_input_select @{DruidEvent} +-- @tfield DruidEvent on_input_select DruidEvent --- On input field unselect callback(self, input_text, input_instance) --- @tfield DruidEvent on_input_unselect @{DruidEvent} +-- @tfield DruidEvent on_input_unselect DruidEvent --- On input field text change callback(self, input_text) --- @tfield DruidEvent on_input_text @{DruidEvent} +-- @tfield DruidEvent on_input_text DruidEvent --- On input field text change to empty string callback(self, input_text) --- @tfield DruidEvent on_input_empty @{DruidEvent} +-- @tfield DruidEvent on_input_empty DruidEvent --- On input field text change to max length string callback(self, input_text) --- @tfield DruidEvent on_input_full @{DruidEvent} +-- @tfield DruidEvent on_input_full DruidEvent --- On trying user input with not allowed character callback(self, params, input_text) --- @tfield DruidEvent on_input_wrong @{DruidEvent} +-- @tfield DruidEvent on_input_wrong DruidEvent --- On cursor position change callback(self, cursor_index, start_index, end_index) --- @tfield DruidEvent on_select_cursor_change @{DruidEvent} +-- @tfield DruidEvent on_select_cursor_change DruidEvent --- The cursor index. The index of letter cursor after. Leftmost cursor - 0 -- @tfield number cursor_index @@ -40,7 +40,7 @@ -- @tfield number end_index --- Text component --- @tfield Text text @{Text} +-- @tfield Text text Text --- Current input value -- @tfield string value @@ -61,7 +61,7 @@ -- @tfield number marked_text_width --- Button component --- @tfield Button button @{Button} +-- @tfield Button button Button --- Is current input selected now -- @tfield boolean is_selected @@ -87,9 +87,19 @@ local component = require("druid.component") local utf8_lua = require("druid.system.utf8") local utf8 = utf8 or utf8_lua -local Input = component.create("input") +---@class druid.input: druid.base_component +---@field on_input_select druid.event +---@field on_input_unselect druid.event +---@field on_input_text druid.event +---@field on_input_empty druid.event +---@field on_input_full druid.event +---@field on_input_wrong druid.event +---@field on_select_cursor_change druid.event +---@field style table +---@field text druid.text +local M = component.create("input") -Input.ALLOWED_ACTIONS = { +M.ALLOWED_ACTIONS = { [const.ACTION_TOUCH] = true, [const.ACTION_TEXT] = true, [const.ACTION_MARKED_TEXT] = true, @@ -132,7 +142,7 @@ end -- @tfield function on_select (self, button_node) Callback on input field selecting -- @tfield function on_unselect (self, button_node) Callback on input field unselecting -- @tfield function on_input_wrong (self, button_node) Callback on wrong user input -function Input.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.IS_LONGTAP_ERASE = style.IS_LONGTAP_ERASE or false @@ -145,12 +155,12 @@ function Input.on_style_change(self, style) end ---- The @{Input} constructor --- @tparam Input self @{Input} +--- The Input constructor +-- @tparam Input self Input -- @tparam node click_node Node to enabled input component --- @tparam node|Text text_node Text node what will be changed on user input. You can pass text component instead of text node name @{Text} +-- @tparam node|Text text_node Text node what will be changed on user input. You can pass text component instead of text node name Text -- @tparam number|nil keyboard_type Gui keyboard type for input field -function Input.init(self, click_node, text_node, keyboard_type) +function M:init(click_node, text_node, keyboard_type) self.druid = self:get_druid() if type(text_node) == "table" then @@ -201,8 +211,8 @@ function Input.init(self, click_node, text_node, keyboard_type) end -function Input.on_input(self, action_id, action) - if not (action_id == nil or Input.ALLOWED_ACTIONS[action_id]) then +function M:on_input(action_id, action) + if not (action_id == nil or M.ALLOWED_ACTIONS[action_id]) then return false end @@ -299,17 +309,17 @@ function Input.on_input(self, action_id, action) end -function Input.on_focus_lost(self) +function M:on_focus_lost() self:unselect() end -function Input.on_input_interrupt(self) +function M:on_input_interrupt() --self:unselect() end -function Input.get_text_selected(self) +function M:get_text_selected() if self.start_index == self.end_index then return self.value end @@ -318,10 +328,10 @@ function Input.get_text_selected(self) end --- Replace selected text with new text --- @tparam Input self @{Input} +-- @tparam Input self Input -- @tparam string text The text to replace selected text -- @treturn string New input text -function Input.get_text_selected_replaced(self, text) +function M:get_text_selected_replaced(text) local left_part = utf8.sub(self.value, 1, self.start_index) local right_part = utf8.sub(self.value, self.end_index + 1, utf8.len(self.value)) local result = left_part .. text .. right_part @@ -336,9 +346,9 @@ end --- Set text for input field --- @tparam Input self @{Input} +-- @tparam Input self Input -- @tparam string input_text The string to apply for input field -function Input.set_text(self, input_text) +function M:set_text(input_text) input_text = tostring(input_text or "") -- Case when update with marked text @@ -385,8 +395,8 @@ end --- Select input field. It will show the keyboard and trigger on_select events --- @tparam Input self @{Input} -function Input.select(self) +-- @tparam Input self Input +function M:select() gui.reset_keyboard() self.marked_value = "" if not self.is_selected then @@ -410,8 +420,8 @@ end --- Remove selection from input. It will hide the keyboard and trigger on_unselect events --- @tparam Input self @{Input} -function Input.unselect(self) +-- @tparam Input self Input +function M:unselect() gui.reset_keyboard() self.marked_value = "" self.value = self.current_value @@ -429,9 +439,9 @@ end --- Return current input field text --- @tparam Input self @{Input} +-- @tparam Input self Input -- @treturn string The current input field text -function Input.get_text(self) +function M:get_text() if self.marked_value ~= "" then return self.value .. self.marked_value end @@ -442,10 +452,10 @@ end --- Set maximum length for input field. -- Pass nil to make input field unliminted (by default) --- @tparam Input self @{Input} +-- @tparam Input self Input -- @tparam number max_length Maximum length for input text field -- @treturn druid.input Current input instance -function Input.set_max_length(self, max_length) +function M:set_max_length(max_length) self.max_length = max_length return self end @@ -454,19 +464,19 @@ end --- Set allowed charaters for input field. -- See: https://defold.com/ref/stable/string/ -- ex: [%a%d] for alpha and numeric --- @tparam Input self @{Input} +-- @tparam Input self Input -- @tparam string characters Regulax exp. for validate user input -- @treturn druid.input Current input instance -function Input.set_allowed_characters(self, characters) +function M:set_allowed_characters(characters) self.allowed_characters = characters return self end --- Reset current input selection and return previous value --- @tparam Input self @{Input} +-- @tparam Input self Input -- @treturn druid.input Current input instance -function Input.reset_changes(self) +function M:reset_changes() self:set_text(self.previous_value) self:unselect() return self @@ -474,12 +484,12 @@ end --- Set cursor position in input field --- @tparam Input self @{Input} +-- @tparam Input self Input -- @tparam number|nil cursor_index Cursor index for cursor position, if nil - will be set to the end of the text -- @tparam number|nil start_index Start index for cursor position, if nil - will be set to the end of the text -- @tparam number|nil end_index End index for cursor position, if nil - will be set to the start_index -- @treturn druid.input Current input instance -function Input.select_cursor(self, cursor_index, start_index, end_index) +function M:select_cursor(cursor_index, start_index, end_index) local len = utf8.len(self.value) self.cursor_index = cursor_index or len @@ -497,11 +507,11 @@ end --- Change cursor position by delta --- @tparam Input self @{Input} +-- @tparam Input self Input -- @tparam number delta side for cursor position, -1 for left, 1 for right -- @tparam boolean is_add_to_selection (Shift key) -- @tparam boolean is_move_to_end (Ctrl key) -function Input.move_selection(self, delta, is_add_to_selection, is_move_to_end) +function M:move_selection(delta, is_add_to_selection, is_move_to_end) local len = utf8.len(self.value) local cursor_index = self.cursor_index local start_index, end_index -- if nil, the selection will be 0 at cursor position @@ -559,4 +569,4 @@ function Input.move_selection(self, delta, is_add_to_selection, is_move_to_end) end -return Input +return M diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index 6d38f83..03a6970 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -18,10 +18,10 @@ -- @alias druid.lang_text --- On change text callback --- @tfield DruidEvent on_change @{DruidEvent} +-- @tfield DruidEvent on_change DruidEvent --- The text component --- @tfield Text text @{Text} +-- @tfield Text text Text --- Text node -- @tfield node node @@ -32,15 +32,21 @@ local Event = require("druid.event") local settings = require("druid.system.settings") local component = require("druid.component") -local LangText = component.create("lang_text") +---@class druid.lang_text: druid.base_component +---@field text druid.text +---@field node node +---@field on_change druid.event +---@field private last_locale_args table +---@field private last_locale string +local M = component.create("lang_text") ---- The @{LangText} constructor --- @tparam LangText self @{LangText} +--- The LangText constructor +-- @tparam LangText self LangText -- @tparam string|node node The node_id or gui.get_node(node_id) -- @tparam string|nil locale_id Default locale id or text from node as default -- @tparam string|nil adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference -function LangText.init(self, node, locale_id, adjust_type) +function M:init(node, locale_id, adjust_type) self.druid = self:get_druid() self.text = self.druid:new_text(node, locale_id, adjust_type) self.node = self.text.node @@ -55,7 +61,7 @@ function LangText.init(self, node, locale_id, adjust_type) end -function LangText.on_language_change(self) +function M:on_language_change() if self.last_locale then self:translate(self.last_locale, unpack(self.last_locale_args)) end @@ -63,10 +69,10 @@ end --- Setup raw text to lang_text component --- @tparam LangText self @{LangText} +-- @tparam LangText self LangText -- @tparam string text Text for text node -- @treturn LangText Current instance -function LangText.set_to(self, text) +function M:set_to(text) self.last_locale = false self.text:set_to(text) self.on_change:trigger() @@ -76,7 +82,7 @@ end --- Translate the text by locale_id --- @tparam LangText self @{LangText} +-- @tparam LangText self LangText -- @tparam string locale_id Locale id -- @tparam string|nil a Optional param to string.format -- @tparam string|nil b Optional param to string.format @@ -86,7 +92,7 @@ end -- @tparam string|nil f Optional param to string.format -- @tparam string|nil g Optional param to string.format -- @treturn LangText Current instance -function LangText.translate(self, locale_id, a, b, c, d, e, f, g) +function M:translate(locale_id, a, b, c, d, e, f, g) self.last_locale_args = { a, b, c, d, e, f, g } self.last_locale = locale_id or self.last_locale self.text:set_to(settings.get_text(self.last_locale, a, b, c, d, e, f, g) or "") @@ -96,7 +102,7 @@ end --- Format string with new text params on localized text --- @tparam LangText self @{LangText} +-- @tparam LangText self LangText -- @tparam string|nil a Optional param to string.format -- @tparam string|nil b Optional param to string.format -- @tparam string|nil c Optional param to string.format @@ -105,11 +111,11 @@ end -- @tparam string|nil f Optional param to string.format -- @tparam string|nil g Optional param to string.format -- @treturn LangText Current instance -function LangText.format(self, a, b, c, d, e, f, g) +function M:format(a, b, c, d, e, f, g) self.last_locale_args = { a, b, c, d, e, f, g } self.text:set_to(settings.get_text(self.last_locale, a, b, c, d, e, f, g) or "") return self end -return LangText +return M diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index dea876b..e29eca3 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -1,45 +1,41 @@ --- Copyright (c) 2024 Maksim Tuprikov . This code is licensed under MIT license - ---- Layout management on node --- --- Example Link --- @module Layout --- @within BaseComponent --- @alias druid.layout - ---- Layout node --- @tfield node node - ---- Current layout mode --- @tfield string mode - ---- - local helper = require("druid.helper") local component = require("druid.component") --- @class druid.layout.row_data --- @tfield width number --- @tfield height number --- @tfield count number +---@alias druid.layout.mode +---| "horizontal" Elements are placed horizontally +---| "vertical" Elements are placed vertically +---| "horizontal_wrap" Elements are placed horizontally, but if the row width is greater than the parent width, the next row is created --- @class druid.layout.rows_data --- @tfield total_width number --- @tfield total_height number --- @tfield nodes_width table --- @tfield nodes_height table --- @tfield rows druid.layout.row_data[]> +---@class druid.layout.row_data +---@field width number +---@field height number +---@field count number --- @class druid.layout: druid.base_component +---@class druid.layout.rows_data +---@field total_width number +---@field total_height number +---@field nodes_width table +---@field nodes_height table +---@field rows druid.layout.row_data[]> + +---@class druid.layout: druid.base_component +---@field node node +---@field is_dirty boolean +---@field entities node[] +---@field margin {x: number, y: number} +---@field padding vector4 +---@field type string +---@field is_resize_width boolean +---@field is_resize_height boolean +---@field is_justify boolean local M = component.create("layout") --- The @{Layout} constructor --- @tparam Layout self @{Layout} --- @tparam node node Gui node --- @tparam string layout_type The layout mode (from const.LAYOUT_MODE) --- @tparam function|nil on_size_changed_callback The callback on window resize -function M.init(self, node, layout_type) - self.node = self:get_node(node) +---Layout component constructor +---@local +---@param node_or_node_id node|string +---@param layout_type druid.layout.mode +function M:init(node_or_node_id, layout_type) + self.node = self:get_node(node_or_node_id) self.is_dirty = true self.entities = {} @@ -51,6 +47,8 @@ function M.init(self, node, layout_type) self.is_justify = false end + +---@local function M:update() if not self.is_dirty then return @@ -60,11 +58,10 @@ function M:update() end --- @tparam Layout self @{Layout} --- @tparam number|nil margin_x --- @tparam number|nil margin_y --- @treturn druid.layout @{Layout} -function M.set_margin(self, margin_x, margin_y) +---@param margin_x number|nil +---@param margin_y number|nil +---@return druid.layout +function M:set_margin(margin_x, margin_y) self.margin.x = margin_x or self.margin.x self.margin.y = margin_y or self.margin.y self.is_dirty = true @@ -73,10 +70,9 @@ function M.set_margin(self, margin_x, margin_y) end --- @tparam Layout self @{Layout} --- @tparam vector4 padding The vector4 with padding values, where x - left, y - top, z - right, w - bottom --- @treturn druid.layout @{Layout} -function M.set_padding(self, padding) +---@param padding vector4 The vector4 with padding values, where x - left, y - top, z - right, w - bottom +---@return druid.layout +function M:set_padding(padding) self.padding = padding self.is_dirty = true @@ -84,19 +80,17 @@ function M.set_padding(self, padding) end --- @tparam Layout self @{Layout} --- @treturn druid.layout @{Layout} -function M.set_dirty(self) +---@return druid.layout +function M:set_dirty() self.is_dirty = true return self end --- @tparam Layout self @{Layout} --- @tparam boolean is_justify --- @treturn druid.layout @{Layout} -function M.set_justify(self, is_justify) +---@param is_justify boolean +---@return druid.layout +function M:set_justify(is_justify) self.is_justify = is_justify self.is_dirty = true @@ -104,10 +98,9 @@ function M.set_justify(self, is_justify) end --- @tparam Layout self @{Layout} --- @tparam string type The layout type: "horizontal", "vertical", "horizontal_wrap" --- @treturn druid.layout @{Layout} -function M.set_type(self, type) +---@param type string The layout type: "horizontal", "vertical", "horizontal_wrap" +---@return druid.layout +function M:set_type(type) self.type = type self.is_dirty = true @@ -115,11 +108,10 @@ function M.set_type(self, type) end --- @tparam Layout self @{Layout} --- @tparam boolean is_hug_width --- @tparam boolean is_hug_height --- @treturn druid.layout @{Layout} -function M.set_hug_content(self, is_hug_width, is_hug_height) +---@param is_hug_width boolean +---@param is_hug_height boolean +---@return druid.layout +function M:set_hug_content(is_hug_width, is_hug_height) self.is_resize_width = is_hug_width or false self.is_resize_height = is_hug_height or false self.is_dirty = true @@ -128,21 +120,20 @@ function M.set_hug_content(self, is_hug_width, is_hug_height) end --- @tparam Layout self @{Layout} --- @tparam string|node node_or_node_id --- @treturn druid.layout @{Layout} -function M.add(self, node_or_node_id) +---@param node_or_node_id node|string node_or_node_id +---@return druid.layout +function M:add(node_or_node_id) -- Acquire node from entity or by id local node = node_or_node_id if type(node_or_node_id) == "table" then assert(node_or_node_id.node, "The entity should have a node") node = node_or_node_id.node else - -- @cast node_or_node_id string|node + ---@cast node_or_node_id string|node node = self:get_node(node_or_node_id) end - -- @cast node node + ---@cast node node table.insert(self.entities, node) gui.set_parent(node, self.node) @@ -152,9 +143,8 @@ function M.add(self, node_or_node_id) end --- @tparam Layout self @{Layout} --- @treturn druid.layout @{Layout} -function M.refresh_layout(self) +---@return druid.layout +function M:refresh_layout() local layout_node = self.node local entities = self.entities @@ -289,9 +279,8 @@ function M.refresh_layout(self) end --- @tparam Layout self @{Layout} --- @treturn druid.layout @{Layout} -function M.clear_layout(self) +---@return druid.layout +function M:clear_layout() for index = #self.entities, 1, -1 do self.entities[index] = nil end @@ -302,10 +291,9 @@ function M.clear_layout(self) end --- @tparam node node --- @treturn number, number --- @local -function M.get_node_size(node) +---@param node node +---@return number, number +function M:get_node_size(node) if not gui.is_enabled(node, false) then return 0, 0 end @@ -323,11 +311,10 @@ function M.get_node_size(node) end --- @tparam Layout self @{Layout} --- Calculate rows data for layout. Contains total width, height and rows info (width, height, count of elements in row) --- @treturn druid.layout.rows_data --- @local -function M.calculate_rows_data(self) +---Calculate rows data for layout. Contains total width, height and rows info (width, height, count of elements in row) +---@local +---@return druid.layout.rows_data +function M:calculate_rows_data() local entities = self.entities local margin = self.margin local type = self.type @@ -353,7 +340,7 @@ function M.calculate_rows_data(self) -- Get node size if it's not calculated yet if not node_width or not node_height then - node_width, node_height = M.get_node_size(node) + node_width, node_height = self:get_node_size(node) rows_data.nodes_width[node] = node_width rows_data.nodes_height[node] = node_height end @@ -407,11 +394,10 @@ function M.calculate_rows_data(self) end --- @tparam node node --- @tparam number x --- @tparam number y --- @treturn node --- @local +---@param node node +---@param x number +---@param y number +---@return node function M:set_node_position(node, x, y) local position = gui.get_position(node) position.x = x diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index 163b017..ad31cce 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -20,7 +20,7 @@ -- @alias druid.progress --- On progress bar change callback(self, new_value) --- @tfield DruidEvent on_change @{DruidEvent} +-- @tfield DruidEvent on_change DruidEvent --- Progress bar fill node -- @tfield node node @@ -49,7 +49,13 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Progress = component.create("progress") +---@class druid.progress: druid.base_component +---@field node node +---@field on_change druid.event +---@field style table +---@field key string +---@field prop hash +local M = component.create("progress") local function check_steps(self, from, to, exactly) @@ -117,19 +123,19 @@ end -- @table style -- @tfield number|nil SPEED Progress bas fill rate. More -> faster. Default: 5 -- @tfield number|nil MIN_DELTA Minimum step to fill progress bar. Default: 0.005 -function Progress.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.SPEED = style.SPEED or 5 self.style.MIN_DELTA = style.MIN_DELTA or 0.005 end ---- The @{Progress} constructor --- @tparam Progress self @{Progress} +--- The Progress constructor +-- @tparam Progress self Progress -- @tparam string|node node Node name or GUI Node itself. -- @tparam string key Progress bar direction: const.SIDE.X or const.SIDE.Y -- @tparam number|nil init_value Initial value of progress bar. Default: 1 -function Progress.init(self, node, key, init_value) +function M:init(node, key, init_value) assert(key == const.SIDE.X or const.SIDE.Y, "Progress bar key should be 'x' or 'y'") self.key = key @@ -155,18 +161,18 @@ function Progress.init(self, node, key, init_value) end -function Progress.on_layout_change(self) +function M:on_layout_change() self:set_to(self.last_value) end -function Progress.on_remove(self) +function M:on_remove() -- Return default size gui.set_size(self.node, self.max_size) end -function Progress.update(self, dt) +function M:update(dt) if self.target then local prev_value = self.last_value local step = math.abs(self.last_value - self.target) * (self.style.SPEED*dt) @@ -187,51 +193,51 @@ end --- Fill a progress bar and stop progress animation --- @tparam Progress self @{Progress} -function Progress.fill(self) +-- @tparam Progress self Progress +function M:fill() set_bar_to(self, 1, true) end --- Empty a progress bar --- @tparam Progress self @{Progress} -function Progress.empty(self) +-- @tparam Progress self Progress +function M:empty() set_bar_to(self, 0, true) end --- Instant fill progress bar to value --- @tparam Progress self @{Progress} +-- @tparam Progress self Progress -- @tparam number to Progress bar value, from 0 to 1 -function Progress.set_to(self, to) +function M:set_to(to) to = helper.clamp(to, 0, 1) set_bar_to(self, to) end --- Return current progress bar value --- @tparam Progress self @{Progress} -function Progress.get(self) +-- @tparam Progress self Progress +function M:get() return self.last_value end --- Set points on progress bar to fire the callback --- @tparam Progress self @{Progress} +-- @tparam Progress self Progress -- @tparam number[] steps Array of progress bar values -- @tparam function callback Callback on intersect step value -- @usage progress:set_steps({0, 0.3, 0.6, 1}, function(self, step) end) -function Progress.set_steps(self, steps, callback) +function M:set_steps(steps, callback) self.steps = steps self.step_callback = callback end --- Start animation of a progress bar --- @tparam Progress self @{Progress} +-- @tparam Progress self Progress -- @tparam number to value between 0..1 -- @tparam function|nil callback Callback on animation ends -function Progress.to(self, to, callback) +function M:to(to, callback) to = helper.clamp(to, 0, 1) -- cause of float error local value = helper.round(to, 5) @@ -247,14 +253,14 @@ end --- Set progress bar max node size --- @tparam Progress self @{Progress} +-- @tparam Progress self Progress -- @tparam vector3 max_size The new node maximum (full) size --- @treturn Progress @{Progress} -function Progress.set_max_size(self, max_size) +-- @treturn Progress Progress +function M:set_max_size(max_size) self.max_size[self.key] = max_size[self.key] self:set_to(self.last_value) return self end -return Progress +return M diff --git a/druid/extended/slider.lua b/druid/extended/slider.lua index 7af97d3..6be43e4 100644 --- a/druid/extended/slider.lua +++ b/druid/extended/slider.lua @@ -8,7 +8,7 @@ -- @alias druid.slider --- On change value callback(self, value) --- @tfield DruidEvent on_change_value @{DruidEvent} +-- @tfield DruidEvent on_change_value DruidEvent --- Slider pin node -- @tfield node node @@ -42,7 +42,19 @@ local helper = require("druid.helper") local const = require("druid.const") local component = require("druid.component") -local Slider = component.create("slider", const.PRIORITY_INPUT_HIGH) +---@class druid.slider: druid.base_component +---@field node node +---@field on_change_value druid.event +---@field style table +---@field private start_pos vector3 +---@field private pos vector3 +---@field private target_pos vector3 +---@field private end_pos vector3 +---@field private dist vector3 +---@field private is_drag boolean +---@field private value number +---@field private steps number[] +local M = component.create("slider", const.PRIORITY_INPUT_HIGH) local function on_change_value(self) @@ -56,12 +68,12 @@ local function set_position(self, value) end ---- The @{Slider} constructor --- @tparam Slider self @{Slider} +--- The Slider constructor +-- @tparam Slider self Slider -- @tparam node node Gui pin node -- @tparam vector3 end_pos The end position of slider -- @tparam function|nil callback On slider change callback -function Slider.init(self, node, end_pos, callback) +function M:init(node, end_pos, callback) self.node = self:get_node(node) self.start_pos = gui.get_position(self.node) @@ -81,18 +93,18 @@ function Slider.init(self, node, end_pos, callback) end -function Slider.on_layout_change(self) +function M:on_layout_change() self:set(self.value) end -function Slider.on_remove(self) +function M:on_remove() -- Return pin to start position gui.set_position(self.node, self.start_pos) end -function Slider.on_window_resized(self) +function M:on_window_resized() local x_koef, y_koef = helper.get_screen_aspect_koef() self._x_koef = x_koef self._y_koef = y_koef @@ -100,7 +112,7 @@ function Slider.on_window_resized(self) end -function Slider.on_input(self, action_id, action) +function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH then return false end @@ -185,10 +197,10 @@ end --- Set value for slider --- @tparam Slider self @{Slider} +-- @tparam Slider self Slider -- @tparam number value Value from 0 to 1 -- @tparam boolean|nil is_silent Don't trigger event if true -function Slider.set(self, value, is_silent) +function M:set(value, is_silent) value = helper.clamp(value, 0, 1) set_position(self, value) self.value = value @@ -200,11 +212,11 @@ end --- Set slider steps. Pin node will -- apply closest step position --- @tparam Slider self @{Slider} +-- @tparam Slider self Slider -- @tparam number[] steps Array of steps -- @usage slider:set_steps({0, 0.2, 0.6, 1}) --- @treturn Slider @{Slider} -function Slider.set_steps(self, steps) +-- @treturn Slider Slider +function M:set_steps(steps) self.steps = steps return self end @@ -214,29 +226,29 @@ end -- User can touch any place of node, pin instantly will -- move at this position and node drag will start. -- This function require the Defold version 1.3.0+ --- @tparam Slider self @{Slider} +-- @tparam Slider self Slider -- @tparam node|string|nil input_node --- @treturn Slider @{Slider} -function Slider.set_input_node(self, input_node) +-- @treturn Slider Slider +function M:set_input_node(input_node) self._input_node = self:get_node(input_node) return self end --- Set Slider input enabled or disabled --- @tparam Slider self @{Slider} +-- @tparam Slider self Slider -- @tparam boolean is_enabled -function Slider.set_enabled(self, is_enabled) +function M:set_enabled(is_enabled) self._is_enabled = is_enabled end --- Check if Slider component is enabled --- @tparam Slider self @{Slider} +-- @tparam Slider self Slider -- @treturn boolean -function Slider.is_enabled(self) +function M:is_enabled() return self._is_enabled end -return Slider +return M diff --git a/druid/extended/swipe.lua b/druid/extended/swipe.lua index 110d9f4..c153ce7 100644 --- a/druid/extended/swipe.lua +++ b/druid/extended/swipe.lua @@ -16,7 +16,7 @@ -- @tparam node|nil click_zone --- Trigger on swipe event(self, swipe_side, dist, delta_time) --- @tfield DruidEvent on_swipe) @{DruidEvent} +-- @tfield DruidEvent on_swipe) DruidEvent --- @@ -25,7 +25,17 @@ local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") -local Swipe = component.create("swipe") +---@class druid.swipe: druid.base_component +---@field node node +---@field on_swipe druid.event +---@field style table +---@field click_zone node +---@field private _trigger_on_move boolean +---@field private _swipe_start_time number +---@field private _start_pos vector3 +---@field private _is_enabled boolean +---@field private _is_mobile boolean +local M = component.create("swipe") local function start_swipe(self, action) @@ -36,7 +46,7 @@ end local function reset_swipe(self, action) - self._swipe_start_time = false + self._swipe_start_time = 0 end @@ -77,7 +87,7 @@ end -- @tfield number|nil SWIPE_TIME Maximum time for swipe trigger. Default: 0.4 -- @tfield number|nil SWIPE_THRESHOLD Minimum distance for swipe trigger. Default: 50 -- @tfield boolean|nil SWIPE_TRIGGER_ON_MOVE If true, trigger on swipe moving, not only release action. Default: false -function Swipe.on_style_change(self, style) +function M:on_style_change(style) self.style = {} self.style.SWIPE_TIME = style.SWIPE_TIME or 0.4 self.style.SWIPE_THRESHOLD = style.SWIPE_THRESHOLD or 50 @@ -85,15 +95,19 @@ function Swipe.on_style_change(self, style) end ---- The @{Swipe} constructor --- @tparam Swipe self @{Swipe} +--- The Swipe constructor +-- @tparam Swipe self Swipe -- @tparam node node Gui node -- @tparam function on_swipe_callback Swipe callback for on_swipe_end event -function Swipe.init(self, node, on_swipe_callback) - self._trigger_on_move = self.style.SWIPE_TRIGGER_ON_MOVE - self.node = self:get_node(node) - self._swipe_start_time = false +---Swipe constructor +---@param node_or_node_id node|string +---@param on_swipe_callback function +function M:init(node_or_node_id, on_swipe_callback) + self._trigger_on_move = self.style.SWIPE_TRIGGER_ON_MOVE + self.node = self:get_node(node_or_node_id) + + self._swipe_start_time = 0 self._start_pos = vmath.vector3(0) self.click_zone = nil @@ -101,7 +115,7 @@ function Swipe.init(self, node, on_swipe_callback) end -function Swipe.on_late_init(self) +function M:on_late_init() if not self.click_zone and const.IS_STENCIL_CHECK then local stencil_node = helper.get_closest_stencil_node(self.node) if stencil_node then @@ -111,7 +125,7 @@ function Swipe.on_late_init(self) end -function Swipe.on_input(self, action_id, action) +function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH then return false end @@ -126,7 +140,7 @@ function Swipe.on_input(self, action_id, action) return false end - if self._swipe_start_time and (self._trigger_on_move or action.released) then + if self._swipe_start_time ~= 0 and (self._trigger_on_move or action.released) then check_swipe(self, action) end @@ -142,18 +156,18 @@ function Swipe.on_input(self, action_id, action) end -function Swipe.on_input_interrupt(self) +function M:on_input_interrupt() reset_swipe(self) end --- Strict swipe click area. Useful for -- restrict events outside stencil node --- @tparam Swipe self @{Swipe} +-- @tparam Swipe self Swipe -- @tparam node|string|nil zone Gui node -function Swipe.set_click_zone(self, zone) +function M:set_click_zone(zone) self.click_zone = self:get_node(zone) end -return Swipe +return M diff --git a/druid/extended/timer.lua b/druid/extended/timer.lua index 235f4be..8bd9ae3 100644 --- a/druid/extended/timer.lua +++ b/druid/extended/timer.lua @@ -1,40 +1,18 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle GUI timers. --- Timer updating by game delta time. If game is not focused - --- timer will be not updated. --- @module Timer --- @within BaseComponent --- @alias druid.timer - ---- On timer tick. Fire every second callback(self, value) --- @tfield DruidEvent on_tick @{DruidEvent} - ---- On timer change enabled state callback(self, is_enabled) --- @tfield DruidEvent on_set_enabled @{DruidEvent} - ---- On timer end callback --- @tfield DruidEvent on_timer_end(self, Timer) @{DruidEvent} - ---- Trigger node --- @tfield node node - ---- Initial timer value --- @tfield number from - ---- Target timer value --- @tfield number target - ---- Current timer value --- @tfield number value - ---- - local Event = require("druid.event") local helper = require("druid.helper") local component = require("druid.component") -local Timer = component.create("timer") +---@class druid.timer: druid.base_component +---@field on_tick druid.event +---@field on_set_enabled druid.event +---@field on_timer_end druid.event +---@field style table +---@field node node +---@field from number +---@field target number +---@field value number +---@field is_on boolean|nil +local M = component.create("timer") local function second_string_min(sec) @@ -44,13 +22,12 @@ local function second_string_min(sec) end ---- The @{Timer} constructor --- @tparam Timer self @{Timer} --- @tparam node node Gui text node --- @tparam number|nil seconds_from Start timer value in seconds --- @tparam number|nil seconds_to End timer value in seconds --- @tparam function|nil callback Function on timer end -function Timer.init(self, node, seconds_from, seconds_to, callback) +---The Timer constructor +---@param node node Gui text node +---@param seconds_from number|nil Start timer value in seconds +---@param seconds_to number|nil End timer value in seconds +---@param callback function|nil Function on timer end +function M:init(node, seconds_from, seconds_to, callback) self.node = self:get_node(node) seconds_to = math.max(seconds_to or 0, 0) @@ -73,7 +50,7 @@ function Timer.init(self, node, seconds_from, seconds_to, callback) end -function Timer.update(self, dt) +function M:update(dt) if not self.is_on then return end @@ -96,42 +73,47 @@ function Timer.update(self, dt) end -function Timer.on_layout_change(self) +function M:on_layout_change() self:set_to(self.last_value) end ---- Set text to text field --- @tparam Timer self @{Timer} --- @tparam number set_to Value in seconds -function Timer.set_to(self, set_to) +---@param self druid.timer +---@param set_to number Value in seconds +---@return druid.timer self +function M:set_to(set_to) self.last_value = set_to gui.set_text(self.node, second_string_min(set_to)) + + return self end ---- Called when update --- @tparam Timer self @{Timer} --- @tparam boolean|nil is_on Timer enable state -function Timer.set_state(self, is_on) +---@param self druid.timer +---@param is_on boolean|nil Timer enable state +---@return druid.timer self +function M:set_state(is_on) self.is_on = is_on - self.on_set_enabled:trigger(self:get_context(), is_on) + + return self end ---- Set time interval --- @tparam Timer self @{Timer} --- @tparam number from Start time in seconds --- @tparam number to Target time in seconds -function Timer.set_interval(self, from, to) +---@param self druid.timer +---@param from number Start time in seconds +---@param to number Target time in seconds +---@return druid.timer self +function M:set_interval(from, to) self.from = from self.value = from self.temp = 0 self.target = to self:set_state(true) self:set_to(from) + + return self end -return Timer +return M diff --git a/druid/helper.lua b/druid/helper.lua index 827e9cf..1cf3c38 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -1,15 +1,13 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Helper module with various usefull GUI functions. --- @usage --- local helper = require("druid.helper") --- helper.centrate_nodes(0, node_1, node_2) --- @module Helper --- @alias druid.helper +--- Druid Helper module local const = require("druid.const") +local gui_get_node = gui.get_node + + +---@class druid.system.helper local M = {} + local POSITION_X = hash("position.x") local SCALE_X = hash("scale.x") local SIZE_X = hash("size.x") @@ -46,39 +44,35 @@ local function get_width(node) end ---- Center two nodes. --- Nodes will be center around 0 x position --- text_node will be first (at left side) --- @function helper.centrate_text_with_icon --- @tparam text|nil text_node Gui text node --- @tparam box|nil icon_node Gui box node --- @tparam number margin Offset between nodes --- @local +---Center two nodes. +--Nodes will be center around 0 x position +--text_node will be first (at left side) +---@param text_node node|nil Gui text node +---@param icon_node node|nil Gui box node +---@param margin number Offset between nodes +---@local function M.centrate_text_with_icon(text_node, icon_node, margin) return M.centrate_nodes(margin, text_node, icon_node) end - ---- Center two nodes. --- Nodes will be center around 0 x position --- icon_node will be first (at left side) --- @function helper.centrate_icon_with_text --- @tparam box|nil icon_node Gui box node --- @tparam text|nil text_node Gui text node --- @tparam number|nil margin Offset between nodes --- @local +---Center two nodes. +--Nodes will be center around 0 x position +--icon_node will be first (at left side) +---@param icon_node node|nil Gui box node +---@param text_node node|nil Gui text node +---@param margin number|nil Offset between nodes +---@local function M.centrate_icon_with_text(icon_node, text_node, margin) return M.centrate_nodes(margin, icon_node, text_node) end ---- Centerate nodes by x position with margin. --- --- This functions calculate total width of nodes and set position for each node. --- The centrate will be around 0 x position. --- @function helper.centrate_nodes --- @tparam number|nil margin Offset between nodes --- @param ... Gui nodes +---Centerate nodes by x position with margin. +--- +---This functions calculate total width of nodes and set position for each node. +---The centrate will be around 0 x position. +---@param margin number|nil Offset between nodes +---@param ... node Nodes to centrate function M.centrate_nodes(margin, ...) margin = margin or 0 @@ -113,10 +107,33 @@ function M.centrate_nodes(margin, ...) end ---- Get current screen stretch multiplier for each side --- @function helper.get_screen_aspect_koef --- @treturn number stretch_x --- @treturn number stretch_y +---@param node_id string|node +---@param template string|nil @Full Path to the template +---@param nodes table|nil @Nodes what created with gui.clone_tree +---@return node +function M.get_node(node_id, template, nodes) + if type(node_id) ~= "string" then + -- Assume it's already node from gui.get_node + return node_id + end + + -- If template is set, then add it to the node_id + if template and #template > 0 then + node_id = template .. "/" .. node_id + end + + -- If nodes is set, then try to find node in it + if nodes then + return nodes[node_id] + end + + return gui_get_node(node_id) +end + + +---Get current screen stretch multiplier for each side +---@return number stretch_x +---@return number stretch_y function M.get_screen_aspect_koef() local window_x, window_y = window.get_size() local stretch_x = window_x / gui.get_width() @@ -126,10 +143,8 @@ function M.get_screen_aspect_koef() end ---- Get current GUI scale for each side --- @function helper.get_gui_scale --- @treturn number scale_x --- @treturn number scale_y +---Get current GUI scale for each side +---@return number scale_x function M.get_gui_scale() local window_x, window_y = window.get_size() return math.min(window_x / gui.get_width(), @@ -137,12 +152,11 @@ function M.get_gui_scale() end ---- Move value from current to target value with step amount --- @function helper.step --- @tparam number current Current value --- @tparam number target Target value --- @tparam number step Step amount --- @treturn number New value +---Move value from current to target value with step amount +---@param current number Current value +---@param target number Target value +---@param step number Step amount +---@return number New value function M.step(current, target, step) if current < target then return math.min(current + step, target) @@ -152,12 +166,11 @@ function M.step(current, target, step) end ---- Clamp value between min and max --- @function helper.clamp --- @tparam number a Value --- @tparam number min Min value --- @tparam number max Max value --- @treturn number Clamped value +---Clamp value between min and max +---@param a number Value +---@param min number Min value +---@param max number Max value +---@return number value Clamped value function M.clamp(a, min, max) if min > max then min, max = max, min @@ -173,22 +186,20 @@ function M.clamp(a, min, max) end ---- Calculate distance between two points --- @function helper.distance --- @tparam number x1 First point x --- @tparam number y1 First point y --- @tparam number x2 Second point x --- @tparam number y2 Second point y --- @treturn number Distance +---Calculate distance between two points +---@param x1 number First point x +---@param y1 number First point y +---@param x2 number Second point x +---@param y2 number Second point y +---@return number Distance function M.distance(x1, y1, x2, y2) return math.sqrt((x2 - x1) ^ 2 + (y2 - y1) ^ 2) end ---- Return sign of value (-1, 0, 1) --- @function helper.sign --- @tparam number val Value --- @treturn number Sign +---Return sign of value +---@param val number Value +---@return number sign Sign of value, -1, 0 or 1 function M.sign(val) if val == 0 then return 0 @@ -198,47 +209,42 @@ function M.sign(val) end ---- Round number to specified decimal places --- @function helper.round --- @tparam number num Number --- @tparam number|nil num_decimal_places Decimal places --- @treturn number Rounded number +---Round number to specified decimal places +---@param num number Number +---@param num_decimal_places number|nil Decimal places +---@return number value Rounded number function M.round(num, num_decimal_places) local mult = 10^(num_decimal_places or 0) return math.floor(num * mult + 0.5) / mult end ---- Lerp between two values --- @function helper.lerp --- @tparam number a First value --- @tparam number b Second value --- @tparam number t Lerp amount --- @treturn number Lerped value +---Lerp between two values +---@param a number First value +---@param b number Second value +---@param t number Lerp amount +---@return number value Lerped value function M.lerp(a, b, t) return a + (b - a) * t end ---- Check if value is in array and return index of it --- @function helper.contains --- @tparam table t Array --- @param value Value --- @treturn number|nil Index of value or nil -function M.contains(t, value) - for i = 1, #t do - if t[i] == value then - return i +---Check if value contains in array +---@param array any[] Array to check +---@param value any Value +function M.contains(array, value) + for index = 1, #array do + if array[index] == value then + return index end end return nil end ---- Make a copy table with all nested tables --- @function helper.deepcopy --- @tparam table orig_table Original table --- @treturn table Copy of original table +---Make a copy table with all nested tables +---@param orig_table table Original table +---@return table Copy of original table function M.deepcopy(orig_table) local orig_type = type(orig_table) local copy @@ -254,11 +260,10 @@ function M.deepcopy(orig_table) end ---- Add all elements from source array to the target array --- @function helper.add_array --- @tparam any[] target Array to put elements from source --- @tparam any[]|nil source The source array to get elements from --- @treturn any[] The target array +---Add all elements from source array to the target array +---@param target any[] Array to put elements from source +---@param source any[]|nil The source array to get elements from +---@return any[] The target array function M.add_array(target, source) assert(target) @@ -274,13 +279,12 @@ function M.add_array(target, source) end ---- Make a check with gui.pick_node, but with additional node_click_area check. --- @function helper.pick_node --- @tparam node node --- @tparam number x --- @tparam number y --- @tparam node|nil node_click_area --- @local +---Make a check with gui.pick_node, but with additional node_click_area check. +---@param node node +---@param x number +---@param y number +---@param node_click_area node|nil +---@local function M.pick_node(node, x, y, node_click_area) local is_pick = gui.pick_node(node, x, y) @@ -291,20 +295,19 @@ function M.pick_node(node, x, y, node_click_area) return is_pick end ---- Get node size adjusted by scale --- @function helper.get_scaled_size --- @tparam node node GUI node --- @treturn vector3 Scaled size + +---Get size of node with scale multiplier +---@param node node GUI node +---@treturn vector3 Scaled size function M.get_scaled_size(node) return vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node)) end ---- Get cumulative parent's node scale --- @function helper.get_scene_scale --- @tparam node node Gui node --- @tparam boolean|nil include_passed_node_scale True if add current node scale to result --- @treturn vector3 The scene node scale +---Get cumulative parent's node scale +---@param node node Gui node +---@param include_passed_node_scale boolean|nil True if add current node scale to result +---@return vector3 The scene node scale function M.get_scene_scale(node, include_passed_node_scale) local scale = include_passed_node_scale and gui.get_scale(node) or vmath.vector3(1) local parent = gui.get_parent(node) @@ -317,10 +320,9 @@ function M.get_scene_scale(node, include_passed_node_scale) end ---- Return closest non inverted clipping parent node for given node --- @function helper.get_closest_stencil_node --- @tparam node node GUI node --- @treturn node|nil The closest stencil node or nil +---Return closest non inverted clipping parent node for given node +---@param node node GUI node +---@return node|nil stencil_node The closest stencil node or nil function M.get_closest_stencil_node(node) if not node then return nil @@ -348,8 +350,15 @@ end -- @function helper.get_pivot_offset -- @tparam number pivot The gui.PIVOT_* constant -- @treturn vector3 Vector offset with [-0.5..0.5] values -function M.get_pivot_offset(pivot) - return const.PIVOTS[pivot] + +---Get pivot offset for given pivot or node +---@param pivot_or_node number|node GUI pivot or node +---@return vector3 offset The pivot offset +function M.get_pivot_offset(pivot_or_node) + if type(pivot_or_node) == "number" then + return const.PIVOTS[pivot_or_node] + end + return const.PIVOTS[gui.get_pivot(pivot_or_node)] end diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 03c722d..0f74a66 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -1,5 +1,3 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - local const = require("druid.const") local settings = require("druid.system.settings") diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index 56de63f..3c4837a 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -10,11 +10,11 @@ -- -- Please review the following API pages: -- --- @{Helper} - A useful set of functions for working with GUI nodes, such as centering nodes, get GUI scale ratio, etc +-- Helper - A useful set of functions for working with GUI nodes, such as centering nodes, get GUI scale ratio, etc -- --- @{DruidEvent} - The core event system in Druid. Learn how to subscribe to any event in every Druid component. +-- DruidEvent - The core event system in Druid. Learn how to subscribe to any event in every Druid component. -- --- @{BaseComponent} - The parent class of all Druid components. You can find all default component methods there. +-- BaseComponent - The parent class of all Druid components. You can find all default component methods there. -- -- # Tech Info # -- @@ -89,7 +89,21 @@ local back_handler = require("druid.base.back_handler") -- local lang_text = require("druid.extended.lang_text") -- local timer_component = require("druid.extended.timer") -local DruidInstance = {} +---@class druid_instance +---@field components_all druid.base_component[] All created components +---@field components_interest table All components sorted by interest +---@field url url +---@field private _context table Druid context +---@field private _style table Druid style table +---@field private _deleted boolean +---@field private _is_late_remove_enabled boolean +---@field private _late_remove druid.base_component[] +---@field private _input_blacklist druid.base_component[]|nil +---@field private _input_whitelist druid.base_component[]|nil +---@field private _input_inited boolean +---@field private _late_init_timer_id number +---@field private _input_components druid.base_component[] +local M = {} local MSG_ADD_FOCUS = hash("acquire_input_focus") local MSG_REMOVE_FOCUS = hash("release_input_focus") @@ -219,17 +233,15 @@ end --- Druid class constructor --- @tparam DruidInstance self -- @tparam table context Druid context. Usually it is self of gui script -- @tparam table style Druid style table -- @local -function DruidInstance.initialize(self, context, style) +function M:initialize(context, style) self._context = context self._style = style or settings.default_style self._deleted = false self._is_late_remove_enabled = false self._late_remove = {} - self._is_debug = false self.url = msg.url() self._input_blacklist = nil @@ -244,11 +256,10 @@ end -- Create new component. --- @tparam DruidInstance self -- @tparam BaseComponent component Component module -- @tparam any ... Other component params to pass it to component:init function -- @treturn BaseComponent Component instance -function DruidInstance.new(self, component, ...) +function M:new(component, ...) local instance = create(self, component) if instance.init then @@ -263,8 +274,7 @@ end --- Call this in gui_script final function. --- @tparam DruidInstance self -function DruidInstance.final(self) +function M:final() local components = self.components_all for i = #components, 1, -1 do @@ -282,10 +292,9 @@ end --- Remove created component from Druid instance. -- -- Component `on_remove` function will be invoked, if exist. --- @tparam DruidInstance self -- @tparam BaseComponent component Component instance -- @treturn boolean True if component was removed -function DruidInstance.remove(self, component) +function M:remove(component) if self._is_late_remove_enabled then table.insert(self._late_remove, component) return false @@ -334,9 +343,8 @@ end --- Druid late update function called after initialization and before the regular update step -- This function is used to check the GUI state and perform actions after all components and nodes have been created. -- An example use case is performing an auto stencil check in the GUI hierarchy for input components. --- @tparam DruidInstance self -- @local -function DruidInstance.late_init(self) +function M:late_init() local late_init_components = self.components_interest[base_component.ON_LATE_INIT] while late_init_components[1] do late_init_components[1]:on_late_init() @@ -353,9 +361,8 @@ end --- Call this in gui_script update function. -- -- Used for: scroll, progress, timer components --- @tparam DruidInstance self -- @tparam number dt Delta time -function DruidInstance.update(self, dt) +function M:update(dt) self._is_late_remove_enabled = true local components = self.components_interest[base_component.ON_UPDATE] @@ -371,11 +378,10 @@ end --- Call this in gui_script on_input function. -- -- Used for almost all components --- @tparam DruidInstance self -- @tparam hash action_id Action_id from on_input -- @tparam table action Action from on_input -- @treturn boolean The boolean value is input was consumed -function DruidInstance.on_input(self, action_id, action) +function M:on_input(action_id, action) self._is_late_remove_enabled = true local components = self.components_interest[base_component.ON_INPUT] @@ -392,11 +398,10 @@ end --- Call this in gui_script on_message function. -- -- Used for special actions. See SPECIFIC_UI_MESSAGES table --- @tparam DruidInstance self -- @tparam hash message_id Message_id from on_message -- @tparam table message Message from on_message -- @tparam url sender Sender from on_message -function DruidInstance.on_message(self, message_id, message, sender) +function M:on_message(message_id, message, sender) local specific_ui_message = base_component.SPECIFIC_UI_MESSAGES[message_id] if specific_ui_message == base_component.ON_MESSAGE_INPUT then @@ -431,9 +436,8 @@ end --- Calls the on_focus_lost function in all related components -- This one called by on_window_callback by global window listener --- @tparam DruidInstance self -- @local -function DruidInstance.on_focus_lost(self) +function M:on_focus_lost() local components = self.components_interest[base_component.ON_FOCUS_LOST] for i = 1, #components do components[i]:on_focus_lost() @@ -443,9 +447,8 @@ end --- Calls the on_focus_gained function in all related components -- This one called by on_window_callback by global window listener --- @tparam DruidInstance self -- @local -function DruidInstance.on_focus_gained(self) +function M:on_focus_gained() local components = self.components_interest[base_component.ON_FOCUS_GAINED] for i = 1, #components do components[i]:on_focus_gained() @@ -456,9 +459,8 @@ end --- Calls the on_language_change function in all related components -- This one called by global druid.on_language_change, but can be -- call manualy to update all translations --- @tparam DruidInstance self -- @local -function DruidInstance.on_language_change(self) +function M:on_language_change() local components = self.components_interest[base_component.ON_LANGUAGE_CHANGE] for i = 1, #components do components[i]:on_language_change() @@ -470,10 +472,9 @@ end -- -- If whitelist is not empty and component not contains in this list, -- component will be not processed on input step --- @tparam DruidInstance self -- @tparam table|BaseComponent|nil whitelist_components The array of component to whitelist --- @treturn self @{DruidInstance} -function DruidInstance.set_whitelist(self, whitelist_components) +-- @treturn self DruidInstance +function M:set_whitelist(whitelist_components) if whitelist_components and whitelist_components._component then whitelist_components = { whitelist_components } end @@ -491,11 +492,10 @@ end --- Set blacklist components for input processing. -- -- If blacklist is not empty and component contains in this list, --- component will be not processed on input step --- @tparam DruidInstance self @{DruidInstance} +-- component will be not processed on input step DruidInstance -- @tparam table|BaseComponent|nil blacklist_components The array of component to blacklist --- @treturn self @{DruidInstance} -function DruidInstance.set_blacklist(self, blacklist_components) +-- @treturn self DruidInstance +function M:set_blacklist(blacklist_components) if blacklist_components and blacklist_components._component then blacklist_components = { blacklist_components } end @@ -510,35 +510,9 @@ function DruidInstance.set_blacklist(self, blacklist_components) end ---- Set debug mode for current Druid instance. It's enable debug log messages --- @tparam DruidInstance self @{DruidInstance} --- @tparam boolean|nil is_debug --- @treturn self @{DruidInstance} +--- Remove all components on late remove step DruidInstance -- @local -function DruidInstance.set_debug(self, is_debug) - self._is_debug = is_debug - return self -end - - ---- Log message, if is_debug mode is enabled --- @tparam DruidInstance self @{DruidInstance} --- @tparam string message --- @tparam table|nil context --- @local -function DruidInstance.log_message(self, message, context) - if not self._is_debug then - return - end - - print("[Druid]:", message, helper.table_to_string(context)) -end - - ---- Remove all components on late remove step --- @tparam DruidInstance self @{DruidInstance} --- @local -function DruidInstance._clear_late_remove(self) +function M:_clear_late_remove() if #self._late_remove == 0 then return end @@ -550,229 +524,188 @@ function DruidInstance._clear_late_remove(self) end ---- Create @{Button} component --- @tparam DruidInstance self --- @tparam string|node node The node_id or gui.get_node(node_id) --- @tparam function|nil callback Button callback --- @tparam any|nil params Button callback params --- @tparam node|string|nil anim_node Button anim node (node, if not provided) --- @treturn Button @{Button} component -function DruidInstance.new_button(self, node, callback, params, anim_node) - return DruidInstance.new(self, button, node, callback, params, anim_node) +--- Create Button component +---@param node string|node The node_id or gui.get_node(node_id) +---@param callback function|nil Button callback +---@param params any|nil Button callback params +---@param anim_node node|string|nil Button anim node (node, if not provided) +---@return druid.button Button component +function M:new_button(node, callback, params, anim_node) + return self:new(button, node, callback, params, anim_node) end ---- Create @{Blocker} component --- @tparam DruidInstance self --- @tparam string|node node The node_id or gui.get_node(node_id) --- @treturn Blocker @{Blocker} component -function DruidInstance.new_blocker(self, node) - return DruidInstance.new(self, blocker, node) +--- Create Blocker component +---@param node string|node The node_id or gui.get_node(node_id) +---@return druid.blocker Blocker component +function M:new_blocker(node) + return self:new(blocker, node) end ---- Create @{BackHandler} component --- @tparam DruidInstance self --- @tparam function|nil callback @The callback(self, custom_args) to call on back event --- @tparam any|nil params Callback argument --- @treturn BackHandler @{BackHandler} component -function DruidInstance.new_back_handler(self, callback, params) - return DruidInstance.new(self, back_handler, callback, params) +--- Create BackHandler component +---@param callback function|nil The callback(self, custom_args) to call on back event +---@param params any|nil Callback argument +---@return druid.back_handler BackHandler component +function M:new_back_handler(callback, params) + return self:new(back_handler, callback, params) end ---- Create @{Hover} component --- @tparam DruidInstance self --- @tparam string|node node The node_id or gui.get_node(node_id) --- @tparam function|nil on_hover_callback Hover callback --- @tparam function|nil on_mouse_hover_callback Mouse hover callback --- @treturn Hover @{Hover} component -function DruidInstance.new_hover(self, node, on_hover_callback, on_mouse_hover_callback) - return DruidInstance.new(self, hover, node, on_hover_callback, on_mouse_hover_callback) +--- Create Hover component +---@param node string|node The node_id or gui.get_node(node_id) +---@param on_hover_callback function|nil Hover callback +---@param on_mouse_hover_callback function|nil Mouse hover callback +---@return druid.hover Hover component +function M:new_hover(node, on_hover_callback, on_mouse_hover_callback) + return self:new(hover, node, on_hover_callback, on_mouse_hover_callback) end ---- Create @{Text} component --- @tparam DruidInstance self --- @tparam string|node node The node_id or gui.get_node(node_id) --- @tparam string|nil value Initial text. Default value is node text from GUI scene. --- @tparam boolean|nil no_adjust If true, text will be not auto-adjust size --- @treturn Text @{Text} component -function DruidInstance.new_text(self, node, value, no_adjust) - return DruidInstance.new(self, text, node, value, no_adjust) +--- Create Text component +---@param node string|node The node_id or gui.get_node(node_id) +---@param value string|nil Initial text. Default value is node text from GUI scene. +---@param no_adjust boolean|nil If true, text will be not auto-adjust size +---@return druid.text Text component +function M:new_text(node, value, no_adjust) + return self:new(text, node, value, no_adjust) end ---- Create @{StaticGrid} component --- @tparam DruidInstance self --- @tparam string|node parent_node The node_id or gui.get_node(node_id). Parent of all Grid items. --- @tparam node item Element prefab. Required to get grid's item size. Can be adjusted separately. --- @tparam number|nil in_row How many nodes in row can be placed --- @treturn StaticGrid @{StaticGrid} component --- @local -function DruidInstance.new_grid(self, parent_node, item, in_row) - return DruidInstance.new(self, static_grid, parent_node, item, in_row) +--- Create StaticGrid component +---@param parent_node string|node The node_id or gui.get_node(node_id). Parent of all Grid items. +---@param item node Element prefab. Required to get grid's item size. Can be adjusted separately. +---@param in_row number|nil How many nodes in row can be placed +---@return druid.grid StaticGrid component +function M:new_grid(parent_node, item, in_row) + return self:new(static_grid, parent_node, item, in_row) end ---- Create @{StaticGrid} component --- @tparam DruidInstance self --- @tparam string|node parent_node The node_id or gui.get_node(node_id). Parent of all Grid items. --- @tparam string|node item Item prefab. Required to get grid's item size. Can be adjusted separately. --- @tparam number|nil in_row How many nodes in row can be placed --- @treturn StaticGrid @{StaticGrid} component -function DruidInstance.new_static_grid(self, parent_node, item, in_row) - return DruidInstance.new(self, static_grid, parent_node, item, in_row) +--- Create StaticGrid component +---@param parent_node string|node The node_id or gui.get_node(node_id). Parent of all Grid items. +---@param item string|node Item prefab. Required to get grid's item size. Can be adjusted separately. +---@param in_row number|nil How many nodes in row can be placed +---@return druid.grid StaticGrid component +function M:new_static_grid(parent_node, item, in_row) + return self:new(static_grid, parent_node, item, in_row) end ---- Create @{Scroll} component --- @tparam DruidInstance self --- @tparam string|node view_node The node_id or gui.get_node(node_id). Will used as user input node. --- @tparam string|node content_node The node_id or gui.get_node(node_id). Will used as scrollable node inside view_node. --- @treturn Scroll @{Scroll} component -function DruidInstance.new_scroll(self, view_node, content_node) - return DruidInstance.new(self, scroll, view_node, content_node) +--- Create Scroll component +---@param view_node string|node The node_id or gui.get_node(node_id). Will used as user input node. +---@param content_node string|node The node_id or gui.get_node(node_id). Will used as scrollable node inside view_node. +---@return druid.scroll Scroll component +function M:new_scroll(view_node, content_node) + return self:new(scroll, view_node, content_node) end ---- Create @{Drag} component --- @tparam DruidInstance self --- @tparam string|node node The node_id or gui.get_node(node_id). Will used as user input node. --- @tparam function|nil on_drag_callback Callback for on_drag_event(self, dx, dy) --- @treturn Drag @{Drag} component -function DruidInstance.new_drag(self, node, on_drag_callback) - return DruidInstance.new(self, drag, node, on_drag_callback) +--- Create Drag component +---@param node string|node The node_id or gui.get_node(node_id). Will used as user input node. +---@param on_drag_callback function|nil Callback for on_drag_event(self, dx, dy) +---@return druid.drag Drag component +function M:new_drag(node, on_drag_callback) + return self:new(drag, node, on_drag_callback) end ---- Create @{Swipe} component --- @tparam DruidInstance self --- @tparam string|node node The node_id or gui.get_node(node_id). Will used as user input node. --- @tparam function|nil on_swipe_callback Swipe callback for on_swipe_end event --- @treturn Swipe @{Swipe} component -function DruidInstance.new_swipe(self, node, on_swipe_callback) - return helper.require_component_message("swipe") +--- Create Swipe component +---@param node string|node The node_id or gui.get_node(node_id). Will used as user input node. +---@param on_swipe_callback function|nil Swipe callback for on_swipe_end event +---@return druid.swipe Swipe component +function M:new_swipe(node, on_swipe_callback) + return helper.require_component_message("swipe") --[[@as druid.swipe]] end ---- Create @{DynamicGrid} component --- Deprecated --- @tparam DruidInstance self --- @tparam string|node parent_node The node_id or gui.get_node(node_id). Parent of all Grid items. --- @treturn DynamicGrid @{DynamicGrid} component -function DruidInstance.new_dynamic_grid(self, parent_node) - return helper.require_component_message("dynamic_grid") +--- Create LangText component +---@param node string|node The_node id or gui.get_node(node_id) +---@param locale_id string|nil Default locale id or text from node as default +---@param adjust_type string|nil Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE +---@return druid.lang_text LangText component +function M:new_lang_text(node, locale_id, adjust_type) + return helper.require_component_message("lang_text") --[[@as druid.lang_text]] end - ---- Create @{LangText} component --- @tparam DruidInstance self --- @tparam string|node node The_node id or gui.get_node(node_id) --- @tparam string|nil locale_id Default locale id or text from node as default --- @tparam string|nil adjust_type Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE --- @treturn LangText @{LangText} component -function DruidInstance.new_lang_text(self, node, locale_id, adjust_type) - return helper.require_component_message("lang_text") +--- Create Slider component +---@param pin_node string|node The_node id or gui.get_node(node_id). +---@param end_pos vector3 The end position of slider +---@param callback function|nil On slider change callback +---@return druid.slider Slider component +function M:new_slider(pin_node, end_pos, callback) + return helper.require_component_message("slider") --[[@as druid.slider]] end - ---- Create @{Slider} component --- @tparam DruidInstance self --- @tparam string|node pin_node The_node id or gui.get_node(node_id). --- @tparam vector3 end_pos The end position of slider --- @tparam function|nil callback On slider change callback --- @treturn Slider @{Slider} component -function DruidInstance.new_slider(self, pin_node, end_pos, callback) - return helper.require_component_message("slider") +--- Create Input component +---@param click_node string|node Button node to enabled input component +---@param text_node string|node|druid.text Text node what will be changed on user input +---@param keyboard_type number|nil Gui keyboard type for input field +---@return druid.input Input component +function M:new_input(click_node, text_node, keyboard_type) + return helper.require_component_message("input") --[[@as druid.input]] end - ---- Create @{Input} component --- @tparam DruidInstance self --- @tparam string|node click_node Button node to enabled input component --- @tparam string|node|druid.text text_node Text node what will be changed on user input --- @tparam number|nil keyboard_type Gui keyboard type for input field --- @treturn Input @{Input} component -function DruidInstance.new_input(self, click_node, text_node, keyboard_type) - return helper.require_component_message("input") +--- Create DataList component +---@param druid_scroll druid.scroll The Scroll instance for Data List component +---@param druid_grid druid.grid The StaticGrid} or @{DynamicGrid instance for Data List component +---@param create_function function The create function callback(self, data, index, data_list). Function should return (node, [component]) +---@return druid.data_list DataList component +function M:new_data_list(druid_scroll, druid_grid, create_function) + return helper.require_component_message("data_list") --[[@as druid.data_list]] end - ---- Create @{DataList} component --- @tparam DruidInstance self --- @tparam Scroll druid_scroll The Scroll instance for Data List component --- @tparam StaticGrid druid_grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component --- @tparam function create_function The create function callback(self, data, index, data_list). Function should return (node, [component]) --- @treturn DataList @{DataList} component -function DruidInstance.new_data_list(self, druid_scroll, druid_grid, create_function) - return helper.require_component_message("data_list") +--- Create Timer component +---@param node string|node Gui text node +---@param seconds_from number Start timer value in seconds +---@param seconds_to number|nil End timer value in seconds +---@param callback function|nil Function on timer end +---@return druid.timer Timer component +function M:new_timer(node, seconds_from, seconds_to, callback) + return helper.require_component_message("timer") --[[@as druid.timer]] end - ---- Create @{Timer} component --- @tparam DruidInstance self --- @tparam string|node node Gui text node --- @tparam number seconds_from Start timer value in seconds --- @tparam number|nil seconds_to End timer value in seconds --- @tparam function|nil callback Function on timer end --- @treturn Timer @{Timer} component -function DruidInstance.new_timer(self, node, seconds_from, seconds_to, callback) - return helper.require_component_message("timer") +--- Create Progress component +---@param node string|node Progress bar fill node or node name +---@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y +---@param init_value number|nil Initial value of progress bar. Default: 1 +---@return druid.progress Progress component +function M:new_progress(node, key, init_value) + return helper.require_component_message("progress") --[[@as druid.progress]] end - ---- Create @{Progress} component --- @tparam DruidInstance self --- @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|nil init_value Initial value of progress bar. Default: 1 --- @treturn Progress @{Progress} component -function DruidInstance.new_progress(self, node, key, init_value) - return helper.require_component_message("progress") +--- Create Layout component +---@param node string|node The_node id or gui.get_node(node_id). +---@param mode string The layout mode +---@return druid.layout Layout component +function M:new_layout(node, mode) + return helper.require_component_message("layout") --[[@as druid.layout]] end - ---- Create @{Layout} component --- @tparam DruidInstance self --- @tparam string|node node The_node id or gui.get_node(node_id). --- @tparam string mode The layout mode --- @treturn Layout @{Layout} component -function DruidInstance.new_layout(self, node, mode) - return helper.require_component_message("layout") +--- Create Hotkey component +---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys +---@param callback function The callback function +---@param callback_argument any|nil The argument to pass into the callback function +---@return druid.hotkey Hotkey component +function M:new_hotkey(keys_array, callback, callback_argument) + return helper.require_component_message("hotkey") --[[@as druid.hotkey]] end - ---- Create @{Hotkey} component --- @tparam DruidInstance self --- @tparam string|string[] keys_array Keys for trigger action. Should contains one action key and any amount of modificator keys --- @tparam function callback The callback function --- @tparam any|nil callback_argument The argument to pass into the callback function --- @treturn Hotkey @{Hotkey} component -function DruidInstance.new_hotkey(self, keys_array, callback, callback_argument) - return helper.require_component_message("hotkey") +--- Create RichText component. +---@param text_node string|node The text node to make Rich Text +---@param value string|nil The initial text value. Default will be gui.get_text(text_node) +---@return druid.rich_text RichText component +function M:new_rich_text(text_node, value) + return helper.require_component_message("rich_text", "custom") --[[@as druid.rich_text]] end - ---- Create @{RichText} component. --- @tparam DruidInstance self --- @tparam string|node text_node The text node to make Rich Text --- @tparam string|nil value The initial text value. Default will be gui.get_text(text_node) --- @treturn RichText @{RichText} component -function DruidInstance.new_rich_text(self, text_node, value) - return helper.require_component_message("rich_text", "custom") -end - - ---- Create @{RichInput} component. +--- Create RichInput component. -- As a template please check rich_input.gui layout. --- @tparam DruidInstance self --- @tparam string template The template string name --- @tparam table nodes Nodes table from gui.clone_tree --- @treturn RichInput @{RichInput} component -function DruidInstance.new_rich_input(self, template, nodes) - return helper.require_component_message("rich_input", "custom") +---@param template string The template string name +---@param nodes table Nodes table from gui.clone_tree +---@return druid.rich_input RichInput component +function M:new_rich_input(template, nodes) + return helper.require_component_message("rich_input", "custom") --[[@as druid.rich_input]] end - -return DruidInstance +return M diff --git a/druid/system/settings.lua b/druid/system/settings.lua index 384a706..ea8f8b6 100755 --- a/druid/system/settings.lua +++ b/druid/system/settings.lua @@ -1,21 +1,15 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid settings file --- @module settings --- @local - +---@class druid.system.settings local M = {} M.default_style = nil - -function M.get_text(name, a, b, c, d, e, f, g) +---@param text_id string +---@vararg any +function M.get_text(text_id, ...) return "[Druid]: locales not inited" end - -function M.play_sound(name) +function M.play_sound(sound_id) end - return M diff --git a/druid/templates/component.template.lua b/druid/templates/component.template.lua index d67bf32..059ef31 100644 --- a/druid/templates/component.template.lua +++ b/druid/templates/component.template.lua @@ -1,21 +1,16 @@ local component = require("druid.component") ---@class component_name : druid.base_component -local Component = component.create("component_name") +local M = component.create("component_name") -- Component constructor. Template name and nodes are optional. Pass it if you use it in your component -function Component:init(template, nodes) - self.druid = self:get_druid(template, nodes) - self.root = self:get_node("root") +function M:init(template, nodes) + self.druid = self:get_druid(template, nodes) + self.root = self:get_node("root") - self.button = self.druid:new_button("button", function() end) + self.button = self.druid:new_button("button", function() end) end --- [OPTIONAL] Call on component remove or on druid:final -function Component:on_remove() -end - - -return Component +return M diff --git a/druid/templates/component_full.template.lua b/druid/templates/component_full.template.lua index 1978cf2..81fd322 100644 --- a/druid/templates/component_full.template.lua +++ b/druid/templates/component_full.template.lua @@ -1,10 +1,10 @@ local component = require("druid.component") ----@class component_name : druid.base_component -local Component = component.create("component_name") +---@class new_component: druid.base_component +local M = component.create("new_component") -- Component constructor. Template name and nodes are optional. Pass it if you use it in your component -function Component:init(template, nodes) +function M:init(template, nodes) -- If your component is gui template, pass the template name and set it -- If your component is cloned my gui.clone_tree, pass nodes to component and set it -- Use inner druid instance to create components inside this component @@ -17,55 +17,55 @@ end -- [OPTIONAL] Call every update step -function Component:update(dt) +function M:update(dt) end -- [OPTIONAL] Call default on_input from gui script -function Component:on_input(action_id, action) +function M:on_input(action_id, action) return false end -- [OPTIONAL] Call on component creation and on component:set_style() function -function Component:on_style_change(style) +function M:on_style_change(style) end -- [OPTIONAL] Call default on_message from gui script -function Component:on_message(message_id, message, sender) +function M:on_message(message_id, message, sender) end -- [OPTIONAL] Call if druid has triggered on_language_change -function Component:on_language_change() +function M:on_language_change() end -- [OPTIONAL] Call if game layout has changed and need to restore values in component -function Component:on_layout_change() +function M:on_layout_change() end -- [OPTIONAL] Call, if input was capturing before this component -- Example: scroll is start scrolling, so you need unhover button -function Component:on_input_interrupt() +function M:on_input_interrupt() end -- [OPTIONAL] Call, if game lost focus -function Component:on_focus_lost() +function M:on_focus_lost() end -- [OPTIONAL] Call, if game gained focus -function Component:on_focus_gained() +function M:on_focus_gained() end -- [OPTIONAL] Call on component remove or on druid:final -function Component:on_remove() +function M:on_remove() end -return Component +return M diff --git a/example/components/container/container.lua b/example/components/container/container.lua index 8e0c977..ffacc27 100644 --- a/example/components/container/container.lua +++ b/example/components/container/container.lua @@ -134,7 +134,7 @@ end --- Set new size of layout node ---@param width number|nil ---@param height number|nil ----@return druid.container @{Container} +---@return druid.container Container function M:set_size(width, height) width = width or self.size.x height = height or self.size.y @@ -191,7 +191,7 @@ end --- Set size for layout node to fit inside it ---@param target_size vector3 ----@return druid.container @{Container} +---@return druid.container Container function M:fit_into_size(target_size) self.fit_size = target_size self:refresh() @@ -200,7 +200,7 @@ end --- Set current size for layout node to fit inside it ----@return druid.container @{Container} +---@return druid.container Container function M:fit_into_window() return self:fit_into_size(vmath.vector3(gui.get_width(), gui.get_height(), 0)) end @@ -221,7 +221,7 @@ end ---@param node_or_container node|string|druid.container|table ---@param mode string|nil stretch, fit, stretch_x, stretch_y. Default: Pick from node, "fit" or "stretch" ---@param on_resize_callback fun(self: userdata, size: vector3)|nil ----@return druid.container @{Container} New created layout instance +---@return druid.container Container New created layout instance function M:add_container(node_or_container, mode, on_resize_callback) local container = nil local node = node_or_container @@ -422,7 +422,7 @@ function M:update_child_containers() end ----@return druid.container @{Container} +---@return druid.container Container function M:create_draggable_corners() self:clear_draggable_corners() @@ -452,7 +452,7 @@ function M:create_draggable_corners() end ----@return druid.container @{Container} +---@return druid.container Container function M:clear_draggable_corners() for index = 1, #self._draggable_corners do local drag_component = self._draggable_corners[index] @@ -505,7 +505,7 @@ end --- Set node for layout node to fit inside it. Pass nil to reset ---@param node string|node The node_id or gui.get_node(node_id) ----@return druid.container @{Layout} +---@return druid.container Layout function M:fit_into_node(node) self._fit_node = self:get_node(node) self:refresh_scale() diff --git a/example/examples/basic/blocker/basic_blocker.lua b/example/examples/basic/blocker/basic_blocker.lua index 1885d91..57bcfc0 100644 --- a/example/examples/basic/blocker/basic_blocker.lua +++ b/example/examples/basic/blocker/basic_blocker.lua @@ -1,6 +1,6 @@ local component = require("druid.component") ----@class basic_blocker: druid.component +---@class basic_blocker: druid.base_component ---@field druid druid_instance ---@field root node ---@field blocker druid.blocker diff --git a/utils/annotations_manual.lua b/utils/annotations_manual.lua index 46b8284..ee86713 100644 --- a/utils/annotations_manual.lua +++ b/utils/annotations_manual.lua @@ -104,23 +104,23 @@ function druid_instance.new(self, component, ...) end --- Set current component style table. --- Invoke `on_style_change` on component, if exist. Component should handle their style changing and store all style params ---@generic T: druid.base_component ----@param self T @{BaseComponent} +---@param self T BaseComponent ---@param druid_style table|nil Druid style module ----@return T @{BaseComponent} +---@return T BaseComponent function druid__base_component.set_style(self, druid_style) end --- Set component template name. --- Use on all your custom components with GUI layouts used as templates. It will check parent template name to build full template name in self:get_node() ---@generic T: druid.base_component ----@param self T @{BaseComponent} +---@param self T BaseComponent ---@param template string BaseComponent template name ----@return T @{BaseComponent} +---@return T BaseComponent function druid__base_component.set_template(self, template) end --- Set current component nodes. --- Use if your component nodes was cloned with `gui.clone_tree` and you got the node tree. ---@generic T: druid.base_component ----@param self T @{BaseComponent} +---@param self T BaseComponent ---@param nodes table BaseComponent nodes table ----@return T @{BaseComponent} +---@return T BaseComponent function druid__base_component.set_nodes(self, nodes) end