Merge pull request #230 from Insality/docs

Docs update
This commit is contained in:
Maksim Tuprikov 2023-07-05 23:20:58 +03:00 committed by GitHub
commit 862b61281d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1452 additions and 731 deletions

174
README.md
View File

@ -10,145 +10,72 @@
**Druid** - powerful Defold component UI library. Use basic and extended **Druid** components or make your own game-specific components to make amazing GUI in your games.
## Overview
## Setup
### Dependency
You can use the **Druid** extension in your own project by adding this project as a [Defold library dependency](https://www.defold.com/manuals/libraries/). Open your game.project file and in the dependencies field under project add:
You can use the **Druid** extension in your own project by adding this project as a [Defold library dependency](https://www.defold.com/manuals/libraries/). Open your `game.project` file and in the dependencies field under project add:
> [https://github.com/Insality/druid/archive/master.zip](https://github.com/Insality/druid/archive/master.zip)
**Druid v0.10.3**
> [https://github.com/Insality/druid/archive/refs/tags/0.10.3.zip](https://github.com/Insality/druid/archive/refs/tags/0.10.3.zip)
Or point to the ZIP file of a [specific release](https://github.com/Insality/druid/releases).
Here is a list of [all releases](https://github.com/Insality/druid/releases).
### Input bindings
**Druid** requires the following input bindings:
- Mouse trigger - `Button 1` -> `touch` _For basic input components_
- Mouse trigger - `Wheel up` -> `mouse_wheel_up` _For scroll component_
- Mouse trigger - `Wheel down` -> `mouse_wheel_down` _For scroll component_
- Key trigger - `Backspace` -> `key_backspace` _For back_handler component, input component_
- Key trigger - `Back` -> `key_back` _For back_handler component, Android back button, input component_
- Key trigger - `Enter` -> `key_enter` _For input component, optional_
- Key trigger - `Esc` -> `key_esc` _For input component, optional_
- Touch triggers - `Touch multi` -> `touch_multi` _For scroll component_
![](media/input_binding_2.png)
![](media/input_binding_1.png)
### Input Bindings
Druid uses `/builtins/input/all.input_binding` input bindins. For advanced setup see the Input Binding section in Advanced Setup.
### Change key bindings [optional]
If you have to use your own key bindings (and key name), you can change it in your *game.project* file.
Here is current default values for key bindings:
```
[druid]
input_text = text
input_touch = touch
input_marked_text = marked_text
input_key_esc = key_esc
input_key_back = key_back
input_key_enter = key_enter
input_key_backspace = key_backspace
input_multitouch = touch_multi
input_scroll_up = mouse_wheel_up
input_scroll_down = mouse_wheel_down
```
### Input capturing [optional]
By default, **Druid** will auto-capture input focus, if any input component will be created. So you don't need to call `msg.post(".", "acquire_input_focus")`
If you don't need this behaviour, you can disable it by setting `druid.no_auto_input` field in _game.project_:
```
[druid]
no_auto_input = 1
```
### Template name check [optional]
By default, **Druid** will auto check the parent component template name to build the full template name for component.
If for some reason you want to pass the full template name by yourself, you can disable it by setting `druid.no_auto_template` field in _game.project_:
```
[druid]
no_auto_template = 1
```
### Stencil check [optional]
When creating input components inside stencil nodes, **Druid** automatically setup `component:set_click_zone()` on _late_init_ component step to restrict input clicks outside this stencil zone.
To disable this feature add next field in your _game.project_ file
```
[druid]
no_stencil_check = 1
```
### Code [optional]
Adjust **Druid** settings, if needed:
```lua
local druid = require("druid.druid")
-- Used for button component and custom components
-- Callback should play sound by name
druid.set_sound_function(callback)
-- Used for lang_text component
-- Callback should return localized string by locale id
druid.set_text_function(callback)
-- Used for change default druid style
druid.set_default_style(your_style)
-- Call this function on language changing in the game,
-- to retranslate all lang_text components:
druid.on_language_change()
-- Call this function inside window.set_listener
-- to catch game focus lost/gained callbacks:
druid.on_window_callback(event)
```
## Usage
Here only basic usage.
How to read this doc.
Annotations.
Example of advanced usage - different doc.
Example of custom components - different doc.
## Components
Here is full **Druid** components list:
| Name | Description | API page | Example Link | Is Basic component[^1] | Preview |
|------|-------------|----------|------------|-------------|---------|
| **[Button](docs_md/01-components.md#button)** | Basic input component. Handles all types of interactions: click, long click, hold click, double click, etc | [Button API](https://insality.github.io/druid/modules/Button.html) | [Button Example](https://insality.github.io/druid/druid/?example=general_buttons) | ✅ | <img src="media/preview/button.gif" width="200" height="100"> |
| **[Text](docs_md/01-components.md#text)** | Wrap on GUI text node, handle different text size adjusting, providing additional text API | [Text API](https://insality.github.io/druid/modules/Text.html) | [Text Example](https://insality.github.io/druid/druid/?example=texts_general) | ✅ | <img src="media/preview/text.gif" width="200" height="100"> |
| **[Scroll](docs_md/01-components.md#scroll)** | Scroll component | [Scroll API](https://insality.github.io/druid/modules/Scroll.html) | [Scroll Example](https://insality.github.io/druid/druid/?example=general_scroll) | ✅ | <img src="media/preview/scroll.gif" width="200" height="100"> |
| **[Blocker](docs_md/01-components.md#blocker)** | Block user input in node zone area | [Blocker API](https://insality.github.io/druid/modules/Blocker.html) | ❌ | ✅ | |
| **[Back Handler](docs_md/01-components.md#back-handler)** | Handle back button (Android back button, backspace key) | [Back Handler API](https://insality.github.io/druid/modules/BackHandler.html) | ❌ | ✅ | |
| **[Static Grid](docs_md/01-components.md#static-grid)** | Component to manage node positions with equal sizes | [Static Grid API](https://insality.github.io/druid/modules/StaticGrid.html) | [Static Gid Example](https://insality.github.io/druid/druid/?example=general_grid) | ✅ | <img src="media/preview/static_grid.gif" width="200" height="100"> |
| **[Hover](docs_md/01-components.md#hover)** | Handle hover node state on node | [Hover API](https://insality.github.io/druid/modules/Hover.html) | ❌ | ✅ | <img src="media/preview/hover.gif" width="200" height="100"> |
| **[Swipe](docs_md/01-components.md#swipe)** | Handle swipe gestures on node | [Swipe API](https://insality.github.io/druid/modules/Swipe.html) | [Swipe Example](https://insality.github.io/druid/druid/?example=general_swipe) | ✅ | <img src="media/preview/swipe.gif" width="200" height="100"> |
| **[Drag](docs_md/01-components.md#drag)** | Handle drag input on node | [Drag API](https://insality.github.io/druid/modules/Drag.html) | [Drag Example](https://insality.github.io/druid/druid/?example=general_drag) | ✅ | <img src="media/preview/drag.gif" width="200" height="100"> |
| **[Checkbox](docs_md/01-components.md#checkbox)** | Checkbox component | [Checkbox API](https://insality.github.io/druid/modules/Checkbox.html) | [Checkbox Example](https://insality.github.io/druid/druid/?example=general_checkboxes) | ❌ | <img src="media/preview/checkbox.gif" width="200" height="100"> |
| **[Checkbox group](docs_md/01-components.md#checkbox-group)** | Several checkboxes in one group | [Checkbox group API](https://insality.github.io/druid/modules/CheckboxGroup.html) | [Checkbox group Example](https://insality.github.io/druid/druid/?example=general_checkboxes) | ❌ | <img src="media/preview/checkbox_group.gif" width="200" height="100"> |
| **[Radio group](docs_md/01-components.md#radio-group)** | Several checkboxes in one group with a single choice | [Radio group API](https://insality.github.io/druid/modules/RadioGroup.html) | [Radio Group Example](https://insality.github.io/druid/druid/?example=general_checkboxes) | ❌ | <img src="media/preview/radio_group.gif" width="200" height="100"> |
| **[Dynamic Grid](docs_md/01-components.md#dynamic-grid)** | Component to manage node positions with different sizes. Only in one row or column | [Dynamic Grid API](https://insality.github.io/druid/modules/DynamicGrid.html) | [Dynamic Grid Example](https://insality.github.io/druid/druid/?example=general_grid) | ❌ | <img src="media/preview/dynamic_grid.gif" width="200" height="100"> |
| **[Data List](docs_md/01-components.md#data-list)** | Component to manage data for huge datasets in scroll | [Data List API](https://insality.github.io/druid/modules/DataList.html) | [Data List Example](https://insality.github.io/druid/druid/?example=general_data_list) | ❌ | <img src="media/preview/data_list.gif" width="200" height="100"> |
| **[Input](docs_md/01-components.md#input)** | User text input component | [Input API](https://insality.github.io/druid/modules/Input.html) | [Input Example](https://insality.github.io/druid/druid/?example=general_input) | ❌ | <img src="media/preview/input.gif" width="200" height="100"> |
| **[Lang text](docs_md/01-components.md#lang-text)** | Wrap on Text component to handle localization | [Lang Text API](https://insality.github.io/druid/modules/LangText.html) | ❌ | ❌ | <img src="media/preview/lang_text.gif" width="200" height="100"> |
| **[Progress](docs_md/01-components.md#progress)** | Progress bar component | [Progress API](https://insality.github.io/druid/modules/Progress.html) | [Progress Example](https://insality.github.io/druid/druid/?example=general_progress_bar) | ❌ | <img src="media/preview/progress.gif" width="200" height="100"> |
| **[Slider](docs_md/01-components.md#slider)** | Slider component | [Slider API](https://insality.github.io/druid/modules/Slider.html) | [Slider Example](https://insality.github.io/druid/druid/?example=general_sliders) | ❌ | <img src="media/preview/slider.gif" width="200" height="100"> |
| **[Timer](docs_md/01-components.md#timer)** | Handle timers on GUI text node | [Timer API](https://insality.github.io/druid/modules/Timer.html) | ❌ | ❌ | <img src="media/preview/timer.gif" width="200" height="100"> |
| **[Hotkey](docs_md/01-components.md#hotkey)** | Handle keyboard hotkeys with key modificators | [Hotkey API](https://insality.github.io/druid/modules/Hotkey.html) | [Hotkey Example](https://insality.github.io/druid/druid/?example=general_hokey) | ❌ | <img src="media/preview/hotkey.gif" width="200" height="100"> |
| **[Layout](docs_md/01-components.md#layout)** | Handle node size depends on layout mode and screen aspect ratio | [Layout API](https://insality.github.io/druid/modules/Layout.html) | [Layout Example](https://insality.github.io/druid/druid/?example=general_layout) | ❌ | <img src="media/preview/layout.gif" width="200" height="100"> |
### Basic Components
| Name | Description | Example | <div style="width:200px">Preview</div> |
|------|-------------|---------|---------|
| **[Button](https://insality.github.io/druid/modules/Button.html)** | Basic input component. Handles all types of interactions: click, long click, hold click, double click, etc | [Button Example](https://insality.github.io/druid/druid/?example=general_buttons) | <img src="media/preview/button.gif" width="200" height="100"> |
| **[Text](https://insality.github.io/druid/modules/Text.html)** | Wrap on GUI text node, handle different text size adjusting, providing additional text API | [Text Example](https://insality.github.io/druid/druid/?example=texts_general) | <img src="media/preview/text.gif" width="200" height="100"> |
| **[Scroll](https://insality.github.io/druid/modules/Scroll.html)** | Scroll component | [Scroll Example](https://insality.github.io/druid/druid/?example=general_scroll) | <img src="media/preview/scroll.gif" width="200" height="100"> |
| **[Blocker](https://insality.github.io/druid/modules/Blocker.html)** | Block user input in node zone area | ❌ | |
| **[Back Handler](https://insality.github.io/druid/modules/BackHandler.html)** | Handle back button (Android back button, backspace key) | ❌ | |
| **[Static Grid](https://insality.github.io/druid/modules/StaticGrid.html)** | Component to manage node positions with equal sizes | [Static Gid Example](https://insality.github.io/druid/druid/?example=general_grid) | <img src="media/preview/static_grid.gif" width="200" height="100"> |
| **[Hover](https://insality.github.io/druid/modules/Hover.html)** | Handle hover node state on node | ❌ | <img src="media/preview/hover.gif" width="200" height="100"> |
| **[Swipe](https://insality.github.io/druid/modules/Swipe.html)** | Handle swipe gestures on node | [Swipe Example](https://insality.github.io/druid/druid/?example=general_swipe) | <img src="media/preview/swipe.gif" width="200" height="100"> |
| **[Drag](https://insality.github.io/druid/modules/Drag.html)** | Handle drag input on node | [Drag Example](https://insality.github.io/druid/druid/?example=general_drag) | <img src="media/preview/drag.gif" width="200" height="100"> |
### Extended components
> Extended components before usage should be registered in **Druid** with `druid.register()` function.
| Name | Description | Example | <div style="width:200px">Preview</div> |
|------|-------------|---------|---------|
| **[Checkbox](https://insality.github.io/druid/modules/Checkbox.html)** | Checkbox component | [Checkbox Example](https://insality.github.io/druid/druid/?example=general_checkboxes) | <img src="media/preview/checkbox.gif" width="200" height="100"> |
| **[Checkbox group](https://insality.github.io/druid/modules/CheckboxGroup.html)** | Several checkboxes in one group | [Checkbox group Example](https://insality.github.io/druid/druid/?example=general_checkboxes) | <img src="media/preview/checkbox_group.gif" width="200" height="100"> |
| **[Radio group](https://insality.github.io/druid/modules/RadioGroup.html)** | Several checkboxes in one group with a single choice | [Radio Group Example](https://insality.github.io/druid/druid/?example=general_checkboxes) | <img src="media/preview/radio_group.gif" width="200" height="100"> |
| **[Dynamic Grid](https://insality.github.io/druid/modules/DynamicGrid.html)** | Component to manage node positions with different sizes. Only in one row or column | [Dynamic Grid Example](https://insality.github.io/druid/druid/?example=general_grid) | <img src="media/preview/dynamic_grid.gif" width="200" height="100"> |
| **[Data List](https://insality.github.io/druid/modules/DataList.html)** | Component to manage data for huge datasets in scroll | [Data List Example](https://insality.github.io/druid/druid/?example=general_data_list) | <img src="media/preview/data_list.gif" width="200" height="100"> |
| **[Input](https://insality.github.io/druid/modules/Input.html)** | User text input component | [Input Example](https://insality.github.io/druid/druid/?example=general_input) | <img src="media/preview/input.gif" width="200" height="100"> |
| **[Lang text](https://insality.github.io/druid/modules/LangText.html)** | Wrap on Text component to handle localization | ❌ | <img src="media/preview/lang_text.gif" width="200" height="100"> |
| **[Progress](https://insality.github.io/druid/modules/Progress.html)** | Progress bar component | [Progress Example](https://insality.github.io/druid/druid/?example=general_progress_bar) | <img src="media/preview/progress.gif" width="200" height="100"> |
| **[Slider](https://insality.github.io/druid/modules/Slider.html)** | Slider component | [Slider Example]() | <img src="media/preview/slider.gif" width="200" height="100"> |
| **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Handle timers on GUI text node | ❌ | <img src="media/preview/timer.gif" width="200" height="100"> |
| **[Hotkey](https://insality.github.io/druid/modules/Hotkey.html)** | Handle keyboard hotkeys with key modificators | [Hotkey Example](https://insality.github.io/druid/druid/?example=general_hokey) | <img src="media/preview/hotkey.gif" width="200" height="100"> |
| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Handle node size depends on layout mode and screen aspect ratio | [Layout Example](https://insality.github.io/druid/druid/?example=general_layout) | <img src="media/preview/layout.gif" width="200" height="100"> |
For a complete overview, see: **_[components.md](docs_md/01-components.md)_**.
[^1]: Non basic components before use should be registered first to be included in build
## Basic usage
@ -174,11 +101,14 @@ function final(self)
self.druid:final()
end
function update(self, dt)
self.druid:update(dt)
end
function on_message(self, message_id, message, sender)
self.druid:on_message(message_id, message, sender)
end
function on_input(self, action_id, action)
return self.druid:on_input(action_id, action)
end

View File

@ -1,12 +1,13 @@
project='Druid'
title='Defold Druid UI Library'
description='Documentation for Druid Library'
title='Defold Druid UI Framework'
description='Documentation for Druid Framework'
file={"./druid",
exclude = {
"./druid/styles/",
"./druid/system/middleclass.lua",
"./druid/templates/",
"./druid/annotations.lua",
"./druid/custom/rich_text/module",
}
}
package='druid'

View File

@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="ldoc_fixed.css" type="text/css" />
</head>
<body>

94
docs_md/advanced-setup.md Normal file
View File

@ -0,0 +1,94 @@
## Input bindings
**Druid** requires the following input bindings:
- Mouse trigger - `Button 1` -> `touch` _For basic input components_
- Mouse trigger - `Wheel up` -> `mouse_wheel_up` _For scroll component_
- Mouse trigger - `Wheel down` -> `mouse_wheel_down` _For scroll component_
- Key trigger - `Backspace` -> `key_backspace` _For back_handler component, input component_
- Key trigger - `Back` -> `key_back` _For back_handler component, Android back button, input component_
- Key trigger - `Enter` -> `key_enter` _For input component, optional_
- Key trigger - `Esc` -> `key_esc` _For input component, optional_
- Touch triggers - `Touch multi` -> `touch_multi` _For scroll component_
![](media/input_binding_2.png)
![](media/input_binding_1.png)
## Change key bindings [optional]
If you have to use your own key bindings (and key name), you can change it in your *game.project* file.
Here is current default values for key bindings:
```
[druid]
input_text = text
input_touch = touch
input_marked_text = marked_text
input_key_esc = key_esc
input_key_back = key_back
input_key_enter = key_enter
input_key_backspace = key_backspace
input_multitouch = touch_multi
input_scroll_up = mouse_wheel_up
input_scroll_down = mouse_wheel_down
```
## Input capturing [optional]
By default, **Druid** will auto-capture input focus, if any input component will be created. So you don't need to call `msg.post(".", "acquire_input_focus")`
If you don't need this behaviour, you can disable it by setting `druid.no_auto_input` field in _game.project_:
```
[druid]
no_auto_input = 1
```
## Template name check [optional]
By default, **Druid** will auto check the parent component template name to build the full template name for component.
If for some reason you want to pass the full template name by yourself, you can disable it by setting `druid.no_auto_template` field in _game.project_:
```
[druid]
no_auto_template = 1
```
## Stencil check [optional]
When creating input components inside stencil nodes, **Druid** automatically setup `component:set_click_zone()` on _late_init_ component step to restrict input clicks outside this stencil zone.
To disable this feature add next field in your _game.project_ file
```
[druid]
no_stencil_check = 1
```
## Code [optional]
Adjust **Druid** settings, if needed:
```lua
local druid = require("druid.druid")
-- Used for button component and custom components
-- Callback should play sound by name: function(sound_id) ... end
druid.set_sound_function(callback)
-- Used for lang_text component
-- Callback should return localized string by locale id: function(locale_id) ... end
druid.set_text_function(callback)
-- Used for change default Druid style
druid.set_default_style(your_style)
-- Call this function on language changing in the game,
-- to retranslate all lang_text components:
druid.on_language_change()
-- Call this function inside window.set_listener
-- to catch game focus lost/gained callbacks:
-- window.set_listener(function(self, event, data) druid.on_window_callback(event, data) end))
druid.on_window_callback(event)
```

View File

@ -446,3 +446,36 @@ And yeah, the new **Druid** logo is here!
- **#204** [System] Fix: wrong code example link, if open example from direct URL
- **#202** [System] Enabled stencil check to true by default. To disable this, use `druid.no_stencil_check` in game.project settings
- [Examples] Add layout, layout fit, progress bar, data list + component examples
### Druid 0.11.0
Hello! What a wonderful day for the new **Druid** update!
Alright, let's get straight to the point. Look at what I have for you!
**Druid Rich Text** has finally been released. The main difference from the existing **Bjorn's** Rich Text is that all visual parameters are customizable directly in the GUI. This allows you to integrate Rich Text more accurately and quickly. Additionally, this Rich Text aligns pixel perfect (well, almost) with regular GUI text node.
This version is the most basic one. Honestly, just wanna to publish current version for your and polish it later.
Another addition is the ability to enable the "HTML mode" for the Button component. In this mode, the button's action occurs in the context of `user action`, allowing operations like "copy and paste text" "show the keyboard" and more. However, in this mode, the button only responds to regular clicks due to the technical implementation of it (so no double clicks or long taps).
**Changelog 0.11.0**
---
- **#191**: [RichText] Finally add Druid Rich Text custom component. Component is used to make formatted text in your's GUI. This Rich Text mostly adjusted visually in GUI and have almost pixel-perfect match with similar GUI text node
- **#39**: [System] Finally add Unit Tests. Yeah, it cover not all **Druid** code, but it's a good start! 🎉
- **#219**: [System] UTF-8 performance optimization. Now Druid will try to use utf8 native extension over lua utf8 library if exists.
- **#156**: [Button] Now button can work in HTML5 with html5.set_interaction_listener.
- The API is `button:set_html5_user_interaction(true)`. In HTML5 mode button have several restrictions. Basically, only the single tap event will work.
- **#227**: Update current URL in HTML5 example
- Now if you will open the example from direct URL, it will be updated to the current URL. So now it's much easier to share the example link with each other.
- **#183**: Documentation about GUI in World Space
- Also not only the GUI in World Space, but overall How to GUI in Defold article.
- **#199**: Having to click twice to unselect one input field and select another
- **#115**: Add debug mode for druid/druid_instance/components
- **#129**: Remove sound function, move inside styles
- **#226**: Data List remove function issue

View File

@ -4,187 +4,153 @@
---@class druid
local druid = {}
--- Create Druid instance.
---@param context table Druid context. Usually it is self of script
---@param style table Druid style module
---@return druid_instance Druid instance
--- 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 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
--- Callback on global language change event.
--- Use to update all lang texts
--- Call this function when the game language changes.
--- This function will translate all current LangText components.
function druid.on_language_change() end
--- Callback on global window event.
--- Used to trigger on_focus_lost and on_focus_gain
--- 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 external druid component.
--- After register you can create the component with druid_instance:new_{name}. For example `druid:new_button(...)`
--- Register a new external Druid component.
--- You can register your own components by creating them with 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 new default style.
--- 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 sound function.
--- Component will call this function to play sound by sound_id
--- 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 text function Druid locale component will call this function to get translated text.
--- After set_text_funtion all existing locale component will be updated
--- 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 On back handler callback(self, params)
---@field params any Params to back callback
---@field on_back druid.event @{DruidEvent} function(self, [params]) .
---@field params any Params to pass in the callback
local druid__back_handler = {}
--- Component init function
---@param self druid.back_handler @{BackHandler}
---@param callback callback On back button
---@param params any Callback argument
function druid__back_handler.init(self, callback, params) end
--- Input handler for component
---@param self druid.back_handler @{BackHandler}
---@param action_id string on_input action id
---@param action table on_input action
function druid__back_handler.on_input(self, action_id, action) end
---@class druid.base_component
---@field ON_INPUT field Component Interests
local druid__base_component = {}
--- Return all children components, recursive (protected)
---@protected
--- 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
function druid__base_component.component:get_childrens(self) end
--- Get current component context (protected)
---@protected
--- 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
function druid__base_component.component:get_context(self) end
--- Return druid with context of calling component (protected).
--- Use it to create component inside of other components.
---@protected
--- Get Druid instance for inner component creation.
---@param self druid.base_component @{BaseComponent}
---@return Druid Druid instance with component context
function druid__base_component.get_druid(self) end
function druid__base_component.component:get_druid(self) 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
function druid__base_component.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
function druid__base_component.component:get_name(self) end
--- Get node for component by name.
--- If component has nodes, node_or_name should be string It auto pick node by template name or from nodes by clone_tree if they was setup via component:set_nodes, component:set_template. If node is not found, the exception will fired
--- 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
function druid__base_component.component:get_node(self, node_or_name) end
--- Return the parent for current component (protected)
---@protected
--- Return the parent component if exist
---@param self druid.base_component @{BaseComponent}
---@return BaseComponent|nil The druid component instance or nil
function druid__base_component.get_parent_component(self) end
function druid__base_component.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
function druid__base_component.component:get_parent_name(self) end
--- Get current component template name (protected)
---@protected
--- 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
function druid__base_component.component:get_template(self) end
--- Return component uid (protected).
--- UID generated in component creation order
---@protected
--- 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
--- Print log information if debug mode is enabled (protected)
---@protected
---@param self druid.base_component @{BaseComponent}
---@param message string
---@param context table
function druid__base_component.log_message(self, message, context) end
function druid__base_component.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 debug logs for component enabled or disabled
---@param self druid.base_component @{BaseComponent}
---@param is_debug bool
function druid__base_component.set_debug(self, is_debug) end
function druid__base_component.component:reset_input_priority(self) end
--- Set component input state.
--- By default it enabled You can disable any input of component by this function
--- By default it enabled If input is disabled, the component will not receive input events
---@param self druid.base_component @{BaseComponent}
---@param state bool The component input state
---@return druid.base_component BaseComponent itself
function druid__base_component.set_input_enabled(self, state) end
function druid__base_component.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 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
function druid__base_component.component:set_input_priority(self, value, is_temporary) end
--- Set current component nodes (protected)
---@protected
--- Set current component nodes
--- Used if your component nodes was cloned with `gui.clone_tree`
---@param self druid.base_component @{BaseComponent}
---@param nodes table BaseComponent nodes table
---@return druid.base_component @{BaseComponent}
function druid__base_component.set_nodes(self, nodes) end
function druid__base_component.component:set_nodes(self, nodes) end
--- Set current component style table (protected).
--- Invoke `on_style_change` on component, if exist. BaseComponent should handle their style changing and store all style params
---@protected
--- Set current component style table.
--- Invoke `on_style_change` on component, if exist. Component should handle their style changing and store all style params
---@param self druid.base_component @{BaseComponent}
---@param druid_style table Druid style module
function druid__base_component.set_style(self, druid_style) end
---@return druid.base_component @{BaseComponent}
function druid__base_component.component:set_style(self, druid_style) end
--- Set current component template name (protected) It will check parent template name to build full template name
---@protected
--- 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()
---@param self druid.base_component @{BaseComponent}
---@param template string BaseComponent template name
---@return druid.base_component @{BaseComponent}
function druid__base_component.set_template(self, template) end
function druid__base_component.component:set_template(self, template) end
---@class druid.blocker : druid.base_component
---@field node node Trigger node
local druid__blocker = {}
--- Component init function
---@param self druid.blocker @{Blocker}
---@param node node Gui node
function druid__blocker.init(self, node) end
--- Return blocked enabled state
--- Return blocker enabled state
---@param self druid.blocker @{Blocker}
---@return bool True, if blocker is enabled
function druid__blocker.is_enabled(self) end
@ -206,6 +172,7 @@ function druid__blocker.set_enabled(self, state) end
---@field on_double_click druid.event On double tap button callback(self, params, button_instance, click_amount)
---@field on_hold_callback druid.event On button hold before long_click callback(self, params, button_instance, time)
---@field on_long_click druid.event On long tap button callback(self, params, button_instance, time)
---@field on_pressed druid.event On pressed button callback(self, params, button_instance)
---@field on_repeated_click druid.event On repeated action button callback(self, params, button_instance, click_amount)
---@field params any Params to click callbacks
---@field pos vector3 Initial pos of anim_node
@ -252,6 +219,13 @@ function druid__button.set_click_zone(self, zone) end
---@return druid.button Current button instance
function druid__button.set_enabled(self, state) end
--- Set buttom click mode to call itself inside html5 callback in user interaction event It required to do protected stuff like copy/paste text, show html keyboard, etc The HTML5 button don't call any events except on_click
---@protected
---@param self druid.button
---@param is_html_mode boolean If true - button will be called inside html5 callback
---@return druid.button Current button instance
function druid__button.set_html5_user_interaction(self, is_html_mode) end
--- Set key-code to trigger this button
---@param self druid.button @{Button}
---@param key hash The action_id of the key
@ -441,6 +415,7 @@ function druid__drag.set_enabled(self, is_enabled) end
---@class druid.drag.style
---@field DRAG_DEADZONE field Distance in pixels to start dragging
---@field NO_USE_SCREEN_KOEF field If screen aspect ratio affects on drag values
local druid__drag__style = {}
@ -542,7 +517,7 @@ local druid__event = {}
---@param self druid.event @{DruidEvent}
function druid__event.clear(self) end
--- Event constructur
--- DruidEvent constructor
---@param self druid.event @{DruidEvent}
---@param initial_callback function Subscribe the callback on new event, if callback exist
function druid__event.initialize(self, initial_callback) end
@ -555,30 +530,21 @@ function druid__event.is_exist(self) end
--- Subscribe callback on event
---@param self druid.event @{DruidEvent}
---@param callback function Callback itself
---@param context table Additional context as first param to callback call
---@param context Any Additional context as first param to callback call, usually it's self
function druid__event.subscribe(self, callback, context) end
--- Trigger the event and call all subscribed callbacks
---@param self druid.event @{DruidEvent}
---@param ... any All event params
---@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 context table Additional context as first param to callback call
---@param context Any Additional context as first param to callback call
function druid__event.unsubscribe(self, callback, context) end
---@class druid.helper
local druid__helper = {}
--- Transform table to oneline string
---@param t table
---@return string
function druid__helper.table_to_string(t) end
---@class druid.hotkey : druid.base_component
---@field button druid.button Button component from click_node
---@field click_node node Button trigger node
@ -607,8 +573,8 @@ local druid__hotkey__style = {}
---@class druid.hover : druid.base_component
---@field on_hover druid.event On hover callback(self, state)
---@field on_mouse_hover druid.event On mouse hover callback(self, state)
---@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)
local druid__hover = {}
--- Component init function
@ -622,6 +588,18 @@ function druid__hover.init(self, node, on_hover_callback) end
---@return bool 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 bool 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 bool 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}
@ -712,6 +690,7 @@ function druid__input.unselect(self) end
---@field IS_LONGTAP_ERASE field Is long tap will erase current input data
---@field IS_UNSELECT_ON_RESELECT field If true, call unselect on select selected input
---@field MASK_DEFAULT_CHAR field Default character mask for password input
---@field NO_CONSUME_INPUT_WHILE_SELECTED field If true, will not consume input while input is selected. It's allow to interact with other components while input is selected (text input still captured)
---@field button_style field Custom button style for input node
---@field on_input_wrong field (self, button_node) Callback on wrong user input
---@field on_select field (self, button_node) Callback on input field selecting
@ -794,6 +773,13 @@ function druid__layout.fit_into_window(self) end
---@param on_size_changed_callback function The callback on window resize
function druid__layout.init(self, node, mode, on_size_changed_callback) end
--- Set max gui upscale for FIT adjust mode (or side).
--- It happens on bigger render gui screen
---@param self druid.layout @{Layout}
---@param max_gui_upscale number
---@return druid.layout @{Layout}
function druid__layout.set_max_gui_upscale(self, max_gui_upscale) end
--- Set maximum size of layout node
---@param self druid.layout @{Layout}
---@param max_size vector3
@ -952,6 +938,11 @@ function druid__rich_input.init(self, template, nodes) end
function druid__rich_input.set_placeholder(self, placeholder_text) end
---@class druid.rich_text : druid.base_component
---@field component field The component druid instance
local druid__rich_text = {}
---@class druid.scroll : druid.base_component
---@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)
@ -1272,7 +1263,7 @@ local druid__swipe__style = {}
---@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)
---@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
@ -1400,211 +1391,194 @@ local druid_const = {}
---@class druid_instance
local druid_instance = {}
--- Call on final function on gui_script.
--- It will call on_remove on all druid components
--- Call this in gui_script final function.
---@param self druid_instance
function druid_instance.final(self) end
--- Druid late update function call after init and before udpate step
---@param self druid_instance
function druid_instance.late_init(self) end
--- Log message, if is_debug mode is enabled
---@param self druid_instance @{DruidInstance}
---@param message string
---@param context table
function druid_instance.log_message(self, message, context) end
--- Create new druid component
--- Create new component.
---@param self druid_instance
---@param component Component Component module
---@param ... args Other component params to pass it to component:init function
function druid_instance.new(self, component, ...) end
--- Create back_handler basic component
--- Create @{BackHandler} component
---@param self druid_instance
---@param callback callback On back button
---@param params any Callback argument
---@return druid.back_handler back_handler component
---@return druid.back_handler @{BackHandler} component
function druid_instance.new_back_handler(self, callback, params) end
--- Create blocker basic component
--- Create @{Blocker} component
---@param self druid_instance
---@param node node Gui node
---@return druid.blocker blocker component
---@return druid.blocker @{Blocker} component
function druid_instance.new_blocker(self, node) end
--- Create button basic component
--- Create @{Button} component
---@param self druid_instance
---@param node node Gui node
---@param node node GUI node
---@param callback function Button callback
---@param params table Button callback params
---@param anim_node node Button anim node (node, if not provided)
---@return druid.button button component
---@return druid.button @{Button} component
function druid_instance.new_button(self, node, callback, params, anim_node) end
--- Create checkbox component
--- Create @{Checkbox} component
---@param self druid_instance
---@param node node Gui node
---@param callback function Checkbox callback
---@param click_node node Trigger node, by default equals to node
---@param initial_state boolean The initial state of checkbox, default - false
---@return druid.checkbox checkbox component
---@return druid.checkbox @{Checkbox} component
function druid_instance.new_checkbox(self, node, callback, click_node, initial_state) end
--- Create checkbox_group component
--- Create @{CheckboxGroup} component
---@param self druid_instance
---@param nodes node[] Array of gui node
---@param callback function Checkbox callback
---@param click_nodes node[] Array of trigger nodes, by default equals to nodes
---@return druid.checkbox_group checkbox_group component
---@return druid.checkbox_group @{CheckboxGroup} component
function druid_instance.new_checkbox_group(self, nodes, callback, click_nodes) end
--- Create data list basic component
--- Create @{DataList} component
---@param self druid_instance
---@param druid_scroll druid.scroll The Scroll instance for Data List component
---@param druid_grid Grid The Grid 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 data_list component
---@return druid.data_list @{DataList} component
function druid_instance.new_data_list(self, druid_scroll, druid_grid, create_function) end
--- Create drag basic component
--- Create @{Drag} component
---@param self druid_instance
---@param node node GUI node to detect dragging
---@param on_drag_callback function Callback for on_drag_event(self, dx, dy)
---@return druid.drag drag component
---@return druid.drag @{Drag} component
function druid_instance.new_drag(self, node, on_drag_callback) end
--- Create dynamic grid component
--- Create @{DynamicGrid} component
---@param self druid_instance
---@param parent node The gui node parent, where items will be placed
---@return druid.dynamic_grid grid component
---@return druid.dynamic_grid @{DynamicGrid} component
function druid_instance.new_dynamic_grid(self, parent) end
--- Create grid basic component Deprecated
---@param self druid_instance
---@param parent node The gui node parent, where items will be placed
---@param element node Element prefab. Need to get it size
---@param in_row number How many nodes in row can be placed
---@return druid.static_grid grid component
function druid_instance.new_grid(self, parent, element, in_row) end
--- Create hotkey component
--- 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 Button callback
---@param params value Button callback params
---@return druid.hotkey hotkey component
---@return druid.hotkey @{Hotkey} component
function druid_instance.new_hotkey(self, keys_array, callback, params) end
--- Create hover basic component
--- Create @{Hover} component
---@param self druid_instance
---@param node node Gui node
---@param on_hover_callback function Hover callback
---@return druid.hover hover component
---@return druid.hover @{Hover} component
function druid_instance.new_hover(self, node, on_hover_callback) end
--- Create input component
--- Create @{Input} component
---@param self druid_instance
---@param click_node node Button node to enabled input component
---@param text_node node Text node what will be changed on user input
---@param keyboard_type number Gui keyboard type for input field
---@return druid.input input component
---@return druid.input @{Input} component
function druid_instance.new_input(self, click_node, text_node, keyboard_type) end
--- Create lang_text component
--- Create @{LangText} component
---@param self druid_instance
---@param node node The text node
---@param locale_id string Default locale id
---@param no_adjust bool If true, will not correct text size
---@return druid.lang_text lang_text component
---@return druid.lang_text @{LangText} component
function druid_instance.new_lang_text(self, node, locale_id, no_adjust) end
--- Create layout component
--- Create @{Layout} component
---@param self druid_instance
---@param node string|node Layout node
---@param mode string The layout mode
---@return druid.layout layout component
---@return druid.layout @{Layout} component
function druid_instance.new_layout(self, node, mode) end
--- Create progress component
--- 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 Initial value of progress bar
---@return druid.progress progress component
---@return druid.progress @{Progress} component
function druid_instance.new_progress(self, node, key, init_value) end
--- Create radio_group component
--- Create @{RadioGroup} component
---@param self druid_instance
---@param nodes node[] Array of gui node
---@param callback function Radio callback
---@param click_nodes node[] Array of trigger nodes, by default equals to nodes
---@return druid.radio_group radio_group component
---@return druid.radio_group @{RadioGroup} component
function druid_instance.new_radio_group(self, nodes, callback, click_nodes) end
--- Create scroll basic component
--- Create @{Scroll} component
---@param self druid_instance
---@param view_node node GUI view scroll node
---@param content_node node GUI content scroll node
---@return druid.scroll scroll component
---@return druid.scroll @{Scroll} component
function druid_instance.new_scroll(self, view_node, content_node) end
--- Create slider component
--- Create @{Slider} component
---@param self druid_instance
---@param node node Gui pin node
---@param end_pos vector3 The end position of slider
---@param callback function On slider change callback
---@return druid.slider slider component
---@return druid.slider @{Slider} component
function druid_instance.new_slider(self, node, end_pos, callback) end
--- Create static grid basic component
--- Create @{StaticGrid} component
---@param self druid_instance
---@param parent node The gui node parent, where items will be placed
---@param element node Element prefab. Need to get it size
---@param in_row number How many nodes in row can be placed
---@return druid.static_grid grid component
---@return druid.static_grid @{StaticGrid} component
function druid_instance.new_static_grid(self, parent, element, in_row) end
--- Create swipe basic component
--- Create @{Swipe} component
---@param self druid_instance
---@param node node Gui node
---@param on_swipe_callback function Swipe callback for on_swipe_end event
---@return druid.swipe swipe component
---@return druid.swipe @{Swipe} component
function druid_instance.new_swipe(self, node, on_swipe_callback) end
--- Create text basic component
--- Create @{Text} component
---@param self druid_instance
---@param node node Gui text node
---@param value string Initial text. Default value is node text from GUI scene.
---@param no_adjust bool If true, text will be not auto-adjust size
---@return Tet text component
---@return druid.text @{Text} component
function druid_instance.new_text(self, node, value, no_adjust) end
--- Create timer component
--- Create @{Timer} component
---@param self druid_instance
---@param node node Gui text node
---@param seconds_from number Start timer value in seconds
---@param seconds_to number End timer value in seconds
---@param callback function Function on timer end
---@return druid.timer timer component
---@return druid.timer @{Timer} component
function druid_instance.new_timer(self, node, seconds_from, seconds_to, callback) end
--- Druid on_input function
--- 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 bool The boolean value is input was consumed
function druid_instance.on_input(self, action_id, action) end
--- Druid on_message function
--- 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 hash Sender from on_message
function druid_instance.on_message(self, message_id, message, sender) end
--- Remove component from druid instance.
--- Remove component from Druid instance.
--- Component `on_remove` function will be invoked, if exist.
---@param self druid_instance
---@param component Component Component instance
@ -1616,20 +1590,14 @@ function druid_instance.remove(self, component) end
---@param blacklist_components table|Component The array of component to blacklist
function druid_instance.set_blacklist(self, blacklist_components) end
--- Set debug mode for current Druid instance.
--- It's enable debug log messages
---@param self druid_instance @{DruidInstance}
---@param is_debug bool
---@return self @{DruidInstance}
function druid_instance.set_debug(self, is_debug) 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|Component The array of component to whitelist
function druid_instance.set_whitelist(self, whitelist_components) end
--- Druid update function
--- 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
@ -1659,57 +1627,199 @@ function formats.second_string_min(s, tab) end
---@class helper
local helper = {}
--- Center two nodes.
--- Nodes will be center around 0 x position icon_node will be first (at left side)
---@param icon_node box Gui box node
---@param text_node text Gui text node
--- 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 Offset between nodes
function helper.centrate_icon_with_text(icon_node, text_node, margin) end
--- Center several nodes nodes.
--- Nodes will be center around 0 x position
---@param margin number Offset between nodes
---@param ... Node Any count of gui Node
---@param ... unknown Gui nodes
function helper.centrate_nodes(margin, ...) end
--- Center two nodes.
--- Nodes will be center around 0 x position text_node will be first (at left side)
---@param text_node text Gui text node
---@param icon_node box Gui box node
---@param margin number Offset between nodes
function helper.centrate_text_with_icon(text_node, icon_node, 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
--- Show deprecated message.
--- Once time per message
---@param message string The deprecated message
function helper.deprecated(message) 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 The gui node to check
---@param offset vector3 The offset to add to result
---@return vector4 Vector with distance to node border: (left, top, right, down)
---@param node node GUI node
---@param offset vector3 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 node
---@param node node Gui node
---@return node|nil The clipping node
--- 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 node offset for given gui pivot
--- 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 gui.pivot The node pivot
---@return vector3 Vector offset with [-1..1] values
---@return vector3 Vector offset with [-0.5..0.5] values
function helper.get_pivot_offset(pivot) end
--- Check if node is enabled in gui hierarchy.
--- Return false, if node or any his parent is disabled
--- 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 bool 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 Fields: width, height, max_ascent, max_descent
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 item unknown Item to insert
---@param index number Index to insert. If nil, item will be inserted at the end of array
---@param shift_policy const.SHIFT Shift policy
---@return item Inserted item
function helper.insert_with_shift(array, item, index, shift_policy) end
--- Check if node is enabled in GUI hierarchy.
--- Return false, if node or any his parent is disabled
---@param node node GUI node
---@return bool Is enabled in hierarchy
function helper.is_enabled(node) end
--- Check if device is mobile (Android or iOS)
--- Check if device is native mobile (Android or iOS)
---@return bool Is mobile
function helper.is_mobile() end
--- Check if device is HTML5
---@return bool Is web
function helper.is_web() 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 Index to remove. If nil, item will be removed from the end of array
---@param shift_policy const.SHIFT Shift policy
---@return item 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 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.rich_text.metrics
---@field width number
---@field height number
---@field offset_x number|nil
---@field offset_y number|nil
---@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<number, druid.rich_text.metrics>
---@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 Pivot
---@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
---@class druid.rich_text.word.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<string, string>
---@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 node_prefab Node
---@field text_prefab Node
---@class GUITextMetrics
---@field width number
---@field height number
---@field max_ascent number
---@field max_descent number

View File

@ -1,15 +1,40 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
-- Copyright (c) 2023 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle back key (android, backspace)
--- 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.
--
-- # Tech Info #
--
-- Back Handler react on release action ACTION_BACK or ACTION_BACKSPACE
--
-- # Notes #
--
-- • Back Handler inheritance @{BaseComponent}, you can use all of its methods in addition to those described here.
-- @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
--- On back handler callback(self, params)
--- @{DruidEvent} function(self, [params]) .
--
-- Trigger on input action ACTION_BACK or ACTION_BACKSPACE
-- @usage
-- -- Subscribe additional callbacks:
-- back_handler.on_back:subscribe(callback)
-- @tfield DruidEvent on_back @{DruidEvent}
--- Params to back callback
-- @tfield any params
--- Params to pass in the callback
-- @usage
-- -- Replace params on runtime:
-- back_handler.params = { ... }
-- @tfield[opt] any params
---
@ -20,20 +45,22 @@ local component = require("druid.component")
local BackHandler = component.create("back_handler")
--- Component init function
--- Component initialize function
-- @tparam BackHandler self @{BackHandler}
-- @tparam callback callback On back button
-- @tparam[opt] any params Callback argument
-- @local
function BackHandler.init(self, callback, params)
self.params = params
self.on_back = Event(callback)
end
--- Input handler for component
--- 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)
if not action[const.RELEASED] then
return false

View File

@ -1,6 +1,22 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
-- Copyright (c) 2023 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to block input on specify zone by node
--- Component to block input in special zone defined by GUI node.
-- # Overview #
--
-- Blocker component необходим, чтобы блокировать пользовательский ввод в определенной зоне.
-- Зона задается размером ноды, на которой находится компонент. Blocker блокирует ввод только для тех
-- элементов, которые находятся перед ним in input stack (созданы до него).
--
-- # Tech Info #
--
-- Blocker consume input if `gui.pick_node` works on it.
--
-- # Notes #
--
-- • Blocker inheritance @{BaseComponent}, you can use all of its methods in addition to those described here.
-- @usage
-- local node = gui.get_node("blocker_node")
-- local blocker = self.druid:new_blocker(node)
-- @module Blocker
-- @within BaseComponent
-- @alias druid.blocker
@ -16,14 +32,20 @@ local component = require("druid.component")
local Blocker = component.create("blocker")
--- Component init function
--- Component initialize function
-- @tparam Blocker self @{Blocker}
-- @tparam node node Gui node
-- @local
function Blocker.init(self, node)
self.node = self:get_node(node)
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)
if action_id ~= const.ACTION_TOUCH and
action_id ~= const.ACTION_MULTITOUCH and
@ -51,7 +73,7 @@ function Blocker.set_enabled(self, state)
end
--- Return blocked enabled state
--- Return blocker enabled state
-- @tparam Blocker self @{Blocker}
-- @treturn bool True, if blocker is enabled
function Blocker.is_enabled(self)

View File

@ -143,7 +143,7 @@ function Scroll.init(self, view_node, content_node)
self.view_border = helper.get_border(self.view_node)
self.content_node = self:get_node(content_node)
self.view_size = vmath.mul_per_elem(gui.get_size(self.view_node), gui.get_scale(self.view_node))
self.view_size = helper.get_scaled_size(self.view_node)
self.position = gui.get_position(self.content_node)
self.target_position = vmath.vector3(self.position)
@ -457,7 +457,6 @@ function Scroll.bind_grid(self, grid)
local size = grid:get_size()
local offset = grid:get_offset()
self:set_size(size, offset)
self:log_message("Change size from grid", { size = size, offset = offset })
end)
self:set_size(grid:get_size(), grid:get_offset())
@ -694,7 +693,7 @@ end
function Scroll._update_size(self)
local content_border = helper.get_border(self.content_node)
local content_size = vmath.mul_per_elem(gui.get_size(self.content_node), gui.get_scale(self.content_node))
local content_size = helper.get_scaled_size(self.content_node)
self.available_pos = get_border_vector(self.view_border - content_border, self._offset)
self.available_size = get_size_vector(self.available_pos)

View File

@ -1,7 +1,20 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Basic class for all Druid components.
-- To create you component, use `component.create`
-- 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
@ -9,14 +22,12 @@ local const = require("druid.const")
local class = require("druid.system.middleclass")
local helper = require("druid.helper")
local BaseComponent = class("druid.component")
local INTERESTS = {} -- Cache interests by component class in runtime
local INTERESTS = {} -- Cache interests per component class in runtime
local IS_AUTO_TEMPLATE = not (sys.get_config("druid.no_auto_template") == "1")
--- Component Interests
-- Component Interests
BaseComponent.ON_INPUT = const.ON_INPUT
BaseComponent.ON_UPDATE = const.ON_UPDATE
BaseComponent.ON_MESSAGE = const.ON_MESSAGE
@ -28,7 +39,6 @@ BaseComponent.ON_MESSAGE_INPUT = const.ON_MESSAGE_INPUT
BaseComponent.ON_WINDOW_RESIZED = const.ON_WINDOW_RESIZED
BaseComponent.ON_LANGUAGE_CHANGE = const.ON_LANGUAGE_CHANGE
BaseComponent.ALL_INTERESTS = {
BaseComponent.ON_INPUT,
BaseComponent.ON_UPDATE,
@ -42,7 +52,6 @@ BaseComponent.ALL_INTERESTS = {
BaseComponent.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
@ -61,23 +70,31 @@ function BaseComponent.static.get_uid()
end
--- Set current component style table (protected).
-- Invoke `on_style_change` on component, if exist. BaseComponent should handle
--- Set current component style table.
--
-- Invoke `on_style_change` on component, if exist. Component should handle
-- their style changing and store all style params
-- @function component:set_style
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam table druid_style Druid style module
-- @treturn BaseComponent @{BaseComponent}
function BaseComponent.set_style(self, druid_style)
self._meta.style = druid_style or const.EMPTY_TABLE
local component_style = self._meta.style[self._component.name] or const.EMPTY_TABLE
self._meta.style = druid_style or {}
local component_style = self._meta.style[self._component.name] or {}
if self.on_style_change then
self:on_style_change(component_style)
end
return self
end
--- Set current component template name (protected)
-- It will check parent template name to build full template name
--- 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()
-- @function component:set_template
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam string template BaseComponent template name
-- @treturn BaseComponent @{BaseComponent}
@ -100,7 +117,8 @@ function BaseComponent.set_template(self, template)
end
--- Get current component template name (protected)
--- Get current component template name.
-- @function component:get_template
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn string Component full template name
function BaseComponent.get_template(self)
@ -108,10 +126,17 @@ function BaseComponent.get_template(self)
end
--- Set current component nodes (protected)
--- Set current component nodes
--
-- Used if your component nodes was cloned with `gui.clone_tree`
-- @function component:set_nodes
-- @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)
function BaseComponent.set_nodes(self, nodes)
self._meta.nodes = nodes
@ -128,7 +153,10 @@ function BaseComponent.set_nodes(self, nodes)
end
--- Get current component context (protected)
--- Context used as first arg in all Druid events
--
-- Context is usually self of gui_script.
-- @function component:get_context
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn table BaseComponent context
function BaseComponent.get_context(self)
@ -136,7 +164,8 @@ function BaseComponent.get_context(self)
end
--- Increase input priority in current input stack
--- Increase input priority in input stack
-- @function component:increase_input_priority
-- @tparam BaseComponent self @{BaseComponent}
-- @local
function BaseComponent.increase_input_priority(self)
@ -144,15 +173,22 @@ function BaseComponent.increase_input_priority(self)
end
--- Get node for component by name.
--- Get component node by name.
--
-- If component has nodes, node_or_name should be string
-- It auto pick node by template name or from nodes by clone_tree
-- 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
-- @function component:get_node
-- @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) ~= const.STRING then
-- Assume it's already node from gui.get_node
return node_or_name
end
local template_name = self:get_template()
local nodes = self:__get_nodes()
@ -161,16 +197,11 @@ function BaseComponent.get_node(self, node_or_name)
end
local node
if type(node_or_name) == const.STRING then
if nodes then
node = nodes[template_name .. node_or_name]
else
node = gui.get_node(template_name .. node_or_name)
end
else
-- Assume it's already node from gui.get_node
node = node_or_name
end
if not node then
assert(node, "No component with name: " .. (template_name or "") .. (node_or_name or ""))
@ -180,8 +211,8 @@ function BaseComponent.get_node(self, node_or_name)
end
--- Return druid with context of calling component (protected).
-- Use it to create component inside of other components.
--- Get Druid instance for inner component creation.
-- @function component:get_druid
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn Druid Druid instance with component context
function BaseComponent.get_druid(self)
@ -191,6 +222,7 @@ end
--- Return component name
-- @function component:get_name
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn string The component name
function BaseComponent.get_name(self)
@ -199,6 +231,7 @@ end
--- Return parent component name
-- @function component:get_parent_name
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn string|nil The parent component name if exist or bil
function BaseComponent.get_parent_name(self)
@ -208,6 +241,7 @@ end
--- Return component input priority
-- @function component:get_input_priority
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn number The component input priority
function BaseComponent.get_input_priority(self)
@ -216,6 +250,9 @@ end
--- Set component input priority
--
-- Default value: 10
-- @function component:set_input_priority
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam number value The new input priority value
-- @tparam boolean is_temporary If true, the reset input priority will return to previous value
@ -223,7 +260,10 @@ end
function BaseComponent.set_input_priority(self, value, is_temporary)
assert(value)
if self._component.input_priority ~= value then
if self._component.input_priority == value then
return self
end
self._component.input_priority = value
self._component._is_input_priority_changed = true
@ -235,13 +275,13 @@ function BaseComponent.set_input_priority(self, value, is_temporary)
for i = 1, #children do
children[i]:set_input_priority(value, is_temporary)
end
end
return self
end
--- Reset component input priority to default value
-- @function component:reset_input_priority
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn number The component input priority
function BaseComponent.reset_input_priority(self)
@ -250,8 +290,10 @@ function BaseComponent.reset_input_priority(self)
end
--- Return component uid (protected).
--- UID generated in component creation order
--- Return component UID.
--
-- UID generated in component creation order.
-- @function component:get_uid
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn number The component uid
function BaseComponent.get_uid(self)
@ -260,7 +302,9 @@ end
--- Set component input state. By default it enabled
-- You can disable any input of component by this function
--
-- If input is disabled, the component will not receive input events
-- @function component:set_input_enabled
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam bool state The component input state
-- @treturn BaseComponent BaseComponent itself
@ -275,7 +319,8 @@ function BaseComponent.set_input_enabled(self, state)
end
--- Return the parent for current component (protected)
--- Return the parent component if exist
-- @function component:get_parent_component
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn BaseComponent|nil The druid component instance or nil
function BaseComponent.get_parent_component(self)
@ -284,6 +329,7 @@ end
--- Setup component context and his style table
-- @function component:setup_component
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam table druid_instance The parent druid instance
-- @tparam table context Druid context. Usually it is self of script
@ -317,6 +363,7 @@ end
--- Basic constructor of component. It will call automaticaly
-- by `BaseComponent.static.create`
-- @function component:initialize
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam string name BaseComponent name
-- @tparam[opt=DEFAULT] number input_priority The input priority. The bigger number processed first
@ -333,10 +380,12 @@ function BaseComponent.initialize(self, name, input_priority)
end
--- Print log information if debug mode is enabled (protected)
--- Print log information if debug mode is enabled
-- @function component:log_message
-- @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
@ -346,14 +395,17 @@ end
--- Set debug logs for component enabled or disabled
-- @function component:set_debug
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam bool is_debug
-- @local
function BaseComponent.set_debug(self, is_debug)
self._component.is_debug = is_debug
end
--- Return true, if input priority was changed
-- @function component:_is_input_priority_changed
-- @tparam BaseComponent self @{BaseComponent}
-- @local
function BaseComponent._is_input_priority_changed(self)
@ -362,6 +414,7 @@ end
--- Reset is_input_priority_changed field
-- @function component:_reset_input_priority_changed
-- @tparam BaseComponent self @{BaseComponent}
-- @local
function BaseComponent._reset_input_priority_changed(self)
@ -375,6 +428,7 @@ end
--- Get current component interests
-- @function component:__get_interests
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn table List of component interests
-- @local
@ -398,6 +452,7 @@ end
--- Get current component nodes
-- @function component:__get_nodes
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn table BaseComponent nodes table
-- @local
@ -412,6 +467,7 @@ end
--- Add child to component children list
-- @function component:__add_children
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam component children The druid component instance
-- @local
@ -421,6 +477,7 @@ end
--- Remove child from component children list
-- @function component:__remove_children
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam component children The druid component instance
-- @local
@ -433,7 +490,8 @@ function BaseComponent.__remove_children(self, children)
end
--- Return all children components, recursive (protected)
--- Return all children components, recursive
-- @function component:get_childrens
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn table Array of childrens if the Druid component instance
function BaseComponent.get_childrens(self)
@ -453,8 +511,8 @@ function BaseComponent.get_childrens(self)
end
--- Create new component. It will inheritance from basic
-- druid component.
--- Create new component. It will inheritance from basic Druid component.
-- @function BaseComponent.static.create
-- @tparam string name BaseComponent name
-- @tparam[opt=DEFAULT] number input_priority The input priority. The bigger number processed first
-- @local

View File

@ -20,10 +20,8 @@ M.ACTION_BACKSPACE = hash(sys.get_config("druid.input_key_backspace", "key_backs
M.ACTION_SCROLL_UP = hash(sys.get_config("druid.input_scroll_up", "mouse_wheel_up"))
M.ACTION_SCROLL_DOWN = hash(sys.get_config("druid.input_scroll_down", "mouse_wheel_down"))
M.IS_STENCIL_CHECK = not (sys.get_config("druid.no_stencil_check") == "1")
M.RELEASED = "released"
M.PRESSED = "pressed"
M.STRING = "string"
@ -83,7 +81,6 @@ M.REVERSE_PIVOTS = {
[gui.PIVOT_NW] = gui.PIVOT_SE,
}
M.LAYOUT_MODE = {
STRETCH_X = "stretch_x",
STRETCH_Y = "stretch_y",
@ -98,7 +95,6 @@ M.VECTOR_ONE = vmath.vector3(1)
M.SYS_INFO = sys.get_sys_info()
M.CURRENT_SYSTEM_NAME = M.SYS_INFO.system_name
M.OS = {
ANDROID = "Android",
IOS = "iPhone OS",
@ -108,14 +104,12 @@ M.OS = {
BROWSER = "HTML5",
}
M.SHIFT = {
NO_SHIFT = 0,
LEFT = -1,
RIGHT = 1,
}
M.TEXT_ADJUST = {
DOWNSCALE = "downscale",
TRIM = "trim",
@ -125,13 +119,11 @@ M.TEXT_ADJUST = {
SCALE_THEN_SCROLL = "scale_then_scroll",
}
M.SIDE = {
X = "x",
Y = "y"
}
M.SWIPE = {
UP = "up",
DOWN = "down",
@ -139,16 +131,11 @@ 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
M.EMPTY_STRING = ""
M.SPACE_STRING = " "
M.EMPTY_TABLE = {}
return M

View File

@ -2,6 +2,10 @@
-- Author: Britzl
-- Modified by: Insality
--- RT
-- @module rich_text.rt
-- @local
local helper = require("druid.helper")
local parser = require("druid.custom.rich_text.module.rt_parse")
local utf8_lua = require("druid.system.utf8")
@ -203,6 +207,7 @@ function M._fill_properties(word, metrics, settings)
word.position = vmath.vector3(0)
if word.image then
-- Image properties
word.scale = gui.get_scale(settings.node_prefab) * word.relative_scale * settings.adjust_scale
word.pivot = gui.get_pivot(settings.node_prefab)
word.size = metrics.node_size
@ -212,6 +217,7 @@ function M._fill_properties(word, metrics, settings)
word.size.x = word.image.width
end
else
-- Text properties
word.scale = gui.get_scale(settings.text_prefab) * word.relative_scale * settings.adjust_scale
word.pivot = gui.get_pivot(settings.text_prefab)
word.size = vmath.vector3(metrics.width, metrics.height, 0)
@ -510,32 +516,6 @@ function M.is_fit_info_area(lines, settings)
end
--- Detected click/touch events on words with an anchor tag
-- These words act as "hyperlinks" and will generate a message when clicked
-- @param words Words to search for anchor tags
-- @param action The action table from on_input
-- @return true if a word was clicked, otherwise false
function M.on_click(words, action)
for i = 1, #words do
local word = words[i]
if word.anchor and gui.pick_node(word.node, action.x, action.y) then
if word.tags and word.tags.a then
local message = {
node_id = gui.get_id(word.node),
text = word.text,
x = action.x, y = action.y,
screen_x = action.screen_x, screen_y = action.screen_y
}
msg.post("#", word.tags.a, message)
return true
end
end
end
return false
end
--- Get all words with a specific tag
-- @param words The words to search (as received from richtext.create)
-- @param tag The tag to search for. Nil to search for words without a tag

View File

@ -1,7 +1,17 @@
-- Copyright (c) 2022 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid Rich Text custom component.
-- @module RichText
-- @within BaseComponent
-- @alias druid.rich_text
--- The component druid instance
-- @tfield DruidInstance druid @{DruidInstance}
local component = require("druid.component")
local rich_text = require("druid.custom.rich_text.module.rt")
---@class druid.rich_text
local RichText = component.create("rich_text")
local SCHEME = {
@ -14,9 +24,9 @@ local SCHEME = {
function RichText:init(template, nodes)
self:set_template(template)
self:set_nodes(nodes)
self.root = self:get_node(SCHEME.ROOT)
self.druid = self:get_druid()
self.root_size = gui.get_size(self.root)
self.text_prefab = self:get_node(SCHEME.TEXT_PREFAB)
self.icon_prefab = self:get_node(SCHEME.ICON_PREFAB)
@ -24,12 +34,10 @@ function RichText:init(template, nodes)
gui.set_enabled(self.text_prefab, false)
gui.set_enabled(self.icon_prefab, false)
self._settings = self:_get_settings()
self._settings = self:_create_settings()
end
---@param text string
---@return rich_text.word[], rich_text.lines_metrics
function RichText:set_text(text)
self:clean()
@ -57,24 +65,25 @@ function RichText:tagged(tag)
end
---@return druid.rich_text_word[]
function RichText:get_words()
return self._words
end
function RichText:_get_settings()
function RichText:_create_settings()
local root_size = gui.get_size(self.root)
return {
-- General settings
-- Adjust scale using to fit the text to the root node area
adjust_scale = 1,
parent = self.root,
width = self.root_size.x,
height = self.root_size.y,
width = root_size.x,
height = root_size.y,
combine_words = false,
text_prefab = self.text_prefab,
node_prefab = self.icon_prefab,
-- Text Settings
size = gui.get_scale(self.text_prefab).x,
shadow = gui.get_shadow(self.text_prefab),
outline = gui.get_outline(self.text_prefab),
text_scale = gui.get_scale(self.text_prefab),
@ -82,7 +91,6 @@ function RichText:_get_settings()
is_multiline = gui.get_line_break(self.text_prefab),
-- Image settings
combine_words = false,
image_pixel_grid_snap = false,
node_scale = gui.get_scale(self.icon_prefab),
image_scale = gui.get_scale(self.icon_prefab),

View File

@ -1,20 +1,49 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid UI Library.
-- Powerful Defold component based UI library. Use standart
-- components or make your own game-specific components to
-- make amazing GUI in your games.
--- Druid UI Component Framework.
-- # Overview #
--
-- Contains the several basic components and examples
-- to how to do your custom complex components to
-- separate UI game logic to small files
-- Druid - powerful Defold component UI library. Use basic and extended
-- Druid components or make your own game-specific components to make
-- amazing GUI in your games.
--
-- require("druid.druid")
-- function init(self)
-- self.druid = druid.new(self)
-- To start using Druid, please refer to the Basic Usage section below.
--
-- # Tech Info #
--
-- • Each Druid instance maintains the self context from the constructor and passes it to each Druid callback.
--
-- See next: @{DruidInstance}
--
-- @usage
-- local druid = require("druid.druid")
--
-- local function on_play(self)
-- print("Gonna play!")
-- end
--
-- @module druid
-- function init(self)
-- self.druid = druid.new(self)
-- self.druid:new_button("button_play", on_play)
-- end
--
-- function final(self)
-- self.druid:final()
-- end
--
-- function update(self, dt)
-- self.druid:update(dt)
-- end
--
-- function on_message(self, message_id, message, sender)
-- self.druid:on_message(message_id, message, sender)
-- end
--
-- function on_input(self, action_id, action)
-- return self.druid:on_input(action_id, action)
-- end
--
-- @module Druid
local const = require("druid.const")
local base_component = require("druid.component")
@ -38,26 +67,39 @@ local function get_druid_instances()
end
--- Register external druid component.
-- After register you can create the component with
-- druid_instance:new_{name}. For example `druid:new_button(...)`
-- @function druid:register
--- 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(...)
function M.register(name, module)
-- TODO: Find better solution to creating elements?
-- Current way is very implicit
druid_instance["new_" .. name] = function(self, ...)
return druid_instance.new(self, module, ...)
end
end
--- Create Druid instance.
--- Create a new Druid instance for creating GUI components.
--
-- @function druid.new
-- @tparam table context Druid context. Usually it is self of script
-- @tparam[opt] table style Druid style module
-- @treturn druid_instance Druid instance
-- @tparam table context The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks.
-- @tparam[opt] table 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
function M.new(context, style)
if settings.default_style == nil then
M.set_default_style(default_style)
@ -69,40 +111,60 @@ function M.new(context, style)
end
--- Set new default style.
--- 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)
function M.set_default_style(style)
settings.default_style = style or {}
end
--- Set text function
-- Druid locale component will call this function
-- to get translated text. After set_text_funtion
-- all existing locale component will be updated
--- 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)
function M.set_text_function(callback)
settings.get_text = callback or const.EMPTY_FUNCTION
M.on_language_change()
end
--- Set sound function.
-- Component will call this function to
-- play sound by sound_id
--- 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)
function M.set_sound_function(callback)
settings.play_sound = callback or const.EMPTY_FUNCTION
end
--- Callback on global window event.
-- Used to trigger on_focus_lost and on_focus_gain
--- 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)
function M.on_window_callback(event)
local instances = get_druid_instances()
@ -126,9 +188,12 @@ function M.on_window_callback(event)
end
--- Callback on global language change event.
-- Use to update all lang texts
--- 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()
function M.on_language_change()
local instances = get_druid_instances()

View File

@ -1,6 +1,9 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid lua event library
--- Druid Event module.
--
-- Event is a simple class to handle callbacks. It's used in many Druid components.
-- You can subscribe to event with `:subscribe` method and unsubscribe with `:unsubscribe`.
-- @module DruidEvent
-- @alias druid.event
@ -9,9 +12,13 @@ local class = require("druid.system.middleclass")
local DruidEvent = class("druid.event")
--- Event constructur
--- DruidEvent constructor
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function initial_callback Subscribe the callback on new event, if callback exist
-- @tparam[opt] function initial_callback Subscribe the callback on new event, if callback exist
-- @usage
-- local Event = require("druid.event")
-- ...
-- local event = Event(initial_callback)
function DruidEvent.initialize(self, initial_callback)
self._callbacks = nil -- initialize later
@ -24,7 +31,14 @@ end
--- Subscribe callback on event
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself
-- @tparam table context Additional context as first param to callback call
-- @tparam[opt] Any context Additional context as first param to callback call, usually it's self
-- @usage
-- local function on_long_callback(self)
-- print("Long click!")
-- end
-- ...
-- local button = self.druid:new_button("button", callback)
-- button.on_long_click:subscribe(on_long_callback, self)
function DruidEvent.subscribe(self, callback, context)
assert(type(self) == "table", "You should subscribe to event with : syntax")
assert(type(callback) == "function", "Callback should be function")
@ -42,7 +56,13 @@ end
--- Unsubscribe callback on event
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself
-- @tparam table context Additional context as first param to callback call
-- @tparam[opt] Any context Additional context as first param to callback call
-- @usage
-- local function on_long_callback(self)
-- print("Long click!")
-- end
-- ...
-- button.on_long_click:unsubscribe(on_long_callback, self)
function DruidEvent.unsubscribe(self, callback, context)
if not self._callbacks then
return
@ -60,6 +80,8 @@ end
--- Return true, if event have at lease one handler
-- @tparam DruidEvent self @{DruidEvent}
-- @treturn bool True if event have handlers
-- @usage
-- local is_long_click_handler_exists = button.on_long_click:is_exist()
function DruidEvent.is_exist(self)
if not self._callbacks then
return false
@ -70,6 +92,8 @@ end
--- Clear the all event handlers
-- @tparam DruidEvent self @{DruidEvent}
-- @usage
-- button.on_long_click:clear()
function DruidEvent.clear(self)
self._callbacks = nil
end
@ -77,13 +101,18 @@ end
--- Trigger the event and call all subscribed callbacks
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam any ... All event params
-- @tparam Any ... All event params
-- @usage
-- local Event = require("druid.event")
-- ...
-- local event = Event()
-- event:trigger("Param1", "Param2")
function DruidEvent.trigger(self, ...)
if not self._callbacks then
return false
end
for index, callback_info in ipairs(self._callbacks) do
for _, callback_info in ipairs(self._callbacks) do
if callback_info.context then
callback_info.callback(callback_info.context, ...)
else

View File

@ -118,8 +118,6 @@ function DataList.add(self, data, index, shift_policy)
helper.insert_with_shift(self._data, data, index, shift_policy)
self:_update_data_info()
self:_check_elements()
self:log_message("Add element", { index = index })
end
@ -133,8 +131,6 @@ function DataList.remove(self, index, shift_policy)
helper.remove_with_shift(self._data, index, shift_policy)
self:_update_data_info()
self:log_message("Remove element", { index = index })
end
@ -255,7 +251,6 @@ function DataList._add_at(self, index)
component = instance
}
self:log_message("Add element at", { index = index })
self.on_element_add:trigger(self:get_context(), index, node, instance)
end
@ -276,7 +271,6 @@ function DataList._remove_at(self, index)
end
self._data_visual[index] = nil
self:log_message("Remove element at", { index = index })
self.on_element_remove:trigger(self:get_context(), index)
end
@ -322,8 +316,6 @@ function DataList._check_elements(self)
progress = 0
end
self:log_message("Check elements", { top_index = self.top_index, last_index = self.last_index, progress = progress })
if self.scroll_progress ~= progress then
self.scroll_progress = progress
self.on_scroll_progress_change:trigger(self:get_context(), progress)

View File

@ -118,7 +118,7 @@ function DynamicGrid.get_pos(self, index, node, origin_index)
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 = self:_get_node_size(node)
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,
@ -308,7 +308,7 @@ function DynamicGrid._add_node(self, node, index, origin_index)
self.nodes[index] = {
node = node,
pos = self:get_pos(index, node, origin_index),
size = self:_get_node_size(node),
size = helper.get_scaled_size(node),
pivot = const.PIVOTS[gui.get_pivot(node)]
}
@ -394,7 +394,7 @@ 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 = self:_get_node_size(new_node)
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
@ -410,11 +410,6 @@ function DynamicGrid._get_next_node_pos(self, origin_node_index, new_node, place
end
function DynamicGrid._get_node_size(self, node)
return vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
end
--- Return side vector to correct node shifting
function DynamicGrid._get_side_vector(self, side, is_forward)
if side == const.SIDE.X then

View File

@ -1,6 +1,6 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid helper module for gui layouts
--- Helper module with various usefull GUI functions.
-- @module Helper
-- @alias druid.helper
@ -9,7 +9,6 @@ local const = require("druid.const")
local M = {}
--- Text node or icon node can be nil
local function get_text_width(text_node)
if text_node then
local text_metrics = M.get_text_metrics_from_node(text_node)
@ -31,8 +30,14 @@ local function get_icon_width(icon_node)
end
local function is_text_node(node)
return gui.get_text(node) ~= nil
end
--- Text node or icon node can be nil
local function get_width(node)
return gui.get_text(node) and get_text_width(node) or get_icon_width(node)
return is_text_node(node) and get_text_width(node) or get_icon_width(node)
end
@ -43,6 +48,7 @@ end
-- @tparam[opt] text text_node Gui text node
-- @tparam[opt] box icon_node Gui box node
-- @tparam number margin Offset between nodes
-- @local
function M.centrate_text_with_icon(text_node, icon_node, margin)
M.centrate_nodes(margin, text_node, icon_node)
end
@ -55,16 +61,19 @@ end
-- @tparam[opt] box icon_node Gui box node
-- @tparam[opt] text text_node Gui text node
-- @tparam[opt=0] number margin Offset between nodes
-- @local
function M.centrate_icon_with_text(icon_node, text_node, margin)
M.centrate_nodes(margin, icon_node, text_node)
end
--- Center several nodes nodes.
-- Nodes will be center around 0 x position
--- 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[opt=0] number margin Offset between nodes
-- @tparam[opt] Node ... Any count of gui Node
-- @param ... Gui nodes
function M.centrate_nodes(margin, ...)
margin = margin or 0
@ -98,6 +107,10 @@ 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
function M.get_screen_aspect_koef()
local window_x, window_y = window.get_size()
local stretch_x = window_x / gui.get_width()
@ -107,6 +120,10 @@ 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
function M.get_gui_scale()
local window_x, window_y = window.get_size()
return math.min(window_x / gui.get_width(),
@ -114,6 +131,12 @@ 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
function M.step(current, target, step)
if current < target then
return math.min(current + step, target)
@ -123,6 +146,12 @@ 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
function M.clamp(a, min, max)
if min > max then
min, max = max, min
@ -138,11 +167,22 @@ 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
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
function M.sign(val)
if val == 0 then
return 0
@ -152,27 +192,47 @@ function M.sign(val)
end
function M.round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
--- Round number to specified decimal places
-- @function helper.round
-- @tparam number num Number
-- @tparam[opt=0] number num_decimal_places Decimal places
-- @treturn number 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
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
end
end
return false
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
function M.deepcopy(orig_table)
local orig_type = type(orig_table)
local copy
@ -188,35 +248,23 @@ function M.deepcopy(orig_table)
end
--- Get text metric from gui node. Replacement of previous gui.get_text_metrics_from_node function
-- @tparam Node text_node
-- @treturn table {width, height, max_ascent, max_descent}
function M.get_text_metrics_from_node(text_node)
local font_name = gui.get_font(text_node)
local font = gui.get_font_resource(font_name)
return resource.get_text_metrics(font, gui.get_text(text_node), {
width = gui.get_size(text_node).x,
leading = gui.get_leading(text_node),
tracking = gui.get_tracking(text_node),
line_break = gui.get_line_break(text_node),
})
--- Get node size adjusted by scale
-- @function helper.get_scaled_size
-- @tparam 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
--- Check if node is enabled in gui hierarchy.
--- Check if node is enabled in GUI hierarchy.
--
-- Return false, if node or any his parent is disabled
-- @function helper.is_enabled
-- @tparam node node Gui node
-- @tparam node node GUI node
-- @treturn bool Is enabled in hierarchy
function M.is_enabled(node)
local is_enabled = gui.is_enabled(node)
local parent = gui.get_parent(node)
while parent and is_enabled do
is_enabled = is_enabled and gui.is_enabled(parent)
parent = gui.get_parent(parent)
end
return is_enabled
return gui.is_enabled(node, true)
end
@ -237,10 +285,10 @@ function M.get_scene_scale(node, include_passed_node_scale)
end
--- Return closest non inverted clipping parent node for node
--- 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 clipping node
-- @tparam node node GUI node
-- @treturn node|nil The closest stencil node or nil
function M.get_closest_stencil_node(node)
if not node then
return nil
@ -262,17 +310,20 @@ function M.get_closest_stencil_node(node)
end
--- Get node offset for given gui pivot
--- 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.
-- @function helper.get_pivot_offset
-- @tparam gui.pivot pivot The node pivot
-- @treturn vector3 Vector offset with [-1..1] values
-- @treturn vector3 Vector offset with [-0.5..0.5] values
function M.get_pivot_offset(pivot)
return const.PIVOTS[pivot]
end
--- Check if device is mobile (Android or iOS)
--- Check if device is native mobile (Android or iOS)
-- @function helper.is_mobile
-- @treturn bool Is mobile
function M.is_mobile()
return const.CURRENT_SYSTEM_NAME == const.OS.IOS or
const.CURRENT_SYSTEM_NAME == const.OS.ANDROID
@ -281,12 +332,14 @@ end
--- Check if device is HTML5
-- @function helper.is_web
-- @treturn bool Is web
function M.is_web()
return const.CURRENT_SYSTEM_NAME == const.OS.BROWSER
end
--- Transform table to oneline string
--- Simple table to one-line string converter
-- @function helper.table_to_string
-- @tparam table t
-- @treturn string
function M.table_to_string(t)
@ -309,13 +362,13 @@ end
--- Distance from node position to his borders
-- @function helper.get_border
-- @tparam node node The gui node to check
-- @tparam vector3 offset The offset to add to result
-- @return vector4 Vector with distance to node border: (left, top, right, down)
-- @tparam node node GUI node
-- @tparam[opt] vector3 offset Offset from node position. Pass current node position to get non relative border values
-- @treturn vector4 Vector4 with border values (left, top, right, down)
function M.get_border(node, offset)
local pivot = gui.get_pivot(node)
local pivot_offset = M.get_pivot_offset(pivot)
local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
local size = M.get_scaled_size(node)
local border = vmath.vector4(
-size.x*(0.5 + pivot_offset.x),
size.y*(0.5 - pivot_offset.y),
@ -334,9 +387,10 @@ function M.get_border(node, offset)
end
--- Get text metric from gui node. Replacement of previous gui.get_text_metrics_from_node function
--- Get text metric from GUI node.
-- @function helper.get_text_metrics_from_node
-- @tparam Node text_node
-- @treturn table {width, height, max_ascent, max_descent}
-- @treturn GUITextMetrics Fields: width, height, max_ascent, max_descent
function M.get_text_metrics_from_node(text_node)
local font_resource = gui.get_font_resource(gui.get_font(text_node))
local options = {
@ -354,6 +408,15 @@ function M.get_text_metrics_from_node(text_node)
end
--- Add value to array with shift policy
--
-- Shift policy can be: left, right, no_shift
-- @function helper.insert_with_shift
-- @tparam table array Array
-- @param item Item to insert
-- @tparam[opt] number index Index to insert. If nil, item will be inserted at the end of array
-- @tparam[opt] const.SHIFT shift_policy Shift policy
-- @treturn item Inserted item
function M.insert_with_shift(array, item, index, shift_policy)
shift_policy = shift_policy or const.SHIFT.RIGHT
@ -377,6 +440,14 @@ function M.insert_with_shift(array, item, index, shift_policy)
end
--- Remove value from array with shift policy
--
-- Shift policy can be: left, right, no_shift
-- @function helper.remove_with_shift
-- @tparam table array Array
-- @tparam[opt] number index Index to remove. If nil, item will be removed from the end of array
-- @tparam[opt] const.SHIFT shift_policy Shift policy
-- @treturn item Removed item
function M.remove_with_shift(array, index, shift_policy)
shift_policy = shift_policy or const.SHIFT.RIGHT
@ -404,6 +475,7 @@ end
--- Show deprecated message. Once time per message
-- @function helper.deprecated
-- @tparam string message The deprecated message
-- @local
local _deprecated_messages = {}
function M.deprecated(message)
if _deprecated_messages[message] then
@ -415,7 +487,8 @@ function M.deprecated(message)
end
-- Show message to require extended component
--- Show message to require extended component
-- @local
function M.extended_component(component_name)
print(string.format("[Druid]: The component %s is extended component. You have to register it via druid.register to use it", component_name))
print("[Druid]: Use next code:")

View File

@ -1,14 +1,46 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Instance of Druid. Make one instance per gui_script with next code:
--- Druid Instance which you use for component creation.
--
-- # Component List #
--
-- For a list of all available components, please refer to the "See Also" section.
--
-- # Notes #
--
-- 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
--
-- @{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.
--
-- # Tech Info #
--
-- • To use Druid, you need to create a Druid instance first. This instance is used to spawn components.
--
-- • When using Druid components, provide the node name as a string argument directly. Avoid calling gui.get_node() before passing it to the component. Because Druid can get nodes from template and cloned gui nodes.
--
-- • All Druid and component methods are called using the colon operator (e.g., self.druid:new_button()).
-- @usage
-- local druid = require("druid.druid")
-- function init(self)
-- self.druid = druid.new(self)
-- local button = self.druid:new_button(...)
--
-- local function close_window(self)
-- print("Yeah! You closed the game!")
-- end
--
-- function init(self)
-- self.druid = druid.new(self)
--
-- -- Call all druid instance function with ":" syntax:
-- local text = self.druid:new_text("text_header", "Hello Druid!")
-- local button = self.druid:new_button("button_close", close_window)
--
-- -- You not need to save component reference if not need it
-- self.druid:new_back_handler(close_window)
-- end
--
-- Learn Druid instance function here
-- @module DruidInstance
-- @alias druid_instance
-- @see Button
@ -39,54 +71,57 @@ local settings = require("druid.system.settings")
local base_component = require("druid.component")
local druid_input = require("druid.helper.druid_input")
local back_handler = require("druid.base.back_handler")
local blocker = require("druid.base.blocker")
local button = require("druid.base.button")
local drag = require("druid.base.drag")
local text = require("druid.base.text")
local hover = require("druid.base.hover")
local scroll = require("druid.base.scroll")
local button = require("druid.base.button")
local blocker = require("druid.base.blocker")
local static_grid = require("druid.base.static_grid")
local swipe = require("druid.base.swipe")
local text = require("druid.base.text")
local back_handler = require("druid.base.back_handler")
-- To use this components, you should register them first
-- local checkbox = require("druid.extended.checkbox")
-- local checkbox_group = require("druid.extended.checkbox_group")
-- local dynamic_grid = require("druid.extended.dynamic_grid")
-- local input = require("druid.extended.input")
-- local lang_text = require("druid.extended.lang_text")
-- local progress = require("druid.extended.progress")
-- local radio_group = require("druid.extended.radio_group")
-- local swipe = require("druid.extended.swipe")
-- local slider = require("druid.extended.slider")
-- local timer_component = require("druid.extended.timer")
-- local checkbox = require("druid.extended.checkbox")
-- local progress = require("druid.extended.progress")
-- local data_list = require("druid.extended.data_list")
-- local lang_text = require("druid.extended.lang_text")
-- local timer_component = require("druid.extended.timer")
-- local radio_group = require("druid.extended.radio_group")
-- local dynamic_grid = require("druid.extended.dynamic_grid")
-- local checkbox_group = require("druid.extended.checkbox_group")
local DruidInstance = class("druid.druid_instance")
local IS_NO_AUTO_INPUT = sys.get_config("druid.no_auto_input") == "1"
local IS_NO_AUTO_INPUT = sys.get_config_int("druid.no_auto_input", 0) == 1
local function input_init(self)
if IS_NO_AUTO_INPUT then
local function set_input_state(self, is_input_inited)
if IS_NO_AUTO_INPUT or (self.input_inited == is_input_inited) then
return
end
if not self.input_inited then
self.input_inited = true
self.input_inited = is_input_inited
if is_input_inited then
druid_input.focus()
else
druid_input.remove()
end
end
local function input_release(self)
if IS_NO_AUTO_INPUT then
return
-- a and b - two Druid components
-- @local
local function sort_input_comparator(a, b)
local a_priority = a:get_input_priority()
local b_priority = b:get_input_priority()
if a_priority ~= b_priority then
return a_priority < b_priority
end
if self.input_inited then
self.input_inited = false
druid_input.remove()
end
return a:get_uid() < b:get_uid()
end
@ -96,17 +131,11 @@ local function sort_input_stack(self)
return
end
table.sort(input_components, function(a, b)
if a:get_input_priority() ~= b:get_input_priority() then
return a:get_input_priority() < b:get_input_priority()
end
return a:get_uid() < b:get_uid()
end)
table.sort(input_components, sort_input_comparator)
end
-- Create the component itself
-- Create the Druid component instance
local function create(self, instance_class)
local instance = instance_class()
instance:setup_component(self, self._context, self._style, instance_class)
@ -123,6 +152,7 @@ local function create(self, instance_class)
end
-- Before processing any input check if we need to update input stack
local function check_sort_input_stack(self, components)
if not components or #components == 0 then
return
@ -150,19 +180,11 @@ local function can_use_input_component(self, component)
local can_by_blacklist = true
if self._input_whitelist and #self._input_whitelist > 0 then
if helper.contains(self._input_whitelist, component) then
can_by_whitelist = true
else
can_by_whitelist = false
end
can_by_whitelist = not not helper.contains(self._input_whitelist, component)
end
if self._input_blacklist and #self._input_blacklist > 0 then
if helper.contains(self._input_blacklist, component) then
can_by_blacklist = false
else
can_by_blacklist = true
end
can_by_blacklist = not helper.contains(self._input_blacklist, component)
end
return can_by_blacklist and can_by_whitelist
@ -173,7 +195,7 @@ local function process_input(self, action_id, action, components)
local is_input_consumed = false
if #components == 0 then
return is_input_consumed
return false
end
for i = #components, 1, -1 do
@ -223,27 +245,15 @@ function DruidInstance.initialize(self, context, style)
self._input_blacklist = nil
self._input_whitelist = nil
self.components_interest = {}
self.components_all = {}
self.components_interest = {}
for i = 1, #base_component.ALL_INTERESTS do
self.components_interest[base_component.ALL_INTERESTS[i]] = {}
end
end
--- Create new druid component
-- @tparam DruidInstance self
-- @tparam Component component Component module
-- @tparam args ... Other component params to pass it to component:init function
-- @local
function DruidInstance.create(self, component, ...)
helper.deprecated("The druid:create is deprecated. Please use druid:new instead")
return DruidInstance.new(self, component, ...)
end
--- Create new druid component
--- Create new component.
-- @tparam DruidInstance self
-- @tparam Component component Component module
-- @tparam args ... Other component params to pass it to component:init function
@ -261,8 +271,7 @@ function DruidInstance.new(self, component, ...)
end
--- Call on final function on gui_script. It will call on_remove
-- on all druid components
--- Call this in gui_script final function.
-- @tparam DruidInstance self
function DruidInstance.final(self)
local components = self.components_all
@ -275,13 +284,12 @@ function DruidInstance.final(self)
self._deleted = true
input_release(self)
self:log_message("Druid final")
set_input_state(self, false)
end
--- Remove component from druid instance.
--- Remove component from Druid instance.
--
-- Component `on_remove` function will be invoked, if exist.
-- @tparam DruidInstance self
-- @tparam Component component Component instance
@ -299,8 +307,8 @@ function DruidInstance.remove(self, component)
if parent then
parent:__remove_children(children[i])
end
children[i] = nil
end
component._meta.children = {}
local all_components = self.components_all
for i = #all_components, 1, -1 do
@ -322,13 +330,14 @@ function DruidInstance.remove(self, component)
end
end
end
self:log_message("Remove", { name = component:get_name(), parent = component:get_parent_name() })
end
--- Druid late update function call after init and before update step
--- 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)
local late_init_components = self.components_interest[base_component.ON_LATE_INIT]
while late_init_components[1] do
@ -338,27 +347,32 @@ function DruidInstance.late_init(self)
if not self.input_inited and #self.components_interest[base_component.ON_INPUT] > 0 then
-- Input init on late init step, to be sure it goes after user go acquire input
input_init(self)
set_input_state(self, true)
end
end
--- Druid update function
--- 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)
self._is_late_remove_enabled = true
local components = self.components_interest[base_component.ON_UPDATE]
for i = 1, #components do
components[i]:update(dt)
end
self._is_late_remove_enabled = false
self._is_late_remove_enabled = false
self:_clear_late_remove()
end
--- Druid on_input function
--- 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
@ -371,23 +385,24 @@ function DruidInstance.on_input(self, action_id, action)
local is_input_consumed = process_input(self, action_id, action, components)
self._is_late_remove_enabled = false
self:_clear_late_remove()
return is_input_consumed
end
--- Druid on_message function
--- 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 hash sender Sender from on_message
function DruidInstance.on_message(self, message_id, message, sender)
-- TODO: refactor for more juicy code
local specific_ui_message = base_component.SPECIFIC_UI_MESSAGES[message_id]
local on_message_input_message = base_component.ON_MESSAGE_INPUT
if specific_ui_message == on_message_input_message then
if specific_ui_message == base_component.ON_MESSAGE_INPUT then
-- ON_MESSAGE_INPUT is special message, need to perform additional logic
local components = self.components_interest[base_component.ON_MESSAGE_INPUT]
if components then
for i = 1, #components do
@ -398,6 +413,7 @@ function DruidInstance.on_message(self, message_id, message, sender)
end
end
elseif specific_ui_message then
-- Resend special message to all components with the related interest
local components = self.components_interest[specific_ui_message]
if components then
for i = 1, #components do
@ -406,6 +422,7 @@ function DruidInstance.on_message(self, message_id, message, sender)
end
end
else
-- Resend message to all components with on_message interest
local components = self.components_interest[base_component.ON_MESSAGE]
for i = 1, #components do
components[i]:on_message(message_id, message, sender)
@ -414,7 +431,7 @@ function DruidInstance.on_message(self, message_id, message, sender)
end
--- Druid on focus lost interest function.
--- 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
@ -423,12 +440,10 @@ function DruidInstance.on_focus_lost(self)
for i = 1, #components do
components[i]:on_focus_lost()
end
self:log_message("On focus lost")
end
--- Druid on focus gained interest function.
--- 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
@ -437,12 +452,10 @@ function DruidInstance.on_focus_gained(self)
for i = 1, #components do
components[i]:on_focus_gained()
end
self:log_message("On focus gained")
end
--- Druid on language change.
--- 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
@ -452,12 +465,11 @@ function DruidInstance.on_language_change(self)
for i = 1, #components do
components[i]:on_language_change()
end
self:log_message("On language change")
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
-- @tparam DruidInstance self
@ -480,6 +492,7 @@ 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}
@ -505,6 +518,7 @@ end
-- @tparam DruidInstance self @{DruidInstance}
-- @tparam bool is_debug
-- @treturn self @{DruidInstance}
-- @local
function DruidInstance.set_debug(self, is_debug)
self._is_debug = is_debug
return self
@ -515,10 +529,12 @@ end
-- @tparam DruidInstance self @{DruidInstance}
-- @tparam string message
-- @tparam[opt] table 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
@ -527,246 +543,250 @@ end
-- @tparam DruidInstance self @{DruidInstance}
-- @local
function DruidInstance._clear_late_remove(self)
if #self._late_remove > 0 then
if #self._late_remove == 0 then
return
end
for i = 1, #self._late_remove do
self:remove(self._late_remove[i])
end
self._late_remove = {}
end
end
--- Create button basic component
--- Create @{Button} component
-- @tparam DruidInstance self
-- @tparam node node Gui node
-- @tparam node node GUI node
-- @tparam function callback Button callback
-- @tparam[opt] table params Button callback params
-- @tparam[opt] node anim_node Button anim node (node, if not provided)
-- @treturn Button button component
-- @treturn Button @{Button} component
function DruidInstance.new_button(self, node, callback, params, anim_node)
return DruidInstance.new(self, button, node, callback, params, anim_node)
end
--- Create blocker basic component
--- Create @{Blocker} component
-- @tparam DruidInstance self
-- @tparam node node Gui node
-- @treturn Blocker blocker component
-- @treturn Blocker @{Blocker} component
function DruidInstance.new_blocker(self, node)
return DruidInstance.new(self, blocker, node)
end
--- Create back_handler basic component
--- Create @{BackHandler} component
-- @tparam DruidInstance self
-- @tparam callback callback On back button
-- @tparam[opt] any params Callback argument
-- @treturn BackHandler back_handler component
-- @treturn BackHandler @{BackHandler} component
function DruidInstance.new_back_handler(self, callback, params)
return DruidInstance.new(self, back_handler, callback, params)
end
--- Create hover basic component
--- Create @{Hover} component
-- @tparam DruidInstance self
-- @tparam node node Gui node
-- @tparam function on_hover_callback Hover callback
-- @treturn Hover hover component
-- @treturn Hover @{Hover} component
function DruidInstance.new_hover(self, node, on_hover_callback)
return DruidInstance.new(self, hover, node, on_hover_callback)
end
--- Create text basic component
--- Create @{Text} component
-- @tparam DruidInstance self
-- @tparam node node Gui text node
-- @tparam[opt] string value Initial text. Default value is node text from GUI scene.
-- @tparam[opt] bool no_adjust If true, text will be not auto-adjust size
-- @treturn Text text component
-- @treturn Text @{Text} component
function DruidInstance.new_text(self, node, value, no_adjust)
return DruidInstance.new(self, text, node, value, no_adjust)
end
--- Create grid basic component
--- Create @{StaticGrid} component
-- Deprecated
-- @tparam DruidInstance self
-- @tparam node parent The gui node parent, where items will be placed
-- @tparam node element Element prefab. Need to get it size
-- @tparam[opt=1] number in_row How many nodes in row can be placed
-- @treturn StaticGrid grid component
-- @treturn StaticGrid @{StaticGrid} component
-- @local
function DruidInstance.new_grid(self, parent, element, in_row)
helper.deprecated("The druid:new_grid is deprecated. Please use druid:new_static_grid instead")
return DruidInstance.new(self, static_grid, parent, element, in_row)
end
--- Create static grid basic component
--- Create @{StaticGrid} component
-- @tparam DruidInstance self
-- @tparam node parent The gui node parent, where items will be placed
-- @tparam node element Element prefab. Need to get it size
-- @tparam[opt=1] number in_row How many nodes in row can be placed
-- @treturn StaticGrid grid component
-- @treturn StaticGrid @{StaticGrid} component
function DruidInstance.new_static_grid(self, parent, element, in_row)
return DruidInstance.new(self, static_grid, parent, element, in_row)
end
--- Create scroll basic component
--- Create @{Scroll} component
-- @tparam DruidInstance self
-- @tparam node view_node GUI view scroll node
-- @tparam node content_node GUI content scroll node
-- @treturn Scroll scroll component
-- @treturn Scroll @{Scroll} component
function DruidInstance.new_scroll(self, view_node, content_node)
return DruidInstance.new(self, scroll, view_node, content_node)
end
--- Create swipe basic component
-- @tparam DruidInstance self
-- @tparam node node Gui node
-- @tparam function on_swipe_callback Swipe callback for on_swipe_end event
-- @treturn Swipe swipe component
function DruidInstance.new_swipe(self, node, on_swipe_callback)
return DruidInstance.new(self, swipe, node, on_swipe_callback)
end
--- Create drag basic component
--- Create @{Drag} component
-- @tparam DruidInstance self
-- @tparam node node GUI node to detect dragging
-- @tparam function on_drag_callback Callback for on_drag_event(self, dx, dy)
-- @treturn Drag drag component
-- @treturn Drag @{Drag} component
function DruidInstance.new_drag(self, node, on_drag_callback)
return DruidInstance.new(self, drag, node, on_drag_callback)
end
--- Create dynamic grid component
--- Create @{Swipe} component
-- @tparam DruidInstance self
-- @tparam node node Gui node
-- @tparam function 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.extended_component("swipe")
end
--- Create @{DynamicGrid} component
-- @tparam DruidInstance self
-- @tparam node parent The gui node parent, where items will be placed
-- @treturn DynamicGrid grid component
-- @treturn DynamicGrid @{DynamicGrid} component
function DruidInstance.new_dynamic_grid(self, parent)
return helper.extended_component("dynamic_grid")
end
--- Create lang_text component
--- Create @{LangText} component
-- @tparam DruidInstance self
-- @tparam node node The text node
-- @tparam string locale_id Default locale id
-- @tparam bool no_adjust If true, will not correct text size
-- @treturn LangText lang_text component
-- @treturn LangText @{LangText} component
function DruidInstance.new_lang_text(self, node, locale_id, no_adjust)
return helper.extended_component("lang_text")
end
--- Create slider component
--- Create @{Slider} component
-- @tparam DruidInstance self
-- @tparam node node Gui pin node
-- @tparam vector3 end_pos The end position of slider
-- @tparam[opt] function callback On slider change callback
-- @treturn Slider slider component
-- @treturn Slider @{Slider} component
function DruidInstance.new_slider(self, node, end_pos, callback)
return helper.extended_component("slider")
end
--- Create checkbox component
--- Create @{Checkbox} component
-- @tparam DruidInstance self
-- @tparam node node Gui node
-- @tparam function callback Checkbox callback
-- @tparam[opt=node] node click_node Trigger node, by default equals to node
-- @tparam[opt=false] boolean initial_state The initial state of checkbox, default - false
-- @treturn Checkbox checkbox component
-- @treturn Checkbox @{Checkbox} component
function DruidInstance.new_checkbox(self, node, callback, click_node, initial_state)
return helper.extended_component("checkbox")
end
--- Create input component
--- Create @{Input} component
-- @tparam DruidInstance self
-- @tparam node click_node Button node to enabled input component
-- @tparam node text_node Text node what will be changed on user input
-- @tparam[opt] number keyboard_type Gui keyboard type for input field
-- @treturn Input input component
-- @treturn Input @{Input} component
function DruidInstance.new_input(self, click_node, text_node, keyboard_type)
return helper.extended_component("input")
end
--- Create checkbox_group component
--- Create @{CheckboxGroup} component
-- @tparam DruidInstance self
-- @tparam node[] nodes Array of gui node
-- @tparam function callback Checkbox callback
-- @tparam[opt=node] node[] click_nodes Array of trigger nodes, by default equals to nodes
-- @treturn CheckboxGroup checkbox_group component
-- @treturn CheckboxGroup @{CheckboxGroup} component
function DruidInstance.new_checkbox_group(self, nodes, callback, click_nodes)
return helper.extended_component("checkbox_group")
end
--- Create data list basic component
--- Create @{DataList} component
-- @tparam DruidInstance self
-- @tparam Scroll druid_scroll The Scroll instance for Data List component
-- @tparam Grid druid_grid The Grid 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 data_list component
-- @treturn DataList @{DataList} component
function DruidInstance.new_data_list(self, druid_scroll, druid_grid, create_function)
return helper.extended_component("data_list")
end
--- Create radio_group component
--- Create @{RadioGroup} component
-- @tparam DruidInstance self
-- @tparam node[] nodes Array of gui node
-- @tparam function callback Radio callback
-- @tparam[opt=node] node[] click_nodes Array of trigger nodes, by default equals to nodes
-- @treturn RadioGroup radio_group component
-- @treturn RadioGroup @{RadioGroup} component
function DruidInstance.new_radio_group(self, nodes, callback, click_nodes)
return helper.extended_component("radio_group")
end
--- Create timer component
--- Create @{Timer} component
-- @tparam DruidInstance self
-- @tparam node node Gui text node
-- @tparam number seconds_from Start timer value in seconds
-- @tparam[opt=0] number seconds_to End timer value in seconds
-- @tparam[opt] function callback Function on timer end
-- @treturn Timer timer component
-- @treturn Timer @{Timer} component
function DruidInstance.new_timer(self, node, seconds_from, seconds_to, callback)
return helper.extended_component("timer")
end
--- Create progress component
--- 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[opt=1] number init_value Initial value of progress bar
-- @treturn Progress progress component
-- @treturn Progress @{Progress} component
function DruidInstance.new_progress(self, node, key, init_value)
return helper.extended_component("progress")
end
--- Create layout component
--- Create @{Layout} component
-- @tparam DruidInstance self
-- @tparam string|node node Layout node
-- @tparam string mode The layout mode
-- @treturn Layout layout component
-- @treturn Layout @{Layout} component
function DruidInstance.new_layout(self, node, mode)
return helper.extended_component("layout")
end
--- Create hotkey component
--- 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 Button callback
-- @tparam[opt] value params Button callback params
-- @treturn Hotkey hotkey component
-- @treturn Hotkey @{Hotkey} component
function DruidInstance.new_hotkey(self, keys_array, callback, params)
return helper.extended_component("hotkey")
end

View File

@ -1,32 +1,5 @@
local middleclass = {
_VERSION = 'middleclass v4.1.1',
_DESCRIPTION = 'Object Orientation for Lua',
_URL = 'https://github.com/kikito/middleclass',
_LICENSE = [[
MIT LICENSE
Copyright (c) 2011 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
}
-- Source: https://github.com/kikito/middleclass
local middleclass = {}
local function _createIndexWrapper(aClass, f)
if f == nil then

View File

@ -205,6 +205,8 @@ local function init_lobby(self)
self.lobby_grid:add(get_title(self, "Rich Texts"))
self.lobby_grid:add(get_button(self, "Rich Text Texts", "rich_text_texts", "/custom/rich_text_texts/rich_text_texts.gui_script"))
self.lobby_grid:add(get_button_disabled(self, "Rich Text Images"))--, "rich_text_images", "/custom/rich_text_texts/rich_text_texts.gui_script"))
self.lobby_grid:add(get_button_disabled(self, "Rich Text Tags"))--, "rich_text_images", "/custom/rich_text_texts/rich_text_texts.gui_script"))
self.lobby_grid:add(get_title(self, "System"))
self.lobby_grid:add(get_button_disabled(self, "Styles"))

View File

@ -1,5 +1,7 @@
local druid = require("druid.druid")
local Swipe = require("druid.extended.swipe")
local function on_swipe_callback(self, direction, distance, swipe_time)
self.text:set_to(direction)
@ -11,7 +13,7 @@ function init(self)
self.druid = druid.new(self)
self.text = self.druid:new_text("text_value")
self.swipe = self.druid:new_swipe("swipe_node", on_swipe_callback)
self.swipe = self.druid:new(Swipe, "swipe_node", on_swipe_callback)
end

View File

@ -1,4 +1,4 @@
#!/bin/bash
use_latest_bob=false
enable_incremental_version=true
bob_sha="4.0:f4a699eb412a2445e894568f2d7466aba61b4c41"
bob_sha="1.4.7:7a608d3ce6ed895d484956c1e76110ed8b78422a"

View File

@ -13,3 +13,5 @@ echo "Update EmmyLua annotations"
original_path=$(pwd)
bash $emmylua_generator_path/export.sh $original_path
mv $emmylua_generator_path/annotations.lua $original_path/druid/annotations.lua
cat ./utils/annotations_manual.lua >> $original_path/druid/annotations.lua
cp $original_path/utils/ldoc_fixed.css $original_path/docs/ldoc_fixed.css

View File

@ -1,3 +1,5 @@
-- Manual Annotations --
---@class druid.rich_text.metrics
---@field width number
---@field height number
@ -49,3 +51,9 @@
---@field default_animation string
---@field node_prefab Node
---@field text_prefab Node
---@class GUITextMetrics
---@field width number
---@field height number
---@field max_ascent number
---@field max_descent number

311
utils/ldoc_fixed.css Normal file
View File

@ -0,0 +1,311 @@
/* BEGIN RESET
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 2.8.2r1
*/
html {
color: #000;
background: #FFF;
}
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
fieldset,img {
border: 0;
}
address,caption,cite,code,dfn,em,strong,th,var,optgroup {
font-style: inherit;
font-weight: inherit;
}
del,ins {
text-decoration: none;
}
li {
margin-left: 20px;
}
caption,th {
text-align: left;
}
h1,h2,h3,h4,h5,h6 {
font-size: 100%;
font-weight: bold;
}
q:before,q:after {
content: '';
}
abbr,acronym {
border: 0;
font-variant: normal;
}
sup {
vertical-align: baseline;
}
sub {
vertical-align: baseline;
}
legend {
color: #000;
}
input,button,textarea,select,optgroup,option {
font-family: inherit;
font-size: inherit;
font-style: inherit;
font-weight: inherit;
}
input,button,textarea,select {*font-size:100%;
}
/* END RESET */
body {
margin-left: 1em;
margin-right: 1em;
font-family: arial, helvetica, geneva, sans-serif;
background-color: #ffffff; margin: 0px;
}
code, tt { font-family: monospace; font-size: 1.1em; }
span.parameter { font-family:monospace; }
span.parameter:after { content:":"; }
span.types:before { content:"("; }
span.types:after { content:")"; }
.type { font-weight: bold; font-style:italic }
body, p, td, th { font-size: .95em; line-height: 1.2em;}
p, ul { margin: 10px 0 0 0px;}
strong { font-weight: bold;}
em { font-style: italic;}
h1 {
font-size: 1.5em;
margin: 0 0 20px 0;
}
h2, h3, h4 { margin: 15px 0 10px 0; }
h2 { font-size: 1.25em; }
h3 { font-size: 1.15em; }
h4 { font-size: 1.06em; }
a:link { font-weight: bold; color: #004080; text-decoration: none; }
a:visited { font-weight: bold; color: #006699; text-decoration: none; }
a:link:hover { text-decoration: underline; }
hr {
color:#cccccc;
background: #00007f;
height: 1px;
}
blockquote { margin-left: 3em; }
ul { list-style-type: disc; }
p.name {
font-family: "Andale Mono", monospace;
padding-top: 1em;
}
pre {
background-color: rgb(245, 245, 245);
border: 1px solid #C0C0C0; /* silver */
padding: 10px;
margin: 10px 0 10px 0;
overflow: auto;
font-family: "Andale Mono", monospace;
}
pre.example {
font-size: .85em;
}
table.index { border: 1px #00007f; }
table.index td { text-align: left; vertical-align: top; }
#container {
margin-left: 1em;
margin-right: 1em;
background-color: #ffffff;
}
#product {
text-align: center;
border-bottom: 1px solid #cccccc;
background-color: #ffffff;
}
#product big {
font-size: 2em;
}
#main {
background-color:#FFFFFF; // #f0f0f0;
border-left: 1px solid #cccccc;
}
#navigation {
position: fixed;
top: 0;
left: 0;
float: left;
width: 14em;
vertical-align: top;
background-color:#FFFFFF; // #f0f0f0;
border-right: 2px solid #cccccc;
overflow: visible;
overflow-y: scroll;
height: 100%;
padding-left: 1em;
}
#navigation h2 {
background-color:#FFFFFF;//:#e7e7e7;
font-size:1.1em;
color:#000000;
text-align: left;
padding:0.2em;
border-bottom:1px solid #dddddd;
}
#navigation ul
{
font-size:1em;
list-style-type: none;
margin: 1px 1px 10px 1px;
}
#navigation li {
text-indent: -1em;
display: block;
margin: 3px 0px 0px 22px;
}
#navigation li li a {
margin: 0px 3px 0px -1em;
}
#content {
margin-left: 14em;
padding: 1em;
padding-left: 2em;
width: 900px;
border-left: 2px solid #cccccc;
// border-right: 2px solid #cccccc;
background-color: #ffffff;
}
#about {
clear: both;
padding-left: 1em;
margin-left: 14em; // avoid the damn sidebar!
border-top: 2px solid #cccccc;
border-left: 2px solid #cccccc;
background-color: #ffffff;
}
@media print {
body {
font: 12pt "Times New Roman", "TimeNR", Times, serif;
}
a { font-weight: bold; color: #004080; text-decoration: underline; }
#main {
background-color: #ffffff;
border-left: 0px;
}
#container {
margin-left: 2%;
margin-right: 2%;
background-color: #ffffff;
}
#content {
padding: 1em;
background-color: #ffffff;
}
#navigation {
display: none;
}
pre.example {
font-family: "Andale Mono", monospace;
font-size: 10pt;
page-break-inside: avoid;
}
}
table.module_list {
border-width: 1px;
border-style: solid;
border-color: #cccccc;
border-collapse: collapse;
}
table.module_list td {
border-width: 1px;
padding: 3px;
border-style: solid;
border-color: #cccccc;
}
table.module_list td.name { background-color: #f0f0f0; ; min-width: 200px; }
table.module_list td.summary { width: 100%; }
table.function_list {
border-width: 1px;
border-style: solid;
border-color: #cccccc;
border-collapse: collapse;
}
table.function_list td {
border-width: 1px;
padding: 3px;
border-style: solid;
border-color: #cccccc;
}
table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; }
table.function_list td.summary { width: 100%; }
dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
dl.table h3, dl.function h3 {font-size: .95em;}
ul.nowrap {
overflow:auto;
whitespace:nowrap;
}
/* stop sublists from having initial vertical space */
ul ul { margin-top: 0px; }
ol ul { margin-top: 0px; }
ol ol { margin-top: 0px; }
ul ol { margin-top: 0px; }
/* make the target distinct; helps when we're navigating to a function */
a:target + * {
background-color: #FF9;
}
/* styles for prettification of source */
pre .comment { color: #558817; }
pre .constant { color: #a8660d; }
pre .escape { color: #844631; }
pre .keyword { color: #aa5050; font-weight: bold; }
pre .library { color: #0e7c6b; }
pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
pre .string { color: #8080ff; }
pre .number { color: #f8660d; }
pre .operator { color: #2239a8; font-weight: bold; }
pre .preprocessor, pre .prepro { color: #a33243; }
pre .global { color: #800080; }
pre .user-keyword { color: #800080; }
pre .prompt { color: #558817; }
pre .url { color: #272fc2; text-decoration: underline; }