diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 0a039c3..8926c40 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -7,17 +7,22 @@ jobs: name: Build and run tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: lfs: true - - uses: actions/setup-java@v1 + + - uses: actions/setup-java@v3 with: - java-version: '17' + distribution: 'zulu' + java-version: '21' - name: Build && Run run: | deployer_url="https://raw.githubusercontent.com/Insality/defold-deployer/1/deployer.sh" curl -s ${deployer_url} | bash -s lbd --headless --settings ./test/test.ini - - name: Upload test report - run: bash <(curl -s https://codecov.io/bash) \ No newline at end of file + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: insality/druid diff --git a/.luacov b/.luacov new file mode 100644 index 0000000..4aff083 --- /dev/null +++ b/.luacov @@ -0,0 +1,73 @@ +local reporter = require("luacov.reporter.defold") + +--- Default values for configuration options. +-- For project specific configuration create '.luacov' file in your project +-- folder. It should be a Lua script setting various options as globals +-- or returning table of options. +-- @class module +-- @name deftest.coverage.configuration +return { + + --- Reporter class to use when creating a report. Default: DefaultReporter from reporter.lua + reporter = reporter, + + --- Filename to store collected stats. Default: "luacov.stats.out". + statsfile = "luacov.stats.out", + + --- Filename to store report. Default: "luacov.report.out". + reportfile = "luacov.report.out", + + --- Enable saving coverage data after every `savestepsize` lines? + -- Setting this flag to `true` in config is equivalent to running LuaCov + -- using `luacov.tick` module. Default: false. + tick = false, + + --- Stats file updating frequency for `luacov.tick`. + -- The lower this value - the more frequently results will be written out to the stats file. + -- You may want to reduce this value (to, for example, 2) to avoid losing coverage data in + -- case your program may terminate without triggering luacov exit hooks that are supposed + -- to save the data. Default: 100. + savestepsize = 100, + + --- Run reporter on completion? Default: true. + runreport = true, + + --- Delete stats file after reporting? Default: false. + deletestats = true, + + --- Process Lua code loaded from raw strings? + -- That is, when the 'source' field in the debug info + -- does not start with '@'. Default: true. + codefromstrings = true, + + --- Lua patterns for files to include when reporting. + -- All will be included if nothing is listed. + -- Do not include the '.lua' extension. Path separator is always '/'. + -- Overruled by `exclude`. + -- @usage + -- include = { + -- "mymodule$", -- the main module + -- "mymodule%/.+$", -- and everything namespaced underneath it + -- } + include = {}, + + --- Lua patterns for files to exclude when reporting. + -- Nothing will be excluded if nothing is listed. + -- Do not include the '.lua' extension. Path separator is always '/'. + -- Overrules `include`. + exclude = { "^test%/.+$" }, + + --- Table mapping names of modules to be included to their filenames. + -- Has no effect if empty. + -- Real filenames mentioned here will be used for reporting + -- even if the modules have been installed elsewhere. + -- Module name can contain '*' wildcard to match groups of modules, + -- in this case corresponding path will be used as a prefix directory + -- where modules from the group are located. + -- @usage + -- modules = { + -- ["some_rock"] = "src/some_rock.lua", + -- ["some_rock.*"] = "src" + -- } + modules = {}, +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 4c7b95d..277b66a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,11 +32,10 @@ "Lua.diagnostics.libraryFiles": "Disable", "Lua.runtime.version": "Lua 5.1", "Lua.workspace.library": [ - "~/Library/Application Support/Code/User/globalStorage/astronachos.defold", - "~/Library/Application Support/Code/User/workspaceStorage/72e25b7e0fdc873ee6f7baa61edbd6b1/astronachos.defold", - "~/Library/Application Support/Code/User/workspaceStorage/1446075a23c89451a63f0e82b2291def/astronachos.defold" + "~/Library/Application Support/Cursor/User/globalStorage/astronachos.defold", + "~/Library/Application Support/Cursor/User/workspaceStorage/1446075a23c89451a63f0e82b2291def/astronachos.defold" ], "files.exclude": { "**/*.gui": true } -} \ No newline at end of file +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b280ec2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +# Contribution Guidelines + +Hello, Defolder! Thanks for your interest in contributing to the **Druid** project. It's a massive project that has been around for a long time, and it's still growing. This project has a lot of places where you can help! + +Finally, there are set of instructions that will help you to contribute to the project. + +Thanks for your help! + +## Update Documentation + +If you see any mistakes in the documentation, you can update it by yourself. + +You can push changes to the `master` branch directly. In case of small fixes, please also update the relative API `md` files. If there is a lot of changes, I will regenerate them manually. + +## Issue Reporting + +If you find any bugs, please report them to the [issue tracker](https://github.com/druid-js/druid/issues). + +## Pull Requests + +Any pull requests are welcome! + +Please, open PR against the `develop` branch. Very nice to have an issue, which this PR fixes. + +You fix should contains only changes, which are related to the issue. Also please keep the code style the same! + +Thanks <3 + +## Add or Update Examples + +Examples contains a GUI scene, a Druid widget for this GUI. This GUI is included to the `examples.gui` and the information about examples are added in `examples_list.lua` file + +You can add new examples or update existing ones. + +To add new example, you need to create a new folder in the `examples` directory. + + diff --git a/README.md b/README.md index c79373d..b6718c8 100644 --- a/README.md +++ b/README.md @@ -7,37 +7,54 @@ [![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality) -**Druid** - powerful **Defold** component UI framework that empowers developers to create stunning and customizable GUIs by leveraging a wide range of embedded components or effortlessly designing their own game-specific components. +**Druid** - a powerful, flexible and easy to use **Defold** component UI framework. Contains a wide range of UI components that you can use to create a beautiful, responsive and customizable GUIs. Provides a powerful way to create, compose and manage your custom components and scenes. ## Druid Example -Check the [**HTML5 version**](https://insality.github.io/druid/druid/) of the **Druid** example app. +Check the [**HTML5 version**](https://insality.github.io/druid/) of the **Druid** example app. In this example you can inspect a variety of **Druid** components and see how they work. Each example page provides a direct link to the corresponding example code, making it easier for you to understand how to use **Druid**. +## Features + +- **Components** - Provides a extensive set of components, from basic buttons to infinity data lists and rich texts +- **Customizable** - You can customize components appearance and behaviour +- **Widgets** - Powerful way to create your own reusable components +- **Input Handling** - Handles input in a stack-based manner and manage input priority +- **Event Based** - Uses [Defold Event](https://github.com/Insality/defold-event) for components callbacks and communication between components + ## Setup -### [Dependency](https://www.defold.com/manuals/libraries/) +### [Dependency](https://defold.com/manuals/libraries/#setting-up-library-dependencies) -Open your `game.project` file and add the following line to the dependencies field under the project section: +Open your `game.project` file and add the following lines to the dependencies field under the project section: -**[Druid](https://github.com/Insality/druid/archive/refs/tags/1.0.zip)** + +**[Druid](https://github.com/Insality/druid/)** ``` https://github.com/Insality/druid/archive/refs/tags/1.0.zip ``` +**[Defold Event](https://github.com/Insality/defold-event)** + +``` +https://github.com/Insality/defold-event/archive/refs/tags/10.zip +``` + +After that, select `Project ▸ Fetch Libraries` to update [library dependencies]((https://defold.com/manuals/libraries/#setting-up-library-dependencies)). This happens automatically whenever you open a project so you will only need to do this if the dependencies change without re-opening the project. + Here is a list of [all releases](https://github.com/Insality/druid/releases). ### Library Size -> **Note:** The library size is calculated based on the build report per platform. The extended components are exlcuded, which are including only on demand. +> **Note:** The library size is calculated based on the build report per platform. Full size contains all components, they can be stripped out in the build process if you don't need them. -| Platform | Library Size | +| Platform | Full Size | | ---------------- | ------------- | -| HTML5 | **38.00 KB** | -| Desktop / Mobile | **65.74 KB** | +| HTML5 | **84.52 KB** | +| Desktop / Mobile | **141.03 KB** | ### Input Bindings @@ -49,167 +66,74 @@ Here is a list of [all releases](https://github.com/Insality/druid/releases). ### Basic usage -To utilize **Druid**, begin by creating a **Druid** instance to instantiate components and include the main functions of **Druid**: *update*, *final*, *on_message*, and *on_input*. - -When using **Druid** components, provide a node name string as an argument. If you don't have the node name available in some cases, you can pass `gui.get_node()` instead. - -All **Druid** and component methods are invoked using the `:` operator, such as `self.druid:new_button()`. - -```lua -local druid = require("druid.druid") - --- All component callbacks pass "self" as first argument --- This "self" is a context data passed in `druid.new(context)` -local function on_button_callback(self) - print("The button clicked!") -end - -function init(self) - self.druid = druid.new(self) - self.button = self.druid:new_button("button_node_name", on_button_callback) -end - --- "final" is a required function for the correct Druid workflow -function final(self) - self.druid:final() -end - --- "update" is used in progress bar, scroll, and timer basic components -function update(self, dt) - self.druid:update(dt) -end - --- "on_message" is used for specific Druid events, like language change or layout change -function on_message(self, message_id, message, sender) - self.druid:on_message(message_id, message, sender) -end - --- "on_input" is used in almost all Druid components --- The return value from `druid:on_input` is required! -function on_input(self, action_id, action) - return self.druid:on_input(action_id, action) -end -``` - -For all **Druid** instance functions, [see here](https://insality.github.io/druid/modules/DruidInstance.html). - - -### Default GUI Script - -Put the following code in your GUI script to start using **Druid**. - -```lua -local druid = require("druid.druid") - -function init(self) - self.druid = druid.new(self) -end - -function final(self) - self.druid:final() -end - -function update(self, dt) - self.druid:update(dt) -end - -function on_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 -``` - - -### Default Widget Template - -Create a new lua file to create a new widget class. This widget can be created with `self.druid:new_widget(widget_class, [template], [nodes])` - -```lua -local M = {} - -function M:init() - self.root = self:get_node("root") - self.button = self.druid:new_button("button", self.on_click) -end - -function M:on_click() - print("Button clicked!") -end - -return M -``` - +Read more in the [Basic Usage](wiki/basic_usage.md) ### API Documentation -**Druid** offers a wide range of components and functions. To facilitate usage, **Druid** provides comprehensive API documentation with examples and annotations. +Best start is from the [Quick API Reference](api/quick_api_reference.md) -Start reading the API documentation [here](https://insality.github.io/druid/modules/Druid.html). +With next quick links: -**Druid** provide the *EmmyLua* annotations to add autocomplete inside your IDE. Check [EmmyLua Setup here](docs_md/advanced-setup.md#emmylua-annotations). - - -### Create custom components - -If you want to create your own components, refer to the [Create Custom Components](docs_md/02-creating_custom_components.md) section in the documentation. - -Custom components are one of the most powerful features of **Druid**. They allow you to create your own components effortlessly and utilize them in your game. +- [Druid Instance](api/druid_instance_api.md) - **Druid** instance returned from `druid.new(self)` +- [Helper](api/druid_helper_api.md) - A lot of useful functions +- [Widgets](wiki/widgets.md) - About widgets and how to use them ## Druid Components Here is full **Druid** components list. -### Basic Components - -> Basic components always included in the build and available for use. +### Components | Name | Description | Example |
Preview
| |------|-------------|---------|---------| -| **[Button](https://insality.github.io/druid/modules/Button.html)** | Logic over GUI Node. Handle the user click interactions: click, long click, double click, etc. | [Button Example](https://insality.github.io/druid/druid/?example=ui_example_basic_button) | | -| **[Text](https://insality.github.io/druid/modules/Text.html)** | Logic over GUI Text. By default Text component fit the text inside text node size area with different adjust modes. | [Text Example](https://insality.github.io/druid/druid/?example=ui_example_basic_text) | | -| **[Scroll](https://insality.github.io/druid/modules/Scroll.html)** | Logic over two GUI Nodes: input and content. Provides basic behaviour for scrollable content. | [Scroll Example](https://insality.github.io/druid/druid/?example=ui_example_basic_scroll) | | -| **[Blocker](https://insality.github.io/druid/modules/Blocker.html)** | Logic over GUI Node. Don't pass any user input below node area size. | [Blocker Example](https://insality.github.io/druid/druid/?example=ui_example_basic_blocker) | | -| **[Back Handler](https://insality.github.io/druid/modules/BackHandler.html)** | Call callback on user "Back" action. It's a Android back button or keyboard backspace key | [Back Handler Example](https://insality.github.io/druid/druid/?example=ui_example_basic_back_handler) | | -| **[Static Grid](https://insality.github.io/druid/modules/StaticGrid.html)** | Logic over GUI Node. Component to manage node positions with all equal node sizes. | [Static Gid Example](https://insality.github.io/druid/druid/?example=ui_example_basic_grid) | | -| **[Hover](https://insality.github.io/druid/modules/Hover.html)** | Logic over GUI Node. Handle hover action over node. For both: mobile touch and mouse cursor. | [Hover Example](https://insality.github.io/druid/druid/?example=ui_example_basic_hover) | | -| **[Swipe](https://insality.github.io/druid/modules/Swipe.html)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/druid/?example=ui_example_basic_swipe) | | -| **[Drag](https://insality.github.io/druid/modules/Drag.html)** | Logic over GUI Node. Handle drag input actions. Can be useful to make on screen controlls. | [Drag Example](https://insality.github.io/druid/druid/?example=ui_example_basic_drag) | | - - -### Extended components - -| Name | Description | Example |
Preview
| -|------|-------------|---------|---------| -| **[Data List](https://insality.github.io/druid/modules/DataList.html)** | Logic over Scroll and Grid components. Create only visible GUI nodes or components to make "infinity" scroll befaviour | [Data List Example](https://insality.github.io/druid/druid/?example=ui_example_data_list_basic) | | -| **[Input](https://insality.github.io/druid/modules/Input.html)** | Logic over GUI Node and GUI Text (or Text component). Provides basic user text input. | [Input Example](https://insality.github.io/druid/druid/?example=ui_example_basic_input) | | -| **[Lang text](https://insality.github.io/druid/modules/LangText.html)** | Logic over Text component to handle localization. Can be translated in real-time with `druid.on_language_change` | [Lang Text Example](https://insality.github.io/druid/druid/?example=ui_example_window_language) | | -| **[Progress](https://insality.github.io/druid/modules/Progress.html)** | Logic over GUI Node. Handle node size and scale to handle progress node size. | [Progress Example](https://insality.github.io/druid/druid/?example=ui_example_basic_progress_bar) | | -| **[Slider](https://insality.github.io/druid/modules/Slider.html)** | Logic over GUI Node. Handle draggable node with position restrictions. | [Slider Example](https://insality.github.io/druid/druid/?example=ui_example_basic_slider) | | -| **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Logic over GUI Text. Handle basic timer functions. | [Timer Example](https://insality.github.io/druid/druid/?example=ui_example_basic_timer) | | -| **[Hotkey](https://insality.github.io/druid/modules/Hotkey.html)** | Allow to set callbacks for keyboard hotkeys with key modificators. | [Hotkey Example](https://insality.github.io/druid/druid/?example=ui_example_basic_hotkey) | | -| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Logic over GUI Node. Arrange nodes inside layout node with margin/paddings settings. | [Layout Example](https://insality.github.io/druid/druid/?example=ui_example_layout_basic) | | -| **[Rich Input](https://insality.github.io/druid/modules/RichInput.html)** | Logic over GUI Node and GUI Text (or Text component). Provides rich text input with different styles and text formatting. | [Rich Input Example](https://insality.github.io/druid/druid/?example=ui_example_basic_rich_input) | | -| **[Rich Text](https://insality.github.io/druid/modules/RichText.html)** | Logic over GUI Text. Provides rich text formatting with different styles and text formatting. | [Rich Text Example](https://insality.github.io/druid/druid/?example=ui_example_basic_rich_text) | | - -For a complete overview, see: **_[components.md](docs_md/01-components.md)_**. +| **[Button](https://insality.github.io/druid/modules/Button.html)** | Logic over GUI Node. Handle the user click interactions: click, long click, double click, etc. | [Button Example](https://insality.github.io/druid/?example=ui_example_basic_button) | | +| **[Text](https://insality.github.io/druid/modules/Text.html)** | Logic over GUI Text. By default Text component fit the text inside text node size area with different adjust modes. | [Text Example](https://insality.github.io/druid/?example=ui_example_basic_text) | | +| **[Scroll](https://insality.github.io/druid/modules/Scroll.html)** | Logic over two GUI Nodes: input and content. Provides basic behaviour for scrollable content. | [Scroll Example](https://insality.github.io/druid/?example=ui_example_basic_scroll) | | +| **[Blocker](https://insality.github.io/druid/modules/Blocker.html)** | Logic over GUI Node. Don't pass any user input below node area size. | [Blocker Example](https://insality.github.io/druid/?example=ui_example_basic_blocker) | | +| **[Back Handler](https://insality.github.io/druid/modules/BackHandler.html)** | Call callback on user "Back" action. It's a Android back button or keyboard backspace key | [Back Handler Example](https://insality.github.io/druid/?example=ui_example_basic_back_handler) | | +| **[Static Grid](https://insality.github.io/druid/modules/StaticGrid.html)** | Logic over GUI Node. Component to manage node positions with all equal node sizes. | [Static Gid Example](https://insality.github.io/druid/?example=ui_example_basic_grid) | | +| **[Hover](https://insality.github.io/druid/modules/Hover.html)** | Logic over GUI Node. Handle hover action over node. For both: mobile touch and mouse cursor. | [Hover Example](https://insality.github.io/druid/?example=ui_example_basic_hover) | | +| **[Swipe](https://insality.github.io/druid/modules/Swipe.html)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/?example=ui_example_basic_swipe) | | +| **[Drag](https://insality.github.io/druid/modules/Drag.html)** | Logic over GUI Node. Handle drag input actions. Can be useful to make on screen controlls. | [Drag Example](https://insality.github.io/druid/?example=ui_example_basic_drag) | | +| **[Data List](https://insality.github.io/druid/modules/DataList.html)** | Logic over Scroll and Grid components. Create only visible GUI nodes or components to make "infinity" scroll befaviour | [Data List Example](https://insality.github.io/druid/?example=ui_example_data_list_basic) | | +| **[Input](https://insality.github.io/druid/modules/Input.html)** | Logic over GUI Node and GUI Text (or Text component). Provides basic user text input. | [Input Example](https://insality.github.io/druid/?example=ui_example_basic_input) | | +| **[Lang text](https://insality.github.io/druid/modules/LangText.html)** | Logic over Text component to handle localization. Can be translated in real-time with `druid.on_language_change` | [Lang Text Example](https://insality.github.io/druid/?example=ui_example_window_language) | | +| **[Progress](https://insality.github.io/druid/modules/Progress.html)** | Logic over GUI Node. Handle node size and scale to handle progress node size. | [Progress Example](https://insality.github.io/druid/?example=ui_example_basic_progress_bar) | | +| **[Slider](https://insality.github.io/druid/modules/Slider.html)** | Logic over GUI Node. Handle draggable node with position restrictions. | [Slider Example](https://insality.github.io/druid/?example=ui_example_basic_slider) | | +| **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Logic over GUI Text. Handle basic timer functions. | [Timer Example](https://insality.github.io/druid/?example=ui_example_basic_timer) | | +| **[Hotkey](https://insality.github.io/druid/modules/Hotkey.html)** | Allow to set callbacks for keyboard hotkeys with key modificators. | [Hotkey Example](https://insality.github.io/druid/?example=ui_example_basic_hotkey) | | +| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Logic over GUI Node. Arrange nodes inside layout node with margin/paddings settings. | [Layout Example](https://insality.github.io/druid/?example=ui_example_layout_basic) | | +| **[Rich Input](https://insality.github.io/druid/modules/RichInput.html)** | Logic over GUI Node and GUI Text (or Text component). Provides rich text input with different styles and text formatting. | [Rich Input Example](https://insality.github.io/druid/?example=ui_example_basic_rich_input) | | +| **[Rich Text](https://insality.github.io/druid/modules/RichText.html)** | Logic over GUI Text. Provides rich text formatting with different styles and text formatting. | [Rich Text Example](https://insality.github.io/druid/?example=ui_example_basic_rich_text) | | ## Druid Events -Any **Druid** components as callbacks use [Druid Events](https://insality.github.io/druid/modules/druid.event.html). In component API ([button example](https://insality.github.io/druid/modules/Button.html#on_click)) pointed list of component events. You can manually subscribe to these events with the following API: +All **Druid** components using [Defold Event](https://github.com/Insality/defold-event) for components callbacks. In component API ([button example](https://insality.github.io/druid/modules/Button.html#on_click)) pointed list of component events. You can manually subscribe to these events with the following API: - **event:subscribe**(callback) - **event:unsubscribe**(callback) -- **event:clear**() - You can subscribe several callbacks to a single event. +Examples: + +```lua +button.on_click:subscribe(function(self, args) + print("Button clicked!") +end) + +scroll.on_scroll:subscribe(function(self, position) + print("Scroll scrolled!") +end) + +input.on_input_unselect:subscribe(function(self, text) + print("User enter input:", text) +end) +``` + ## Details - **Druid** processes input in a stack-based manner. The most recently created button will be checked first. Create your input GUI components from back to front. @@ -220,7 +144,7 @@ You can subscribe several callbacks to a single event. ## Examples -Try the [**HTML5 version**](https://insality.github.io/druid/druid/) of the **Druid** example app. +Try the [**HTML5 version**](https://insality.github.io/druid/) of the **Druid** example app. Each example page provides a direct link to the corresponding example code, making it easier for you to understand how to use **Druid**. @@ -228,21 +152,19 @@ Or refer directly to the [**example folder**](https://github.com/Insality/druid/ ## Documentation -To better understand **Druid**, read the following documentation: -- [How To GUI in Defold](https://forum.defold.com/t/how-to-gui-in-defold/73256) -- [Druid components](docs_md/01-components.md) -- [Create custom components](docs_md/02-creating_custom_components.md) -- [See FAQ article](docs_md/FAQ.md) -- [Druid styles](docs_md/03-styles.md) +You can find the full **Druid** functions at [Quick API Reference](api/quick_api_reference.md) -You can find the full **Druid** [documentation here](https://insality.github.io/druid/modules/Druid.html). +To better understand **Druid**, read the following documentation: + +- [How To GUI in Defold](https://forum.defold.com/t/how-to-gui-in-defold/73256) +- [Widgets](wiki/widgets.md) +- [Create custom components](docs_md/02-creating_custom_components.md) +- [Druid styles](docs_md/03-styles.md) ## Licenses -- Developed and supported by [Insality](https://github.com/Insality) -- Original idea by [AGulev](https://github.com/AGulev) -- Assets from [Kenney](http://www.kenney.nl/) +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Issues and suggestions @@ -256,13 +178,17 @@ For a complete history of the development of **Druid**, please check the [change ## 👏 Contributors +Special thanks to all the contributors who have helped make **Druid** better! + +Read the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information. + ## ❤️ Support project ❤️ Your donation helps me stay engaged in creating valuable projects for **Defold**. If you appreciate what I'm doing, please consider supporting me! -[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality) \ No newline at end of file +[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality) diff --git a/api/components/base/back_handler_api.md b/api/components/base/back_handler_api.md new file mode 100644 index 0000000..f55d129 --- /dev/null +++ b/api/components/base/back_handler_api.md @@ -0,0 +1,36 @@ +# druid.back_handler API + +> at /druid/base/back_handler.lua + +The component that handles the back handler action, like backspace or android back button + + +## Functions +- [init](#init) + + +## Fields +- [on_back](#on_back) +- [params](#params) + + + +### init + +--- +```lua +back_handler:init([callback], [params]) +``` + +- **Parameters:** + - `[callback]` *(function|nil)*: The callback to call when the back handler is triggered + - `[params]` *(any)*: Custom args to pass in the callback + + +## Fields + +- **on_back** (_event_): Trigger on back handler action, fun(self, params) + + +- **params** (_any_): Custom args to pass in the callback + diff --git a/api/components/base/blocker_api.md b/api/components/base/blocker_api.md new file mode 100644 index 0000000..e7390f1 --- /dev/null +++ b/api/components/base/blocker_api.md @@ -0,0 +1,58 @@ +# druid.blocker API + +> at /druid/base/blocker.lua + + +## Functions +- [init](#init) +- [set_enabled](#set_enabled) +- [is_enabled](#is_enabled) + + +## Fields +- [node](#node) + + + +### init + +--- +```lua +blocker:init(node) +``` + +- **Parameters:** + - `node` *(string|node)*: The node to use as a blocker + +### set_enabled + +--- +```lua +blocker:set_enabled(state) +``` + +Set blocker enabled state + +- **Parameters:** + - `state` *(boolean)*: The new enabled state + +- **Returns:** + - `self` *(druid.blocker)*: The blocker instance + +### is_enabled + +--- +```lua +blocker:is_enabled() +``` + +Get blocker enabled state + +- **Returns:** + - `is_enabled` *(boolean)*: True if the blocker is enabled + + +## Fields + +- **node** (_node_) + diff --git a/api/components/base/button_api.md b/api/components/base/button_api.md new file mode 100644 index 0000000..c80a6ee --- /dev/null +++ b/api/components/base/button_api.md @@ -0,0 +1,256 @@ +# druid.button API + +> at /druid/base/button.lua + +Druid component to make clickable node with various interaction callbacks + + +## Functions +- [init](#init) +- [set_animations_disabled](#set_animations_disabled) +- [set_enabled](#set_enabled) +- [is_enabled](#is_enabled) +- [set_click_zone](#set_click_zone) +- [set_key_trigger](#set_key_trigger) +- [get_key_trigger](#get_key_trigger) +- [set_check_function](#set_check_function) +- [set_web_user_interaction](#set_web_user_interaction) + + +## Fields +- [on_click](#on_click) +- [on_pressed](#on_pressed) +- [on_repeated_click](#on_repeated_click) +- [on_long_click](#on_long_click) +- [on_double_click](#on_double_click) +- [on_hold_callback](#on_hold_callback) +- [on_click_outside](#on_click_outside) +- [node](#node) +- [node_id](#node_id) +- [anim_node](#anim_node) +- [params](#params) +- [hover](#hover) +- [click_zone](#click_zone) +- [start_scale](#start_scale) +- [start_pos](#start_pos) +- [disabled](#disabled) +- [key_trigger](#key_trigger) +- [style](#style) +- [druid](#druid) +- [is_repeated_started](#is_repeated_started) +- [last_pressed_time](#last_pressed_time) +- [last_released_time](#last_released_time) +- [click_in_row](#click_in_row) +- [can_action](#can_action) + + + +### init + +--- +```lua +button:init(node_or_node_id, [callback], [custom_args], [anim_node]) +``` + +The constructor for the button component + +- **Parameters:** + - `node_or_node_id` *(string|node)*: Node name or GUI Node itself + - `[callback]` *(fun()|nil)*: Callback on button click + - `[custom_args]` *(any)*: Custom args for any Button event + - `[anim_node]` *(string|node|nil)*: Node to animate instead of trigger node + +### set_animations_disabled + +--- +```lua +button:set_animations_disabled() +``` + +Remove default button style animations + +- **Returns:** + - `self` *(druid.button)*: The current button instance + +### set_enabled + +--- +```lua +button:set_enabled([state]) +``` + +Set button enabled state. +The style.on_set_enabled will be triggered. +Disabled button is not clickable. + +- **Parameters:** + - `[state]` *(boolean|nil)*: Enabled state + +- **Returns:** + - `self` *(druid.button)*: The current button instance + +### is_enabled + +--- +```lua +button:is_enabled() +``` + +Get button enabled state. +By default all Buttons is enabled on creating. + +- **Returns:** + - `is_enabled` *(boolean)*: True, if button is enabled now, False overwise + +### set_click_zone + +--- +```lua +button:set_click_zone([zone]) +``` + +Set additional button click area. +Useful to restrict click outside out stencil node or scrollable content. +If button node placed inside stencil node, it will be automatically set to this stencil node. + +- **Parameters:** + - `[zone]` *(string|node|nil)*: Gui node + +- **Returns:** + - `self` *(druid.button)*: The current button instance + +### set_key_trigger + +--- +```lua +button:set_key_trigger(key) +``` + +Set key name to trigger this button by keyboard. + +- **Parameters:** + - `key` *(string|hash)*: The action_id of the input key. Example: "key_space" + +- **Returns:** + - `self` *(druid.button)*: The current button instance + +### get_key_trigger + +--- +```lua +button:get_key_trigger() +``` + +Get current key name to trigger this button. + +- **Returns:** + - `key_trigger` *(hash)*: The action_id of the input key + +### set_check_function + +--- +```lua +button:set_check_function([check_function], [failure_callback]) +``` + +Set function for additional check for button click availability + +- **Parameters:** + - `[check_function]` *(function|nil)*: Should return true or false. If true - button can be pressed. + - `[failure_callback]` *(function|nil)*: Function will be called on button click, if check function return false + +- **Returns:** + - `self` *(druid.button)*: The current button instance + +### set_web_user_interaction + +--- +```lua +button:set_web_user_interaction([is_web_mode]) +``` + +Set Button mode to work inside user HTML5 interaction event. +It's required to make protected things like copy & paste text, show mobile keyboard, etc +The HTML5 button's doesn't call any events except on_click event. +If the game is not HTML, html mode will be not enabled + +- **Parameters:** + - `[is_web_mode]` *(boolean|nil)*: If true - button will be called inside html5 callback + +- **Returns:** + - `self` *(druid.button)*: The current button instance + + +## Fields + +- **on_click** (_event_): function(self, custom_args, button_instance) + + +- **on_pressed** (_event_): function(self, custom_args, button_instance) + + +- **on_repeated_click** (_event_): function(self, custom_args, button_instance, click_count) + + +- **on_long_click** (_event_): function(self, custom_args, button_instance, hold_time) + + +- **on_double_click** (_event_): function(self, custom_args, button_instance, click_amount) + + +- **on_hold_callback** (_event_): function(self, custom_args, button_instance, press_time) + + +- **on_click_outside** (_event_): function(self, custom_args, button_instance) + + +- **node** (_node_): Clickable node + + +- **node_id** (_hash_): Node id + + +- **anim_node** (_node_): Animation node. In default case equals to clickable node + + +- **params** (_any_): Custom arguments for any Button event + + +- **hover** (_druid.hover_): Hover component for this button + + +- **click_zone** (_node_): Click zone node to restrict click area + + +- **start_scale** (_vector3_): Start scale of the button + + +- **start_pos** (_vector3_): Start position of the button + + +- **disabled** (_boolean_): Is button disabled + + +- **key_trigger** (_hash_): Key trigger for this button + + +- **style** (_table_): Style for this button + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **is_repeated_started** (_boolean_) + + +- **last_pressed_time** (_integer_) + + +- **last_released_time** (_integer_) + + +- **click_in_row** (_integer_) + + +- **can_action** (_boolean_): Can't interact, if touch outside of button + diff --git a/api/components/base/component_api.md b/api/components/base/component_api.md new file mode 100644 index 0000000..4501b2b --- /dev/null +++ b/api/components/base/component_api.md @@ -0,0 +1,445 @@ +# druid.component API + +> at /druid/component.lua + + +## Functions +- [create](#create) +- [create_widget](#create_widget) + +- [init](#init) +- [update](#update) +- [on_remove](#on_remove) +- [on_input](#on_input) +- [on_input_interrupt](#on_input_interrupt) +- [on_message](#on_message) +- [on_late_init](#on_late_init) +- [on_focus_lost](#on_focus_lost) +- [on_focus_gained](#on_focus_gained) +- [on_style_change](#on_style_change) +- [on_layout_change](#on_layout_change) +- [on_window_resized](#on_window_resized) +- [on_language_change](#on_language_change) +- [set_style](#set_style) +- [set_template](#set_template) +- [get_template](#get_template) +- [set_nodes](#set_nodes) +- [get_context](#get_context) +- [get_node](#get_node) +- [get_druid](#get_druid) +- [get_name](#get_name) +- [get_parent_name](#get_parent_name) +- [get_input_priority](#get_input_priority) +- [set_input_priority](#set_input_priority) +- [reset_input_priority](#reset_input_priority) +- [get_uid](#get_uid) +- [set_input_enabled](#set_input_enabled) +- [get_input_enabled](#get_input_enabled) +- [get_parent_component](#get_parent_component) +- [get_nodes](#get_nodes) +- [get_childrens](#get_childrens) + + +## Fields +- [druid](#druid) + + + +### create + +--- +```lua +component.create([name], [input_priority]) +``` + +Сreate a new component class, which will inherit from the base Druid component. + +- **Parameters:** + - `[name]` *(string|nil)*: The name of the component + - `[input_priority]` *(number|nil)*: The input priority. The bigger number processed first. Default value: 10 + +- **Returns:** + - `` *(druid.component)*: + +### create_widget + +--- +```lua +component.create_widget(self, widget_class, context) +``` + +Create the Druid component instance + +- **Parameters:** + - `self` *(druid.instance)*: The Druid Factory used to create components + - `widget_class` *(druid.widget)*: + - `context` *(table)*: + +- **Returns:** + - `` *(druid.widget)*: + +### init + +--- +```lua +component:init() +``` + +Called when component is created + +### update + +--- +```lua +component:update() +``` + +Called every frame + +### on_remove + +--- +```lua +component:on_remove() +``` + +Called when component is removed + +### on_input + +--- +```lua +component:on_input() +``` + +Called when input event is triggered + +### on_input_interrupt + +--- +```lua +component:on_input_interrupt() +``` + +Called when input event is consumed before + +### on_message + +--- +```lua +component:on_message() +``` + +Called when message is received + +### on_late_init + +--- +```lua +component:on_late_init() +``` + +Called before update once time after GUI init + +### on_focus_lost + +--- +```lua +component:on_focus_lost() +``` + +Called when app lost focus + +### on_focus_gained + +--- +```lua +component:on_focus_gained() +``` + +Called when app gained focus + +### on_style_change + +--- +```lua +component:on_style_change() +``` + +Called when style is changed + +### on_layout_change + +--- +```lua +component:on_layout_change() +``` + +Called when GUI layout is changed + +### on_window_resized + +--- +```lua +component:on_window_resized() +``` + +Called when window is resized + +### on_language_change + +--- +```lua +component:on_language_change() +``` + +Called when language is changed + +### set_style + +--- +```lua +component:set_style([druid_style]) +``` + +Set component style. Pass nil to clear style + +- **Parameters:** + - `[druid_style]` *(table|nil)*: + +- **Returns:** + - `self` *()*: The component itself for chaining + +### set_template + +--- +```lua +component:set_template([template]) +``` + +Set component template name. Pass nil to clear template. +This template id used to access nodes inside the template on GUI scene. +Parent template will be added automatically if exist. + +- **Parameters:** + - `[template]` *(string|nil)*: + +- **Returns:** + - `self` *()*: The component itself for chaining + +### get_template + +--- +```lua +component:get_template() +``` + +Get full template name. + +- **Returns:** + - `` *(string)*: + +### set_nodes + +--- +```lua +component:set_nodes(nodes) +``` + +Set current component nodes, returned from `gui.clone_tree` function. + +- **Parameters:** + - `nodes` *(table)*: + +- **Returns:** + - `` *(druid.component)*: + +### get_context + +--- +```lua +component:get_context() +``` + +Return current component context + +- **Returns:** + - `context` *(any)*: Usually it's self of script but can be any other Druid component + +### get_node + +--- +```lua +component:get_node(node_id) +``` + +Get component node by node_id. Respect to current template and nodes. + +- **Parameters:** + - `node_id` *(string|node)*: + +- **Returns:** + - `` *(node)*: + +### get_druid + +--- +```lua +component:get_druid([template], [nodes]) +``` + +Get Druid instance for inner component creation. + +- **Parameters:** + - `[template]` *(string|nil)*: + - `[nodes]` *(table|nil)*: + +- **Returns:** + - `` *(druid.instance)*: + +### get_name + +--- +```lua +component:get_name() +``` + +Get component name + +- **Returns:** + - `name` *(string)*: The component name + uid + +### get_parent_name + +--- +```lua +component:get_parent_name() +``` + +Get parent component name + +- **Returns:** + - `parent_name` *(string|nil)*: The parent component name if exist or nil + +### get_input_priority + +--- +```lua +component:get_input_priority() +``` + +Get component input priority, the bigger number processed first. Default value: 10 + +- **Returns:** + - `` *(number)*: + +### set_input_priority + +--- +```lua +component:set_input_priority(value, [is_temporary]) +``` + +Set component input priority, the bigger number processed first. Default value: 10 + +- **Parameters:** + - `value` *(number)*: + - `[is_temporary]` *(boolean|nil)*: If true, the reset input priority will return to previous value + +- **Returns:** + - `self` *(druid.component)*: The component itself for chaining + +### reset_input_priority + +--- +```lua +component:reset_input_priority() +``` + +Reset component input priority to it's default value, that was set in `create` function or `set_input_priority` + +- **Returns:** + - `self` *(druid.component)*: The component itself for chaining + +### get_uid + +--- +```lua +component:get_uid() +``` + +Get component UID, unique identifier created in component creation order. + +- **Returns:** + - `uid` *(number)*: The component uid + +### set_input_enabled + +--- +```lua +component:set_input_enabled(state) +``` + +Set component input state. By default it's enabled. +If input is disabled, the component will not receive input events. +Recursive for all children components. + +- **Parameters:** + - `state` *(boolean)*: + +- **Returns:** + - `self` *(druid.component)*: The component itself for chaining + +### get_input_enabled + +--- +```lua +component:get_input_enabled() +``` + +Get component input state. By default it's enabled. Can be disabled by `set_input_enabled` function. + +- **Returns:** + - `` *(boolean)*: + +### get_parent_component + +--- +```lua +component:get_parent_component() +``` + +Get parent component + +- **Returns:** + - `parent_component` *(druid.component|nil)*: The parent component if exist or nil + +### get_nodes + +--- +```lua +component:get_nodes() +``` + +Get current component nodes + +- **Returns:** + - `` *(table|nil)*: + +### get_childrens + +--- +```lua +component:get_childrens() +``` + +Return all children components, recursive + +- **Returns:** + - `Array` *(table)*: of childrens if the Druid component instance + + +## Fields + +- **druid** (_druid.instance_): Druid instance to create inner components + diff --git a/api/components/base/drag_api.md b/api/components/base/drag_api.md new file mode 100644 index 0000000..34640c6 --- /dev/null +++ b/api/components/base/drag_api.md @@ -0,0 +1,176 @@ +# druid.drag API + +> at /druid/base/drag.lua + +A component that allows you to subscribe to drag events over a node + + +## Functions +- [init](#init) +- [set_drag_cursors](#set_drag_cursors) +- [set_click_zone](#set_click_zone) +- [set_enabled](#set_enabled) +- [is_enabled](#is_enabled) + + +## Fields +- [node](#node) +- [on_touch_start](#on_touch_start) +- [on_touch_end](#on_touch_end) +- [on_drag_start](#on_drag_start) +- [on_drag](#on_drag) +- [on_drag_end](#on_drag_end) +- [style](#style) +- [click_zone](#click_zone) +- [is_touch](#is_touch) +- [is_drag](#is_drag) +- [can_x](#can_x) +- [can_y](#can_y) +- [dx](#dx) +- [dy](#dy) +- [touch_id](#touch_id) +- [x](#x) +- [y](#y) +- [screen_x](#screen_x) +- [screen_y](#screen_y) +- [touch_start_pos](#touch_start_pos) +- [druid](#druid) +- [hover](#hover) + + + +### init + +--- +```lua +drag:init(node_or_node_id, [on_drag_callback]) +``` + +The constructor for Drag component + +- **Parameters:** + - `node_or_node_id` *(string|node)*: The node to subscribe to drag events over + - `[on_drag_callback]` *(fun(self: any, touch: any))*: The callback to call when a drag occurs + +### set_drag_cursors + +--- +```lua +drag:set_drag_cursors(is_enabled) +``` + +Set Drag component enabled state. + +- **Parameters:** + - `is_enabled` *(boolean)*: True if Drag component is enabled + +### set_click_zone + +--- +```lua +drag:set_click_zone([node]) +``` + +Set Drag click zone + +- **Parameters:** + - `[node]` *(string|node|nil)*: Node or node id + +- **Returns:** + - `self` *(druid.drag)*: Current instance + +### set_enabled + +--- +```lua +drag:set_enabled(is_enabled) +``` + +Set Drag component enabled state. + +- **Parameters:** + - `is_enabled` *(boolean)*: + +- **Returns:** + - `self` *(druid.drag)*: Current instance + +### is_enabled + +--- +```lua +drag:is_enabled() +``` + +Check if Drag component is capture input + +- **Returns:** + - `is_enabled` *(boolean)*: True if Drag component is enabled + + +## Fields + +- **node** (_node_): The node to subscribe to drag events over + + +- **on_touch_start** (_event_): fun(self, touch) The event triggered when a touch starts + + +- **on_touch_end** (_event_): fun(self, touch) The event triggered when a touch ends + + +- **on_drag_start** (_event_): fun(self, touch) The event triggered when a drag starts + + +- **on_drag** (_event_): fun(self, touch) The event triggered when a drag occurs + + +- **on_drag_end** (_event_): fun(self, touch) The event triggered when a drag ends + + +- **style** (_druid.drag.style_): The style of Drag component + + +- **click_zone** (_node_): The click zone of Drag component + + +- **is_touch** (_boolean_): True if a touch is active + + +- **is_drag** (_boolean_): True if a drag is active + + +- **can_x** (_boolean_): True if Drag can move horizontally + + +- **can_y** (_boolean_): True if Drag can move vertically + + +- **dx** (_number_): The horizontal drag distance + + +- **dy** (_number_): The vertical drag distance + + +- **touch_id** (_number_): The touch id + + +- **x** (_number_): The current x position + + +- **y** (_number_): The current y position + + +- **screen_x** (_number_): The current screen x position + + +- **screen_y** (_number_): The current screen y position + + +- **touch_start_pos** (_vector3_): The touch start position + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **hover** (_druid.hover_): The component for handling hover events on a node + diff --git a/api/components/base/hover_api.md b/api/components/base/hover_api.md new file mode 100644 index 0000000..5064a7d --- /dev/null +++ b/api/components/base/hover_api.md @@ -0,0 +1,144 @@ +# druid.hover API + +> at /druid/base/hover.lua + +The component for handling hover events on a node + + +## Functions +- [init](#init) +- [set_hover](#set_hover) +- [is_hovered](#is_hovered) +- [set_mouse_hover](#set_mouse_hover) +- [is_mouse_hovered](#is_mouse_hovered) +- [set_click_zone](#set_click_zone) +- [set_enabled](#set_enabled) +- [is_enabled](#is_enabled) + + +## Fields +- [node](#node) +- [on_hover](#on_hover) +- [on_mouse_hover](#on_mouse_hover) +- [style](#style) +- [click_zone](#click_zone) + + + +### init + +--- +```lua +hover:init(node, on_hover_callback, on_mouse_hover) +``` + +The constructor for the hover component + +- **Parameters:** + - `node` *(node)*: Gui node + - `on_hover_callback` *(function)*: Hover callback + - `on_mouse_hover` *(function)*: On mouse hover callback + +### set_hover + +--- +```lua +hover:set_hover([state]) +``` + +Set hover state + +- **Parameters:** + - `[state]` *(boolean|nil)*: The hover state + +### is_hovered + +--- +```lua +hover:is_hovered() +``` + +Return current hover state. True if touch action was on the node at current time + +- **Returns:** + - `is_hovered` *(boolean)*: The current hovered state + +### set_mouse_hover + +--- +```lua +hover:set_mouse_hover([state]) +``` + +Set mouse hover state + +- **Parameters:** + - `[state]` *(boolean|nil)*: The mouse hover state + +### is_mouse_hovered + +--- +```lua +hover:is_mouse_hovered() +``` + +Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time + +- **Returns:** + - `The` *(boolean)*: current hovered state + +### set_click_zone + +--- +```lua +hover:set_click_zone([zone]) +``` + +Strict hover click area. Useful for no click events outside stencil node + +- **Parameters:** + - `[zone]` *(string|node|nil)*: Gui node + +### set_enabled + +--- +```lua +hover:set_enabled([state]) +``` + +Set enable state of hover component. +If hover is not enabled, it will not generate +any hover events + +- **Parameters:** + - `[state]` *(boolean|nil)*: The hover enabled state + +### is_enabled + +--- +```lua +hover:is_enabled() +``` + +Return current hover enabled state + +- **Returns:** + - `The` *(boolean)*: hover enabled state + + +## Fields + +- **node** (_node_): Gui node + + +- **on_hover** (_event_): fun(self: druid.hover, is_hover: boolean) Hover event + + +- **on_mouse_hover** (_event_): fun(self: druid.hover, is_hover: boolean) Mouse hover event + + +- **style** (_druid.hover.style_): Style of the hover component + + +- **click_zone** (_node_): Click zone of the hover component + diff --git a/api/components/base/scroll_api.md b/api/components/base/scroll_api.md new file mode 100644 index 0000000..cf747dd --- /dev/null +++ b/api/components/base/scroll_api.md @@ -0,0 +1,377 @@ +# druid.scroll API + +> at /druid/base/scroll.lua + + +## Functions +- [init](#init) +- [scroll_to](#scroll_to) +- [scroll_to_index](#scroll_to_index) +- [scroll_to_percent](#scroll_to_percent) +- [get_percent](#get_percent) +- [set_size](#set_size) +- [set_view_size](#set_view_size) +- [update_view_size](#update_view_size) +- [set_inert](#set_inert) +- [is_inert](#is_inert) +- [set_extra_stretch_size](#set_extra_stretch_size) +- [get_scroll_size](#get_scroll_size) +- [set_points](#set_points) +- [set_horizontal_scroll](#set_horizontal_scroll) +- [set_vertical_scroll](#set_vertical_scroll) +- [is_node_in_view](#is_node_in_view) +- [bind_grid](#bind_grid) +- [set_click_zone](#set_click_zone) + + +## Fields +- [node](#node) +- [click_zone](#click_zone) +- [on_scroll](#on_scroll) +- [on_scroll_to](#on_scroll_to) +- [on_point_scroll](#on_point_scroll) +- [view_node](#view_node) +- [view_border](#view_border) +- [content_node](#content_node) +- [view_size](#view_size) +- [position](#position) +- [target_position](#target_position) +- [available_pos](#available_pos) +- [available_size](#available_size) +- [drag](#drag) +- [selected](#selected) +- [is_animate](#is_animate) +- [style](#style) +- [druid](#druid) +- [hover](#hover) +- [points](#points) +- [available_pos_extra](#available_pos_extra) +- [available_size_extra](#available_size_extra) + + + +### init + +--- +```lua +scroll:init(view_node, content_node) +``` + +The Scroll constructor + +- **Parameters:** + - `view_node` *(string|node)*: GUI view scroll node + - `content_node` *(string|node)*: GUI content scroll node + +### scroll_to + +--- +```lua +scroll:scroll_to(point, [is_instant]) +``` + +Start scroll to target point. + +- **Parameters:** + - `point` *(vector3)*: Target point + - `[is_instant]` *(boolean|nil)*: Instant scroll flag + +### scroll_to_index + +--- +```lua +scroll:scroll_to_index(index, [skip_cb]) +``` + +Scroll to item in scroll by point index. + +- **Parameters:** + - `index` *(number)*: Point index + - `[skip_cb]` *(boolean|nil)*: If true, skip the point callback + +### scroll_to_percent + +--- +```lua +scroll:scroll_to_percent(percent, [is_instant]) +``` + +Start scroll to target scroll percent + +- **Parameters:** + - `percent` *(vector3)*: target percent + - `[is_instant]` *(boolean|nil)*: instant scroll flag + +### get_percent + +--- +```lua +scroll:get_percent() +``` + +Return current scroll progress status. + Values will be in [0..1] interval + +- **Returns:** + - `New` *(vector3)*: vector with scroll progress values + +### set_size + +--- +```lua +scroll:set_size(size, [offset]) +``` + +Set scroll content size. + It will change content gui node size + +- **Parameters:** + - `size` *(vector3)*: The new size for content node + - `[offset]` *(vector3|nil)*: Offset value to set, where content is starts + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### set_view_size + +--- +```lua +scroll:set_view_size(size) +``` + +Set new scroll view size in case the node size was changed. + +- **Parameters:** + - `size` *(vector3)*: The new size for view node + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### update_view_size + +--- +```lua +scroll:update_view_size() +``` + +Refresh scroll view size, used when view node size is changed + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### set_inert + +--- +```lua +scroll:set_inert(state) +``` + +Enable or disable scroll inert + If disabled, scroll through points (if exist) + If no points, just simple drag without inertion + +- **Parameters:** + - `state` *(boolean)*: Inert scroll state + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### is_inert + +--- +```lua +scroll:is_inert() +``` + +Return if scroll have inertion + +- **Returns:** + - `is_inert` *(boolean)*: If scroll have inertion + +### set_extra_stretch_size + +--- +```lua +scroll:set_extra_stretch_size([stretch_size]) +``` + +Set extra size for scroll stretching + Set 0 to disable stretching effect + +- **Parameters:** + - `[stretch_size]` *(number|nil)*: Size in pixels of additional scroll area + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### get_scroll_size + +--- +```lua +scroll:get_scroll_size() +``` + +Return vector of scroll size with width and height. + +- **Returns:** + - `Available` *(vector3)*: scroll size + +### set_points + +--- +```lua +scroll:set_points(points) +``` + +Set points of interest. + Scroll will always centered on closer points + +- **Parameters:** + - `points` *(table)*: Array of vector3 points + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### set_horizontal_scroll + +--- +```lua +scroll:set_horizontal_scroll(state) +``` + +Lock or unlock horizontal scroll + +- **Parameters:** + - `state` *(boolean)*: True, if horizontal scroll is enabled + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### set_vertical_scroll + +--- +```lua +scroll:set_vertical_scroll(state) +``` + +Lock or unlock vertical scroll + +- **Parameters:** + - `state` *(boolean)*: True, if vertical scroll is enabled + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### is_node_in_view + +--- +```lua +scroll:is_node_in_view(node) +``` + +Check node if it visible now on scroll. + Extra border is not affected. Return true for elements in extra scroll zone + +- **Parameters:** + - `node` *(node)*: The node to check + +- **Returns:** + - `True` *(boolean)*: if node in visible scroll area + +### bind_grid + +--- +```lua +scroll:bind_grid([grid]) +``` + +Bind the grid component (Static or Dynamic) to recalculate + scroll size on grid changes + +- **Parameters:** + - `[grid]` *(druid.grid|nil)*: Druid grid component + +- **Returns:** + - `self` *(druid.scroll)*: Current scroll instance + +### set_click_zone + +--- +```lua +scroll:set_click_zone(node) +``` + +Strict drag scroll area. Useful for + restrict events outside stencil node + +- **Parameters:** + - `node` *(string|node)*: Gui node + + +## Fields + +- **node** (_node_): The root node + + +- **click_zone** (_node_): Optional click zone to restrict scroll area + + +- **on_scroll** (_event_): Triggered on scroll move with (self, position) + + +- **on_scroll_to** (_event_): Triggered on scroll_to with (self, target, is_instant) + + +- **on_point_scroll** (_event_): Triggered on scroll_to_index with (self, index, point) + + +- **view_node** (_node_): The scroll view node (static part) + + +- **view_border** (_vector4_): The scroll view borders + + +- **content_node** (_node_): The scroll content node (moving part) + + +- **view_size** (_vector3_): Size of the view node + + +- **position** (_vector3_): Current scroll position + + +- **target_position** (_vector3_): Target scroll position for animations + + +- **available_pos** (_vector4_): Available content position (min_x, max_y, max_x, min_y) + + +- **available_size** (_vector3_): Size of available positions (width, height, 0) + + +- **drag** (_druid.drag_): The drag component instance + + +- **selected** (_number_): Current selected point of interest index + + +- **is_animate** (_boolean_): True if scroll is animating + + +- **style** (_druid.scroll.style_): Component style parameters + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **hover** (_druid.hover_): The component for handling hover events on a node + + +- **points** (_table_) + + +- **available_pos_extra** (_unknown_) + + +- **available_size_extra** (_vector3_) + diff --git a/api/components/base/static_grid_api.md b/api/components/base/static_grid_api.md new file mode 100644 index 0000000..795349a --- /dev/null +++ b/api/components/base/static_grid_api.md @@ -0,0 +1,387 @@ +# druid.grid API + +> at /druid/base/static_grid.lua + +The component for manage the nodes position in the grid with various options + + +## Functions +- [init](#init) +- [get_pos](#get_pos) +- [get_index](#get_index) +- [get_index_by_node](#get_index_by_node) +- [set_anchor](#set_anchor) +- [refresh](#refresh) +- [set_pivot](#set_pivot) +- [add](#add) +- [set_items](#set_items) +- [remove](#remove) +- [get_size](#get_size) +- [get_size_for](#get_size_for) +- [get_borders](#get_borders) +- [get_all_pos](#get_all_pos) +- [set_position_function](#set_position_function) +- [clear](#clear) +- [get_offset](#get_offset) +- [set_in_row](#set_in_row) +- [set_item_size](#set_item_size) +- [sort_nodes](#sort_nodes) + + +## Fields +- [on_add_item](#on_add_item) +- [on_remove_item](#on_remove_item) +- [on_change_items](#on_change_items) +- [on_clear](#on_clear) +- [on_update_positions](#on_update_positions) +- [parent](#parent) +- [nodes](#nodes) +- [first_index](#first_index) +- [last_index](#last_index) +- [anchor](#anchor) +- [pivot](#pivot) +- [node_size](#node_size) +- [border](#border) +- [in_row](#in_row) +- [style](#style) +- [node_pivot](#node_pivot) + + + +### init + +--- +```lua +grid:init(parent, element, [in_row]) +``` + +The constructor for the grid component + +- **Parameters:** + - `parent` *(string|node)*: The GUI Node container, where grid's items will be placed + - `element` *(node)*: Element prefab. Need to get it size + - `[in_row]` *(number|nil)*: How many nodes in row can be placed. By default 1 + +### get_pos + +--- +```lua +grid:get_pos(index) +``` + +Return pos for grid node index + +- **Parameters:** + - `index` *(number)*: The grid element index + +- **Returns:** + - `position` *(vector3)*: Node position + +### get_index + +--- +```lua +grid:get_index(pos) +``` + +Return grid index by position + +- **Parameters:** + - `pos` *(vector3)*: The node position in the grid + +- **Returns:** + - `index` *(number)*: The node index + +### get_index_by_node + +--- +```lua +grid:get_index_by_node(node) +``` + +Return grid index by node + +- **Parameters:** + - `node` *(node)*: The gui node in the grid + +- **Returns:** + - `index` *(number|nil)*: The node index + +### set_anchor + +--- +```lua +grid:set_anchor(anchor) +``` + +Set grid anchor. Default anchor is equal to anchor of grid parent node + +- **Parameters:** + - `anchor` *(vector3)*: Anchor + +### refresh + +--- +```lua +grid:refresh() +``` + +Instantly update the grid content + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### set_pivot + +--- +```lua +grid:set_pivot(pivot) +``` + +Set grid pivot + +- **Parameters:** + - `pivot` *(constant)*: The new pivot + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### add + +--- +```lua +grid:add(item, [index], [shift_policy], [is_instant]) +``` + +Add new item to the grid + +- **Parameters:** + - `item` *(node)*: GUI node + - `[index]` *(number|nil)*: The item position. By default add as last item + - `[shift_policy]` *(number|nil)*: How shift nodes, if required. Default: const.SHIFT.RIGHT + - `[is_instant]` *(boolean|nil)*: If true, update node positions instantly + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### set_items + +--- +```lua +grid:set_items(nodes, [is_instant]) +``` + +Set new items to the grid. All previous items will be removed + +- **Parameters:** + - `nodes` *(node[])*: The new grid nodes + - `[is_instant]` *(boolean|nil)*: If true, update node positions instantly + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### remove + +--- +```lua +grid:remove(index, [shift_policy], [is_instant]) +``` + +Remove the item from the grid. Note that gui node will be not deleted + +- **Parameters:** + - `index` *(number)*: The grid node index to remove + - `[shift_policy]` *(number|nil)*: How shift nodes, if required. Default: const.SHIFT.RIGHT + - `[is_instant]` *(boolean|nil)*: If true, update node positions instantly + +- **Returns:** + - `node` *(node)*: The deleted gui node from grid + +### get_size + +--- +```lua +grid:get_size() +``` + +Return grid content size + +- **Returns:** + - `size` *(vector3)*: The grid content size + +### get_size_for + +--- +```lua +grid:get_size_for(count) +``` + +Return grid content size for given count of nodes + +- **Parameters:** + - `count` *(number)*: The count of nodes + +- **Returns:** + - `size` *(vector3)*: The grid content size + +### get_borders + +--- +```lua +grid:get_borders() +``` + +Return grid content borders + +- **Returns:** + - `borders` *(vector4)*: The grid content borders + +### get_all_pos + +--- +```lua +grid:get_all_pos() +``` + +Return array of all node positions + +- **Returns:** + - `positions` *(vector3[])*: All grid node positions + +### set_position_function + +--- +```lua +grid:set_position_function(callback) +``` + +Change set position function for grid nodes. It will call on + update poses on grid elements. Default: gui.set_position + +- **Parameters:** + - `callback` *(function)*: Function on node set position + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### clear + +--- +```lua +grid:clear() +``` + +Clear grid nodes array. GUI nodes will be not deleted! + If you want to delete GUI nodes, use static_grid.nodes array before grid:clear + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### get_offset + +--- +```lua +grid:get_offset() +``` + +Return StaticGrid offset, where StaticGrid content starts. + +- **Returns:** + - `offset` *(vector3)*: The StaticGrid offset + +### set_in_row + +--- +```lua +grid:set_in_row(in_row) +``` + +Set new in_row elements for grid + +- **Parameters:** + - `in_row` *(number)*: The new in_row value + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### set_item_size + +--- +```lua +grid:set_item_size([width], [height]) +``` + +Set new node size for grid + +- **Parameters:** + - `[width]` *(number|nil)*: The new node width + - `[height]` *(number|nil)*: The new node height + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + +### sort_nodes + +--- +```lua +grid:sort_nodes(comparator) +``` + +Sort grid nodes by custom comparator function + +- **Parameters:** + - `comparator` *(function)*: The comparator function. (a, b) -> boolean + +- **Returns:** + - `self` *(druid.grid)*: Current grid instance + + +## Fields + +- **on_add_item** (_event_): Trigger on add item event, fun(self, item, index) + + +- **on_remove_item** (_event_): Trigger on remove item event, fun(self, index) + + +- **on_change_items** (_event_): Trigger on change items event, fun(self, index) + + +- **on_clear** (_event_): Trigger on clear event, fun(self) + + +- **on_update_positions** (_event_): Trigger on update positions event, fun(self) + + +- **parent** (_node_): Parent node + + +- **nodes** (_node[]_): Nodes array + + +- **first_index** (_number_): First index + + +- **last_index** (_number_): Last index + + +- **anchor** (_vector3_): Anchor + + +- **pivot** (_vector3_): Pivot + + +- **node_size** (_vector3_): Node size + + +- **border** (_vector4_): Border + + +- **in_row** (_number_): In row + + +- **style** (_druid.grid.style_): Style + + +- **node_pivot** (_unknown_) + diff --git a/api/components/base/text_api.md b/api/components/base/text_api.md new file mode 100644 index 0000000..4d29dcf --- /dev/null +++ b/api/components/base/text_api.md @@ -0,0 +1,298 @@ +# druid.text API + +> at /druid/base/text.lua + +The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +## Functions +- [init](#init) +- [get_text_size](#get_text_size) +- [get_text_index_by_width](#get_text_index_by_width) +- [set_to](#set_to) +- [set_text](#set_text) +- [get_text](#get_text) +- [set_size](#set_size) +- [set_color](#set_color) +- [set_alpha](#set_alpha) +- [set_scale](#set_scale) +- [set_pivot](#set_pivot) +- [is_multiline](#is_multiline) +- [set_text_adjust](#set_text_adjust) +- [set_minimal_scale](#set_minimal_scale) +- [get_text_adjust](#get_text_adjust) + + +## Fields +- [node](#node) +- [on_set_text](#on_set_text) +- [on_update_text_scale](#on_update_text_scale) +- [on_set_pivot](#on_set_pivot) +- [style](#style) +- [pos](#pos) +- [node_id](#node_id) +- [start_size](#start_size) +- [text_area](#text_area) +- [adjust_type](#adjust_type) +- [color](#color) +- [last_value](#last_value) +- [last_scale](#last_scale) + + + +### init + +--- +```lua +text:init(node, [value], [adjust_type]) +``` + +The Text constructor + +- **Parameters:** + - `node` *(string|node)*: Node name or GUI Text Node itself + - `[value]` *(string|nil)*: Initial text. Default value is node text from GUI scene. Default: nil + - `[adjust_type]` *(string|nil)*: Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE + +### get_text_size + +--- +```lua +text:get_text_size([text]) +``` + +Calculate text width with font with respect to trailing space + +- **Parameters:** + - `[text]` *(string|nil)*: The text to calculate the size of, if nil - use current text + +- **Returns:** + - `width` *(number)*: The text width + - `height` *(number)*: The text height + +### get_text_index_by_width + +--- +```lua +text:get_text_index_by_width(width) +``` + +Get chars count by width + +- **Parameters:** + - `width` *(number)*: The width to get the chars count of + +- **Returns:** + - `index` *(number)*: The chars count + +### set_to + +--- +```lua +text:set_to(set_to) +``` + +Set text to text field + +- **Parameters:** + - `set_to` *(string)*: Text for node + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### set_text + +--- +```lua +text:set_text([new_text]) +``` + +- **Parameters:** + - `[new_text]` *(any)*: + +- **Returns:** + - `` *(druid.text)*: + +### get_text + +--- +```lua +text:get_text() +``` + +- **Returns:** + - `` *(unknown)*: + +### set_size + +--- +```lua +text:set_size(size) +``` + +Set text area size + +- **Parameters:** + - `size` *(vector3)*: The new text area size + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### set_color + +--- +```lua +text:set_color(color) +``` + +Set color + +- **Parameters:** + - `color` *(vector4)*: Color for node + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### set_alpha + +--- +```lua +text:set_alpha(alpha) +``` + +Set alpha + +- **Parameters:** + - `alpha` *(number)*: Alpha for node + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### set_scale + +--- +```lua +text:set_scale(scale) +``` + +Set scale + +- **Parameters:** + - `scale` *(vector3)*: Scale for node + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### set_pivot + +--- +```lua +text:set_pivot(pivot) +``` + +Set text pivot. Text will re-anchor inside text area + +- **Parameters:** + - `pivot` *(userdata)*: The gui.PIVOT_* constant + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### is_multiline + +--- +```lua +text:is_multiline() +``` + +Return true, if text with line break + +- **Returns:** + - `Is` *(boolean)*: text node with line break + +### set_text_adjust + +--- +```lua +text:set_text_adjust([adjust_type], [minimal_scale]) +``` + +Set text adjust, refresh the current text visuals, if needed +Values are: "downscale", "trim", "no_adjust", "downscale_limited", +"scroll", "scale_then_scroll", "trim_left", "scale_then_trim", "scale_then_trim_left" + +- **Parameters:** + - `[adjust_type]` *(string|nil)*: See const.TEXT_ADJUST. If pass nil - use current adjust type + - `[minimal_scale]` *(number|nil)*: To remove minimal scale, use `text:set_minimal_scale(nil)`, if pass nil - not change minimal scale + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### set_minimal_scale + +--- +```lua +text:set_minimal_scale(minimal_scale) +``` + +Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types + +- **Parameters:** + - `minimal_scale` *(number)*: If pass nil - not use minimal scale + +- **Returns:** + - `self` *(druid.text)*: Current text instance + +### get_text_adjust + +--- +```lua +text:get_text_adjust() +``` + +Return current text adjust type + +- **Returns:** + - `adjust_type` *(string)*: The current text adjust type + + +## Fields + +- **node** (_node_): The text node + + +- **on_set_text** (_event_): The event triggered when the text is set, fun(self, text) + + +- **on_update_text_scale** (_event_): The event triggered when the text scale is updated, fun(self, scale, metrics) + + +- **on_set_pivot** (_event_): The event triggered when the text pivot is set, fun(self, pivot) + + +- **style** (_druid.text.style_): The style of the text + + +- **pos** (_unknown_) + + +- **node_id** (_unknown_) + + +- **start_size** (_unknown_) + + +- **text_area** (_unknown_) + + +- **adjust_type** (_string|nil_) + + +- **color** (_unknown_) + + +- **last_value** (_unknown_) + + +- **last_scale** (_vector3_) + diff --git a/api/components/custom/rich_input_api.md b/api/components/custom/rich_input_api.md new file mode 100644 index 0000000..1ebca04 --- /dev/null +++ b/api/components/custom/rich_input_api.md @@ -0,0 +1,183 @@ +# druid.rich_input API + +> at /druid/custom/rich_input/rich_input.lua + +The component that handles a rich text input field, it's a wrapper around the druid.input component + + +## Functions +- [init](#init) +- [on_input](#on_input) +- [set_placeholder](#set_placeholder) +- [select](#select) +- [set_text](#set_text) +- [set_font](#set_font) +- [get_text](#get_text) +- [set_allowed_characters](#set_allowed_characters) + + +## Fields +- [root](#root) +- [input](#input) +- [cursor](#cursor) +- [cursor_text](#cursor_text) +- [cursor_position](#cursor_position) +- [druid](#druid) +- [is_lshift](#is_lshift) +- [is_lctrl](#is_lctrl) +- [is_button_input_enabled](#is_button_input_enabled) +- [drag](#drag) +- [placeholder](#placeholder) +- [text_position](#text_position) + + + +### init + +--- +```lua +rich_input:init(template, nodes) +``` + +- **Parameters:** + - `template` *(string)*: The template string name + - `nodes` *(table)*: Nodes table from gui.clone_tree + +### on_input + +--- +```lua +rich_input:on_input([action_id], [action]) +``` + +- **Parameters:** + - `[action_id]` *(any)*: + - `[action]` *(any)*: + +- **Returns:** + - `` *(boolean)*: + +### set_placeholder + +--- +```lua +rich_input:set_placeholder(placeholder_text) +``` + +Set placeholder text + +- **Parameters:** + - `placeholder_text` *(string)*: The placeholder text + +- **Returns:** + - `self` *(druid.rich_input)*: Current instance + +### select + +--- +```lua +rich_input:select() +``` + +Select input field + +- **Returns:** + - `self` *(druid.rich_input)*: Current instance + +### set_text + +--- +```lua +rich_input:set_text(text) +``` + +Set input field text + +- **Parameters:** + - `text` *(string)*: The input text + +- **Returns:** + - `self` *(druid.rich_input)*: Current instance + +### set_font + +--- +```lua +rich_input:set_font(font) +``` + +Set input field font + +- **Parameters:** + - `font` *(hash)*: The font hash + +- **Returns:** + - `self` *(druid.rich_input)*: Current instance + +### get_text + +--- +```lua +rich_input:get_text() +``` + +Set input field text + +- **Returns:** + - `` *(string)*: + +### set_allowed_characters + +--- +```lua +rich_input:set_allowed_characters(characters) +``` + +Set allowed charaters for input field. + See: https://defold.com/ref/stable/string/ + ex: [%a%d] for alpha and numeric + +- **Parameters:** + - `characters` *(string)*: Regulax exp. for validate user input + +- **Returns:** + - `self` *(druid.rich_input)*: Current instance + + +## Fields + +- **root** (_node_): The root node of the rich input + + +- **input** (_druid.input_): The input component + + +- **cursor** (_node_): The cursor node + + +- **cursor_text** (_node_): The cursor text node + + +- **cursor_position** (_vector3_): The position of the cursor + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **is_lshift** (_boolean_) + + +- **is_lctrl** (_boolean_) + + +- **is_button_input_enabled** (_unknown_) + + +- **drag** (_druid.drag_): A component that allows you to subscribe to drag events over a node + + +- **placeholder** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **text_position** (_unknown_) + diff --git a/api/components/custom/rich_text_api.md b/api/components/custom/rich_text_api.md new file mode 100644 index 0000000..a234ae8 --- /dev/null +++ b/api/components/custom/rich_text_api.md @@ -0,0 +1,145 @@ +# druid.rich_text API + +> at /druid/custom/rich_text/rich_text.lua + +The component that handles a rich text display, allows to custom color, size, font, etc. of the parts of the text + + +## Functions +- [init](#init) +- [set_text](#set_text) +- [get_text](#get_text) +- [clear](#clear) +- [tagged](#tagged) +- [get_words](#get_words) +- [get_line_metric](#get_line_metric) + + +## Fields +- [root](#root) +- [text_prefab](#text_prefab) +- [style](#style) + + + +### init + +--- +```lua +rich_text:init(text_node, [value]) +``` + +- **Parameters:** + - `text_node` *(string|node)*: The text node to make Rich Text + - `[value]` *(string|nil)*: The initial text value. Default will be gui.get_text(text_node) + +### set_text + +--- +```lua +rich_text:set_text([text]) +``` + +Set text for Rich Text + +- **Parameters:** + - `[text]` *(string|nil)*: The text to set + +- **Returns:** + - `words` *(druid.rich_text.word[])*: + - `line_metrics` *(druid.rich_text.lines_metrics)*: + +- **Example Usage:** + +```lua +rich_text:set_text("<color=red>Foobar</color>") +rich_text:set_text("<color=1.0,0,0,1.0>Foobar</color>") +rich_text:set_text("<color=#ff0000>Foobar</color>") +rich_text:set_text("<color=#ff0000ff>Foobar</color>") +rich_text:set_text("<shadow=red>Foobar</shadow>") +rich_text:set_text("<shadow=1.0,0,0,1.0>Foobar</shadow>") +rich_text:set_text("<shadow=#ff0000>Foobar</shadow>") +rich_text:set_text("<shadow=#ff0000ff>Foobar</shadow>") +rich_text:set_text("<outline=red>Foobar</outline>") +rich_text:set_text("<outline=1.0,0,0,1.0>Foobar</outline>") +rich_text:set_text("<outline=#ff0000>Foobar</outline>") +rich_text:set_text("<outline=#ff0000ff>Foobar</outline>") +rich_text:set_text("<font=MyCoolFont>Foobar</font>") +rich_text:set_text("<size=2>Twice as large</size>") +rich_text:set_text("<br/>Insert a line break") +rich_text:set_text("<nobr>Prevent the text from breaking") +rich_text:set_text("<img=texture:image>Display image") +rich_text:set_text("<img=texture:image,size>Display image with size") +rich_text:set_text("<img=texture:image,width,height>Display image with width and height") +``` +### get_text + +--- +```lua +rich_text:get_text() +``` + +Get the current text of the rich text + +- **Returns:** + - `text` *(string)*: The current text of the rich text + +### clear + +--- +```lua +rich_text:clear() +``` + +Clear all created words. + +### tagged + +--- +```lua +rich_text:tagged(tag) +``` + +Get all words, which has a passed tag. + +- **Parameters:** + - `tag` *(string)*: The tag to get the words for + +- **Returns:** + - `words` *(druid.rich_text.word[])*: The words with the passed tag + +### get_words + +--- +```lua +rich_text:get_words() +``` + +Get all current created words, each word is a table that contains the information about the word + +- **Returns:** + - `` *(druid.rich_text.word[])*: + +### get_line_metric + +--- +```lua +rich_text:get_line_metric() +``` + +Get the current line metrics + +- **Returns:** + - `lines_metrics` *(druid.rich_text.lines_metrics)*: The line metrics of the rich text + + +## Fields + +- **root** (_node_): The root node of the rich text + + +- **text_prefab** (_node_): The text prefab node + + +- **style** (_table_) + diff --git a/api/components/extended/container_api.md b/api/components/extended/container_api.md new file mode 100644 index 0000000..88044d1 --- /dev/null +++ b/api/components/extended/container_api.md @@ -0,0 +1,359 @@ +# druid.container API + +> at /druid/extended/container.lua + +The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +## Functions +- [init](#init) +- [refresh_origins](#refresh_origins) +- [set_pivot](#set_pivot) +- [set_size](#set_size) +- [get_position](#get_position) +- [set_position](#set_position) +- [get_size](#get_size) +- [get_scale](#get_scale) +- [fit_into_size](#fit_into_size) +- [fit_into_window](#fit_into_window) +- [add_container](#add_container) +- [remove_container_by_node](#remove_container_by_node) +- [set_parent_container](#set_parent_container) +- [refresh](#refresh) +- [refresh_scale](#refresh_scale) +- [update_child_containers](#update_child_containers) +- [create_draggable_corners](#create_draggable_corners) +- [clear_draggable_corners](#clear_draggable_corners) +- [fit_into_node](#fit_into_node) +- [set_min_size](#set_min_size) + + +## Fields +- [node](#node) +- [druid](#druid) +- [node_offset](#node_offset) +- [origin_size](#origin_size) +- [size](#size) +- [origin_position](#origin_position) +- [position](#position) +- [pivot_offset](#pivot_offset) +- [center_offset](#center_offset) +- [mode](#mode) +- [fit_size](#fit_size) +- [min_size_x](#min_size_x) +- [min_size_y](#min_size_y) +- [on_size_changed](#on_size_changed) +- [node_fill_x](#node_fill_x) +- [node_fill_y](#node_fill_y) +- [x_koef](#x_koef) +- [y_koef](#y_koef) +- [x_anchor](#x_anchor) +- [y_anchor](#y_anchor) +- [style](#style) + + + +### init + +--- +```lua +container:init(node, mode, [callback]) +``` + +- **Parameters:** + - `node` *(node)*: Gui node + - `mode` *(string)*: Layout mode + - `[callback]` *(fun(self: druid.container, size: vector3)|nil)*: Callback on size changed + +### refresh_origins + +--- +```lua +container:refresh_origins() +``` + +Refresh the origins of the container, origins is the size and position of the container when it was created + +### set_pivot + +--- +```lua +container:set_pivot(pivot) +``` + +Set the pivot of the container + +- **Parameters:** + - `pivot` *(constant)*: The pivot to set + +### set_size + +--- +```lua +container:set_size([width], [height], [anchor_pivot]) +``` + +Set new size of layout node + +- **Parameters:** + - `[width]` *(number|nil)*: The width to set + - `[height]` *(number|nil)*: The height to set + - `[anchor_pivot]` *(constant|nil)*: If set will keep the corner possition relative to the new size + +- **Returns:** + - `Container` *(druid.container)*: + +### get_position + +--- +```lua +container:get_position() +``` + +Get the position of the container + +- **Returns:** + - `position` *(vector3)*: The position of the container + +### set_position + +--- +```lua +container:set_position(pos_x, pos_y) +``` + +Set the position of the container + +- **Parameters:** + - `pos_x` *(number)*: The x position to set + - `pos_y` *(number)*: The y position to set + +### get_size + +--- +```lua +container:get_size() +``` + +Get the current size of the layout node + +- **Returns:** + - `size` *(vector3)*: The current size of the layout node + +### get_scale + +--- +```lua +container:get_scale() +``` + +Get the current scale of the layout node + +- **Returns:** + - `scale` *(vector3)*: The current scale of the layout node + +### fit_into_size + +--- +```lua +container:fit_into_size(target_size) +``` + +Set size for layout node to fit inside it + +- **Parameters:** + - `target_size` *(vector3)*: The target size to fit into + +- **Returns:** + - `self` *(druid.container)*: Current container instance + +### fit_into_window + +--- +```lua +container:fit_into_window() +``` + +Set current size for layout node to fit inside it + +- **Returns:** + - `self` *(druid.container)*: Current container instance + +### add_container + +--- +```lua +container:add_container(node_or_container, [mode], [on_resize_callback]) +``` + +- **Parameters:** + - `node_or_container` *(string|table|druid.container|node)*: The component used for managing the size and positions with other containers relations to create a adaptable layouts + - `[mode]` *(string|nil)*: stretch, fit, stretch_x, stretch_y. Default: Pick from node, "fit" or "stretch" + - `[on_resize_callback]` *(fun(self: userdata, size: vector3)|nil)*: + +- **Returns:** + - `Container` *(druid.container)*: New created layout instance + +### remove_container_by_node + +--- +```lua +container:remove_container_by_node([node]) +``` + +- **Parameters:** + - `[node]` *(any)*: + +- **Returns:** + - `` *(druid.container|nil)*: + +### set_parent_container + +--- +```lua +container:set_parent_container([parent_container]) +``` + +- **Parameters:** + - `[parent_container]` *(druid.container|nil)*: The component used for managing the size and positions with other containers relations to create a adaptable layouts + +### refresh + +--- +```lua +container:refresh() +``` + + Glossary + Center Offset - vector from node position to visual center of node + +### refresh_scale + +--- +```lua +container:refresh_scale() +``` + +### update_child_containers + +--- +```lua +container:update_child_containers() +``` + +### create_draggable_corners + +--- +```lua +container:create_draggable_corners() +``` + +- **Returns:** + - `self` *(druid.container)*: Current container instance + +### clear_draggable_corners + +--- +```lua +container:clear_draggable_corners() +``` + +- **Returns:** + - `self` *(druid.container)*: Current container instance + +### fit_into_node + +--- +```lua +container:fit_into_node(node) +``` + +Set node for layout node to fit inside it. Pass nil to reset + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id) + +- **Returns:** + - `self` *(druid.container)*: Current container instance + +### set_min_size + +--- +```lua +container:set_min_size([min_size_x], [min_size_y]) +``` + +Set the minimum size of the container + +- **Parameters:** + - `[min_size_x]` *(number|nil)*: The minimum size x + - `[min_size_y]` *(number|nil)*: The minimum size y + +- **Returns:** + - `self` *(druid.container)*: Current container instance + + +## Fields + +- **node** (_node_): The gui node + + +- **druid** (_druid.instance_): The druid instance + + +- **node_offset** (_vector4_): The node offset + + +- **origin_size** (_vector3_): The origin size + + +- **size** (_vector3_): The current size + + +- **origin_position** (_vector3_): The origin position + + +- **position** (_vector3_): The current position + + +- **pivot_offset** (_vector3_): The pivot offset + + +- **center_offset** (_vector3_): The center offset + + +- **mode** (_string_): The layout mode + + +- **fit_size** (_vector3_): The fit size + + +- **min_size_x** (_number_): The minimum size x + + +- **min_size_y** (_number_): The minimum size y + + +- **on_size_changed** (_event_): fun(self: druid.container, size: vector3) The event triggered when the size changes + + +- **node_fill_x** (_nil_) + + +- **node_fill_y** (_nil_) + + +- **x_koef** (_number_) + + +- **y_koef** (_number_) + + +- **x_anchor** (_unknown_) + + +- **y_anchor** (_unknown_) + + +- **style** (_table_) + diff --git a/api/components/extended/data_list_api.md b/api/components/extended/data_list_api.md new file mode 100644 index 0000000..934cb1b --- /dev/null +++ b/api/components/extended/data_list_api.md @@ -0,0 +1,236 @@ +# druid.data_list API + +> at /druid/extended/data_list.lua + +The component used for managing a list of data with a scrollable view, used to manage huge list data and render only visible elements + + +## Functions +- [init](#init) +- [on_remove](#on_remove) +- [set_use_cache](#set_use_cache) +- [set_data](#set_data) +- [get_data](#get_data) +- [add](#add) +- [remove](#remove) +- [remove_by_data](#remove_by_data) +- [clear](#clear) +- [get_index](#get_index) +- [get_created_nodes](#get_created_nodes) +- [get_created_components](#get_created_components) +- [scroll_to_index](#scroll_to_index) + + +## Fields +- [scroll](#scroll) +- [grid](#grid) +- [on_scroll_progress_change](#on_scroll_progress_change) +- [on_element_add](#on_element_add) +- [on_element_remove](#on_element_remove) +- [top_index](#top_index) +- [last_index](#last_index) +- [scroll_progress](#scroll_progress) + + + +### init + +--- +```lua +data_list:init(scroll, grid, create_function) +``` + +- **Parameters:** + - `scroll` *(druid.scroll)*: The Scroll instance for Data List component + - `grid` *(druid.grid)*: The StaticGrid instance for Data List component + - `create_function` *(function)*: The create function callback(self, data, index, data_list). Function should return (node, [component]) + +### on_remove + +--- +```lua +data_list:on_remove() +``` + +Druid System on_remove function + +### set_use_cache + +--- +```lua +data_list:set_use_cache(is_use_cache) +``` + +Set use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove + +- **Parameters:** + - `is_use_cache` *(boolean)*: Use cache version of DataList + +- **Returns:** + - `self` *(druid.data_list)*: Current DataList instance + +### set_data + +--- +```lua +data_list:set_data(data) +``` + +Set new data set for DataList component + +- **Parameters:** + - `data` *(table)*: The new data array + +- **Returns:** + - `self` *(druid.data_list)*: Current DataList instance + +### get_data + +--- +```lua +data_list:get_data() +``` + +Return current data from DataList component + +- **Returns:** + - `data` *(table)*: The current data array + +### add + +--- +```lua +data_list:add(data, [index], [shift_policy]) +``` + +Add element to DataList + +- **Parameters:** + - `data` *(table)*: The data to add + - `[index]` *(number|nil)*: The index to add the data at + - `[shift_policy]` *(number|nil)*: The constant from const.SHIFT.* + +- **Returns:** + - `self` *(druid.data_list)*: Current DataList instance + +### remove + +--- +```lua +data_list:remove([index], [shift_policy]) +``` + +Remove element from DataList + +- **Parameters:** + - `[index]` *(number|nil)*: The index to remove the data at + - `[shift_policy]` *(number|nil)*: The constant from const.SHIFT.* + +- **Returns:** + - `self` *(druid.data_list)*: Current DataList instance + +### remove_by_data + +--- +```lua +data_list:remove_by_data(data, [shift_policy]) +``` + +Remove element from DataList by data value + +- **Parameters:** + - `data` *(table)*: The data to remove + - `[shift_policy]` *(number|nil)*: The constant from const.SHIFT.* + +- **Returns:** + - `self` *(druid.data_list)*: Current DataList instance + +### clear + +--- +```lua +data_list:clear() +``` + +Clear the DataList and refresh visuals + +- **Returns:** + - `self` *(druid.data_list)*: Current DataList instance + +### get_index + +--- +```lua +data_list:get_index(data) +``` + +Return index for data value + +- **Parameters:** + - `data` *(table)*: + +- **Returns:** + - `` *(unknown|nil)*: + +### get_created_nodes + +--- +```lua +data_list:get_created_nodes() +``` + +Return all currenly created nodes in DataList + +- **Returns:** + - `List` *(node[])*: of created nodes + +### get_created_components + +--- +```lua +data_list:get_created_components() +``` + +Return all currenly created components in DataList + +- **Returns:** + - `components` *(druid.component[])*: List of created components + +### scroll_to_index + +--- +```lua +data_list:scroll_to_index(index) +``` + +Instant scroll to element with passed index + +- **Parameters:** + - `index` *(number)*: The index to scroll to + + +## Fields + +- **scroll** (_druid.scroll_): The scroll instance for Data List component + + +- **grid** (_druid.grid_): The StaticGrid or DynamicGrid instance for Data List component + + +- **on_scroll_progress_change** (_event_): The event triggered when the scroll progress changes + + +- **on_element_add** (_event_): The event triggered when a new element is added + + +- **on_element_remove** (_event_): The event triggered when an element is removed + + +- **top_index** (_number_): The top index of the visible elements + + +- **last_index** (_number_): The last index of the visible elements + + +- **scroll_progress** (_number_): The scroll progress + diff --git a/api/components/extended/hotkey_api.md b/api/components/extended/hotkey_api.md new file mode 100644 index 0000000..5231bd0 --- /dev/null +++ b/api/components/extended/hotkey_api.md @@ -0,0 +1,125 @@ +# druid.hotkey API + +> at /druid/extended/hotkey.lua + +The component used for managing hotkeys and trigger callbacks when hotkeys are pressed + + +## Functions +- [init](#init) +- [on_style_change](#on_style_change) +- [add_hotkey](#add_hotkey) +- [is_processing](#is_processing) +- [on_focus_gained](#on_focus_gained) +- [on_input](#on_input) +- [set_repeat](#set_repeat) + + +## Fields +- [on_hotkey_pressed](#on_hotkey_pressed) +- [on_hotkey_released](#on_hotkey_released) +- [style](#style) +- [druid](#druid) + + + +### init + +--- +```lua +hotkey:init(keys, callback, [callback_argument]) +``` + +The Hotkey constructor + +- **Parameters:** + - `keys` *(string|string[])*: The keys to be pressed for trigger callback. Should contains one key and any modificator keys + - `callback` *(function)*: The callback function + - `[callback_argument]` *(any)*: The argument to pass into the callback function + +### on_style_change + +--- +```lua +hotkey:on_style_change(style) +``` + +- **Parameters:** + - `style` *(druid.hotkey.style)*: + +### add_hotkey + +--- +```lua +hotkey:add_hotkey(keys, [callback_argument]) +``` + +Add hotkey for component callback + +- **Parameters:** + - `keys` *(string|hash|hash[]|string[])*: that have to be pressed before key pressed to activate + - `[callback_argument]` *(any)*: The argument to pass into the callback function + +- **Returns:** + - `self` *(druid.hotkey)*: Current instance + +### is_processing + +--- +```lua +hotkey:is_processing() +``` + +- **Returns:** + - `` *(boolean)*: + +### on_focus_gained + +--- +```lua +hotkey:on_focus_gained() +``` + +### on_input + +--- +```lua +hotkey:on_input([action_id], action) +``` + +- **Parameters:** + - `[action_id]` *(hash|nil)*: The action id + - `action` *(action)*: The action + +- **Returns:** + - `is_consume` *(boolean)*: True if the action is consumed + +### set_repeat + +--- +```lua +hotkey:set_repeat(is_enabled_repeated) +``` + +If true, the callback will be triggered on action.repeated + +- **Parameters:** + - `is_enabled_repeated` *(boolean)*: The flag value + +- **Returns:** + - `self` *(druid.hotkey)*: Current instance + + +## Fields + +- **on_hotkey_pressed** (_event_): fun(self, context, callback_argument) The event triggered when a hotkey is pressed + + +- **on_hotkey_released** (_event_): fun(self, context, callback_argument) The event triggered when a hotkey is released + + +- **style** (_druid.hotkey.style_): The style of the hotkey component + + +- **druid** (_druid.instance_): The Druid Factory used to create components + diff --git a/api/components/extended/input_api.md b/api/components/extended/input_api.md new file mode 100644 index 0000000..738498c --- /dev/null +++ b/api/components/extended/input_api.md @@ -0,0 +1,314 @@ +# druid.input API + +> at /druid/extended/input.lua + +The component used for managing input fields in basic way + + +## Functions +- [init](#init) +- [on_focus_lost](#on_focus_lost) +- [on_input_interrupt](#on_input_interrupt) +- [get_text_selected](#get_text_selected) +- [get_text_selected_replaced](#get_text_selected_replaced) +- [set_text](#set_text) +- [select](#select) +- [unselect](#unselect) +- [get_text](#get_text) +- [set_max_length](#set_max_length) +- [set_allowed_characters](#set_allowed_characters) +- [reset_changes](#reset_changes) +- [select_cursor](#select_cursor) +- [move_selection](#move_selection) + + +## Fields +- [on_input_select](#on_input_select) +- [on_input_unselect](#on_input_unselect) +- [on_input_text](#on_input_text) +- [on_input_empty](#on_input_empty) +- [on_input_full](#on_input_full) +- [on_input_wrong](#on_input_wrong) +- [on_select_cursor_change](#on_select_cursor_change) +- [style](#style) +- [text](#text) +- [ALLOWED_ACTIONS](#ALLOWED_ACTIONS) +- [druid](#druid) +- [is_selected](#is_selected) +- [value](#value) +- [previous_value](#previous_value) +- [current_value](#current_value) +- [marked_value](#marked_value) +- [is_empty](#is_empty) +- [text_width](#text_width) +- [market_text_width](#market_text_width) +- [total_width](#total_width) +- [cursor_index](#cursor_index) +- [start_index](#start_index) +- [end_index](#end_index) +- [max_length](#max_length) +- [allowed_characters](#allowed_characters) +- [keyboard_type](#keyboard_type) +- [button](#button) +- [marked_text_width](#marked_text_width) + + + +### init + +--- +```lua +input:init(click_node, text_node, [keyboard_type]) +``` + +- **Parameters:** + - `click_node` *(node)*: Node to enabled input component + - `text_node` *(druid.text|node)*: Text node what will be changed on user input. You can pass text component instead of text node name Text + - `[keyboard_type]` *(number|nil)*: Gui keyboard type for input field + +### on_focus_lost + +--- +```lua +input:on_focus_lost() +``` + +### on_input_interrupt + +--- +```lua +input:on_input_interrupt() +``` + +### get_text_selected + +--- +```lua +input:get_text_selected() +``` + +- **Returns:** + - `` *(string|unknown)*: + +### get_text_selected_replaced + +--- +```lua +input:get_text_selected_replaced(text) +``` + +Replace selected text with new text + +- **Parameters:** + - `text` *(string)*: The text to replace selected text + +- **Returns:** + - `new_text` *(string)*: New input text + +### set_text + +--- +```lua +input:set_text(input_text) +``` + +Set text for input field + +- **Parameters:** + - `input_text` *(string)*: The string to apply for input field + +### select + +--- +```lua +input:select() +``` + +Select input field. It will show the keyboard and trigger on_select events + +### unselect + +--- +```lua +input:unselect() +``` + +Remove selection from input. It will hide the keyboard and trigger on_unselect events + +### get_text + +--- +```lua +input:get_text() +``` + +Return current input field text + +- **Returns:** + - `text` *(string)*: The current input field text + +### set_max_length + +--- +```lua +input:set_max_length(max_length) +``` + +Set maximum length for input field. + Pass nil to make input field unliminted (by default) + +- **Parameters:** + - `max_length` *(number)*: Maximum length for input text field + +- **Returns:** + - `self` *(druid.input)*: Current input instance + +### set_allowed_characters + +--- +```lua +input:set_allowed_characters(characters) +``` + +Set allowed charaters for input field. + See: https://defold.com/ref/stable/string/ + ex: [%a%d] for alpha and numeric + +- **Parameters:** + - `characters` *(string)*: Regulax exp. for validate user input + +- **Returns:** + - `self` *(druid.input)*: Current input instance + +### reset_changes + +--- +```lua +input:reset_changes() +``` + +Reset current input selection and return previous value + +- **Returns:** + - `self` *(druid.input)*: Current input instance + +### select_cursor + +--- +```lua +input:select_cursor([cursor_index], [start_index], [end_index]) +``` + +Set cursor position in input field + +- **Parameters:** + - `[cursor_index]` *(number|nil)*: Cursor index for cursor position, if nil - will be set to the end of the text + - `[start_index]` *(number|nil)*: Start index for cursor position, if nil - will be set to the end of the text + - `[end_index]` *(number|nil)*: End index for cursor position, if nil - will be set to the start_index + +- **Returns:** + - `self` *(druid.input)*: Current input instance + +### move_selection + +--- +```lua +input:move_selection(delta, is_add_to_selection, is_move_to_end) +``` + +Change cursor position by delta + +- **Parameters:** + - `delta` *(number)*: side for cursor position, -1 for left, 1 for right + - `is_add_to_selection` *(boolean)*: (Shift key) + - `is_move_to_end` *(boolean)*: (Ctrl key) + +- **Returns:** + - `self` *(druid.input)*: Current input instance + + +## Fields + +- **on_input_select** (_event_): fun(self: druid.input, input: druid.input) The event triggered when the input field is selected + + +- **on_input_unselect** (_event_): fun(self: druid.input, text: string, input: druid.input) The event triggered when the input field is unselected + + +- **on_input_text** (_event_): fun(self: druid.input) The event triggered when the input field is changed + + +- **on_input_empty** (_event_): fun(self: druid.input) The event triggered when the input field is empty + + +- **on_input_full** (_event_): fun(self: druid.input) The event triggered when the input field is full + + +- **on_input_wrong** (_event_): fun(self: druid.input) The event triggered when the input field is wrong + + +- **on_select_cursor_change** (_event_): fun(self: druid.input, cursor_index: number, start_index: number, end_index: number) The event triggered when the cursor index is changed + + +- **style** (_druid.input.style_): The style of the input component + + +- **text** (_druid.text_): The text component + + +- **ALLOWED_ACTIONS** (_table_) + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **is_selected** (_boolean_) + + +- **value** (_unknown_) + + +- **previous_value** (_unknown_) + + +- **current_value** (_unknown_) + + +- **marked_value** (_string_) + + +- **is_empty** (_boolean_) + + +- **text_width** (_integer_) + + +- **market_text_width** (_integer_) + + +- **total_width** (_integer_) + + +- **cursor_index** (_integer_) + + +- **start_index** (_number_) + + +- **end_index** (_number_) + + +- **max_length** (_nil_) + + +- **allowed_characters** (_nil_) + + +- **keyboard_type** (_number_) + + +- **button** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **marked_text_width** (_number_) + diff --git a/api/components/extended/lang_text_api.md b/api/components/extended/lang_text_api.md new file mode 100644 index 0000000..8bd9b10 --- /dev/null +++ b/api/components/extended/lang_text_api.md @@ -0,0 +1,121 @@ +# druid.lang_text API + +> at /druid/extended/lang_text.lua + +The component used for displaying localized text, can automatically update text when locale is changed + + +## Functions +- [init](#init) +- [on_language_change](#on_language_change) +- [set_to](#set_to) +- [set_text](#set_text) +- [translate](#translate) +- [format](#format) + + +## Fields +- [text](#text) +- [node](#node) +- [on_change](#on_change) +- [druid](#druid) + + + +### init + +--- +```lua +lang_text:init(node, [locale_id], [adjust_type]) +``` + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id) + - `[locale_id]` *(string|nil)*: Default locale id or text from node as default + - `[adjust_type]` *(string|nil)*: Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference + +- **Returns:** + - `` *(druid.lang_text)*: + +### on_language_change + +--- +```lua +lang_text:on_language_change() +``` + +### set_to + +--- +```lua +lang_text:set_to(text) +``` + +Setup raw text to lang_text component + +- **Parameters:** + - `text` *(string)*: Text for text node + +- **Returns:** + - `self` *(druid.lang_text)*: Current instance + +### set_text + +--- +```lua +lang_text:set_text(text) +``` + +Setup raw text to lang_text component + +- **Parameters:** + - `text` *(string)*: Text for text node + +- **Returns:** + - `self` *(druid.lang_text)*: Current instance + +### translate + +--- +```lua +lang_text:translate(locale_id, ...) +``` + +Translate the text by locale_id + +- **Parameters:** + - `locale_id` *(string)*: Locale id + - `...` *(...)*: vararg + +- **Returns:** + - `self` *(druid.lang_text)*: Current instance + +### format + +--- +```lua +lang_text:format(...) +``` + +Format string with new text params on localized text + +- **Parameters:** + - `...` *(...)*: vararg + +- **Returns:** + - `self` *(druid.lang_text)*: Current instance + + +## Fields + +- **text** (_druid.text_): The text component + + +- **node** (_node_): The node of the text component + + +- **on_change** (_event_): The event triggered when the text is changed + + +- **druid** (_druid.instance_): The Druid Factory used to create components + diff --git a/api/components/extended/layout_api.md b/api/components/extended/layout_api.md new file mode 100644 index 0000000..470ac7c --- /dev/null +++ b/api/components/extended/layout_api.md @@ -0,0 +1,326 @@ +# druid.layout API + +> at /druid/extended/layout.lua + +The component used for managing the layout of nodes, placing them inside the node size with respect to the size and pivot of each node + + +## Functions +- [init](#init) +- [update](#update) +- [get_entities](#get_entities) +- [set_node_index](#set_node_index) +- [set_margin](#set_margin) +- [set_padding](#set_padding) +- [set_dirty](#set_dirty) +- [set_justify](#set_justify) +- [set_type](#set_type) +- [set_hug_content](#set_hug_content) +- [add](#add) +- [remove](#remove) +- [get_size](#get_size) +- [get_content_size](#get_content_size) +- [refresh_layout](#refresh_layout) +- [clear_layout](#clear_layout) +- [get_node_size](#get_node_size) +- [calculate_rows_data](#calculate_rows_data) +- [set_node_position](#set_node_position) + + +## Fields +- [node](#node) +- [rows_data](#rows_data) +- [is_dirty](#is_dirty) +- [entities](#entities) +- [margin](#margin) +- [padding](#padding) +- [type](#type) +- [is_resize_width](#is_resize_width) +- [is_resize_height](#is_resize_height) +- [is_justify](#is_justify) +- [on_size_changed](#on_size_changed) +- [size](#size) + + + +### init + +--- +```lua +layout:init(node_or_node_id, layout_type) +``` + +```lua +layout_type: + | "horizontal" + | "vertical" + | "horizontal_wrap" +``` + +- **Parameters:** + - `node_or_node_id` *(string|node)*: + - `layout_type` *("horizontal"|"horizontal_wrap"|"vertical")*: + +### update + +--- +```lua +layout:update() +``` + +### get_entities + +--- +```lua +layout:get_entities() +``` + +- **Returns:** + - `entities` *(node[])*: The entities to manage the layout of + +### set_node_index + +--- +```lua +layout:set_node_index(node, index) +``` + +- **Parameters:** + - `node` *(node)*: The node to set the index of + - `index` *(number)*: The index to set the node to + +- **Returns:** + - `self` *(druid.layout)*: for chaining + +### set_margin + +--- +```lua +layout:set_margin([margin_x], [margin_y]) +``` + +Set the margin of the layout + +- **Parameters:** + - `[margin_x]` *(number|nil)*: The margin x + - `[margin_y]` *(number|nil)*: The margin y + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### set_padding + +--- +```lua +layout:set_padding([padding_x], [padding_y], [padding_z], [padding_w]) +``` + +- **Parameters:** + - `[padding_x]` *(number|nil)*: The padding x + - `[padding_y]` *(number|nil)*: The padding y + - `[padding_z]` *(number|nil)*: The padding z + - `[padding_w]` *(number|nil)*: The padding w + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### set_dirty + +--- +```lua +layout:set_dirty() +``` + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### set_justify + +--- +```lua +layout:set_justify(is_justify) +``` + +- **Parameters:** + - `is_justify` *(boolean)*: + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### set_type + +--- +```lua +layout:set_type(type) +``` + +- **Parameters:** + - `type` *(string)*: The layout type: "horizontal", "vertical", "horizontal_wrap" + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### set_hug_content + +--- +```lua +layout:set_hug_content(is_hug_width, is_hug_height) +``` + +- **Parameters:** + - `is_hug_width` *(boolean)*: + - `is_hug_height` *(boolean)*: + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### add + +--- +```lua +layout:add(node_or_node_id) +``` + +Add node to layout + +- **Parameters:** + - `node_or_node_id` *(string|node)*: node_or_node_id + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### remove + +--- +```lua +layout:remove(node_or_node_id) +``` + +Remove node from layout + +- **Parameters:** + - `node_or_node_id` *(string|node)*: node_or_node_id + +- **Returns:** + - `self` *(druid.layout)*: for chaining + +### get_size + +--- +```lua +layout:get_size() +``` + +- **Returns:** + - `` *(vector3)*: + +### get_content_size + +--- +```lua +layout:get_content_size() +``` + +- **Returns:** + - `` *(number)*: + - `` *(number)*: + +### refresh_layout + +--- +```lua +layout:refresh_layout() +``` + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### clear_layout + +--- +```lua +layout:clear_layout() +``` + +- **Returns:** + - `self` *(druid.layout)*: Current layout instance + +### get_node_size + +--- +```lua +layout:get_node_size(node) +``` + +- **Parameters:** + - `node` *(node)*: + +- **Returns:** + - `width` *(number)*: The width of the node + - `height` *(number)*: The height of the node + +### calculate_rows_data + +--- +```lua +layout:calculate_rows_data() +``` + +Calculate rows data for layout. Contains total width, height and rows info (width, height, count of elements in row) + +- **Returns:** + - `` *(druid.layout.rows_data)*: + +### set_node_position + +--- +```lua +layout:set_node_position(node, x, y) +``` + +- **Parameters:** + - `node` *(node)*: + - `x` *(number)*: + - `y` *(number)*: + +- **Returns:** + - `` *(node)*: + + +## Fields + +- **node** (_node_): The node to manage the layout of + + +- **rows_data** (_druid.layout.rows_data_): Last calculated rows data + + +- **is_dirty** (_boolean_) + + +- **entities** (_node[]_): The entities to manage the layout of + + +- **margin** (_{ x: number, y: number }_): The margin of the layout + + +- **padding** (_vector4_): The padding of the layout + + +- **type** (_string_): The type of the layout + + +- **is_resize_width** (_boolean_): True if the layout should resize the width of the node + + +- **is_resize_height** (_boolean_): True if the layout should resize the height of the node + + +- **is_justify** (_boolean_): True if the layout should justify the nodes + + +- **on_size_changed** (_event.on_size_changed_): The event triggered when the size of the layout is changed + + +- **size** (_unknown_) + diff --git a/api/components/extended/progress_api.md b/api/components/extended/progress_api.md new file mode 100644 index 0000000..e14f5a1 --- /dev/null +++ b/api/components/extended/progress_api.md @@ -0,0 +1,232 @@ +# druid.progress API + +> at /druid/extended/progress.lua + +The component used to manage a node as a progress bar, changing the size and scale of the node + + +## Functions +- [init](#init) +- [on_style_change](#on_style_change) +- [on_layout_change](#on_layout_change) +- [on_remove](#on_remove) +- [update](#update) +- [fill](#fill) +- [empty](#empty) +- [set_to](#set_to) +- [get](#get) +- [set_steps](#set_steps) +- [to](#to) +- [set_max_size](#set_max_size) + + +## Fields +- [node](#node) +- [on_change](#on_change) +- [style](#style) +- [key](#key) +- [prop](#prop) +- [scale](#scale) +- [size](#size) +- [max_size](#max_size) +- [slice](#slice) +- [last_value](#last_value) +- [slice_size](#slice_size) +- [target](#target) +- [steps](#steps) +- [step_callback](#step_callback) +- [target_callback](#target_callback) + + + +### init + +--- +```lua +progress:init(node, key, [init_value]) +``` + +- **Parameters:** + - `node` *(string|node)*: Node name or GUI Node itself. + - `key` *(string)*: Progress bar direction: "x" or "y" + - `[init_value]` *(number|nil)*: Initial value of progress bar. Default: 1 + +### on_style_change + +--- +```lua +progress:on_style_change(style) +``` + +- **Parameters:** + - `style` *(druid.progress.style)*: + +### on_layout_change + +--- +```lua +progress:on_layout_change() +``` + +### on_remove + +--- +```lua +progress:on_remove() +``` + +### update + +--- +```lua +progress:update(dt) +``` + +- **Parameters:** + - `dt` *(number)*: Delta time + +### fill + +--- +```lua +progress:fill() +``` + +Fill the progress bar + +- **Returns:** + - `self` *(druid.progress)*: Current progress instance + +### empty + +--- +```lua +progress:empty() +``` + +Empty the progress bar + +- **Returns:** + - `self` *(druid.progress)*: Current progress instance + +### set_to + +--- +```lua +progress:set_to(to) +``` + +Instant fill progress bar to value + +- **Parameters:** + - `to` *(number)*: Progress bar value, from 0 to 1 + +- **Returns:** + - `self` *(druid.progress)*: Current progress instance + +### get + +--- +```lua +progress:get() +``` + +Return the current value of the progress bar + +- **Returns:** + - `value` *(number)*: The current value of the progress bar + +### set_steps + +--- +```lua +progress:set_steps(steps, callback) +``` + +Set points on progress bar to fire the callback + +- **Parameters:** + - `steps` *(number[])*: Array of progress bar values + - `callback` *(function)*: Callback on intersect step value + +- **Returns:** + - `self` *(druid.progress)*: Current progress instance + +### to + +--- +```lua +progress:to(to, [callback]) +``` + +Start animation of a progress bar + +- **Parameters:** + - `to` *(number)*: value between 0..1 + - `[callback]` *(function|nil)*: Callback on animation ends + +- **Returns:** + - `self` *(druid.progress)*: Current progress instance + +### set_max_size + +--- +```lua +progress:set_max_size(max_size) +``` + +Set progress bar max node size + +- **Parameters:** + - `max_size` *(vector3)*: The new node maximum (full) size + +- **Returns:** + - `self` *(druid.progress)*: Current progress instance + + +## Fields + +- **node** (_node_) + + +- **on_change** (_event_) + + +- **style** (_druid.progress.style_) + + +- **key** (_string_) + + +- **prop** (_hash_) + + +- **scale** (_unknown_) + + +- **size** (_unknown_) + + +- **max_size** (_unknown_) + + +- **slice** (_unknown_) + + +- **last_value** (_number_) + + +- **slice_size** (_unknown_) + + +- **target** (_nil_) + + +- **steps** (_number[]_) + + +- **step_callback** (_function_) + + +- **target_callback** (_function|nil_) + diff --git a/api/components/extended/slider_api.md b/api/components/extended/slider_api.md new file mode 100644 index 0000000..1d74989 --- /dev/null +++ b/api/components/extended/slider_api.md @@ -0,0 +1,164 @@ +# druid.slider API + +> at /druid/extended/slider.lua + +The component to make a draggable node over a line with a progress report + + +## Functions +- [init](#init) +- [on_layout_change](#on_layout_change) +- [on_remove](#on_remove) +- [on_window_resized](#on_window_resized) +- [on_input](#on_input) +- [set](#set) +- [set_steps](#set_steps) +- [set_input_node](#set_input_node) +- [set_enabled](#set_enabled) +- [is_enabled](#is_enabled) + + +## Fields +- [node](#node) +- [on_change_value](#on_change_value) +- [style](#style) + + + +### init + +--- +```lua +slider:init(node, end_pos, [callback]) +``` + +The Slider constructor + +- **Parameters:** + - `node` *(node)*: GUI node to drag as a slider + - `end_pos` *(vector3)*: The end position of slider, should be on the same axis as the node + - `[callback]` *(function|nil)*: On slider change callback + +### on_layout_change + +--- +```lua +slider:on_layout_change() +``` + +### on_remove + +--- +```lua +slider:on_remove() +``` + +### on_window_resized + +--- +```lua +slider:on_window_resized() +``` + +### on_input + +--- +```lua +slider:on_input(action_id, action) +``` + +- **Parameters:** + - `action_id` *(number)*: The action id + - `action` *(action)*: The action table + +- **Returns:** + - `is_consumed` *(boolean)*: True if the input was consumed + +### set + +--- +```lua +slider:set(value, [is_silent]) +``` + +Set value for slider + +- **Parameters:** + - `value` *(number)*: Value from 0 to 1 + - `[is_silent]` *(boolean|nil)*: Don't trigger event if true + +- **Returns:** + - `self` *(druid.slider)*: Current slider instance + +### set_steps + +--- +```lua +slider:set_steps(steps) +``` + +Set slider steps. Pin node will +apply closest step position + +- **Parameters:** + - `steps` *(number[])*: Array of steps + +- **Returns:** + - `self` *(druid.slider)*: Current slider instance + +### set_input_node + +--- +```lua +slider:set_input_node([input_node]) +``` + +Set input zone for slider. +User can touch any place of node, pin instantly will +move at this position and node drag will start. +This function require the Defold version 1.3.0+ + +- **Parameters:** + - `[input_node]` *(string|node|nil)*: + +- **Returns:** + - `self` *(druid.slider)*: Current slider instance + +### set_enabled + +--- +```lua +slider:set_enabled(is_enabled) +``` + +Set Slider input enabled or disabled + +- **Parameters:** + - `is_enabled` *(boolean)*: True if slider is enabled + +- **Returns:** + - `self` *(druid.slider)*: Current slider instance + +### is_enabled + +--- +```lua +slider:is_enabled() +``` + +Check if Slider component is enabled + +- **Returns:** + - `is_enabled` *(boolean)*: True if slider is enabled + + +## Fields + +- **node** (_node_): The node to manage the slider + + +- **on_change_value** (_event_): The event triggered when the slider value changes + + +- **style** (_table_): The style of the slider + diff --git a/api/components/extended/swipe_api.md b/api/components/extended/swipe_api.md new file mode 100644 index 0000000..0ecb1cb --- /dev/null +++ b/api/components/extended/swipe_api.md @@ -0,0 +1,57 @@ +# druid.swipe API + +> at /druid/extended/swipe.lua + +The component to manage swipe events over a node + + +## Functions +- [init](#init) +- [set_click_zone](#set_click_zone) + + +## Fields +- [node](#node) +- [on_swipe](#on_swipe) +- [style](#style) +- [click_zone](#click_zone) + + + +### init + +--- +```lua +swipe:init(node_or_node_id, on_swipe_callback) +``` + +- **Parameters:** + - `node_or_node_id` *(string|node)*: + - `on_swipe_callback` *(function)*: + +### set_click_zone + +--- +```lua +swipe:set_click_zone([zone]) +``` + +Set the click zone for the swipe, useful for restricting events outside stencil node + +- **Parameters:** + - `[zone]` *(string|node|nil)*: Gui node + + +## Fields + +- **node** (_node_): The node to manage the swipe + + +- **on_swipe** (_event_): fun(context, side, dist, dt) The event triggered when a swipe is detected + + +- **style** (_druid.swipe.style_): The style of the swipe + + +- **click_zone** (_node_): The click zone of the swipe + diff --git a/api/components/extended/timer_api.md b/api/components/extended/timer_api.md new file mode 100644 index 0000000..e483443 --- /dev/null +++ b/api/components/extended/timer_api.md @@ -0,0 +1,122 @@ +# druid.timer API + +> at /druid/extended/timer.lua + +The component that handles a text to display a seconds timer + + +## Functions +- [init](#init) +- [set_to](#set_to) +- [set_state](#set_state) +- [set_interval](#set_interval) + + +## Fields +- [on_tick](#on_tick) +- [on_set_enabled](#on_set_enabled) +- [on_timer_end](#on_timer_end) +- [node](#node) +- [from](#from) +- [target](#target) +- [value](#value) +- [is_on](#is_on) +- [temp](#temp) +- [last_value](#last_value) + + + +### init + +--- +```lua +timer:init(node, [seconds_from], [seconds_to], [callback]) +``` + +- **Parameters:** + - `node` *(node)*: Gui text node + - `[seconds_from]` *(number|nil)*: Start timer value in seconds + - `[seconds_to]` *(number|nil)*: End timer value in seconds + - `[callback]` *(function|nil)*: Function on timer end + +- **Returns:** + - `` *(druid.timer)*: + +### set_to + +--- +```lua +timer:set_to(set_to) +``` + +Set the timer to a specific value + +- **Parameters:** + - `set_to` *(number)*: Value in seconds + +- **Returns:** + - `self` *(druid.timer)*: Current timer instance + +### set_state + +--- +```lua +timer:set_state([is_on]) +``` + +Set the timer to a specific value + +- **Parameters:** + - `[is_on]` *(boolean|nil)*: Timer enable state + +- **Returns:** + - `self` *(druid.timer)*: Current timer instance + +### set_interval + +--- +```lua +timer:set_interval(from, to) +``` + +Set the timer interval + +- **Parameters:** + - `from` *(number)*: Start time in seconds + - `to` *(number)*: Target time in seconds + +- **Returns:** + - `self` *(druid.timer)*: Current timer instance + + +## Fields + +- **on_tick** (_event_): fun(context, value) The event triggered when the timer ticks + + +- **on_set_enabled** (_event_): fun(context, is_on) The event triggered when the timer is enabled + + +- **on_timer_end** (_event_): fun(context) The event triggered when the timer ends + + +- **node** (_node_): The node to display the timer + + +- **from** (_number_): The start time of the timer + + +- **target** (_number_): The target time of the timer + + +- **value** (_number_): The current value of the timer + + +- **is_on** (_boolean_): True if the timer is on + + +- **temp** (_unknown_) + + +- **last_value** (_number_) + diff --git a/api/components/widgets/fps_panel_api.md b/api/components/widgets/fps_panel_api.md new file mode 100644 index 0000000..273120d --- /dev/null +++ b/api/components/widgets/fps_panel_api.md @@ -0,0 +1,97 @@ +# druid.widget.fps_panel API + +> at /druid/widget/fps_panel/fps_panel.lua + + +## Functions +- [init](#init) +- [on_remove](#on_remove) +- [update](#update) +- [push_fps_value](#push_fps_value) + + +## Fields +- [root](#root) +- [delta_time](#delta_time) +- [collect_time](#collect_time) +- [collect_time_counter](#collect_time_counter) +- [graph_samples](#graph_samples) +- [fps_samples](#fps_samples) +- [mini_graph](#mini_graph) +- [text_min_fps](#text_min_fps) +- [text_fps](#text_fps) +- [timer_id](#timer_id) +- [previous_time](#previous_time) + + + +### init + +--- +```lua +fps_panel:init() +``` + +### on_remove + +--- +```lua +fps_panel:on_remove() +``` + +### update + +--- +```lua +fps_panel:update([dt]) +``` + +- **Parameters:** + - `[dt]` *(any)*: + +### push_fps_value + +--- +```lua +fps_panel:push_fps_value() +``` + + +## Fields + +- **root** (_node_) + + +- **delta_time** (_number_): in seconds + + +- **collect_time** (_integer_): in seconds + + +- **collect_time_counter** (_integer_) + + +- **graph_samples** (_number_) + + +- **fps_samples** (_table_): Store frame time in seconds last collect_time seconds + + +- **mini_graph** (_druid.widget.mini_graph_): Widget to display a several lines with different height in a row +Init, set amount of samples and max value of value means that the line will be at max height +Use `push_line_value` to add a new value to the line +Or `set_line_value` to set a value to the line by index +Setup colors inside template file (at minimum and maximum) + + +- **text_min_fps** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **text_fps** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **timer_id** (_unknown_) + + +- **previous_time** (_unknown_) + diff --git a/api/components/widgets/memory_panel_api.md b/api/components/widgets/memory_panel_api.md new file mode 100644 index 0000000..a530bc8 --- /dev/null +++ b/api/components/widgets/memory_panel_api.md @@ -0,0 +1,105 @@ +# druid.widget.memory_panel API + +> at /druid/widget/memory_panel/memory_panel.lua + + +## Functions +- [init](#init) +- [on_remove](#on_remove) +- [set_low_memory_limit](#set_low_memory_limit) +- [push_next_value](#push_next_value) +- [update_text_memory](#update_text_memory) + + +## Fields +- [root](#root) +- [delta_time](#delta_time) +- [samples_count](#samples_count) +- [memory_limit](#memory_limit) +- [mini_graph](#mini_graph) +- [max_value](#max_value) +- [text_per_second](#text_per_second) +- [text_memory](#text_memory) +- [memory](#memory) +- [memory_samples](#memory_samples) +- [timer_id](#timer_id) + + + +### init + +--- +```lua +memory_panel:init() +``` + +### on_remove + +--- +```lua +memory_panel:on_remove() +``` + +### set_low_memory_limit + +--- +```lua +memory_panel:set_low_memory_limit([limit]) +``` + +- **Parameters:** + - `[limit]` *(any)*: + +### push_next_value + +--- +```lua +memory_panel:push_next_value() +``` + +### update_text_memory + +--- +```lua +memory_panel:update_text_memory() +``` + + +## Fields + +- **root** (_node_) + + +- **delta_time** (_number_) + + +- **samples_count** (_integer_) + + +- **memory_limit** (_integer_) + + +- **mini_graph** (_druid.widget.mini_graph_): Widget to display a several lines with different height in a row +Init, set amount of samples and max value of value means that the line will be at max height +Use `push_line_value` to add a new value to the line +Or `set_line_value` to set a value to the line by index +Setup colors inside template file (at minimum and maximum) + + +- **max_value** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **text_per_second** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **text_memory** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **memory** (_unknown_) + + +- **memory_samples** (_table_) + + +- **timer_id** (_unknown_) + diff --git a/api/components/widgets/mini_graph_api.md b/api/components/widgets/mini_graph_api.md new file mode 100644 index 0000000..e34291e --- /dev/null +++ b/api/components/widgets/mini_graph_api.md @@ -0,0 +1,233 @@ +# druid.widget.mini_graph API + +> at /druid/widget/mini_graph/mini_graph.lua + +Widget to display a several lines with different height in a row +Init, set amount of samples and max value of value means that the line will be at max height +Use `push_line_value` to add a new value to the line +Or `set_line_value` to set a value to the line by index +Setup colors inside template file (at minimum and maximum) + + +## Functions +- [init](#init) +- [on_remove](#on_remove) +- [clear](#clear) +- [set_samples](#set_samples) +- [get_samples](#get_samples) +- [set_line_value](#set_line_value) +- [get_line_value](#get_line_value) +- [push_line_value](#push_line_value) +- [set_max_value](#set_max_value) +- [set_line_height](#set_line_height) +- [get_lowest_value](#get_lowest_value) +- [get_highest_value](#get_highest_value) +- [on_drag_widget](#on_drag_widget) +- [toggle_hide](#toggle_hide) + + +## Fields +- [root](#root) +- [text_header](#text_header) +- [icon_drag](#icon_drag) +- [content](#content) +- [layout](#layout) +- [prefab_line](#prefab_line) +- [color_zero](#color_zero) +- [color_one](#color_one) +- [is_hidden](#is_hidden) +- [max_value](#max_value) +- [lines](#lines) +- [values](#values) +- [container](#container) +- [default_size](#default_size) +- [samples](#samples) + + + +### init + +--- +```lua +mini_graph:init() +``` + +### on_remove + +--- +```lua +mini_graph:on_remove() +``` + +### clear + +--- +```lua +mini_graph:clear() +``` + +### set_samples + +--- +```lua +mini_graph:set_samples([samples]) +``` + +- **Parameters:** + - `[samples]` *(any)*: + +### get_samples + +--- +```lua +mini_graph:get_samples() +``` + +- **Returns:** + - `` *(unknown)*: + +### set_line_value + +--- +```lua +mini_graph:set_line_value(index, value) +``` + +Set normalized to control the color of the line + +- **Parameters:** + - `index` *(number)*: + - `value` *(number)*: The normalized value from 0 to 1 + +- **Example Usage:** + +```lua +for index = 1, mini_graph:get_samples() do + mini_graph:set_line_value(index, math.random()) +end +``` +### get_line_value + +--- +```lua +mini_graph:get_line_value([index]) +``` + +- **Parameters:** + - `[index]` *(any)*: + +- **Returns:** + - `` *(number)*: + +### push_line_value + +--- +```lua +mini_graph:push_line_value([value]) +``` + +- **Parameters:** + - `[value]` *(any)*: + +### set_max_value + +--- +```lua +mini_graph:set_max_value([max_value]) +``` + +- **Parameters:** + - `[max_value]` *(any)*: + +### set_line_height + +--- +```lua +mini_graph:set_line_height([index]) +``` + +- **Parameters:** + - `[index]` *(any)*: + +### get_lowest_value + +--- +```lua +mini_graph:get_lowest_value() +``` + +### get_highest_value + +--- +```lua +mini_graph:get_highest_value() +``` + +### on_drag_widget + +--- +```lua +mini_graph:on_drag_widget([dx], [dy]) +``` + +- **Parameters:** + - `[dx]` *(any)*: + - `[dy]` *(any)*: + +### toggle_hide + +--- +```lua +mini_graph:toggle_hide() +``` + +- **Returns:** + - `` *(druid.widget.mini_graph)*: + + +## Fields + +- **root** (_node_) + + +- **text_header** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **icon_drag** (_node_) + + +- **content** (_node_) + + +- **layout** (_druid.layout_): The component used for managing the layout of nodes, placing them inside the node size with respect to the size and pivot of each node + + +- **prefab_line** (_node_) + + +- **color_zero** (_unknown_) + + +- **color_one** (_unknown_) + + +- **is_hidden** (_boolean_) + + +- **max_value** (_integer_): in this value line will be at max height + + +- **lines** (_table_) + + +- **values** (_table_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **default_size** (_vector3_) + + +- **samples** (_any_) + diff --git a/api/components/widgets/properties_panel/property_button_api.md b/api/components/widgets/properties_panel/property_button_api.md new file mode 100644 index 0000000..fd9daa4 --- /dev/null +++ b/api/components/widgets/properties_panel/property_button_api.md @@ -0,0 +1,97 @@ +# druid.widget.property_button API + +> at /druid/widget/properties_panel/properties/property_button.lua + + +## Functions +- [init](#init) +- [on_click](#on_click) +- [set_text_property](#set_text_property) +- [set_text_button](#set_text_button) +- [set_color](#set_color) + + +## Fields +- [root](#root) +- [container](#container) +- [text_name](#text_name) +- [button](#button) +- [text_button](#text_button) +- [druid](#druid) +- [selected](#selected) + + + +### init + +--- +```lua +property_button:init() +``` + +### on_click + +--- +```lua +property_button:on_click() +``` + +### set_text_property + +--- +```lua +property_button:set_text_property(text) +``` + +- **Parameters:** + - `text` *(string)*: + +- **Returns:** + - `` *(druid.widget.property_button)*: + +### set_text_button + +--- +```lua +property_button:set_text_button(text) +``` + +- **Parameters:** + - `text` *(string)*: + +- **Returns:** + - `` *(druid.widget.property_button)*: + +### set_color + +--- +```lua +property_button:set_color([color_value]) +``` + +- **Parameters:** + - `[color_value]` *(any)*: + + +## Fields + +- **root** (_node_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **button** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **text_button** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **selected** (_node_) + diff --git a/api/components/widgets/properties_panel/property_checkbox_api.md b/api/components/widgets/properties_panel/property_checkbox_api.md new file mode 100644 index 0000000..95cf50c --- /dev/null +++ b/api/components/widgets/properties_panel/property_checkbox_api.md @@ -0,0 +1,112 @@ + +# druid.widget.property_checkbox API + +> at /druid/widget/properties_panel/properties/property_checkbox.lua + + +## Functions +- [init](#init) +- [set_value](#set_value) +- [get_value](#get_value) +- [on_click](#on_click) +- [set_text_property](#set_text_property) +- [on_change](#on_change) + + +## Fields +- [root](#root) +- [druid](#druid) +- [text_name](#text_name) +- [button](#button) +- [selected](#selected) +- [icon](#icon) +- [container](#container) +- [on_change_value](#on_change_value) + + + +### init + +--- +```lua +property_checkbox:init() +``` + +### set_value + +--- +```lua +property_checkbox:set_value(value, [is_instant]) +``` + +- **Parameters:** + - `value` *(boolean)*: + - `[is_instant]` *(any)*: + +### get_value + +--- +```lua +property_checkbox:get_value() +``` + +- **Returns:** + - `` *(boolean)*: + +### on_click + +--- +```lua +property_checkbox:on_click() +``` + +### set_text_property + +--- +```lua +property_checkbox:set_text_property(text) +``` + +Set the text property of the checkbox + +- **Parameters:** + - `text` *(string)*: + +### on_change + +--- +```lua +property_checkbox:on_change(callback) +``` + +Set the callback function for when the checkbox value changes + +- **Parameters:** + - `callback` *(function)*: + + +## Fields + +- **root** (_node_) + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **button** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **selected** (_node_) + + +- **icon** (_node_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **on_change_value** (_unknown_) + diff --git a/api/components/widgets/properties_panel/property_input_api.md b/api/components/widgets/properties_panel/property_input_api.md new file mode 100644 index 0000000..f889ddb --- /dev/null +++ b/api/components/widgets/properties_panel/property_input_api.md @@ -0,0 +1,90 @@ +# druid.widget.property_input API + +> at /druid/widget/properties_panel/properties/property_input.lua + +## Functions + +- [init](#init) +- [set_text_property](#set_text_property) +- [set_text_value](#set_text_value) +- [on_change](#on_change) + +## Fields + +- [root](#root) +- [container](#container) +- [text_name](#text_name) +- [button](#button) +- [druid](#druid) +- [selected](#selected) +- [rich_input](#rich_input) + + + +### init + +--- +```lua +property_input:init() +``` + +### set_text_property + +--- +```lua +property_input:set_text_property(text) +``` + +- **Parameters:** + - `text` *(string)*: + +- **Returns:** + - `` *(druid.widget.property_input)*: + +### set_text_value + +--- +```lua +property_input:set_text_value(text) +``` + +- **Parameters:** + - `text` *(string|number)*: + +- **Returns:** + - `` *(druid.widget.property_input)*: + +### on_change + +--- +```lua +property_input:on_change(callback, [callback_context]) +``` + +- **Parameters:** + - `callback` *(fun(self: druid.widget.property_input, text: string))*: + - `[callback_context]` *(any)*: + + +## Fields + +- **root** (_node_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **button** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **selected** (_node_) + + +- **rich_input** (_druid.rich_input_): The component that handles a rich text input field, it's a wrapper around the druid.input component + diff --git a/api/components/widgets/properties_panel/property_left_right_selector_api.md b/api/components/widgets/properties_panel/property_left_right_selector_api.md new file mode 100644 index 0000000..db194e2 --- /dev/null +++ b/api/components/widgets/properties_panel/property_left_right_selector_api.md @@ -0,0 +1,171 @@ +# druid.widget.property_left_right_selector API + +> at /druid/widget/properties_panel/properties/property_left_right_selector.lua + + +## Functions +- [init](#init) +- [set_text](#set_text) +- [on_button_left](#on_button_left) +- [on_button_right](#on_button_right) +- [add_step](#add_step) +- [set_number_type](#set_number_type) +- [set_array_type](#set_array_type) +- [set_value](#set_value) +- [get_value](#get_value) + + +## Fields +- [root](#root) +- [druid](#druid) +- [text_name](#text_name) +- [button](#button) +- [selected](#selected) +- [value](#value) +- [on_change_value](#on_change_value) +- [text_value](#text_value) +- [button_left](#button_left) +- [button_right](#button_right) +- [container](#container) +- [number_type](#number_type) +- [array_type](#array_type) + + + +### init + +--- +```lua +property_left_right_selector:init() +``` + +### set_text + +--- +```lua +property_left_right_selector:set_text([text]) +``` + +- **Parameters:** + - `[text]` *(any)*: + +- **Returns:** + - `` *(druid.widget.property_left_right_selector)*: + +### on_button_left + +--- +```lua +property_left_right_selector:on_button_left() +``` + +### on_button_right + +--- +```lua +property_left_right_selector:on_button_right() +``` + +### add_step + +--- +```lua +property_left_right_selector:add_step(koef) +``` + +- **Parameters:** + - `koef` *(number)*: -1 0 1, on 0 will not move + +### set_number_type + +--- +```lua +property_left_right_selector:set_number_type([min], [max], [is_loop], [steps]) +``` + +- **Parameters:** + - `[min]` *(any)*: + - `[max]` *(any)*: + - `[is_loop]` *(any)*: + - `[steps]` *(any)*: + +- **Returns:** + - `` *(druid.widget.property_left_right_selector)*: + +### set_array_type + +--- +```lua +property_left_right_selector:set_array_type([array], [is_loop], [steps]) +``` + +- **Parameters:** + - `[array]` *(any)*: + - `[is_loop]` *(any)*: + - `[steps]` *(any)*: + +- **Returns:** + - `` *(druid.widget.property_left_right_selector)*: + +### set_value + +--- +```lua +property_left_right_selector:set_value(value, [is_instant]) +``` + +- **Parameters:** + - `value` *(string|number)*: + - `[is_instant]` *(any)*: + +### get_value + +--- +```lua +property_left_right_selector:get_value() +``` + +- **Returns:** + - `` *(string|number)*: + + +## Fields + +- **root** (_node_) + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **button** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **selected** (_node_) + + +- **value** (_string_) + + +- **on_change_value** (_event_): fun(value: string|number) + + +- **text_value** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **button_left** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **button_right** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **number_type** (_table_) + + +- **array_type** (_table_) + diff --git a/api/components/widgets/properties_panel/property_slider_api.md b/api/components/widgets/properties_panel/property_slider_api.md new file mode 100644 index 0000000..3c0cb19 --- /dev/null +++ b/api/components/widgets/properties_panel/property_slider_api.md @@ -0,0 +1,150 @@ +# druid.widget.property_slider API + +> at /druid/widget/properties_panel/properties/property_slider.lua + + +## Functions +- [init](#init) +- [set_text_function](#set_text_function) +- [set_text_property](#set_text_property) +- [on_change](#on_change) +- [set_value](#set_value) +- [get_value](#get_value) +- [update_value](#update_value) +- [set_number_type](#set_number_type) + + +## Fields +- [root](#root) +- [container](#container) +- [druid](#druid) +- [text_name](#text_name) +- [text_value](#text_value) +- [slider](#slider) +- [on_change_value](#on_change_value) +- [selected](#selected) +- [min](#min) +- [max](#max) +- [step](#step) + + + +### init + +--- +```lua +property_slider:init() +``` + +### set_text_function + +--- +```lua +property_slider:set_text_function(callback) +``` + +- **Parameters:** + - `callback` *(fun(value: number):string)*: + +### set_text_property + +--- +```lua +property_slider:set_text_property(text) +``` + +Sets the text property of the slider + +- **Parameters:** + - `text` *(string)*: + +### on_change + +--- +```lua +property_slider:on_change(callback) +``` + +Sets the callback function for when the slider value changes + +- **Parameters:** + - `callback` *(fun(value: number))*: + +### set_value + +--- +```lua +property_slider:set_value(value, [is_instant]) +``` + +- **Parameters:** + - `value` *(number)*: + - `[is_instant]` *(any)*: + +### get_value + +--- +```lua +property_slider:get_value() +``` + +- **Returns:** + - `` *(number)*: + +### update_value + +--- +```lua +property_slider:update_value([value]) +``` + +- **Parameters:** + - `[value]` *(any)*: + +### set_number_type + +--- +```lua +property_slider:set_number_type([min], [max], [step]) +``` + +- **Parameters:** + - `[min]` *(any)*: + - `[max]` *(any)*: + - `[step]` *(any)*: + + +## Fields + +- **root** (_node_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **text_value** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **slider** (_druid.slider_): The component to make a draggable node over a line with a progress report + + +- **on_change_value** (_event_): fun(value:number) + + +- **selected** (_node_) + + +- **min** (_integer_) + + +- **max** (_integer_) + + +- **step** (_number_) + diff --git a/api/components/widgets/properties_panel/property_text_api.md b/api/components/widgets/properties_panel/property_text_api.md new file mode 100644 index 0000000..331e1bf --- /dev/null +++ b/api/components/widgets/properties_panel/property_text_api.md @@ -0,0 +1,66 @@ +# druid.widget.property_text API + +> at /druid/widget/properties_panel/properties/property_text.lua + + +## Functions +- [init](#init) +- [set_text_property](#set_text_property) +- [set_text_value](#set_text_value) + + +## Fields +- [root](#root) +- [container](#container) +- [text_name](#text_name) +- [text_right](#text_right) + + + +### init + +--- +```lua +property_text:init() +``` + +### set_text_property + +--- +```lua +property_text:set_text_property(text) +``` + +- **Parameters:** + - `text` *(string)*: + +- **Returns:** + - `` *(druid.widget.property_text)*: + +### set_text_value + +--- +```lua +property_text:set_text_value([text]) +``` + +- **Parameters:** + - `[text]` *(string|nil)*: + +- **Returns:** + - `` *(druid.widget.property_text)*: + + +## Fields + +- **root** (_node_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **text_right** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + diff --git a/api/components/widgets/properties_panel/property_vector3_api.md b/api/components/widgets/properties_panel/property_vector3_api.md new file mode 100644 index 0000000..a7eda57 --- /dev/null +++ b/api/components/widgets/properties_panel/property_vector3_api.md @@ -0,0 +1,104 @@ +# druid.widget.property_vector3 API + +> at /druid/widget/properties_panel/properties/property_vector3.lua + + +## Functions +- [init](#init) +- [set_text_property](#set_text_property) +- [set_value](#set_value) + + +## Fields +- [root](#root) +- [container](#container) +- [text_name](#text_name) +- [button](#button) +- [druid](#druid) +- [selected_x](#selected_x) +- [selected_y](#selected_y) +- [selected_z](#selected_z) +- [rich_input_x](#rich_input_x) +- [rich_input_y](#rich_input_y) +- [rich_input_z](#rich_input_z) +- [value](#value) +- [on_change](#on_change) + + + +### init + +--- +```lua +property_vector3:init() +``` + +### set_text_property + +--- +```lua +property_vector3:set_text_property(text) +``` + +- **Parameters:** + - `text` *(string)*: + +- **Returns:** + - `` *(druid.widget.property_vector3)*: + +### set_value + +--- +```lua +property_vector3:set_value(x, y, z) +``` + +- **Parameters:** + - `x` *(number)*: + - `y` *(number)*: + - `z` *(number)*: + +- **Returns:** + - `` *(druid.widget.property_vector3)*: + + +## Fields + +- **root** (_node_) + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **text_name** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **button** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **druid** (_druid.instance_): The Druid Factory used to create components + + +- **selected_x** (_node_) + + +- **selected_y** (_node_) + + +- **selected_z** (_node_) + + +- **rich_input_x** (_druid.rich_input_): The component that handles a rich text input field, it's a wrapper around the druid.input component + + +- **rich_input_y** (_druid.rich_input_): The component that handles a rich text input field, it's a wrapper around the druid.input component + + +- **rich_input_z** (_druid.rich_input_): The component that handles a rich text input field, it's a wrapper around the druid.input component + + +- **value** (_unknown_) + + +- **on_change** (_unknown_) + diff --git a/api/components/widgets/properties_panel_api.md b/api/components/widgets/properties_panel_api.md new file mode 100644 index 0000000..2b82694 --- /dev/null +++ b/api/components/widgets/properties_panel_api.md @@ -0,0 +1,366 @@ +# druid.widget.properties_panel API + +> at /druid/widget/properties_panel/properties_panel.lua + + +## Functions +- [properties_constructors](#properties_constructors) +- [init](#init) +- [on_remove](#on_remove) +- [on_drag_widget](#on_drag_widget) +- [clear_created_properties](#clear_created_properties) +- [clear](#clear) +- [on_size_changed](#on_size_changed) +- [update](#update) +- [add_checkbox](#add_checkbox) +- [add_slider](#add_slider) +- [add_button](#add_button) +- [add_input](#add_input) +- [add_text](#add_text) +- [add_left_right_selector](#add_left_right_selector) +- [add_vector3](#add_vector3) +- [add_inner_widget](#add_inner_widget) +- [add_widget](#add_widget) +- [remove](#remove) +- [set_hidden](#set_hidden) +- [is_hidden](#is_hidden) +- [set_properties_per_page](#set_properties_per_page) +- [set_page](#set_page) + + +## Fields +- [root](#root) +- [scroll](#scroll) +- [layout](#layout) +- [container](#container) +- [container_content](#container_content) +- [container_scroll_view](#container_scroll_view) +- [contaienr_scroll_content](#contaienr_scroll_content) +- [button_hidden](#button_hidden) +- [text_header](#text_header) +- [paginator](#paginator) +- [properties](#properties) +- [content](#content) +- [default_size](#default_size) +- [current_page](#current_page) +- [properties_per_page](#properties_per_page) +- [property_checkbox_prefab](#property_checkbox_prefab) +- [property_slider_prefab](#property_slider_prefab) +- [property_button_prefab](#property_button_prefab) +- [property_input_prefab](#property_input_prefab) +- [property_text_prefab](#property_text_prefab) +- [property_left_right_selector_prefab](#property_left_right_selector_prefab) +- [property_vector3_prefab](#property_vector3_prefab) +- [is_dirty](#is_dirty) + + + +### properties_constructors + +--- +```lua +properties_panel:properties_constructors() +``` + +List of properties functions to create a new widget. Used to not spawn non-visible widgets but keep the reference + +### init + +--- +```lua +properties_panel:init() +``` + +### on_remove + +--- +```lua +properties_panel:on_remove() +``` + +### on_drag_widget + +--- +```lua +properties_panel:on_drag_widget([dx], [dy]) +``` + +- **Parameters:** + - `[dx]` *(any)*: + - `[dy]` *(any)*: + +### clear_created_properties + +--- +```lua +properties_panel:clear_created_properties() +``` + +### clear + +--- +```lua +properties_panel:clear() +``` + +### on_size_changed + +--- +```lua +properties_panel:on_size_changed([new_size]) +``` + +- **Parameters:** + - `[new_size]` *(any)*: + +### update + +--- +```lua +properties_panel:update([dt]) +``` + +- **Parameters:** + - `[dt]` *(any)*: + +### add_checkbox + +--- +```lua +properties_panel:add_checkbox([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(checkbox: druid.widget.property_checkbox)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_slider + +--- +```lua +properties_panel:add_slider([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(slider: druid.widget.property_slider)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_button + +--- +```lua +properties_panel:add_button([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(button: druid.widget.property_button)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_input + +--- +```lua +properties_panel:add_input([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(input: druid.widget.property_input)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_text + +--- +```lua +properties_panel:add_text([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(text: druid.widget.property_text)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_left_right_selector + +--- +```lua +properties_panel:add_left_right_selector([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(selector: druid.widget.property_left_right_selector)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_vector3 + +--- +```lua +properties_panel:add_vector3([on_create]) +``` + +- **Parameters:** + - `[on_create]` *(fun(vector3: druid.widget.property_vector3)|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_inner_widget + +--- +```lua +properties_panel:add_inner_widget(widget_class, [template], [nodes], [on_create]) +``` + +- **Parameters:** + - `widget_class` *()*: + - `[template]` *(string|nil)*: + - `[nodes]` *(node|table|nil)*: + - `[on_create]` *(fun(widget: )|nil)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### add_widget + +--- +```lua +properties_panel:add_widget(create_widget_callback) +``` + +- **Parameters:** + - `create_widget_callback` *(fun():druid.widget)*: + +- **Returns:** + - `` *(druid.widget.properties_panel)*: + +### remove + +--- +```lua +properties_panel:remove([widget]) +``` + +- **Parameters:** + - `[widget]` *(any)*: + +### set_hidden + +--- +```lua +properties_panel:set_hidden([is_hidden]) +``` + +- **Parameters:** + - `[is_hidden]` *(any)*: + +### is_hidden + +--- +```lua +properties_panel:is_hidden() +``` + +- **Returns:** + - `` *(unknown)*: + +### set_properties_per_page + +--- +```lua +properties_panel:set_properties_per_page(properties_per_page) +``` + +- **Parameters:** + - `properties_per_page` *(number)*: + +### set_page + +--- +```lua +properties_panel:set_page([page]) +``` + +- **Parameters:** + - `[page]` *(any)*: + + +## Fields + +- **root** (_node_) + + +- **scroll** (_druid.scroll_) + + +- **layout** (_druid.layout_): The component used for managing the layout of nodes, placing them inside the node size with respect to the size and pivot of each node + + +- **container** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **container_content** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **container_scroll_view** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **contaienr_scroll_content** (_druid.container_): The component used for managing the size and positions with other containers relations to create a adaptable layouts + + +- **button_hidden** (_druid.button_): Druid component to make clickable node with various interaction callbacks + + +- **text_header** (_druid.text_): The component to handle text behaviour over a GUI Text node, mainly used to automatically adjust text size to fit the text area + + +- **paginator** (_druid.widget.property_left_right_selector_) + + +- **properties** (_druid.widget[]_): List of created properties + + +- **content** (_node_) + + +- **default_size** (_vector3_) + + +- **current_page** (_integer_) + + +- **properties_per_page** (_integer_) + + +- **property_checkbox_prefab** (_node_) + + +- **property_slider_prefab** (_node_) + + +- **property_button_prefab** (_node_) + + +- **property_input_prefab** (_node_) + + +- **property_text_prefab** (_node_) + + +- **property_left_right_selector_prefab** (_node_) + + +- **property_vector3_prefab** (_node_) + + +- **is_dirty** (_boolean_) + diff --git a/api/druid_api.md b/api/druid_api.md new file mode 100644 index 0000000..aa43670 --- /dev/null +++ b/api/druid_api.md @@ -0,0 +1,104 @@ +# druid API + +> at /druid/druid.lua + +Entry point for Druid UI Framework. +Create a new Druid instance and adjust the Druid settings here. + +## Table of Contents + + +## Functions +- [new](#new) +- [set_default_style](#set_default_style) +- [set_text_function](#set_text_function) +- [set_sound_function](#set_sound_function) +- [init_window_listener](#init_window_listener) +- [on_window_callback](#on_window_callback) +- [on_language_change](#on_language_change) + + + +### new + +--- +```lua +druid.new(context, [style]) +``` + +Create a new Druid instance for creating GUI components. + +- **Parameters:** + - `context` *(table)*: The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks. + - `[style]` *(table|nil)*: The Druid style table to override style parameters for this Druid instance. + +- **Returns:** + - `druid_instance` *(druid.instance)*: The new Druid instance + +### set_default_style + +--- +```lua +druid.set_default_style(style) +``` + +Set the default style for all Druid instances. + +- **Parameters:** + - `style` *(table)*: Default style + +### set_text_function + +--- +```lua +druid.set_text_function(callback) +``` + +Set the text function for the LangText component. + +- **Parameters:** + - `callback` *(fun(text_id: string):string)*: Get localized text function + +### set_sound_function + +--- +```lua +druid.set_sound_function(callback) +``` + +Set the sound function to able components to play sounds. + +- **Parameters:** + - `callback` *(fun(sound_id: string))*: Sound play callback + +### init_window_listener + +--- +```lua +druid.init_window_listener() +``` + +Subscribe Druid to the window listener. It will override your previous +window listener, so if you have one, you should call M.on_window_callback manually. + +### on_window_callback + +--- +```lua +druid.on_window_callback(window_event) +``` + +Set the window callback to enable Druid window events. + +- **Parameters:** + - `window_event` *(constant)*: Event param from window listener + +### on_language_change + +--- +```lua +druid.on_language_change() +``` + +Call this function when the game language changes. +It will notify all Druid instances to update the lang text components. diff --git a/api/druid_helper_api.md b/api/druid_helper_api.md new file mode 100644 index 0000000..98ba510 --- /dev/null +++ b/api/druid_helper_api.md @@ -0,0 +1,548 @@ +# druid.helper API + +> at /druid/helper.lua + +The helper module contains various functions that are used in the Druid library. +You can use these functions in your projects as well. + + +## Functions +- [centrate_text_with_icon](#centrate_text_with_icon) +- [centrate_icon_with_text](#centrate_icon_with_text) +- [centrate_nodes](#centrate_nodes) +- [get_node](#get_node) +- [get_screen_aspect_koef](#get_screen_aspect_koef) +- [get_gui_scale](#get_gui_scale) +- [step](#step) +- [clamp](#clamp) +- [distance](#distance) +- [sign](#sign) +- [round](#round) +- [lerp](#lerp) +- [contains](#contains) +- [deepcopy](#deepcopy) +- [add_array](#add_array) +- [pick_node](#pick_node) +- [get_scaled_size](#get_scaled_size) +- [get_scene_scale](#get_scene_scale) +- [get_closest_stencil_node](#get_closest_stencil_node) +- [get_pivot_offset](#get_pivot_offset) +- [is_mobile](#is_mobile) +- [is_web](#is_web) +- [is_web_mobile](#is_web_mobile) +- [is_multitouch_supported](#is_multitouch_supported) +- [table_to_string](#table_to_string) +- [get_border](#get_border) +- [get_text_metrics_from_node](#get_text_metrics_from_node) +- [insert_with_shift](#insert_with_shift) +- [remove_with_shift](#remove_with_shift) +- [get_full_position](#get_full_position) +- [get_animation_data_from_node](#get_animation_data_from_node) + + +## Fields +- [PROP_SIZE_X](#PROP_SIZE_X) +- [PROP_SIZE_Y](#PROP_SIZE_Y) +- [PROP_SCALE_X](#PROP_SCALE_X) +- [PROP_SCALE_Y](#PROP_SCALE_Y) + + + +### centrate_text_with_icon + +--- +```lua +helper.centrate_text_with_icon([text_node], [icon_node], margin) +``` + +Center two nodes. +Nodes will be center around 0 x position +text_node will be first (at left side) + +- **Parameters:** + - `[text_node]` *(node|nil)*: Gui text node + - `[icon_node]` *(node|nil)*: Gui box node + - `margin` *(number)*: Offset between nodes + +- **Returns:** + - `` *(unknown)*: + +### centrate_icon_with_text + +--- +```lua +helper.centrate_icon_with_text([icon_node], [text_node], [margin]) +``` + +Center two nodes. +Nodes will be center around 0 x position +icon_node will be first (at left side) + +- **Parameters:** + - `[icon_node]` *(node|nil)*: Gui box node + - `[text_node]` *(node|nil)*: Gui text node + - `[margin]` *(number|nil)*: Offset between nodes + +- **Returns:** + - `` *(unknown)*: + +### centrate_nodes + +--- +```lua +helper.centrate_nodes([margin], ...) +``` + +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. + +- **Parameters:** + - `[margin]` *(number|nil)*: Offset between nodes + - `...` *(...)*: vararg + +- **Returns:** + - `` *(unknown)*: + +### get_node + +--- +```lua +helper.get_node(node_id, [template], [nodes]) +``` + +- **Parameters:** + - `node_id` *(string|node)*: + - `[template]` *(string|nil)*: Full Path to the template + - `[nodes]` *(table|nil)*: Nodes what created with gui.clone_tree + +- **Returns:** + - `` *(node)*: + +### get_screen_aspect_koef + +--- +```lua +helper.get_screen_aspect_koef() +``` + +Get current screen stretch multiplier for each side + +- **Returns:** + - `stretch_x` *(number)*: + - `stretch_y` *(number)*: + +### get_gui_scale + +--- +```lua +helper.get_gui_scale() +``` + +Get current GUI scale for each side + +- **Returns:** + - `scale_x` *(number)*: + +### step + +--- +```lua +helper.step(current, target, step) +``` + +Move value from current to target value with step amount + +- **Parameters:** + - `current` *(number)*: Current value + - `target` *(number)*: Target value + - `step` *(number)*: Step amount + +- **Returns:** + - `New` *(number)*: value + +### clamp + +--- +```lua +helper.clamp(value, [v1], [v2]) +``` + +Clamp value between min and max. Works with nil values and swap min and max if needed. + +- **Parameters:** + - `value` *(number)*: Value + - `[v1]` *(number|nil)*: Min value. If nil, value will be clamped to positive infinity + - `[v2]` *(number|nil)*: Max value If nil, value will be clamped to negative infinity + +- **Returns:** + - `value` *(number)*: Clamped value + +### distance + +--- +```lua +helper.distance(x1, y1, x2, y2) +``` + +Calculate distance between two points + +- **Parameters:** + - `x1` *(number)*: First point x + - `y1` *(number)*: First point y + - `x2` *(number)*: Second point x + - `y2` *(number)*: Second point y + +- **Returns:** + - `Distance` *(number)*: + +### sign + +--- +```lua +helper.sign(val) +``` + +Return sign of value + +- **Parameters:** + - `val` *(number)*: Value + +- **Returns:** + - `sign` *(number)*: Sign of value, -1, 0 or 1 + +### round + +--- +```lua +helper.round(num, [num_decimal_places]) +``` + +Round number to specified decimal places + +- **Parameters:** + - `num` *(number)*: Number + - `[num_decimal_places]` *(number|nil)*: Decimal places + +- **Returns:** + - `value` *(number)*: Rounded number + +### lerp + +--- +```lua +helper.lerp(a, b, t) +``` + +Lerp between two values + +- **Parameters:** + - `a` *(number)*: First value + - `b` *(number)*: Second value + - `t` *(number)*: Lerp amount + +- **Returns:** + - `value` *(number)*: Lerped value + +### contains + +--- +```lua +helper.contains([array], [value]) +``` + +Check if value contains in array + +- **Parameters:** + - `[array]` *(any[])*: Array to check + - `[value]` *(any)*: Value + +- **Returns:** + - `` *(integer|nil)*: + +### deepcopy + +--- +```lua +helper.deepcopy(orig_table) +``` + +Make a copy table with all nested tables + +- **Parameters:** + - `orig_table` *(table)*: Original table + +- **Returns:** + - `Copy` *(table)*: of original table + +### add_array + +--- +```lua +helper.add_array([target], [source]) +``` + +Add all elements from source array to the target array + +- **Parameters:** + - `[target]` *(any[])*: Array to put elements from source + - `[source]` *(any[]|nil)*: The source array to get elements from + +- **Returns:** + - `The` *(any[])*: target array + +### pick_node + +--- +```lua +helper.pick_node(node, x, y, [node_click_area]) +``` + +Make a check with gui.pick_node, but with additional node_click_area check. + +- **Parameters:** + - `node` *(node)*: + - `x` *(number)*: + - `y` *(number)*: + - `[node_click_area]` *(node|nil)*: Additional node to check for click area. If nil, only node will be checked + +- **Returns:** + - `` *(unknown)*: + +### get_scaled_size + +--- +```lua +helper.get_scaled_size(node) +``` + +Get size of node with scale multiplier + +- **Parameters:** + - `node` *(node)*: GUI node + +- **Returns:** + - `scaled_size` *(vector3)*: + +### get_scene_scale + +--- +```lua +helper.get_scene_scale(node, [include_passed_node_scale]) +``` + +Get cumulative parent's node scale + +- **Parameters:** + - `node` *(node)*: Gui node + - `[include_passed_node_scale]` *(boolean|nil)*: True if add current node scale to result + +- **Returns:** + - `The` *(vector3)*: scene node scale + +### get_closest_stencil_node + +--- +```lua +helper.get_closest_stencil_node(node) +``` + +Return closest non inverted clipping parent node for given node + +- **Parameters:** + - `node` *(node)*: GUI node + +- **Returns:** + - `stencil_node` *(node|nil)*: The closest stencil node or nil + +### get_pivot_offset + +--- +```lua +helper.get_pivot_offset(pivot_or_node) +``` + +Get pivot offset for given pivot or node +Offset shown in [-0.5 .. 0.5] range, where -0.5 is left or bottom, 0.5 is right or top. + +- **Parameters:** + - `pivot_or_node` *(number|node)*: GUI pivot or node + +- **Returns:** + - `offset` *(vector3)*: The pivot offset + +### is_mobile + +--- +```lua +helper.is_mobile() +``` + +Check if device is native mobile (Android or iOS) + +- **Returns:** + - `Is` *(boolean)*: mobile + +### is_web + +--- +```lua +helper.is_web() +``` + +Check if device is HTML5 + +- **Returns:** + - `` *(boolean)*: + +### is_web_mobile + +--- +```lua +helper.is_web_mobile() +``` + +Check if device is HTML5 mobile + +- **Returns:** + - `` *(boolean)*: + +### is_multitouch_supported + +--- +```lua +helper.is_multitouch_supported() +``` + +Check if device is mobile and can support multitouch + +- **Returns:** + - `is_multitouch` *(boolean)*: Is multitouch supported + +### table_to_string + +--- +```lua +helper.table_to_string(t) +``` + +Simple table to one-line string converter + +- **Parameters:** + - `t` *(table)*: + +- **Returns:** + - `` *(string)*: + +### get_border + +--- +```lua +helper.get_border(node, [offset]) +``` + +Distance from node position to his borders + +- **Parameters:** + - `node` *(node)*: GUI node + - `[offset]` *(vector3|nil)*: Offset from node position. Pass current node position to get non relative border values + +- **Returns:** + - `border` *(vector4)*: Vector4 with border values (left, top, right, down) + +### get_text_metrics_from_node + +--- +```lua +helper.get_text_metrics_from_node(text_node) +``` + +Get text metric from GUI node. + +- **Parameters:** + - `text_node` *(node)*: + +- **Returns:** + - `` *(GUITextMetrics)*: + +### insert_with_shift + +--- +```lua +helper.insert_with_shift(array, [item], [index], [shift_policy]) +``` + +Add value to array with shift policy +Shift policy can be: left, right, no_shift + +- **Parameters:** + - `array` *(table)*: Array + - `[item]` *(any)*: Item to insert + - `[index]` *(number|nil)*: Index to insert. If nil, item will be inserted at the end of array + - `[shift_policy]` *(number|nil)*: The druid_const.SHIFT.* constant + +- **Returns:** + - `Inserted` *(any)*: item + +### remove_with_shift + +--- +```lua +helper.remove_with_shift([array], [index], [shift_policy]) +``` + +Remove value from array with shift policy + Shift policy can be: left, right, no_shift + +- **Parameters:** + - `[array]` *(any[])*: Array + - `[index]` *(number|nil)*: Index to remove. If nil, item will be removed from the end of array + - `[shift_policy]` *(number|nil)*: The druid_const.SHIFT.* constant + +- **Returns:** + - `Removed` *(any)*: item + +### get_full_position + +--- +```lua +helper.get_full_position(node, [root]) +``` + +Get full position of node in the GUI tree + +- **Parameters:** + - `node` *(node)*: GUI node + - `[root]` *(node|nil)*: GUI root node to stop search + +- **Returns:** + - `` *(unknown)*: + +### get_animation_data_from_node + +--- +```lua +helper.get_animation_data_from_node(node, atlas_path) +``` + +- **Parameters:** + - `node` *(node)*: + - `atlas_path` *(string)*: Path to the atlas + +- **Returns:** + - `` *(druid.system.animation_data)*: + + +## Fields + +- **PROP_SIZE_X** (_unknown_) + + +- **PROP_SIZE_Y** (_unknown_) + + +- **PROP_SCALE_X** (_unknown_) + + +- **PROP_SCALE_Y** (_unknown_) + diff --git a/api/druid_instance_api.md b/api/druid_instance_api.md new file mode 100644 index 0000000..6055c93 --- /dev/null +++ b/api/druid_instance_api.md @@ -0,0 +1,553 @@ +# druid.instance API + +> at /druid/system/druid_instance.lua + +The Druid Factory used to create components + + +## Functions +- [create_druid_instance](#create_druid_instance) + +- [new](#new) +- [final](#final) +- [remove](#remove) +- [update](#update) +- [on_input](#on_input) +- [on_message](#on_message) +- [on_window_event](#on_window_event) +- [set_whitelist](#set_whitelist) +- [set_blacklist](#set_blacklist) +- [new_widget](#new_widget) +- [new_button](#new_button) +- [new_blocker](#new_blocker) +- [new_back_handler](#new_back_handler) +- [new_hover](#new_hover) +- [new_text](#new_text) +- [new_grid](#new_grid) +- [new_scroll](#new_scroll) +- [new_drag](#new_drag) +- [new_swipe](#new_swipe) +- [new_lang_text](#new_lang_text) +- [new_slider](#new_slider) +- [new_input](#new_input) +- [new_data_list](#new_data_list) +- [new_timer](#new_timer) +- [new_progress](#new_progress) +- [new_layout](#new_layout) +- [new_container](#new_container) +- [new_hotkey](#new_hotkey) +- [new_rich_text](#new_rich_text) +- [new_rich_input](#new_rich_input) + + +## Fields +- [components_all](#components_all) +- [components_interest](#components_interest) + + + +### create_druid_instance + +--- +```lua +instance.create_druid_instance(context, [style]) +``` + +Druid class constructor which used to create a Druid's components + +- **Parameters:** + - `context` *(table)*: Druid context. Usually it is self of gui script + - `[style]` *(table?)*: Druid style table + +- **Returns:** + - `` *(druid.instance)*: + +### new + +--- +```lua +instance:new(component, ...) +``` + +Create new Druid component instance + +- **Parameters:** + - `component` *()*: The component class to create + - `...` *(...)*: vararg + +- **Returns:** + - `instance` *()*: The new ready to use component + +### final + +--- +```lua +instance:final() +``` + +Call this in gui_script final function. + +### remove + +--- +```lua +instance:remove(component) +``` + +Remove created component from Druid instance. + Component `on_remove` function will be invoked, if exist. + +- **Parameters:** + - `component` *()*: Component instance + +- **Returns:** + - `is_removed` *(boolean)*: True if component was removed + +### update + +--- +```lua +instance:update(dt) +``` + +Call this in gui_script update function. + +- **Parameters:** + - `dt` *(number)*: Delta time + +### on_input + +--- +```lua +instance:on_input(action_id, action) +``` + +Call this in gui_script on_input function. + +- **Parameters:** + - `action_id` *(hash)*: Action_id from on_input + - `action` *(table)*: Action from on_input + +- **Returns:** + - `is_input_consumed` *(boolean)*: The boolean value is input was consumed + +### on_message + +--- +```lua +instance:on_message(message_id, message, sender) +``` + +Call this in gui_script on_message function. + +- **Parameters:** + - `message_id` *(hash)*: Message_id from on_message + - `message` *(table)*: Message from on_message + - `sender` *(url)*: Sender from on_message + +### on_window_event + +--- +```lua +instance:on_window_event(window_event) +``` + +Called when the window event occurs + +- **Parameters:** + - `window_event` *(number)*: The window event + +### set_whitelist + +--- +```lua +instance:set_whitelist(whitelist_components) +``` + +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 + +- **Parameters:** + - `whitelist_components` *(table|druid.component[])*: The array of component to whitelist + +- **Returns:** + - `self` *(druid.instance)*: The Druid instance + +### set_blacklist + +--- +```lua +instance:set_blacklist(blacklist_components) +``` + +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 DruidInstance + +- **Parameters:** + - `blacklist_components` *(table|druid.component[])*: The array of component to blacklist + +- **Returns:** + - `self` *(druid.instance)*: The Druid instance + +### new_widget + +--- +```lua +instance:new_widget(widget, [template], [nodes], ...) +``` + +Create new Druid widget instance + +- **Parameters:** + - `widget` *()*: The widget class to create + - `[template]` *(string|nil)*: The template name used by widget + - `[nodes]` *(node|table|nil)*: The nodes table from gui.clone_tree or prefab node to use for clone + - `...` *(...)*: vararg + +- **Returns:** + - `widget` *()*: The new ready to use widget + +### new_button + +--- +```lua +instance:new_button(node, [callback], [params], [anim_node]) +``` + +Create Button component + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id) + - `[callback]` *(function|event|nil)*: Button callback + - `[params]` *(any)*: Button callback params + - `[anim_node]` *(string|node|nil)*: Button anim node (node, if not provided) + +- **Returns:** + - `button` *(druid.button)*: The new button component + +### new_blocker + +--- +```lua +instance:new_blocker(node) +``` + +Create Blocker component + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id) + +- **Returns:** + - `blocker` *(druid.blocker)*: The new blocker component + +### new_back_handler + +--- +```lua +instance:new_back_handler([callback], [params]) +``` + +Create BackHandler component + +- **Parameters:** + - `[callback]` *(function|nil)*: The callback(self, custom_args) to call on back event + - `[params]` *(any)*: Callback argument + +- **Returns:** + - `back_handler` *(druid.back_handler)*: The new back handler component + +### new_hover + +--- +```lua +instance:new_hover(node, [on_hover_callback], [on_mouse_hover_callback]) +``` + +Create Hover component + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id) + - `[on_hover_callback]` *(function|nil)*: Hover callback + - `[on_mouse_hover_callback]` *(function|nil)*: Mouse hover callback + +- **Returns:** + - `hover` *(druid.hover)*: The new hover component + +### new_text + +--- +```lua +instance:new_text(node, [value], [adjust_type]) +``` + +Create Text component + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id) + - `[value]` *(string|nil)*: Initial text. Default value is node text from GUI scene. + - `[adjust_type]` *(string|nil)*: Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference + +- **Returns:** + - `text` *(druid.text)*: The new text component + +### new_grid + +--- +```lua +instance:new_grid(parent_node, item, [in_row]) +``` + +Create Grid component + +- **Parameters:** + - `parent_node` *(string|node)*: The node_id or gui.get_node(node_id). Parent of all Grid items. + - `item` *(string|node)*: Item prefab. Required to get grid's item size. Can be adjusted separately. + - `[in_row]` *(number|nil)*: How many nodes in row can be placed + +- **Returns:** + - `grid` *(druid.grid)*: The new grid component + +### new_scroll + +--- +```lua +instance:new_scroll(view_node, content_node) +``` + +Create Scroll component + +- **Parameters:** + - `view_node` *(string|node)*: The node_id or gui.get_node(node_id). Will used as user input node. + - `content_node` *(string|node)*: The node_id or gui.get_node(node_id). Will used as scrollable node inside view_node. + +- **Returns:** + - `scroll` *(druid.scroll)*: The new scroll component + +### new_drag + +--- +```lua +instance:new_drag(node, [on_drag_callback]) +``` + +Create Drag component + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id). Will used as user input node. + - `[on_drag_callback]` *(function|nil)*: Callback for on_drag_event(self, dx, dy) + +- **Returns:** + - `drag` *(druid.drag)*: The new drag component + +### new_swipe + +--- +```lua +instance:new_swipe(node, [on_swipe_callback]) +``` + +Create Swipe component + +- **Parameters:** + - `node` *(string|node)*: The node_id or gui.get_node(node_id). Will used as user input node. + - `[on_swipe_callback]` *(function|nil)*: Swipe callback for on_swipe_end event + +- **Returns:** + - `swipe` *(druid.swipe)*: The new swipe component + +### new_lang_text + +--- +```lua +instance:new_lang_text(node, [locale_id], [adjust_type]) +``` + +Create LangText component + +- **Parameters:** + - `node` *(string|node)*: The_node id or gui.get_node(node_id) + - `[locale_id]` *(string|nil)*: Default locale id or text from node as default + - `[adjust_type]` *(string|nil)*: Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE + +- **Returns:** + - `lang_text` *(druid.lang_text)*: The new lang text component + +### new_slider + +--- +```lua +instance:new_slider(pin_node, end_pos, [callback]) +``` + +Create Slider component + +- **Parameters:** + - `pin_node` *(string|node)*: The_node id or gui.get_node(node_id). + - `end_pos` *(vector3)*: The end position of slider + - `[callback]` *(function|nil)*: On slider change callback + +- **Returns:** + - `slider` *(druid.slider)*: The new slider component + +### new_input + +--- +```lua +instance:new_input(click_node, text_node, [keyboard_type]) +``` + +Create Input component + +- **Parameters:** + - `click_node` *(string|node)*: Button node to enabled input component + - `text_node` *(string|druid.text|node)*: Text node what will be changed on user input + - `[keyboard_type]` *(number|nil)*: Gui keyboard type for input field + +- **Returns:** + - `input` *(druid.input)*: The new input component + +### new_data_list + +--- +```lua +instance:new_data_list(druid_scroll, druid_grid, create_function) +``` + +Create DataList component + +- **Parameters:** + - `druid_scroll` *(druid.scroll)*: The Scroll instance for Data List component + - `druid_grid` *(druid.grid)*: The Grid instance for Data List component + - `create_function` *(function)*: The create function callback(self, data, index, data_list). Function should return (node, [component]) + +- **Returns:** + - `data_list` *(druid.data_list)*: The new data list component + +### new_timer + +--- +```lua +instance:new_timer(node, [seconds_from], [seconds_to], [callback]) +``` + +Create Timer component + +- **Parameters:** + - `node` *(string|node)*: Gui text node + - `[seconds_from]` *(number|nil)*: Start timer value in seconds + - `[seconds_to]` *(number|nil)*: End timer value in seconds + - `[callback]` *(function|nil)*: Function on timer end + +- **Returns:** + - `timer` *(druid.timer)*: The new timer component + +### new_progress + +--- +```lua +instance:new_progress(node, key, [init_value]) +``` + +Create Progress component + +- **Parameters:** + - `node` *(string|node)*: Progress bar fill node or node name + - `key` *(string)*: Progress bar direction: const.SIDE.X or const.SIDE.Y + - `[init_value]` *(number|nil)*: Initial value of progress bar. Default: 1 + +- **Returns:** + - `progress` *(druid.progress)*: The new progress component + +### new_layout + +--- +```lua +instance:new_layout(node, [mode]) +``` + +Create Layout component + +- **Parameters:** + - `node` *(string|node)*: The_node id or gui.get_node(node_id). + - `[mode]` *(string|nil)*: vertical|horizontal|horizontal_wrap. Default: horizontal + +- **Returns:** + - `layout` *(druid.layout)*: The new layout component + +### new_container + +--- +```lua +instance:new_container(node, [mode], [callback]) +``` + +Create Container component + +- **Parameters:** + - `node` *(string|node)*: The_node id or gui.get_node(node_id). + - `[mode]` *(string|nil)*: Layout mode + - `[callback]` *(fun(self: druid.container, size: vector3)|nil)*: Callback on size changed + +- **Returns:** + - `container` *(druid.container)*: The new container component + +### new_hotkey + +--- +```lua +instance:new_hotkey(keys_array, [callback], [callback_argument]) +``` + +Create Hotkey component + +- **Parameters:** + - `keys_array` *(string|string[])*: Keys for trigger action. Should contains one action key and any amount of modificator keys + - `[callback]` *(function|event|nil)*: The callback function + - `[callback_argument]` *(any)*: The argument to pass into the callback function + +- **Returns:** + - `hotkey` *(druid.hotkey)*: The new hotkey component + +### new_rich_text + +--- +```lua +instance:new_rich_text(text_node, [value]) +``` + +Create RichText component. + +- **Parameters:** + - `text_node` *(string|node)*: The text node to make Rich Text + - `[value]` *(string|nil)*: The initial text value. Default will be gui.get_text(text_node) + +- **Returns:** + - `rich_text` *(druid.rich_text)*: The new rich text component + +### new_rich_input + +--- +```lua +instance:new_rich_input(template, [nodes]) +``` + +Create RichInput component. + As a template please check rich_input.gui layout. + +- **Parameters:** + - `template` *(string)*: The template string name + - `[nodes]` *(table|nil)*: Nodes table from gui.clone_tree + +- **Returns:** + - `rich_input` *(druid.rich_input)*: The new rich input component + + +## Fields + +- **components_all** (_druid.component[]_): All created components + + +- **components_interest** (_table_): All components sorted by interest + diff --git a/api/quick_api_reference.md b/api/quick_api_reference.md new file mode 100644 index 0000000..2055a62 --- /dev/null +++ b/api/quick_api_reference.md @@ -0,0 +1,678 @@ +# Quick API Reference + +# Table of Contents +1. [Druid](#druid) +2. [Druid Instance](#druid-instance) +3. [Components](#components) + 1. [Base Component](#base-component) + 2. [Blocker](#blocker) + 3. [Button](#button) + 4. [Container](#container) + 5. [Data List](#data-list) + 6. [Drag](#drag) + 7. [Grid](#grid) + 8. [Hotkey](#hotkey) + 9. [Hover](#hover) + 10. [Input](#input) + 11. [Lang Text](#lang-text) + 12. [Layout](#layout) + 13. [Progress](#progress) + 14. [Rich Input](#rich-input) + 15. [Rich Text](#rich-text) + 16. [Scroll](#scroll) + 17. [Slider](#slider) + 18. [Swipe](#swipe) + 19. [Text](#text) + 20. [Timer](#timer) +4. [Helper](#helper) +5. [Widgets](#widgets) + +# API Reference + +## [Druid](druid_api.md) + +Inspect [API Here](druid_api.md) + +```lua +local druid = require("druid.druid") + +druid.init_window_listener() +druid.on_language_change() +druid.on_window_callback(window_event) +druid.set_default_style(style) +druid.set_sound_function(callback) +druid.set_text_function(callback) + +self.druid = druid.new(context, [style]) +``` + +## [Druid Instance](druid_instance_api.md) + +Inspect [API Here](druid_instance_api.md) + +```lua +-- Lifecycle +self.druid:final() +self.druid:update(dt) +self.druid:on_input(action_id, action) +self.druid:on_message(message_id, message, sender) + +-- Custom components +self.druid:new(component, ...) +self.druid:new_widget(widget, [template], [nodes], ...) + +-- Built-in components +self.druid:new_button(node, [callback], [params], [anim_node]) +self.druid:new_text(node, [value], [no_adjust]) +self.druid:new_grid(parent_node, item, [in_row]) +self.druid:new_scroll(view_node, content_node) +self.druid:new_data_list(druid_scroll, druid_grid, create_function) +self.druid:new_progress(node, key, [init_value]) +self.druid:new_lang_text(node, [locale_id], [adjust_type]) +self.druid:new_rich_text(text_node, [value]) +self.druid:new_back_handler([callback], [params]) +self.druid:new_blocker(node) +self.druid:new_hover(node, [on_hover_callback], [on_mouse_hover_callback]) +self.druid:new_drag(node, [on_drag_callback]) +self.druid:new_swipe(node, [on_swipe_callback]) +self.druid:new_input(click_node, text_node, [keyboard_type]) +self.druid:new_rich_input(template, [nodes]) +self.druid:new_layout(node, [mode]) +self.druid:new_container(node, [mode], [callback]) +self.druid:new_hotkey(keys_array, [callback], [callback_argument]) +self.druid:new_slider(pin_node, end_pos, [callback]) +self.druid:new_timer(node, [seconds_from], [seconds_to], [callback]) + +-- Operational +self.druid:remove(component) +self.druid:set_blacklist(blacklist_components) +self.druid:set_whitelist(whitelist_components) +``` + +## Components + +### [Base Component](components/base/component_api.md) + +Inspect [API Here](components/base/component_api.md) + +Basic methods for all components and widgets. + +```lua +component:get_childrens() +component:get_context() +component:get_druid([template], [nodes]) +component:get_input_priority() +component:get_node(node_id) +component:get_nodes() +component:get_parent_component() +component:get_template() +component:reset_input_priority() +component:set_input_enabled(state) +component:set_input_priority(value, [is_temporary]) +component:set_nodes(nodes) +component:set_style([druid_style]) +component:set_template([template]) + +-- All widgets goes with created Druid instance +widget.druid +``` + +### [Blocker](components/base/blocker_api.md) + +Inspect [API Here](components/base/blocker_api.md) + +```lua +local blocker = self.druid:new_blocker(node) + +blocker:is_enabled() +blocker:set_enabled(state) +``` + +### [Button](components/base/button_api.md) + +Inspect [API Here](components/base/button_api.md) + +```lua +local button = require("druid.base.button") + +button:init(node_or_node_id, [callback], [custom_args], [anim_node]) +button:set_animations_disabled() +button:set_enabled([state]) +button:is_enabled() +button:set_click_zone([zone]) +button:set_key_trigger(key) +button:get_key_trigger() +button:set_check_function([check_function], [failure_callback]) +button:set_web_user_interaction([is_web_mode]) + +button.on_click +button.on_pressed +button.on_repeated_click +button.on_long_click +button.on_double_click +button.on_hold_callback +button.on_click_outside +button.node +button.node_id +button.anim_node +button.params +button.hover +button.click_zone +button.start_scale +button.start_pos +button.disabled +button.key_trigger +button.style +button.druid +button.is_repeated_started +button.last_pressed_time +button.last_released_time +button.click_in_row +button.can_action +``` + +### [Container](components/extended/container_api.md) + +Inspect [API Here](components/extended/container_api.md) + +```lua +local container = self.druid:new_container(node, [mode], [callback]) + +container:add_container(node_or_container, [mode], [on_resize_callback]) +container:clear_draggable_corners() +container:create_draggable_corners() +container:fit_into_node(node) +container:fit_into_size(target_size) +container:fit_into_window() +container:get_position() +container:get_scale() +container:get_size() +container:on_window_resized() +container:refresh() +container:refresh_origins() +container:refresh_scale() +container:remove_container_by_node([node]) +container:set_min_size([min_size_x], [min_size_y]) +container:set_parent_container([parent_container]) +container:set_pivot(pivot) +container:set_position(pos_x, pos_y) +container:set_size([width], [height], [anchor_pivot]) +container:update_child_containers() +``` + +### [Data List](components/extended/data_list_api.md) + +Inspect [API Here](components/extended/data_list_api.md) + +```lua +local data_list = self.druid:new_data_list(druid_scroll, druid_grid, create_function) + +data_list:add(data, [index], [shift_policy]) +data_list:clear() +data_list:get_created_components() +data_list:get_created_nodes() +data_list:get_data() +data_list:get_index(data) +data_list:remove([index], [shift_policy]) +data_list:remove_by_data(data, [shift_policy]) +data_list:scroll_to_index(index) +data_list:set_data(data) +data_list:set_use_cache(is_use_cache) +``` + +### [Drag](components/base/drag_api.md) + +Inspect [API Here](components/base/drag_api.md) + +```lua +local drag = self.druid:new_drag(node, [on_drag_callback]) + +drag:is_enabled() +drag:on_window_resized() +drag:set_click_zone([node]) +drag:set_drag_cursors(is_enabled) +drag:set_enabled(is_enabled) +``` + +### [Grid](components/base/static_grid_api.md) + +Inspect [API Here](components/base/static_grid_api.md) + +```lua +local grid = self.druid:new_grid(parent_node, item, [in_row]) + +grid:add(item, [index], [shift_policy], [is_instant]) +grid:clear() +grid:get_all_pos() +grid:get_borders() +grid:get_index(pos) +grid:get_index_by_node(node) +grid:get_offset() +grid:get_pos(index) +grid:get_size() +grid:get_size_for([count]) +grid:refresh() +grid:remove(index, [shift_policy], [is_instant]) +grid:set_anchor(anchor) +grid:set_in_row(in_row) +grid:set_item_size([width], [height]) +grid:set_items(nodes, [is_instant]) +grid:set_pivot([pivot]) +grid:set_position_function(callback) +grid:sort_nodes(comparator) +``` + +### [Hotkey](components/extended/hotkey_api.md) + +Inspect [API Here](components/extended/hotkey_api.md) + +```lua +local hotkey = self.druid:new_hotkey(keys_array, [callback], [callback_argument]) + +hotkey:add_hotkey(keys, [callback_argument]) +hotkey:is_processing() +hotkey:on_focus_gained() +hotkey:set_repeat(is_enabled_repeated) +``` + +### [Hover](components/base/hover_api.md) + +Inspect [API Here](components/base/hover_api.md) + +```lua +local hover = self.druid:new_hover(node, [on_hover_callback], [on_mouse_hover_callback]) + +hover:is_enabled() +hover:is_hovered() +hover:is_mouse_hovered() +hover:set_click_zone([zone]) +hover:set_enabled([state]) +hover:set_hover([state]) +hover:set_mouse_hover([state]) +``` + +### [Input](components/extended/input_api.md) + +Inspect [API Here](components/extended/input_api.md) + +```lua +local input = self.druid:new_input(click_node, text_node, [keyboard_type]) + +input:get_text() +input:get_text_selected() +input:get_text_selected_replaced(text) +input:move_selection(delta, is_add_to_selection, is_move_to_end) +input:on_focus_lost() +input:reset_changes() +input:select() +input:select_cursor([cursor_index], [start_index], [end_index]) +input:set_allowed_characters(characters) +input:set_max_length(max_length) +input:set_text(input_text) +input:unselect() +``` + +### [Lang Text](components/extended/lang_text_api.md) + +Inspect [API Here](components/extended/lang_text_api.md) + +```lua +local lang_text = self.druid:new_lang_text(node, [locale_id], [adjust_type]) + +lang_text:format([a], [b], [c], [d], [e], [f], [g]) +lang_text:on_language_change() +lang_text:set_text(text) +lang_text:set_to(text) +lang_text:translate(locale_id, [a], [b], [c], [d], [e], [f], [g]) +``` + +### [Layout](components/extended/layout_api.md) + +Inspect [API Here](components/extended/layout_api.md) + +```lua +local layout = self.druid:new_layout(node, [mode]) + +layout:add(node_or_node_id) +layout:calculate_rows_data() +layout:clear_layout() +layout:get_content_size() +layout:get_entities() +layout:get_node_size(node) +layout:get_size() +layout:refresh_layout() +layout:remove(node_or_node_id) +layout:set_dirty() +layout:set_hug_content(is_hug_width, is_hug_height) +layout:set_justify(is_justify) +layout:set_margin([margin_x], [margin_y]) +layout:set_node_index([node], [index]) +layout:set_node_position(node, x, y) +layout:set_padding([padding_x], [padding_y], [padding_z], [padding_w]) +layout:set_type(type) +layout:update() +``` + +### [Progress](components/extended/progress_api.md) + +Inspect [API Here](components/extended/progress_api.md) + +```lua +local progress = self.druid:new_progress(node, key, [init_value]) + +progress:empty() +progress:fill() +progress:get() +progress:set_max_size(max_size) +progress:set_steps(steps, callback) +progress:set_to(to) +progress:to(to, [callback]) +progress:update([dt]) +``` + +### [Rich Input](components/custom/rich_input_api.md) + +Inspect [API Here](components/custom/rich_input_api.md) + +```lua +local rich_input = self.druid:new_rich_input(template, [nodes]) + +rich_input:get_text() +rich_input:select() +rich_input:set_allowed_characters(characters) +rich_input:set_font(font) +rich_input:set_placeholder(placeholder_text) +rich_input:set_text(text) +``` + +### [Rich Text](components/custom/rich_text_api.md) + +Inspect [API Here](components/custom/rich_text_api.md) + +```lua +local rich_text = self.druid:new_rich_text(text_node, [value]) + +rich_text:characters(word) +rich_text:clear() +rich_text:get_line_metric() +rich_text:get_text() +rich_text:get_words() +rich_text:set_text([text]) +rich_text:tagged(tag) +``` + +### [Scroll](components/base/scroll_api.md) + +Inspect [API Here](components/base/scroll_api.md) + +```lua +local scroll = self.druid:new_scroll(view_node, content_node) + +scroll:bind_grid([grid]) +scroll:get_percent() +scroll:get_scroll_size() +scroll:is_inert() +scroll:is_node_in_view(node) +scroll:scroll_to(point, [is_instant]) +scroll:scroll_to_index(index, [skip_cb]) +scroll:scroll_to_percent(percent, [is_instant]) +scroll:set_click_zone(node) +scroll:set_extra_stretch_size([stretch_size]) +scroll:set_horizontal_scroll(state) +scroll:set_inert(state) +scroll:set_points(points) +scroll:set_size(size, [offset]) +scroll:set_vertical_scroll(state) +scroll:set_view_size(size) +scroll:update([dt]) +scroll:update_view_size() +``` + +### [Slider](components/extended/slider_api.md) + +Inspect [API Here](components/extended/slider_api.md) + +```lua +local slider = self.druid:new_slider(pin_node, end_pos, [callback]) + +slider:is_enabled() +slider:set(value, [is_silent]) +slider:set_enabled(is_enabled) +slider:set_input_node([input_node]) +slider:set_steps(steps) +``` + +### [Swipe](components/extended/swipe_api.md) + +Inspect [API Here](components/extended/swipe_api.md) + +```lua +local swipe = self.druid:new_swipe(node, [on_swipe_callback]) + +swipe:set_click_zone([zone]) +``` + +### [Text](components/base/text_api.md) + +Inspect [API Here](components/base/text_api.md) + +```lua +local text = self.druid:new_text(node, [value], [no_adjust]) + +text:get_text() +text:get_text_adjust() +text:get_text_index_by_width(width) +text:get_text_size([text]) +text:is_multiline() +text:set_alpha(alpha) +text:set_color(color) +text:set_minimal_scale(minimal_scale) +text:set_pivot(pivot) +text:set_scale(scale) +text:set_size(size) +text:set_text([new_text]) +text:set_text_adjust([adjust_type], [minimal_scale]) +text:set_to(set_to) +``` + +### [Timer](components/extended/timer_api.md) + +Inspect [API Here](components/extended/timer_api.md) + +```lua +local timer = self.druid:new_timer(node, [seconds_from], [seconds_to], [callback]) + +timer:set_interval(from, to) +timer:set_state([is_on]) +timer:set_to(set_to) +timer:update([dt]) +``` + +## [Helper](druid_helper_api.md) + +Inspect [API Here](druid_helper_api.md) + +```lua +local helper = require("druid.helper") + +helper.add_array([target], [source]) +helper.centrate_icon_with_text([icon_node], [text_node], [margin]) +helper.centrate_nodes([margin], ...) +helper.centrate_text_with_icon([text_node], [icon_node], margin) +helper.clamp(value, [v1], [v2]) +helper.contains([array], [value]) +helper.deepcopy(orig_table) +helper.distance(x1, y1, x2, y2) +helper.get_animation_data_from_node(node, atlas_path) +helper.get_border(node, [offset]) +helper.get_closest_stencil_node(node) +helper.get_full_position(node, [root]) +helper.get_gui_scale() +helper.get_node(node_id, [template], [nodes]) +helper.get_pivot_offset(pivot_or_node) +helper.get_scaled_size(node) +helper.get_scene_scale(node, [include_passed_node_scale]) +helper.get_screen_aspect_koef() +helper.get_text_metrics_from_node(text_node) +helper.insert_with_shift(array, [item], [index], [shift_policy]) +helper.is_mobile() +helper.is_multitouch_supported() +helper.is_web() +helper.is_web_mobile() +helper.lerp(a, b, t) +helper.pick_node(node, x, y, [node_click_area]) +helper.remove_with_shift([array], [index], [shift_policy]) +helper.round(num, [num_decimal_places]) +helper.sign(val) +helper.step(current, target, step) +helper.table_to_string(t) +``` + +## [Widgets](widgets_api.md) + +Inspect [API Here](widgets_api.md) + +### [FPS Panel](widgets/fps_panel_api.md) + +Inspect [API Here](widgets/fps_panel_api.md) + +```lua +local fps_panel = require("druid.widget.fps_panel.fps_panel") + +fps_panel:init() +fps_panel:on_remove() +fps_panel:update([dt]) +fps_panel:push_fps_value() + +fps_panel.root +fps_panel.delta_time +fps_panel.collect_time +fps_panel.collect_time_counter +fps_panel.graph_samples +fps_panel.fps_samples +fps_panel.mini_graph +fps_panel.text_min_fps +fps_panel.text_fps +fps_panel.timer_id +fps_panel.previous_time +``` + +### [Memory Panel](widgets/memory_panel_api.md) + +Inspect [API Here](widgets/memory_panel_api.md) + +```lua +local memory_panel = require("druid.widget.memory_panel.memory_panel") + +memory_panel:init() +memory_panel:on_remove() +memory_panel:set_low_memory_limit([limit]) +memory_panel:push_next_value() +memory_panel:update_text_memory() + +memory_panel.root +memory_panel.delta_time +memory_panel.samples_count +memory_panel.memory_limit +memory_panel.mini_graph +memory_panel.max_value +memory_panel.text_per_second +memory_panel.text_memory +memory_panel.memory +memory_panel.memory_samples +memory_panel.timer_id +``` + +### [Mini Graph](widgets/mini_graph_api.md) + +Inspect [API Here](widgets/mini_graph_api.md) + +```lua +local mini_graph = require("druid.widget.mini_graph.mini_graph") + +mini_graph:init() +mini_graph:on_remove() +mini_graph:clear() +mini_graph:set_samples([samples]) +mini_graph:get_samples() +mini_graph:set_line_value(index, value) +mini_graph:get_line_value([index]) +mini_graph:push_line_value([value]) +mini_graph:set_max_value([max_value]) +mini_graph:set_line_height([index]) +mini_graph:get_lowest_value() +mini_graph:get_highest_value() +mini_graph:on_drag_widget([dx], [dy]) +mini_graph:toggle_hide() + +mini_graph.root +mini_graph.text_header +mini_graph.icon_drag +mini_graph.content +mini_graph.layout +mini_graph.prefab_line +mini_graph.color_zero +mini_graph.color_one +mini_graph.is_hidden +mini_graph.max_value +mini_graph.lines +mini_graph.values +mini_graph.container +mini_graph.default_size +mini_graph.samples +``` + +### [Properties Panel](widgets/properties_panel_api.md) + +Inspect [API Here](widgets/properties_panel_api.md) + +```lua +local properties_panel = require("druid.widget.properties_panel.properties_panel") + +properties_panel:properties_constructors() +properties_panel:init() +properties_panel:on_remove() +properties_panel:on_drag_widget([dx], [dy]) +properties_panel:clear_created_properties() +properties_panel:clear() +properties_panel:on_size_changed([new_size]) +properties_panel:update([dt]) +properties_panel:add_checkbox([on_create]) +properties_panel:add_slider([on_create]) +properties_panel:add_button([on_create]) +properties_panel:add_input([on_create]) +properties_panel:add_text([on_create]) +properties_panel:add_left_right_selector([on_create]) +properties_panel:add_vector3([on_create]) +properties_panel:add_inner_widget(widget_class, [template], [nodes], [on_create]) +properties_panel:add_widget(create_widget_callback) +properties_panel:remove([widget]) +properties_panel:set_hidden([is_hidden]) +properties_panel:is_hidden() +properties_panel:set_properties_per_page(properties_per_page) +properties_panel:set_page([page]) + +properties_panel.root +properties_panel.scroll +properties_panel.layout +properties_panel.container +properties_panel.container_content +properties_panel.container_scroll_view +properties_panel.contaienr_scroll_content +properties_panel.button_hidden +properties_panel.text_header +properties_panel.paginator +properties_panel.properties +properties_panel.content +properties_panel.default_size +properties_panel.current_page +properties_panel.properties_per_page +properties_panel.property_checkbox_prefab +properties_panel.property_slider_prefab +properties_panel.property_button_prefab +properties_panel.property_input_prefab +properties_panel.property_text_prefab +properties_panel.property_left_right_selector_prefab +properties_panel.property_vector3_prefab +properties_panel.is_dirty +``` diff --git a/docs/druid/archive/archive_files.json b/docs/archive/archive_files.json similarity index 100% rename from docs/druid/archive/archive_files.json rename to docs/archive/archive_files.json diff --git a/docs/druid/archive/game0.arcd b/docs/archive/game0.arcd similarity index 100% rename from docs/druid/archive/game0.arcd rename to docs/archive/game0.arcd diff --git a/docs/druid/archive/game0.arci b/docs/archive/game0.arci similarity index 100% rename from docs/druid/archive/game0.arci rename to docs/archive/game0.arci diff --git a/docs/druid/archive/game0.dmanifest b/docs/archive/game0.dmanifest similarity index 100% rename from docs/druid/archive/game0.dmanifest rename to docs/archive/game0.dmanifest diff --git a/docs/druid/archive/game0.projectc b/docs/archive/game0.projectc similarity index 95% rename from docs/druid/archive/game0.projectc rename to docs/archive/game0.projectc index e94fa93..cbd8123 100644 --- a/docs/druid/archive/game0.projectc +++ b/docs/archive/game0.projectc @@ -123,7 +123,7 @@ max_count = 16 launch_screen = /builtins/manifests/ios/LaunchScreen.storyboardc pre_renderered_icons = 0 bundle_identifier = example.unnamed -bundle_name = +bundle_name = infoplist = /builtins/manifests/ios/Info.plist privacymanifest = /builtins/manifests/ios/PrivacyInfo.xcprivacy default_language = en @@ -134,28 +134,28 @@ version_code = 817 minimum_sdk_version = 19 target_sdk_version = 34 package = com.insality.druid -gcm_sender_id = +gcm_sender_id = manifest = /builtins/manifests/android/AndroidManifest.xml iap_provider = GooglePlay input_method = HiddenInputField immersive_mode = 0 display_cutout = 1 debuggable = 0 -proguard = +proguard = extract_native_libs = 1 [osx] -app_icon = +app_icon = infoplist = /builtins/manifests/osx/Info.plist privacymanifest = /builtins/manifests/osx/PrivacyInfo.xcprivacy bundle_identifier = example.unnamed -bundle_name = +bundle_name = bundle_version = 1 default_language = en localizations = en [windows] -app_icon = +app_icon = [html5] custom_heap_size = 0 @@ -164,7 +164,7 @@ htmlfile = /builtins/manifests/web/engine_template.html cssfile = /builtins/manifests/web/dark_theme.css splash_image = /media/druid_logo.png archive_location_prefix = archive -archive_location_suffix = +archive_location_suffix = engine_arguments = --verify-graphics-calls=false wasm_streaming = 0 show_fullscreen_button = 0 @@ -179,7 +179,7 @@ max_particle_count = 0 [network] http_timeout = 0 -ssl_certificates = +ssl_certificates = http_thread_count = 4 http_cache_enabled = 1 @@ -213,8 +213,6 @@ max_time_step = 0.5 [druid] no_auto_input = 0 -no_stencil_check = 0 -no_auto_template = 0 input_text = text input_touch = touch input_marked_text = marked_text @@ -227,7 +225,7 @@ input_scroll_up = mouse_wheel_up input_scroll_down = mouse_wheel_down [native_extension] -app_manifest = +app_manifest = [saver] autosave_timer = 2 diff --git a/docs/druid/archive/game0.public.der b/docs/archive/game0.public.der similarity index 100% rename from docs/druid/archive/game0.public.der rename to docs/archive/game0.public.der diff --git a/docs/druid/archive/game1.arcd b/docs/archive/game1.arcd similarity index 100% rename from docs/druid/archive/game1.arcd rename to docs/archive/game1.arcd diff --git a/docs/druid/dmloader.js b/docs/dmloader.js similarity index 100% rename from docs/druid/dmloader.js rename to docs/dmloader.js diff --git a/docs/druid/druid.wasm b/docs/druid.wasm similarity index 100% rename from docs/druid/druid.wasm rename to docs/druid.wasm diff --git a/docs/druid/index.html b/docs/druid/index.html deleted file mode 100644 index a95252f..0000000 --- a/docs/druid/index.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - - - druid 1.0 - - - - - -
- - -
- -
-
-
-
- - - - - - diff --git a/docs/druid/druid_logo.png b/docs/druid_logo.png similarity index 100% rename from docs/druid/druid_logo.png rename to docs/druid_logo.png diff --git a/docs/druid/druid_wasm.js b/docs/druid_wasm.js similarity index 100% rename from docs/druid/druid_wasm.js rename to docs/druid_wasm.js diff --git a/docs/index.html b/docs/index.html index 192ca28..a95252f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,186 +1,158 @@ - - - + + - Defold Druid UI Framework - + + + + + + + druid 1.0 + + -
+
+ + +
+ +
+
+
+
+ + -
- -
-
-
- - -
- - - - - - -
- - -

Documentation for Druid Framework

- -

Modules

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BackHandlerComponent with event on back and backspace button.
BlockerComponent to consume input in special zone defined by GUI node.
ButtonDruid Component for Handling User Click Interactions: Click, Long Click, Double Click, and More.
DragComponent to handle drag action on node.
HoverComponent to handle hover node interaction
ScrollComponent to handle scroll content.
StaticGridComponent to handle component's position by row and columns.
TextComponent for Wrapping GUI Text Nodes: Druid Text -

## Overview ## -

Druid Text is a component that provides various adjustment modes for text nodes.

BaseComponentBasic class for all Druid components.
RichInputDruid Rich Input custom component.
RichTextDruid Rich Text Custom Component.
DruidDruid UI Component Framework.
DruidEventDruid Event Module -

The Event module provides a simple class for handling callbacks.

DataListComponent to manage data for huge dataset in scroll.
DynamicGridComponent to handle placing components in row
HotkeyDruid hotkey component
InputDruid input text component.
LangTextComponent to wrap over GUI Text nodes with localization helpers -

# Overview # -

• The initialization of druid.set_text_function is required to enable localization - using the localization ID.

LayoutLayout management on node
ProgressDruid component to handle the progress bars.
SliderDruid slider component
SwipeComponent to handle swipe gestures on node.
TimerComponent to handle GUI timers.
HelperHelper module with various usefull GUI functions.
DruidInstanceDruid Instance which you use for component creation.
- -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
+ diff --git a/docs/ldoc_fixed.css b/docs/ldoc_fixed.css deleted file mode 100644 index e63d191..0000000 --- a/docs/ldoc_fixed.css +++ /dev/null @@ -1,311 +0,0 @@ -/* 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; } - diff --git a/docs/modules/BackHandler.html b/docs/modules/BackHandler.html deleted file mode 100644 index e8f7dc7..0000000 --- a/docs/modules/BackHandler.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module BackHandler

-

Component with event on back and backspace button.

-

- # Overview # -

Back Handler is recommended to put in every game window to close it - or in main screen to call settings window. -

# Notes # -

• Back Handler inheritance BaseComponent, you can use all of its methods in addition to those described here. -

• Back Handler react on release action ACTION_BACK or ACTION_BACKSPACE

-

Usage:

-
    -
    local callback = function(self, params) ... end
    -
    -local params = {}
    -local back_handler = self.druid:new_back_handler(callback, [params])
    -
    -
- - -

Fields

- - - - - - - - - -
on_backThe DruidEvent Event on back handler action.
paramsCustom args to pass in the callback
- -
-
- - -

Fields

- -
-
- - on_back -
-
- The DruidEvent Event on back handler action. -

Trigger on input action ACTION_BACK or ACTION_BACKSPACE - - -

- - - - -

Usage:

-
    -
    -- Subscribe additional callbacks:
    -back_handler.on_back:subscribe(callback)
    -
- -
-
- - params -
-
- Custom args to pass in the callback - - -
    -
  • params - any or nil - -
  • -
- - - - -

Usage:

-
    -
    -- Replace params on runtime:
    -back_handler.params = { ... }
    -
- -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/BaseComponent.html b/docs/modules/BaseComponent.html deleted file mode 100644 index 39eb118..0000000 --- a/docs/modules/BaseComponent.html +++ /dev/null @@ -1,549 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module BaseComponent

-

Basic class for all Druid components.

-

- To create you custom component, use static function `component.create`

-

Usage:

-
    -
    -- Create your component:
    -local component = require("druid.component")
    -
    -local AwesomeComponent = component.create("awesome_component")
    -
    -function AwesomeComponent:init(template, nodes)
    -    self:set_template(template)
    -    self:set_nodes(nodes)
    -    self.druid = self:get_druid()
    -end
    -
    -return AwesomeComponent
    -
    -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
get_childrens(self)Return all children components, recursive
get_context(self)Context used as first arg in all Druid events
get_druid(self, template, nodes)Get Druid instance for inner component creation.
get_input_priority(self)Return component input priority
get_name(self)Return component name
get_node(self, node_or_name)Get component node by name.
get_parent_component(self)Return the parent component if exist
get_parent_name(self)Return parent component name
get_template(self)Get current component template name.
get_uid(self)Return component UID.
reset_input_priority(self)Reset component input priority to default value
set_input_enabled(self, state)Set component input state.
set_input_priority(self, value, is_temporary)Set component input priority
- -
-
- - -

Functions

- -
-
- - get_childrens(self) -
-
- Return all children components, recursive - - -

Parameters:

- - -

Returns:

-
    - - table - Array of childrens if the Druid component instance -
- - - - -
-
- - get_context(self) -
-
- Context used as first arg in all Druid events Context is usually self of gui_script. - - -

Parameters:

- - -

Returns:

-
    - - table - BaseComponent context -
- - - - -
-
- - get_druid(self, template, nodes) -
-
- Get Druid instance for inner component creation. - - -

Parameters:

-
    -
  • self - BaseComponent - BaseComponent -
  • -
  • template - string or nil - The template name -
  • -
  • nodes - table or nil - The nodes table -
  • -
- -

Returns:

-
    - - DruidInstance - Druid instance with component context -
- - - - -
-
- - get_input_priority(self) -
-
- Return component input priority - - -

Parameters:

- - -

Returns:

-
    - - number - The component input priority -
- - - - -
-
- - get_name(self) -
-
- Return component name - - -

Parameters:

- - -

Returns:

-
    - - string - The component name -
- - - - -
-
- - get_node(self, node_or_name) -
-
- 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 - - -

Parameters:

-
    -
  • self - BaseComponent - BaseComponent -
  • -
  • node_or_name - string or node - Node name or node itself -
  • -
- -

Returns:

-
    - - node - Gui node -
- - - - -
-
- - get_parent_component(self) -
-
- Return the parent component if exist - - -

Parameters:

- - -

Returns:

-
    - - BaseComponent or nil - The druid component instance or nil -
- - - - -
-
- - get_parent_name(self) -
-
- Return parent component name - - -

Parameters:

- - -

Returns:

-
    - - string or nil - The parent component name if exist or bil -
- - - - -
-
- - get_template(self) -
-
- Get current component template name. - - -

Parameters:

- - -

Returns:

-
    - - string - Component full template name -
- - - - -
-
- - get_uid(self) -
-
- Return component UID. -

UID generated in component creation order. - - -

Parameters:

- - -

Returns:

-
    - - number - The component uid -
- - - - -
-
- - reset_input_priority(self) -
-
- Reset component input priority to default value - - -

Parameters:

- - -

Returns:

-
    - - number - The component input priority -
- - - - -
-
- - set_input_enabled(self, state) -
-
- Set component input state. By default it enabled -

If input is disabled, the component will not receive input events - - -

Parameters:

-
    -
  • self - BaseComponent - BaseComponent -
  • -
  • state - boolean or nil - The component input state -
  • -
- -

Returns:

-
    - - BaseComponent - BaseComponent itself -
- - - - -
-
- - set_input_priority(self, value, is_temporary) -
-
- Set component input priority Default value: 10 - - -

Parameters:

-
    -
  • self - BaseComponent - BaseComponent -
  • -
  • value - number - The new input priority value -
  • -
  • is_temporary - boolean or nil - If true, the reset input priority will return to previous value -
  • -
- -

Returns:

-
    - - number - The component input priority -
- - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Blocker.html b/docs/modules/Blocker.html deleted file mode 100644 index c3ec691..0000000 --- a/docs/modules/Blocker.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Blocker

-

Component to consume input in special zone defined by GUI node.

-

- # Overview # -

# Notes # -

Blocker consume input if `gui.pick_node` works on it. -

• Blocker inheritance BaseComponent, you can use all of its methods in addition to those described here. -

• Blocker initial enabled state is `gui.is_enabled(node, true)` -

• The Blocker node should be enabled to capture the input

-

Usage:

-
    -
    local node = gui.get_node("blocker_node")
    -local blocker = self.druid:new_blocker(node)
    -
    -
- - -

Functions

- - - - - - - - - - - - - -
init(self, node)The Blocker constructor
is_enabled(self)Return blocker enabled state
set_enabled(self, state)Set enabled blocker component state.
-

Fields

- - - - - -
nodeBlocker node
- -
-
- - -

Functions

- -
-
- - init(self, node) -
-
- The Blocker constructor - - -

Parameters:

-
    -
  • self - Blocker - Blocker -
  • -
  • node - node - Gui node -
  • -
- - - - - -
-
- - is_enabled(self) -
-
- Return blocker enabled state - - -

Parameters:

- - -

Returns:

-
    - - boolean - @True, if blocker is enabled -
- - - - -
-
- - set_enabled(self, state) -
-
- Set enabled blocker component state. -

Don't change node enabled state itself. - - -

Parameters:

-
    -
  • self - Blocker - Blocker -
  • -
  • state - boolean or nil - Enabled state -
  • -
- - - - - -
-
-

Fields

- -
-
- - node -
-
- Blocker node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Button.html b/docs/modules/Button.html deleted file mode 100644 index 6bcc4cd..0000000 --- a/docs/modules/Button.html +++ /dev/null @@ -1,880 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Button

-

Druid Component for Handling User Click Interactions: Click, Long Click, Double Click, and More.

-

-

# Overview # -

This component provides a versatile solution for handling user click interactions. - It allows you to make any GUI node clickable and define various callbacks for different types of clicks. -

# Notes # -

• The click callback will not trigger if the cursor moves outside the node's - area between the pressed and released states. -

• If a button has a double click event subscriber and the double click event is triggered, - the regular click callback will not be triggered. -

• Buttons can be triggered using a keyboard key by calling the button:set_key_trigger method. -

• To animate a small icon on a big button panel, you can use an animation node. - The trigger node name should be set as "big panel," and the animation node should be set as "small icon." -

Example Link

-

Usage:

-
    -
    local function on_button_click(self, args, button)
    -    print("Button has clicked with params: " .. args)
    -    print("Also the button component is passed in callback params")
    -end
    -
    -local custom_args = "Any variable to pass inside callback"
    -local button = self.druid:new_button("button_name", on_button_click, custom_args)
    -
    -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
get_key_trigger(self)Get current key name to trigger this button.
init(self, node, callback, custom_args, anim_node)The Button constructor
is_enabled(self)Get button enabled state.
set_check_function(self, check_function, failure_callback)Set function for additional check for button click availability
set_click_zone(self, zone)Set additional button click area.
set_enabled(self, state)Set button enabled state.
set_key_trigger(self, key)Set key name to trigger this button by keyboard.
set_web_user_interaction(self, is_web_mode)Set Button mode to work inside user HTML5 interaction event.
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
anim_nodeButton animation node.
click_zoneAdditional button click area, defined by another GUI node
hoverThe Hover: Button Hover component
nodeButton trigger node
node_idThe GUI node id from button node
on_clickThe DruidEvent: Event on successful release action over button.
on_click_outsideThe DruidEvent: Event calls if click event was outside of button.
on_double_clickThe DruidEvent: Event on double tap action over button.
on_hold_callbackThe DruidEvent: Event calls every frame before on_long_click event.
on_long_clickThe DruidEvent: Event on long tap action over button.
on_pressedThe DruidEvent: Event triggered if button was pressed by user.
on_repeated_clickThe DruidEvent: Event on repeated action over button.
paramsCustom args for any Button event.
- -
-
- - -

Functions

- -
-
- - get_key_trigger(self) -
-
- Get current key name to trigger this button. - - -

Parameters:

-
    -
  • self - Button - -
  • -
- -

Returns:

-
    - - hash - The action_id of the input key -
- - - -

Usage:

-
    -
    local key_hash = button:get_key_trigger()
    -
- -
-
- - init(self, node, callback, custom_args, anim_node) -
-
- The Button constructor - - -

Parameters:

-
    -
  • self - Button - Button -
  • -
  • node - string or node - The node_id or gui.get_node(node_id) -
  • -
  • callback - function - On click button callback -
  • -
  • custom_args - any or nil - Button events custom arguments -
  • -
  • anim_node - string, node or nil - Node to animate instead of trigger node. -
  • -
- - - - - -
-
- - is_enabled(self) -
-
- Get button enabled state. -

By default all Buttons is enabled on creating. - - -

Parameters:

-
    -
  • self - Button - Button -
  • -
- -

Returns:

-
    - - boolean - @True, if button is enabled now, False overwise -
- - - -

Usage:

-
    -
    local is_enabled = button:is_enabled()
    -
- -
-
- - set_check_function(self, check_function, failure_callback) -
-
- Set function for additional check for button click availability - - -

Parameters:

-
    -
  • self - Button - -
  • -
  • check_function - function or nil - Should return true or false. If true - button can be pressed. -
  • -
  • failure_callback - function or nil - Function will be called on button click, if check function return false -
  • -
- -

Returns:

-
    - - Button - Current button instance -
- - - - -
-
- - set_click_zone(self, zone) -
-
- Set additional button click area. - Useful to restrict click outside out stencil node or scrollable content. -

This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check - - -

Parameters:

- - -

Returns:

-
    - - Button - Current button instance -
- - - -

Usage:

-
    -
    button:set_click_zone("stencil_node")
    -
- -
-
- - set_enabled(self, state) -
-
- Set button enabled state. - The style.on_set_enabled will be triggered. - Disabled button is not clickable. - - -

Parameters:

-
    -
  • self - Button - Button -
  • -
  • state - boolean or nil - Enabled state -
  • -
- -

Returns:

-
    - - Button - Current button instance -
- - - -

Usage:

-
    -
    button:set_enabled(false)
    -button:set_enabled(true)
    -
- -
-
- - set_key_trigger(self, key) -
-
- Set key name to trigger this button by keyboard. - - -

Parameters:

-
    -
  • self - Button - Button -
  • -
  • key - hash or string - The action_id of the input key -
  • -
- -

Returns:

-
    - - Button - Current button instance -
- - - -

Usage:

-
    -
    button:set_key_trigger("key_space")
    -
- -
-
- - set_web_user_interaction(self, is_web_mode) -
-
- Set Button mode to work inside user HTML5 interaction event. -

It's required to make protected things like copy & paste text, show mobile keyboard, etc - The HTML5 button's doesn't call any events except on_click event. -

If the game is not HTML, html mode will be not enabled - - -

Parameters:

-
    -
  • self - Button - -
  • -
  • is_web_mode - boolean or nil - If true - button will be called inside html5 callback -
  • -
- -

Returns:

-
    - - Button - Current button instance -
- - - -

Usage:

-
    -
    button:set_web_user_interaction(true)
    -
- -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in Druid styles table - or create your own style - - -

Fields:

-
    -
  • LONGTAP_TIME - number or nil - Minimum time to trigger on_hold_callback. Default: 0.4 -
  • -
  • AUTOHOLD_TRIGGER - number or nil - Maximum hold time to trigger button release while holding. Default: 0.8 -
  • -
  • DOUBLETAP_TIME - number or nil - Time between double taps. Default: 0.4 -
  • -
  • on_click - function - function(self, node) -
  • -
  • on_click_disabled - function - function(self, node) -
  • -
  • on_hover - function - function(self, node, hover_state) -
  • -
  • on_mouse_hover - function - function(self, node, hover_state) -
  • -
  • on_set_enabled - function - function(self, node, enabled_state) -
  • -
- - - - - -
-
-

Fields

- -
-
- - anim_node -
-
- Button animation node. - In default case equals to clickable node. -

Usecase: You have the big clickable panel, but want to animate only one small icon on it. - - -

    -
  • anim_node - node or nil - Default node -
  • -
- - - - - -
-
- - click_zone -
-
- Additional button click area, defined by another GUI node - - -
    -
  • click_zone - node or nil - -
  • -
- - - - - -
-
- - hover -
-
- The Hover: Button Hover component - - -
    -
  • hover - Hover - Hover -
  • -
- - - - - -
-
- - node -
-
- Button trigger node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - node_id -
-
- The GUI node id from button node - - -
    -
  • node_id - hash - -
  • -
- - - - - -
-
- - on_click -
-
- The DruidEvent: Event on successful release action over button. - - - - - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_click:subscribe(function(self, custom_args, button_instance)
    -    print("On button click!")
    -end)
    -
- -
-
- - on_click_outside -
-
- The DruidEvent: Event calls if click event was outside of button. -

This event will be triggered for each button what was not clicked on user click action -

Usecase: Hide the popup when click outside - - -

    -
  • on_click_outside - DruidEvent - DruidEvent -
  • -
- - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_click_outside:subscribe(function(self, custom_args, button_instance)
    -    print("On click Button outside!")
    -end)
    -
- -
-
- - on_double_click -
-
- The DruidEvent: Event on double tap action over button. -

If secondary click was too fast after previous one, the double - click will be called instead usual click (if on_double_click subscriber exists) - - -

- - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_double_click:subscribe(function(self, custom_args, button_instance, click_amount)
    -    print("On double Button click!")
    -end)
    -
- -
-
- - on_hold_callback -
-
- The DruidEvent: Event calls every frame before on_long_click event. -

If long_click subscriber exists, the on_hold_callback will be called before long_click trigger. -

Usecase: Animate button progress of long tap - - -

    -
  • on_hold_callback - DruidEvent - DruidEvent -
  • -
- - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_double_click:subscribe(function(self, custom_args, button_instance, time)
    -    print("On hold Button callback!")
    -end)
    -
- -
-
- - on_long_click -
-
- The DruidEvent: Event on long tap action over button. -

This callback will be triggered if user pressed the button and hold the some amount of time. - The amount of time picked from button style param: LONGTAP_TIME - - -

- - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_long_click:subscribe(function(self, custom_args, button_instance, hold_time)
    -    print("On long Button click!")
    -end)
    -
- -
-
- - on_pressed -
-
- The DruidEvent: Event triggered if button was pressed by user. - - - - - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_pressed:subscribe(function(self, custom_args, button_instance)
    -    print("On Button pressed!")
    -end)
    -
- -
-
- - on_repeated_click -
-
- The DruidEvent: Event on repeated action over button. -

This callback will be triggered if user hold the button. The repeat rate pick from `input.repeat_interval` in game.project - - -

    -
  • on_repeated_click - DruidEvent - DruidEvent -
  • -
- - - - -

Usage:

-
    -
    -- Custom args passed in Button constructor
    -button.on_repeated_click:subscribe(function(self, custom_args, button_instance, click_count)
    -    print("On repeated Button click!")
    -end)
    -
- -
-
- - params -
-
- Custom args for any Button event. Setup in Button constructor - - -
    -
  • params - any - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Checkbox.html b/docs/modules/Checkbox.html deleted file mode 100644 index fd0aef1..0000000 --- a/docs/modules/Checkbox.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Checkbox

-

Druid checkbox component

-

Example Link

- - -

Functions

- - - - - - - - - - - - - -
get_state(self)Return checkbox state
init(self, node, callback, click_node, initial_state)The Checkbox constructor
set_state(self, state, is_silent, is_instant)Set checkbox state
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - -
buttonButton component from click_node
click_nodeButton trigger node
nodeVisual node
on_change_stateOn change state callback(self, state)
- -
-
- - -

Functions

- -
-
- - get_state(self) -
-
- Return checkbox state - - -

Parameters:

- - -

Returns:

-
    - - boolean - Checkbox state -
- - - - -
-
- - init(self, node, callback, click_node, initial_state) -
-
- The Checkbox constructor - - -

Parameters:

-
    -
  • self - Checkbox - Checkbox -
  • -
  • node - node - Gui node -
  • -
  • callback - function - Checkbox callback -
  • -
  • click_node - node or nil - Trigger node, by default equals to node. Default: node -
  • -
  • initial_state - boolean or nil - The initial state of checkbox, default - false -
  • -
- - - - - -
-
- - set_state(self, state, is_silent, is_instant) -
-
- Set checkbox state - - -

Parameters:

-
    -
  • self - Checkbox - Checkbox -
  • -
  • state - boolean or nil - Checkbox state -
  • -
  • is_silent - boolean or nil - Don't trigger on_change_state if true -
  • -
  • is_instant - boolean or nil - If instant checkbox change -
  • -
- - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • on_change_state - function - (self, node, state) -
  • -
- - - - - -
-
-

Fields

- -
-
- - button -
-
- Button component from click_node - - -
    -
  • button - Button - Button -
  • -
- - - - - -
-
- - click_node -
-
- Button trigger node - - -
    -
  • click_node - node or nil - -
  • -
- - - - - -
-
- - node -
-
- Visual node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_change_state -
-
- On change state callback(self, state) - - - - - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/CheckboxGroup.html b/docs/modules/CheckboxGroup.html deleted file mode 100644 index 5ff8ec1..0000000 --- a/docs/modules/CheckboxGroup.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module CheckboxGroup

-

Checkbox group module

-

Example Link

- - -

Functions

- - - - - - - - - - - - - -
get_state(self)Return checkbox group state
init(self, nodes, callback, click_nodes)The CheckboxGroup constructor
set_state(self, indexes, is_instant)Set checkbox group state
-

Fields

- - - - - - - - - -
checkboxesArray of checkbox components
on_checkbox_clickOn any checkbox click callback(self, index)
- -
-
- - -

Functions

- -
-
- - get_state(self) -
-
- Return checkbox group state - - -

Parameters:

- - -

Returns:

-
    - - boolean[] - Array if checkboxes state -
- - - - -
-
- - init(self, nodes, callback, click_nodes) -
-
- The CheckboxGroup constructor - - -

Parameters:

-
    -
  • self - CheckboxGroup - CheckboxGroup -
  • -
  • nodes - node[] - Array of gui node -
  • -
  • callback - function - Checkbox callback -
  • -
  • click_nodes - node[] or nil - Array of trigger nodes, by default equals to nodes -
  • -
- - - - - -
-
- - set_state(self, indexes, is_instant) -
-
- Set checkbox group state - - -

Parameters:

-
    -
  • self - CheckboxGroup - CheckboxGroup -
  • -
  • indexes - boolean[] - Array of checkbox state -
  • -
  • is_instant - boolean or nil - If instant state change -
  • -
- - - - - -
-
-

Fields

- -
-
- - checkboxes -
-
- Array of checkbox components - - - - - - - - -
-
- - on_checkbox_click -
-
- On any checkbox click callback(self, index) - - -
    -
  • on_checkbox_click - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/DataList.html b/docs/modules/DataList.html deleted file mode 100644 index 680d3ce..0000000 --- a/docs/modules/DataList.html +++ /dev/null @@ -1,712 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module DataList

-

Component to manage data for huge dataset in scroll.

-

- It requires Druid Scroll and Druid Grid (Static or Dynamic) components -

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
add(self, data, index, shift_policy)Add element to DataList.
clear(self)Clear the DataList and refresh visuals
get_created_components(self)Return all currenly created components in DataList
get_created_nodes(self)Return all currenly created nodes in DataList
get_data(self)Return current data from DataList component
get_index(self, data)Return index for data value
init(self, scroll, grid, create_function)The DataList constructor
on_remove(self)Druid System on_remove function
remove(self, index, shift_policy)Remove element from DataList.
remove_by_data(self, data, shift_policy)Remove element from DataList by data value.
scroll_to_index(self, index)Instant scroll to element with passed index
set_data(self, data)Set new data set for DataList component
set_use_cache(self, is_use_cache)Set refresh function for DataList component
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
gridThe Druid Grid component
last_indexThe current last index of visual elements
on_element_addOn DataList visual element created Event callback(self, index, node, instance)
on_element_removeOn DataList visual element created Event callback(self, index)
on_scroll_progress_changeEvent triggered when scroll progress is changed; event(self, progress_value)
scrollThe Druid scroll component
scroll_progressThe current progress of scroll posititon
top_indexThe current top index of visual elements
- -
-
- - -

Functions

- -
-
- - add(self, data, index, shift_policy) -
-
- Add element to DataList. Currenly untested - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • data - table - -
  • -
  • index - number or nil - -
  • -
  • shift_policy - number or nil - The constant from const.SHIFT.* -
  • -
- - - - - -
-
- - clear(self) -
-
- Clear the DataList and refresh visuals - - -

Parameters:

- - - - - - -
-
- - get_created_components(self) -
-
- Return all currenly created components in DataList - - -

Parameters:

- - -

Returns:

-
    - - druid.base_component[] - List of created nodes -
- - - - -
-
- - get_created_nodes(self) -
-
- Return all currenly created nodes in DataList - - -

Parameters:

- - -

Returns:

-
    - - node[] - List of created nodes -
- - - - -
-
- - get_data(self) -
-
- Return current data from DataList component - - -

Parameters:

- - -

Returns:

-
    - - table - The current data array -
- - - - -
-
- - get_index(self, data) -
-
- Return index for data value - - -

Parameters:

- - - - - - -
-
- - init(self, scroll, grid, create_function) -
-
- The DataList constructor - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • scroll - Scroll - The Scroll instance for Data List component -
  • -
  • grid - StaticGrid - The StaticGrid or DynamicGrid instance for Data List component -
  • -
  • create_function - function - The create function callback(self, data, index, data_list). Function should return (node, [component]) -
  • -
- - - - - -
-
- - on_remove(self) -
-
- Druid System on_remove function - - -

Parameters:

- - - - - - -
-
- - remove(self, index, shift_policy) -
-
- Remove element from DataList. Currenly untested - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • index - number or nil - -
  • -
  • shift_policy - number or nil - The constant from const.SHIFT.* -
  • -
- - - - - -
-
- - remove_by_data(self, data, shift_policy) -
-
- Remove element from DataList by data value. Currenly untested - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • data - table - -
  • -
  • shift_policy - number or nil - The constant from const.SHIFT.* -
  • -
- - - - - -
-
- - scroll_to_index(self, index) -
-
- Instant scroll to element with passed index - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • index - number - -
  • -
- - - - - -
-
- - set_data(self, data) -
-
- Set new data set for DataList component - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • data - table - The new data array -
  • -
- -

Returns:

-
    - - druid.data_list - Current DataList instance -
- - - - -
-
- - set_use_cache(self, is_use_cache) -
-
- Set refresh function for DataList component - - -

Parameters:

-
    -
  • self - DataList - DataList -
  • -
  • is_use_cache - boolean - Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove -
  • -
- -

Returns:

-
    - - druid.data_list - Current DataList instance -
- - - - -
-
-

Fields

- -
-
- - grid -
-
- The Druid Grid component - - - - - - - - -
-
- - last_index -
-
- The current last index of visual elements - - -
    -
  • last_index - number - -
  • -
- - - - - -
-
- - on_element_add -
-
- On DataList visual element created Event callback(self, index, node, instance) - - - - - - - - -
-
- - on_element_remove -
-
- On DataList visual element created Event callback(self, index) - - -
    -
  • on_element_remove - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - on_scroll_progress_change -
-
- Event triggered when scroll progress is changed; event(self, progress_value) - - -
    -
  • on_scroll_progress_change - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - scroll -
-
- The Druid scroll component - - -
    -
  • scroll - Scroll - Scroll -
  • -
- - - - - -
-
- - scroll_progress -
-
- The current progress of scroll posititon - - -
    -
  • scroll_progress - number - -
  • -
- - - - - -
-
- - top_index -
-
- The current top index of visual elements - - -
    -
  • top_index - number - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Drag.html b/docs/modules/Drag.html deleted file mode 100644 index 51a7c36..0000000 --- a/docs/modules/Drag.html +++ /dev/null @@ -1,633 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Drag

-

Component to handle drag action on node.

-

- Drag have correct handling for multitouch and swap - touched while dragging. Drag will be processed even - the cursor is outside of node, if drag is already started -

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - -
init(self, node, on_drag_callback)The Drag constructor
is_enabled(self)Check if Drag component is enabled
set_click_zone(self, node)Strict drag click area.
set_enabled(self, is_enabled)Set Drag input enabled or disabled
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
can_xIs drag component process vertical dragging.
can_yIs drag component process horizontal.
is_dragIs component now dragging
is_touchIs component now touching
nodeDrag node
on_dragon drag progress callback(self, dx, dy, total_x, total_y, touch)
on_drag_endEvent on drag end callback(self, total_x, total_y, touch)
on_drag_startEvent on drag start callback(self, touch)
on_touch_endEvent on touch end callback(self)
on_touch_startEvent on touch start callback(self)
screen_xCurrent touch x screen position
screen_yCurrent touch y screen position
touch_start_posTouch start position
xCurrent touch x position
yCurrent touch y position
- -
-
- - -

Functions

- -
-
- - init(self, node, on_drag_callback) -
-
- The Drag constructor - - -

Parameters:

-
    -
  • self - Drag - Drag -
  • -
  • node - node - GUI node to detect dragging -
  • -
  • on_drag_callback - function - Callback for on_drag_event(self, dx, dy) -
  • -
- - - - - -
-
- - is_enabled(self) -
-
- Check if Drag component is enabled - - -

Parameters:

-
    -
  • self - Drag - Drag -
  • -
- -

Returns:

-
    - - boolean - -
- - - - -
-
- - set_click_zone(self, node) -
-
- Strict drag click area. Useful for - restrict events outside stencil node - - -

Parameters:

- - - - - - -
-
- - set_enabled(self, is_enabled) -
-
- Set Drag input enabled or disabled - - -

Parameters:

-
    -
  • self - Drag - Drag -
  • -
  • is_enabled - boolean or nil - -
  • -
- - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • DRAG_DEADZONE - number or nil - Distance in pixels to start dragging. Default: 10 -
  • -
  • NO_USE_SCREEN_KOEF - boolean or nil - If screen aspect ratio affects on drag values. Default: false -
  • -
- - - - - -
-
-

Fields

- -
-
- - can_x -
-
- Is drag component process vertical dragging. Default - true - - -
    -
  • can_x - boolean - -
  • -
- - - - - -
-
- - can_y -
-
- Is drag component process horizontal. Default - true - - -
    -
  • can_y - boolean - -
  • -
- - - - - -
-
- - is_drag -
-
- Is component now dragging - - -
    -
  • is_drag - boolean - -
  • -
- - - - - -
-
- - is_touch -
-
- Is component now touching - - -
    -
  • is_touch - boolean - -
  • -
- - - - - -
-
- - node -
-
- Drag node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_drag -
-
- on drag progress callback(self, dx, dy, total_x, total_y, touch) - - - - - - - - -
-
- - on_drag_end -
-
- Event on drag end callback(self, total_x, total_y, touch) - - - - - - - - -
-
- - on_drag_start -
-
- Event on drag start callback(self, touch) - - - - - - - - -
-
- - on_touch_end -
-
- Event on touch end callback(self) - - - - - - - - -
-
- - on_touch_start -
-
- Event on touch start callback(self) - - - - - - - - -
-
- - screen_x -
-
- Current touch x screen position - - -
    -
  • screen_x - number - -
  • -
- - - - - -
-
- - screen_y -
-
- Current touch y screen position - - -
    -
  • screen_y - number - -
  • -
- - - - - -
-
- - touch_start_pos -
-
- Touch start position - - -
    -
  • touch_start_pos - vector3 - -
  • -
- - - - - -
-
- - x -
-
- Current touch x position - - -
    -
  • x - number - -
  • -
- - - - - -
-
- - y -
-
- Current touch y position - - -
    -
  • y - number - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Druid.html b/docs/modules/Druid.html deleted file mode 100644 index 0af243a..0000000 --- a/docs/modules/Druid.html +++ /dev/null @@ -1,374 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Druid

-

Druid UI Component Framework.

-

- # Overview # -

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. -

To start using Druid, please refer to the Usage section below. -

# Notes # -

• 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
    -
    -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
    -
    -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
druid.new(context, style)Create a new Druid instance for creating GUI components.
druid.on_language_change()Call this function when the game language changes.
druid.on_window_callback(event)Set the window callback to enable on_focus_gain and on_focus_lost functions.
druid.register(name, module)Register a new external Druid component.
druid.set_default_style(style)Set your own default style for all Druid instances.
druid.set_sound_function(callback)Set the Druid sound function to play UI sounds if used.
druid.set_text_function(callback)Set the text function for the LangText component.
- -
-
- - -

Functions

- -
-
- - druid.new(context, style) -
-
- Create a new Druid instance for creating GUI components. - - -

Parameters:

-
    -
  • context - table - The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks. -
  • -
  • style - table or nil - The Druid style table to override style parameters for this Druid instance. -
  • -
- -

Returns:

-
    - - druid_instance - The Druid instance DruidInstance. -
- - - -

Usage:

-
    -
    local druid = require("druid.druid")
    -
    -function init(self)
    -   self.druid = druid.new(self)
    -end
    -
- -
-
- - druid.on_language_change() -
-
- Call this function when the game language changes. -

This function will translate all current LangText components. - - - - - - -

Usage:

-
    -
    druid.on_language_change()
    -
- -
-
- - druid.on_window_callback(event) -
-
- 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. - - -

Parameters:

-
    -
  • event - string - Event param from window listener -
  • -
- - - - -

Usage:

-
    -
    window.set_listener(function(_, event)
    -   druid.on_window_callback(event)
    -end)
    -
- -
-
- - druid.register(name, module) -
-
- 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. - - -

Parameters:

-
    -
  • name - string - module name -
  • -
  • module - table - 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(...)
    -
- -
-
- - druid.set_default_style(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. - - -

Parameters:

-
    -
  • style - table - Druid style module -
  • -
- - - - -

Usage:

-
    -
    local my_style = require("path.to.my.style")
    -druid.set_default_style(my_style)
    -
- -
-
- - druid.set_sound_function(callback) -
-
- 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). - - -

Parameters:

-
    -
  • callback - function - Sound play callback -
  • -
- - - - -

Usage:

-
    -
    druid.set_sound_function(function(sound_id)
    -    sound.play(sound_id) -- Replace with your real function
    -end)
    -
- -
-
- - druid.set_text_function(callback) -
-
- 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. - - -

Parameters:

-
    -
  • callback - function - Get localized text function -
  • -
- - - - -

Usage:

-
    -
    druid.set_text_function(function(text_id)
    -   return lang_data[text_id] -- Replace with your real function
    -end)
    -
- -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/DruidEvent.html b/docs/modules/DruidEvent.html deleted file mode 100644 index a761399..0000000 --- a/docs/modules/DruidEvent.html +++ /dev/null @@ -1,399 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module DruidEvent

-

Druid Event Module -

The Event module provides a simple class for handling callbacks.

-

It is used in many Druid components. -

You can subscribe to an event using the `:subscribe` method and unsubscribe using the `:unsubscribe` method.

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
clear(self)Clear the all event handlers
create(callback, callback_context)DruidEvent constructor
is_empty(self)Return true, if event not have handler
is_exist(self)Return true, if event have at lease one handler
is_subscribed(self, callback, callback_context)Check is event subscribed.
subscribe(self, callback, callback_context)Subscribe callback on event
trigger(self, ...)Trigger the event and call all subscribed callbacks
unsubscribe(self, callback, callback_context)Unsubscribe callback on event
- -
-
- - -

Functions

- -
-
- - clear(self) -
-
- Clear the all event handlers - - -

Parameters:

- - - - - -

Usage:

-
    -
    button.on_long_click:clear()
    -
- -
-
- - create(callback, callback_context) -
-
- DruidEvent constructor - - -

Parameters:

-
    -
  • callback - function or nil - Subscribe the callback on new event, if callback exist -
  • -
  • callback_context - any or nil - Additional context as first param to callback call -
  • -
- - - - -

Usage:

-
    -
    local Event = require("druid.event")
    -...
    -local event = Event(callback)
    -
- -
-
- - is_empty(self) -
-
- Return true, if event not have handler - - -

Parameters:

- - -

Returns:

-
    - - boolean - True if event not have handlers -
- - - -

Usage:

-
    -
    local is_long_click_handler_not_exists = button.on_long_click:is_empty()
    -
- -
-
- - is_exist(self) -
-
- Return true, if event have at lease one handler - - -

Parameters:

- - -

Returns:

-
    - - boolean - True if event have handlers -
- - - -

Usage:

-
    -
    local is_long_click_handler_exists = button.on_long_click:is_exist()
    -
- -
-
- - is_subscribed(self, callback, callback_context) -
-
- Check is event subscribed. - - -

Parameters:

-
    -
  • self - DruidEvent - DruidEvent -
  • -
  • callback - function - Callback itself -
  • -
  • callback_context - any or nil - Additional context as first param to callback call -
  • -
- -

Returns:

-
    - - boolean, - number|nil @Is event subscribed, return index of callback in event as second param -
- - - - -
-
- - subscribe(self, callback, callback_context) -
-
- Subscribe callback on event - - -

Parameters:

-
    -
  • self - DruidEvent - DruidEvent -
  • -
  • callback - function - Callback itself -
  • -
  • callback_context - any or nil - Additional context as first param to callback call, usually it's self -
  • -
- -

Returns:

-
    - - boolean - True if callback was subscribed -
- - - -

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)
    -
- -
-
- - trigger(self, ...) -
-
- Trigger the event and call all subscribed callbacks - - -

Parameters:

-
    -
  • self - DruidEvent - DruidEvent -
  • -
  • ... - any - All event params -
  • -
- - - - -

Usage:

-
    -
    local Event = require("druid.event")
    -...
    -local event = Event()
    -event:trigger("Param1", "Param2")
    -
- -
-
- - unsubscribe(self, callback, callback_context) -
-
- Unsubscribe callback on event - - -

Parameters:

-
    -
  • self - DruidEvent - DruidEvent -
  • -
  • callback - function - Callback itself -
  • -
  • callback_context - any or nil - 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)
    -
- -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/DruidInstance.html b/docs/modules/DruidInstance.html deleted file mode 100644 index afa2ecb..0000000 --- a/docs/modules/DruidInstance.html +++ /dev/null @@ -1,1223 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module DruidInstance

-

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()).

-

See also:

- -

Usage:

-
    -
    local druid = require("druid.druid")
    -
    -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
    -
    -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
final(self)Call this in gui_script final function.
new_back_handler(self, callback, params)Create BackHandler component
new_blocker(self, node)Create Blocker component
new_button(self, node, callback, params, anim_node)Create Button component
new_data_list(self, druid_scroll, druid_grid, create_function)Create DataList component
new_drag(self, node, on_drag_callback)Create Drag component
new_dynamic_grid(self, parent_node)Create DynamicGrid component - Deprecated
new_hotkey(self, keys_array, callback, callback_argument)Create Hotkey component
new_hover(self, node, on_hover_callback, on_mouse_hover_callback)Create Hover component
new_input(self, click_node, text_node, keyboard_type)Create Input component
new_lang_text(self, node, locale_id, adjust_type)Create LangText component
new_layout(self, node, mode)Create Layout component
new_progress(self, node, key, init_value)Create Progress component
new_rich_input(self, template, nodes)Create RichInput component.
new_rich_text(self, text_node, value)Create RichText component.
new_scroll(self, view_node, content_node)Create Scroll component
new_slider(self, pin_node, end_pos, callback)Create Slider component
new_static_grid(self, parent_node, item, in_row)Create StaticGrid component
new_swipe(self, node, on_swipe_callback)Create Swipe component
new_text(self, node, value, no_adjust)Create Text component
new_timer(self, node, seconds_from, seconds_to, callback)Create Timer component
on_input(self, action_id, action)Call this in gui_script on_input function.
on_message(self, message_id, message, sender)Call this in gui_script on_message function.
remove(self, component)Remove created component from Druid instance.
set_blacklist(self, blacklist_components)Set blacklist components for input processing.
set_whitelist(self, whitelist_components)Set whitelist components for input processing.
update(self, dt)Call this in gui_script update function.
- -
-
- - -

Functions

- -
-
- - final(self) -
-
- Call this in gui_script final function. - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
- - - - - -
-
- - new_back_handler(self, callback, params) -
-
- Create BackHandler component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • callback - function or nil - @The callback(self, custom_args) to call on back event -
  • -
  • params - any or nil - Callback argument -
  • -
- -

Returns:

-
    - - BackHandler - BackHandler component -
- - - - -
-
- - new_blocker(self, node) -
-
- Create Blocker component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The node_id or gui.get_node(node_id) -
  • -
- -

Returns:

-
    - - Blocker - Blocker component -
- - - - -
-
- - new_button(self, node, callback, params, anim_node) -
-
- Create Button component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The node_id or gui.get_node(node_id) -
  • -
  • callback - function or nil - Button callback -
  • -
  • params - any or nil - Button callback params -
  • -
  • anim_node - node, string or nil - Button anim node (node, if not provided) -
  • -
- -

Returns:

-
    - - Button - Button component -
- - - - -
-
- - new_data_list(self, druid_scroll, druid_grid, create_function) -
-
- Create DataList component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • druid_scroll - Scroll - The Scroll instance for Data List component -
  • -
  • druid_grid - StaticGrid - The StaticGrid or DynamicGrid instance for Data List component -
  • -
  • create_function - function - The create function callback(self, data, index, data_list). Function should return (node, [component]) -
  • -
- -

Returns:

-
    - - DataList - DataList component -
- - - - -
-
- - new_drag(self, node, on_drag_callback) -
-
- Create Drag component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The node_id or gui.get_node(node_id). Will used as user input node. -
  • -
  • on_drag_callback - function or nil - Callback for on_drag_event(self, dx, dy) -
  • -
- -

Returns:

-
    - - Drag - Drag component -
- - - - -
-
- - new_dynamic_grid(self, parent_node) -
-
- Create DynamicGrid component - Deprecated - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • parent_node - string or node - The node_id or gui.get_node(node_id). Parent of all Grid items. -
  • -
- -

Returns:

-
    - - DynamicGrid - DynamicGrid component -
- - - - -
-
- - new_hotkey(self, keys_array, callback, callback_argument) -
-
- Create Hotkey component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • keys_array - string or string[] - Keys for trigger action. Should contains one action key and any amount of modificator keys -
  • -
  • callback - function - The callback function -
  • -
  • callback_argument - any or nil - The argument to pass into the callback function -
  • -
- -

Returns:

-
    - - Hotkey - Hotkey component -
- - - - -
-
- - new_hover(self, node, on_hover_callback, on_mouse_hover_callback) -
-
- Create Hover component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The node_id or gui.get_node(node_id) -
  • -
  • on_hover_callback - function or nil - Hover callback -
  • -
  • on_mouse_hover_callback - function or nil - Mouse hover callback -
  • -
- -

Returns:

-
    - - Hover - Hover component -
- - - - -
-
- - new_input(self, click_node, text_node, keyboard_type) -
-
- Create Input component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • click_node - string or node - Button node to enabled input component -
  • -
  • text_node - string, node or druid.text - Text node what will be changed on user input -
  • -
  • keyboard_type - number or nil - Gui keyboard type for input field -
  • -
- -

Returns:

-
    - - Input - Input component -
- - - - -
-
- - new_lang_text(self, node, locale_id, adjust_type) -
-
- Create LangText component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The_node id or gui.get_node(node_id) -
  • -
  • locale_id - string or nil - Default locale id or text from node as default -
  • -
  • adjust_type - string or nil - Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE -
  • -
- -

Returns:

-
    - - LangText - LangText component -
- - - - -
-
- - new_layout(self, node, mode) -
-
- Create Layout component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The_node id or gui.get_node(node_id). -
  • -
  • mode - string - The layout mode -
  • -
- -

Returns:

-
    - - Layout - Layout component -
- - - - -
-
- - new_progress(self, node, key, init_value) -
-
- Create Progress component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - Progress bar fill node or node name -
  • -
  • key - string - Progress bar direction: const.SIDE.X or const.SIDE.Y -
  • -
  • init_value - number or nil - Initial value of progress bar. Default: 1 -
  • -
- -

Returns:

-
    - - Progress - Progress component -
- - - - -
-
- - new_rich_input(self, template, nodes) -
-
- Create RichInput component. - As a template please check rich_input.gui layout. - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • template - string - The template string name -
  • -
  • nodes - table - Nodes table from gui.clone_tree -
  • -
- -

Returns:

-
    - - RichInput - RichInput component -
- - - - -
-
- - new_rich_text(self, text_node, value) -
-
- Create RichText component. - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • text_node - string or node - The text node to make Rich Text -
  • -
  • value - string or nil - The initial text value. Default will be gui.get_text(text_node) -
  • -
- -

Returns:

-
    - - RichText - RichText component -
- - - - -
-
- - new_scroll(self, view_node, content_node) -
-
- Create Scroll component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • view_node - string or node - The node_id or gui.get_node(node_id). Will used as user input node. -
  • -
  • content_node - string or node - The node_id or gui.get_node(node_id). Will used as scrollable node inside view_node. -
  • -
- -

Returns:

-
    - - Scroll - Scroll component -
- - - - -
-
- - new_slider(self, pin_node, end_pos, callback) -
-
- Create Slider component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • pin_node - string or node - The_node id or gui.get_node(node_id). -
  • -
  • end_pos - vector3 - The end position of slider -
  • -
  • callback - function or nil - On slider change callback -
  • -
- -

Returns:

-
    - - Slider - Slider component -
- - - - -
-
- - new_static_grid(self, parent_node, item, in_row) -
-
- Create StaticGrid component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • parent_node - string or node - The node_id or gui.get_node(node_id). Parent of all Grid items. -
  • -
  • item - string or node - Item prefab. Required to get grid's item size. Can be adjusted separately. -
  • -
  • in_row - number or nil - How many nodes in row can be placed -
  • -
- -

Returns:

-
    - - StaticGrid - StaticGrid component -
- - - - -
-
- - new_swipe(self, node, on_swipe_callback) -
-
- Create Swipe component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The node_id or gui.get_node(node_id). Will used as user input node. -
  • -
  • on_swipe_callback - function or nil - Swipe callback for on_swipe_end event -
  • -
- -

Returns:

-
    - - Swipe - Swipe component -
- - - - -
-
- - new_text(self, node, value, no_adjust) -
-
- Create Text component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - The node_id or gui.get_node(node_id) -
  • -
  • value - string or nil - Initial text. Default value is node text from GUI scene. -
  • -
  • no_adjust - boolean or nil - If true, text will be not auto-adjust size -
  • -
- -

Returns:

-
    - - Text - Text component -
- - - - -
-
- - new_timer(self, node, seconds_from, seconds_to, callback) -
-
- Create Timer component - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • node - string or node - Gui text node -
  • -
  • seconds_from - number - Start timer value in seconds -
  • -
  • seconds_to - number or nil - End timer value in seconds -
  • -
  • callback - function or nil - Function on timer end -
  • -
- -

Returns:

-
    - - Timer - Timer component -
- - - - -
-
- - on_input(self, action_id, action) -
-
- Call this in gui_script on_input function. -

Used for almost all components - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • action_id - hash - Action_id from on_input -
  • -
  • action - table - Action from on_input -
  • -
- -

Returns:

-
    - - boolean - The boolean value is input was consumed -
- - - - -
-
- - on_message(self, message_id, message, sender) -
-
- Call this in gui_script on_message function. -

Used for special actions. See SPECIFIC_UI_MESSAGES table - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • message_id - hash - Message_id from on_message -
  • -
  • message - table - Message from on_message -
  • -
  • sender - url - Sender from on_message -
  • -
- - - - - -
-
- - remove(self, component) -
-
- Remove created component from Druid instance. -

Component `on_remove` function will be invoked, if exist. - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • component - BaseComponent - Component instance -
  • -
- -

Returns:

-
    - - boolean - True if component was removed -
- - - - -
-
- - set_blacklist(self, blacklist_components) -
-
- 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 - - -

Parameters:

-
    -
  • self - DruidInstance - DruidInstance -
  • -
  • blacklist_components - table, BaseComponent or nil - The array of component to blacklist -
  • -
- -

Returns:

-
    - - self - DruidInstance -
- - - - -
-
- - set_whitelist(self, whitelist_components) -
-
- 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 - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • whitelist_components - table, BaseComponent or nil - The array of component to whitelist -
  • -
- -

Returns:

-
    - - self - DruidInstance -
- - - - -
-
- - update(self, dt) -
-
- Call this in gui_script update function. -

Used for: scroll, progress, timer components - - -

Parameters:

-
    -
  • self - DruidInstance - -
  • -
  • dt - number - Delta time -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/DynamicGrid.html b/docs/modules/DynamicGrid.html deleted file mode 100644 index d6e7af6..0000000 --- a/docs/modules/DynamicGrid.html +++ /dev/null @@ -1,788 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module DynamicGrid

-

Component to handle placing components in row

-

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_get_side_vector(self, side, is_forward)Return side vector to correct node shifting
add(self, node, index, shift_policy, is_instant)Add new node to the grid
clear(self)Clear grid nodes array.
get_all_pos(self)Return array of all node positions
get_borders(self)Return grid content borders
get_index_by_node(self, node)Return grid index by node
get_offset(self)Return DynamicGrid offset, where DynamicGrid content starts.
get_pos(self, index, node, origin_index)Return pos for grid node index
get_size(self, border)Return grid content size
init(self, parent)The DynamicGrid constructor
remove(self, index, shift_policy, is_instant)Remove the item from the grid.
set_position_function(self, callback)Change set position function for grid nodes.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
borderThe size of item content
first_indexThe first index of node in grid
last_indexThe last index of node in grid
node_sizeItem size
nodesList of all grid elements.
on_add_itemOn item add callback(self, node, index)
on_change_itemsOn item add or remove callback(self, index)
on_clearOn grid clear callback(self)
on_remove_itemOn item remove callback(self, index)
on_update_positionsOn update item positions callback(self)
parentParent gui node
- -
-
- - -

Functions

- -
-
- - _get_side_vector(self, side, is_forward) -
-
- Return side vector to correct node shifting - - -

Parameters:

-
    -
  • self - -
  • -
  • side - -
  • -
  • is_forward - -
  • -
- - - - - -
-
- - add(self, node, index, shift_policy, is_instant) -
-
- Add new node to the grid - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • node - node - Gui node -
  • -
  • index - number or nil - The node position. By default add as last node -
  • -
  • shift_policy - number or nil - How shift nodes, if required. Default: const.SHIFT.RIGHT -
  • -
  • is_instant - boolean or nil - If true, update node positions instantly -
  • -
- - - - - -
-
- - clear(self) -
-
- Clear grid nodes array. GUI nodes will be not deleted! - If you want to delete GUI nodes, use dynamic_grid.nodes array before grid:clear - - -

Parameters:

- - -

Returns:

-
    - - druid.dynamic_grid - Current grid instance -
- - - - -
-
- - get_all_pos(self) -
-
- Return array of all node positions - - -

Parameters:

- - -

Returns:

-
    - - vector3[] - All grid node positions -
- - - - -
-
- - get_borders(self) -
-
- Return grid content borders - - -

Parameters:

- - -

Returns:

-
    - - vector3 - The grid content borders -
- - - - -
-
- - get_index_by_node(self, node) -
-
- Return grid index by node - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • node - node - The gui node in the grid -
  • -
- -

Returns:

-
    - - number - The node index -
- - - - -
-
- - get_offset(self) -
-
- Return DynamicGrid offset, where DynamicGrid content starts. - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid The DynamicGrid instance -
  • -
- -

Returns:

-
    - - vector3 - The DynamicGrid offset -
- - - - -
-
- - get_pos(self, index, node, origin_index) -
-
- Return pos for grid node index - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • index - number - The grid element index -
  • -
  • node - node - The node to be placed -
  • -
  • origin_index - number or nil - Index of nearby node -
  • -
- -

Returns:

-
    - - vector3 - node position -
- - - - -
-
- - get_size(self, border) -
-
- Return grid content size - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • border - vector3 - -
  • -
- -

Returns:

-
    - - vector3 - The grid content size -
- - - - -
-
- - init(self, parent) -
-
- The DynamicGrid constructor - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • parent - node - The gui node parent, where items will be placed -
  • -
- - - - - -
-
- - remove(self, index, shift_policy, is_instant) -
-
- Remove the item from the grid. Note that gui node will be not deleted - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • index - number - The grid node index to remove -
  • -
  • shift_policy - number or nil - How shift nodes, if required. Default: const.SHIFT.RIGHT -
  • -
  • is_instant - boolean or nil - If true, update node positions instantly -
  • -
- -

Returns:

-
    - - node - The deleted gui node from grid -
- - - - -
-
- - set_position_function(self, callback) -
-
- Change set position function for grid nodes. It will call on - update poses on grid elements. Default: gui.set_position - - -

Parameters:

-
    -
  • self - DynamicGrid - DynamicGrid -
  • -
  • callback - function - Function on node set position -
  • -
- -

Returns:

-
    - - druid.dynamic_grid - Current grid instance -
- - - - -
-
-

Fields

- -
-
- - border -
-
- The size of item content - - -
    -
  • border - vector4 - -
  • -
- - - - - -
-
- - first_index -
-
- The first index of node in grid - - -
    -
  • first_index - number - -
  • -
- - - - - -
-
- - last_index -
-
- The last index of node in grid - - -
    -
  • last_index - number - -
  • -
- - - - - -
-
- - node_size -
-
- Item size - - -
    -
  • node_size - vector3 - -
  • -
- - - - - -
-
- - nodes -
-
- List of all grid elements. Contains from node, pos, size, pivot - - -
    -
  • nodes - node[] - -
  • -
- - - - - -
-
- - on_add_item -
-
- On item add callback(self, node, index) - - - - - - - - -
-
- - on_change_items -
-
- On item add or remove callback(self, index) - - - - - - - - -
-
- - on_clear -
-
- On grid clear callback(self) - - - - - - - - -
-
- - on_remove_item -
-
- On item remove callback(self, index) - - - - - - - - -
-
- - on_update_positions -
-
- On update item positions callback(self) - - -
    -
  • on_update_positions - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - parent -
-
- Parent gui node - - -
    -
  • parent - node - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Helper.html b/docs/modules/Helper.html deleted file mode 100644 index 1bc2ed6..0000000 --- a/docs/modules/Helper.html +++ /dev/null @@ -1,927 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Helper

-

Helper module with various usefull GUI functions.

-

-

Usage:

-
    -
    local helper = require("druid.helper")
    -helper.centrate_nodes(0, node_1, node_2)
    -
    -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
helper.add_array(target, source)Add all elements from source array to the target array
helper.centrate_nodes(margin, ...)Centerate nodes by x position with margin.
helper.clamp(a, min, max)Clamp value between min and max
helper.contains(t, value)Check if value is in array and return index of it
helper.deepcopy(orig_table)Make a copy table with all nested tables
helper.distance(x1, y1, x2, y2)Calculate distance between two points
helper.get_border(node, offset)Distance from node position to his borders
helper.get_closest_stencil_node(node)Return closest non inverted clipping parent node for given node
helper.get_gui_scale()Get current GUI scale for each side
helper.get_pivot_offset(pivot)Get node offset for given GUI pivot.
helper.get_scaled_size(node)Get node size adjusted by scale
helper.get_scene_scale(node, include_passed_node_scale)Get cumulative parent's node scale
helper.get_screen_aspect_koef()Get current screen stretch multiplier for each side
helper.get_text_metrics_from_node(text_node)Get text metric from GUI node.
helper.insert_with_shift(array, any, index, shift_policy)Add value to array with shift policy
helper.is_mobile()Check if device is native mobile (Android or iOS)
helper.is_multitouch_supported()Check if device is mobile and can support multitouch
helper.is_web()Check if device is HTML5
helper.is_web_mobile()Check if device is HTML5 mobile
helper.lerp(a, b, t)Lerp between two values
helper.remove_with_shift(array, index, shift_policy)Remove value from array with shift policy
helper.round(num, num_decimal_places)Round number to specified decimal places
helper.sign(val)Return sign of value (-1, 0, 1)
helper.step(current, target, step)Move value from current to target value with step amount
helper.table_to_string(t)Simple table to one-line string converter
- -
-
- - -

Functions

- -
-
- - helper.add_array(target, source) -
-
- Add all elements from source array to the target array - - -

Parameters:

-
    -
  • target - any[] - Array to put elements from source -
  • -
  • source - any[] or nil - The source array to get elements from -
  • -
- -

Returns:

-
    - - any[] - The target array -
- - - - -
-
- - helper.centrate_nodes(margin, ...) -
-
- 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. - - -

Parameters:

-
    -
  • margin - number or nil - Offset between nodes -
  • -
  • ... - Gui nodes -
  • -
- - - - - -
-
- - helper.clamp(a, min, max) -
-
- Clamp value between min and max - - -

Parameters:

-
    -
  • a - number - Value -
  • -
  • min - number - Min value -
  • -
  • max - number - Max value -
  • -
- -

Returns:

-
    - - number - Clamped value -
- - - - -
-
- - helper.contains(t, value) -
-
- Check if value is in array and return index of it - - -

Parameters:

-
    -
  • t - table - Array -
  • -
  • value - Value -
  • -
- -

Returns:

-
    - - number or nil - Index of value or nil -
- - - - -
-
- - helper.deepcopy(orig_table) -
-
- Make a copy table with all nested tables - - -

Parameters:

-
    -
  • orig_table - table - Original table -
  • -
- -

Returns:

-
    - - table - Copy of original table -
- - - - -
-
- - helper.distance(x1, y1, x2, y2) -
-
- Calculate distance between two points - - -

Parameters:

-
    -
  • x1 - number - First point x -
  • -
  • y1 - number - First point y -
  • -
  • x2 - number - Second point x -
  • -
  • y2 - number - Second point y -
  • -
- -

Returns:

-
    - - number - Distance -
- - - - -
-
- - helper.get_border(node, offset) -
-
- Distance from node position to his borders - - -

Parameters:

-
    -
  • node - node - GUI node -
  • -
  • offset - vector3 or nil - Offset from node position. Pass current node position to get non relative border values -
  • -
- -

Returns:

-
    - - vector4 - Vector4 with border values (left, top, right, down) -
- - - - -
-
- - helper.get_closest_stencil_node(node) -
-
- Return closest non inverted clipping parent node for given node - - -

Parameters:

-
    -
  • node - node - GUI node -
  • -
- -

Returns:

-
    - - node or nil - The closest stencil node or nil -
- - - - -
-
- - helper.get_gui_scale() -
-
- Get current GUI scale for each side - - - -

Returns:

-
    -
  1. - number - scale_x
  2. -
  3. - number - scale_y
  4. -
- - - - -
-
- - helper.get_pivot_offset(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. - - -

Parameters:

-
    -
  • pivot - number - The gui.PIVOT_* constant -
  • -
- -

Returns:

-
    - - vector3 - Vector offset with [-0.5..0.5] values -
- - - - -
-
- - helper.get_scaled_size(node) -
-
- Get node size adjusted by scale - - -

Parameters:

-
    -
  • node - node - GUI node -
  • -
- -

Returns:

-
    - - vector3 - Scaled size -
- - - - -
-
- - helper.get_scene_scale(node, include_passed_node_scale) -
-
- Get cumulative parent's node scale - - -

Parameters:

-
    -
  • node - node - Gui node -
  • -
  • include_passed_node_scale - boolean or nil - True if add current node scale to result -
  • -
- -

Returns:

-
    - - vector3 - The scene node scale -
- - - - -
-
- - helper.get_screen_aspect_koef() -
-
- Get current screen stretch multiplier for each side - - - -

Returns:

-
    -
  1. - number - stretch_x
  2. -
  3. - number - stretch_y
  4. -
- - - - -
-
- - helper.get_text_metrics_from_node(text_node) -
-
- Get text metric from GUI node. - - -

Parameters:

-
    -
  • text_node - node - -
  • -
- -

Returns:

-
    - - GUITextMetrics - -
- - - -

Usage:

-
    -
    type GUITextMetrics = {
    -  width: number,
    -  height: number,
    -  max_ascent: number,
    -  max_descent: number
    -}
    -
- -
-
- - helper.insert_with_shift(array, any, index, shift_policy) -
-
- Add value to array with shift policy Shift policy can be: left, right, no_shift - - -

Parameters:

-
    -
  • array - table - Array -
  • -
  • any - Item to insert -
  • -
  • index - number or nil - Index to insert. If nil, item will be inserted at the end of array -
  • -
  • shift_policy - number or nil - The druid_const.SHIFT.* constant -
  • -
- -

Returns:

-
    - - any - Inserted item -
- - - - -
-
- - helper.is_mobile() -
-
- Check if device is native mobile (Android or iOS) - - - -

Returns:

-
    - - boolean - Is mobile -
- - - - -
-
- - helper.is_multitouch_supported() -
-
- Check if device is mobile and can support multitouch - - - -

Returns:

-
    - - boolean - Is multitouch supported -
- - - - -
-
- - helper.is_web() -
-
- Check if device is HTML5 - - - -

Returns:

-
    - - boolean - Is web -
- - - - -
-
- - helper.is_web_mobile() -
-
- Check if device is HTML5 mobile - - - -

Returns:

-
    - - boolean - Is web mobile -
- - - - -
-
- - helper.lerp(a, b, t) -
-
- Lerp between two values - - -

Parameters:

-
    -
  • a - number - First value -
  • -
  • b - number - Second value -
  • -
  • t - number - Lerp amount -
  • -
- -

Returns:

-
    - - number - Lerped value -
- - - - -
-
- - helper.remove_with_shift(array, index, shift_policy) -
-
- Remove value from array with shift policy Shift policy can be: left, right, no_shift - - -

Parameters:

-
    -
  • array - table - Array -
  • -
  • index - number or nil - Index to remove. If nil, item will be removed from the end of array -
  • -
  • shift_policy - number or nil - The druid_const.SHIFT.* constant -
  • -
- -

Returns:

-
    - - any - Removed item -
- - - - -
-
- - helper.round(num, num_decimal_places) -
-
- Round number to specified decimal places - - -

Parameters:

-
    -
  • num - number - Number -
  • -
  • num_decimal_places - number or nil - Decimal places -
  • -
- -

Returns:

-
    - - number - Rounded number -
- - - - -
-
- - helper.sign(val) -
-
- Return sign of value (-1, 0, 1) - - -

Parameters:

-
    -
  • val - number - Value -
  • -
- -

Returns:

-
    - - number - Sign -
- - - - -
-
- - helper.step(current, target, step) -
-
- Move value from current to target value with step amount - - -

Parameters:

-
    -
  • current - number - Current value -
  • -
  • target - number - Target value -
  • -
  • step - number - Step amount -
  • -
- -

Returns:

-
    - - number - New value -
- - - - -
-
- - helper.table_to_string(t) -
-
- Simple table to one-line string converter - - -

Parameters:

- - -

Returns:

-
    - - string - -
- - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Hotkey.html b/docs/modules/Hotkey.html deleted file mode 100644 index 6237aa5..0000000 --- a/docs/modules/Hotkey.html +++ /dev/null @@ -1,373 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Hotkey

-

Druid hotkey component

-

Example Link

- - -

Functions

- - - - - - - - - - - - - -
add_hotkey(self, keys, callback_argument)Add hotkey for component callback
init(self, keys, callback, callback_argument)The Hotkey constructor
set_repeat(self, is_enabled_repeated)If true, the callback will be triggered on action.repeated
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - -
buttonButton component from click_node
click_nodeButton trigger node
nodeVisual node
on_hotkey_pressedOn hotkey released callback(self, argument)
on_hotkey_releasedOn hotkey released callback(self, argument)
- -
-
- - -

Functions

- -
-
- - add_hotkey(self, keys, callback_argument) -
-
- Add hotkey for component callback - - -

Parameters:

-
    -
  • self - Hotkey - Hotkey -
  • -
  • keys - string[], hash[], string or hash - that have to be pressed before key pressed to activate -
  • -
  • callback_argument - any or nil - The argument to pass into the callback function -
  • -
- -

Returns:

-
    - - Hotkey - Current instance -
- - - - -
-
- - init(self, keys, callback, callback_argument) -
-
- The Hotkey constructor - - -

Parameters:

-
    -
  • self - Hotkey - Hotkey -
  • -
  • keys - string[] or string - The keys to be pressed for trigger callback. Should contains one key and any modificator keys -
  • -
  • callback - function - The callback function -
  • -
  • callback_argument - any or nil - The argument to pass into the callback function -
  • -
- - - - - -
-
- - set_repeat(self, is_enabled_repeated) -
-
- If true, the callback will be triggered on action.repeated - - -

Parameters:

-
    -
  • self - Hotkey - Hotkey -
  • -
  • is_enabled_repeated - bool - The flag value -
  • -
- -

Returns:

-
    - - Hotkey - -
- - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • MODIFICATORS - string[] - The list of action_id as hotkey modificators -
  • -
- - - - - -
-
-

Fields

- -
-
- - button -
-
- Button component from click_node - - -
    -
  • button - Button - Button -
  • -
- - - - - -
-
- - click_node -
-
- Button trigger node - - -
    -
  • click_node - node or nil - -
  • -
- - - - - -
-
- - node -
-
- Visual node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_hotkey_pressed -
-
- On hotkey released callback(self, argument) - - -
    -
  • on_hotkey_pressed - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - on_hotkey_released -
-
- On hotkey released callback(self, argument) - - -
    -
  • on_hotkey_released - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Hover.html b/docs/modules/Hover.html deleted file mode 100644 index 65c7eed..0000000 --- a/docs/modules/Hover.html +++ /dev/null @@ -1,469 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Hover

-

Component to handle hover node interaction

-

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
init(self, node, on_hover_callback, on_mouse_hover)The Hover constructor
is_enabled(self)Return current hover enabled state
is_hovered(self)Return current hover state.
is_mouse_hovered(self)Return current hover state.
set_click_zone(self, zone)Strict hover click area.
set_enabled(self, state)Set enable state of hover component.
set_hover(self, state)Set hover state
set_mouse_hover(self, state)Set mouse hover state
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - -
nodeHover node
on_hoverOn hover callback(self, state, hover_instance)
on_mouse_hoverOn mouse hover callback(self, state, hover_instance)
- -
-
- - -

Functions

- -
-
- - init(self, node, on_hover_callback, on_mouse_hover) -
-
- The Hover constructor - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
  • node - node - Gui node -
  • -
  • on_hover_callback - function - Hover callback -
  • -
  • on_mouse_hover - function - On mouse hover callback -
  • -
- - - - - -
-
- - is_enabled(self) -
-
- Return current hover enabled state - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
- -

Returns:

-
    - - boolean - The hover enabled state -
- - - - -
-
- - is_hovered(self) -
-
- Return current hover state. True if touch action was on the node at current time - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
- -

Returns:

-
    - - boolean - The current hovered state -
- - - - -
-
- - is_mouse_hovered(self) -
-
- Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
- -

Returns:

-
    - - boolean - The current hovered state -
- - - - -
-
- - set_click_zone(self, zone) -
-
- Strict hover click area. Useful for - no click events outside stencil node - - -

Parameters:

- - - - - - -
-
- - set_enabled(self, state) -
-
- Set enable state of hover component. - If hover is not enabled, it will not generate - any hover events - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
  • state - boolean or nil - The hover enabled state -
  • -
- - - - - -
-
- - set_hover(self, state) -
-
- Set hover state - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
  • state - boolean or nil - The hover state -
  • -
- - - - - -
-
- - set_mouse_hover(self, state) -
-
- Set mouse hover state - - -

Parameters:

-
    -
  • self - Hover - Hover -
  • -
  • state - boolean or nil - The mouse hover state -
  • -
- - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • ON_HOVER_CURSOR - string - Mouse hover style on node hover - (optional) -
  • -
  • ON_MOUSE_HOVER_CURSOR - string - Mouse hover style on node mouse hover - (optional) -
  • -
- - - - - -
-
-

Fields

- -
-
- - node -
-
- Hover node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_hover -
-
- On hover callback(self, state, hover_instance) - - - - - - - - -
-
- - on_mouse_hover -
-
- On mouse hover callback(self, state, hover_instance) - - - - - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Input.html b/docs/modules/Input.html deleted file mode 100644 index ee1a9e4..0000000 --- a/docs/modules/Input.html +++ /dev/null @@ -1,1086 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Input

-

Druid input text component.

-

- Carry on user text input -

Example Link

-

Info:

-
    -
  • Author: Part of code from Britzl gooey input component
  • -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
get_text(self)Return current input field text
get_text_selected_replaced(self, text)Replace selected text with new text
init(self, click_node, text_node, keyboard_type)The Input constructor
move_selection(self, delta, is_add_to_selection, is_move_to_end)Change cursor position by delta
reset_changes(self)Reset current input selection and return previous value
select(self)Select input field.
select_cursor(self, cursor_index, start_index, end_index)Set cursor position in input field
set_allowed_characters(self, characters)Set allowed charaters for input field.
set_max_length(self, max_length)Set maximum length for input field.
set_text(self, input_text)Set text for input field
unselect(self)Remove selection from input.
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
allowerd_charactersPattern matching for user input
buttonButton component
current_valueCurrent input value with marked text
cursor_indexThe cursor index.
end_indexTheselection end index.
is_emptyIs current input is empty now
is_selectedIs current input selected now
keyboard_typeGui keyboard type for input field
marked_text_widthMarked text width
marked_valueMarked text for input field.
max_lengthMax length for input text
on_input_emptyOn input field text change to empty string callback(self, input_text)
on_input_fullOn input field text change to max length string callback(self, input_text)
on_input_selectOn input field select callback(self, input_instance)
on_input_textOn input field text change callback(self, input_text)
on_input_unselectOn input field unselect callback(self, input_text, input_instance)
on_input_wrongOn trying user input with not allowed character callback(self, params, input_text)
on_select_cursor_changeOn cursor position change callback(self, cursor_index, start_index, end_index)
previous_valuePrevious input value
start_indexThe selection start index.
textText component
text_widthText width
valueCurrent input value
- -
-
- - -

Functions

- -
-
- - get_text(self) -
-
- Return current input field text - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
- -

Returns:

-
    - - string - The current input field text -
- - - - -
-
- - get_text_selected_replaced(self, text) -
-
- Replace selected text with new text - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • text - string - The text to replace selected text -
  • -
- -

Returns:

-
    - - string - New input text -
- - - - -
-
- - init(self, click_node, text_node, keyboard_type) -
-
- The Input constructor - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • click_node - node - Node to enabled input component -
  • -
  • text_node - node or Text - Text node what will be changed on user input. You can pass text component instead of text node name Text -
  • -
  • keyboard_type - number or nil - Gui keyboard type for input field -
  • -
- - - - - -
-
- - move_selection(self, delta, is_add_to_selection, is_move_to_end) -
-
- Change cursor position by delta - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • delta - number - side for cursor position, -1 for left, 1 for right -
  • -
  • is_add_to_selection - boolean - (Shift key) -
  • -
  • is_move_to_end - boolean - (Ctrl key) -
  • -
- - - - - -
-
- - reset_changes(self) -
-
- Reset current input selection and return previous value - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
- -

Returns:

-
    - - druid.input - Current input instance -
- - - - -
-
- - select(self) -
-
- Select input field. It will show the keyboard and trigger on_select events - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
- - - - - -
-
- - select_cursor(self, cursor_index, start_index, end_index) -
-
- Set cursor position in input field - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • cursor_index - number or nil - Cursor index for cursor position, if nil - will be set to the end of the text -
  • -
  • start_index - number or nil - Start index for cursor position, if nil - will be set to the end of the text -
  • -
  • end_index - number or nil - End index for cursor position, if nil - will be set to the start_index -
  • -
- -

Returns:

-
    - - druid.input - Current input instance -
- - - - -
-
- - set_allowed_characters(self, characters) -
-
- Set allowed charaters for input field. - See: https://defold.com/ref/stable/string/ - ex: [%a%d] for alpha and numeric - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • characters - string - Regulax exp. for validate user input -
  • -
- -

Returns:

-
    - - druid.input - Current input instance -
- - - - -
-
- - set_max_length(self, max_length) -
-
- Set maximum length for input field. - Pass nil to make input field unliminted (by default) - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • max_length - number - Maximum length for input text field -
  • -
- -

Returns:

-
    - - druid.input - Current input instance -
- - - - -
-
- - set_text(self, input_text) -
-
- Set text for input field - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
  • input_text - string - The string to apply for input field -
  • -
- - - - - -
-
- - unselect(self) -
-
- Remove selection from input. It will hide the keyboard and trigger on_unselect events - - -

Parameters:

-
    -
  • self - Input - Input -
  • -
- - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • IS_LONGTAP_ERASE - boolean - Is long tap will erase current input data. Default: false -
  • -
  • MASK_DEFAULT_CHAR - string - Default character mask for password input. Default: *] -
  • -
  • IS_UNSELECT_ON_RESELECT - boolean - If true, call unselect on select selected input. Default: false -
  • -
  • on_select - function - (self, button_node) Callback on input field selecting -
  • -
  • on_unselect - function - (self, button_node) Callback on input field unselecting -
  • -
  • on_input_wrong - function - (self, button_node) Callback on wrong user input -
  • -
- - - - - -
-
-

Fields

- -
-
- - allowerd_characters -
-
- Pattern matching for user input - - -
    -
  • allowerd_characters - string or nil - -
  • -
- - - - - -
-
- - button -
-
- Button component - - -
    -
  • button - Button - Button -
  • -
- - - - - -
-
- - current_value -
-
- Current input value with marked text - - -
    -
  • current_value - string - -
  • -
- - - - - -
-
- - cursor_index -
-
- The cursor index. The index of letter cursor after. Leftmost cursor - 0 - - -
    -
  • cursor_index - number - -
  • -
- - - - - -
-
- - end_index -
-
- Theselection end index. The index of letter cursor before. Rightmost selection - #text - - -
    -
  • end_index - number - -
  • -
- - - - - -
-
- - is_empty -
-
- Is current input is empty now - - -
    -
  • is_empty - boolean - -
  • -
- - - - - -
-
- - is_selected -
-
- Is current input selected now - - -
    -
  • is_selected - boolean - -
  • -
- - - - - -
-
- - keyboard_type -
-
- Gui keyboard type for input field - - -
    -
  • keyboard_type - number - -
  • -
- - - - - -
-
- - marked_text_width -
-
- Marked text width - - -
    -
  • marked_text_width - number - -
  • -
- - - - - -
-
- - marked_value -
-
- Marked text for input field. Info: https://defold.com/manuals/input-key-and-text/#marked-text - - -
    -
  • marked_value - string - -
  • -
- - - - - -
-
- - max_length -
-
- Max length for input text - - -
    -
  • max_length - number or nil - -
  • -
- - - - - -
-
- - on_input_empty -
-
- On input field text change to empty string callback(self, input_text) - - - - - - - - -
-
- - on_input_full -
-
- On input field text change to max length string callback(self, input_text) - - - - - - - - -
-
- - on_input_select -
-
- On input field select callback(self, input_instance) - - - - - - - - -
-
- - on_input_text -
-
- On input field text change callback(self, input_text) - - - - - - - - -
-
- - on_input_unselect -
-
- On input field unselect callback(self, input_text, input_instance) - - -
    -
  • on_input_unselect - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - on_input_wrong -
-
- On trying user input with not allowed character callback(self, params, input_text) - - - - - - - - -
-
- - on_select_cursor_change -
-
- On cursor position change callback(self, cursor_index, start_index, end_index) - - -
    -
  • on_select_cursor_change - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - previous_value -
-
- Previous input value - - -
    -
  • previous_value - string - -
  • -
- - - - - -
-
- - start_index -
-
- The selection start index. The index of letter cursor after. Leftmost selection - 0 - - -
    -
  • start_index - number - -
  • -
- - - - - -
-
- - text -
-
- Text component - - -
    -
  • text - Text - Text -
  • -
- - - - - -
-
- - text_width -
-
- Text width - - -
    -
  • text_width - number - -
  • -
- - - - - -
-
- - value -
-
- Current input value - - - - - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/LangText.html b/docs/modules/LangText.html deleted file mode 100644 index be1a8b1..0000000 --- a/docs/modules/LangText.html +++ /dev/null @@ -1,380 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module LangText

-

Component to wrap over GUI Text nodes with localization helpers -

# Overview # -

• The initialization of druid.set_text_function is required to enable localization - using the localization ID.

-

-

• The LangText component supports up to 7 string format parameters. - This limitation exists due to certain issues with using ... arguments. -

# Notes # -

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - -
format(self, a, b, c, d, e, f, g)Format string with new text params on localized text
init(self, node, locale_id, adjust_type)The LangText constructor
set_to(self, text)Setup raw text to lang_text component
translate(self, locale_id, a, b, c, d, e, f, g)Translate the text by locale_id
-

Fields

- - - - - - - - - - - - - -
nodeText node
on_changeOn change text callback
textThe text component
- -
-
- - -

Functions

- -
-
- - format(self, a, b, c, d, e, f, g) -
-
- Format string with new text params on localized text - - -

Parameters:

-
    -
  • self - LangText - LangText -
  • -
  • a - string or nil - Optional param to string.format -
  • -
  • b - string or nil - Optional param to string.format -
  • -
  • c - string or nil - Optional param to string.format -
  • -
  • d - string or nil - Optional param to string.format -
  • -
  • e - string or nil - Optional param to string.format -
  • -
  • f - string or nil - Optional param to string.format -
  • -
  • g - string or nil - Optional param to string.format -
  • -
- -

Returns:

-
    - - LangText - Current instance -
- - - - -
-
- - init(self, node, locale_id, adjust_type) -
-
- The LangText constructor - - -

Parameters:

-
    -
  • self - LangText - LangText -
  • -
  • node - string or node - The node_id or gui.get_node(node_id) -
  • -
  • locale_id - string or nil - Default locale id or text from node as default -
  • -
  • adjust_type - string or nil - Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference -
  • -
- - - - - -
-
- - set_to(self, text) -
-
- Setup raw text to lang_text component - - -

Parameters:

-
    -
  • self - LangText - LangText -
  • -
  • text - string - Text for text node -
  • -
- -

Returns:

-
    - - LangText - Current instance -
- - - - -
-
- - translate(self, locale_id, a, b, c, d, e, f, g) -
-
- Translate the text by locale_id - - -

Parameters:

-
    -
  • self - LangText - LangText -
  • -
  • locale_id - string - Locale id -
  • -
  • a - string or nil - Optional param to string.format -
  • -
  • b - string or nil - Optional param to string.format -
  • -
  • c - string or nil - Optional param to string.format -
  • -
  • d - string or nil - Optional param to string.format -
  • -
  • e - string or nil - Optional param to string.format -
  • -
  • f - string or nil - Optional param to string.format -
  • -
  • g - string or nil - Optional param to string.format -
  • -
- -

Returns:

-
    - - LangText - Current instance -
- - - - -
-
-

Fields

- -
-
- - node -
-
- Text node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_change -
-
- On change text callback - - - - - - - - -
-
- - text -
-
- The text component - - -
    -
  • text - Text - Text -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Layout.html b/docs/modules/Layout.html deleted file mode 100644 index 0058f48..0000000 --- a/docs/modules/Layout.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Layout

-

Layout management on node

-

Example Link

- - -

Fields

- - - - - - - - - -
modeCurrent layout mode
nodeLayout node
- -
-
- - -

Fields

- -
-
- - mode -
-
- Current layout mode - - - - - - - - -
-
- - node -
-
- Layout node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/PinKnob.html b/docs/modules/PinKnob.html deleted file mode 100644 index d97d64e..0000000 --- a/docs/modules/PinKnob.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module PinKnob

-

Druid pin knob custom component.

-

- It's simple rotating input element

- - -

Functions

- - - - - - - - - - - - - -
init(self, callback, template, nodes)The PinKnob constructor
set_angle(self, cur_value, min, max)Set current and min/max angles for component
set_friction(self, value)Set current and min/max angles for component
-

Fields

- - - - - - - - - - - - - -
druidThe component druid instance
is_dragIs currently under user control
nodeThe pin node
- -
-
- - -

Functions

- -
-
- - init(self, callback, template, nodes) -
-
- The PinKnob constructor - - -

Parameters:

-
    -
  • self - PinKnob - PinKnob -
  • -
  • callback - function - Callback(self, value) on value changed -
  • -
  • template - string - The template string name -
  • -
  • nodes - table - Nodes table from gui.clone_tree -
  • -
- - - - - -
-
- - set_angle(self, cur_value, min, max) -
-
- Set current and min/max angles for component - - -

Parameters:

-
    -
  • self - PinKnob - PinKnob -
  • -
  • cur_value - number - The new value for pin knob -
  • -
  • min - number - The minimum value for pin knob -
  • -
  • max - number - The maximum value for pin knob -
  • -
- -

Returns:

-
    - - PinKnob - PinKnob -
- - - - -
-
- - set_friction(self, value) -
-
- Set current and min/max angles for component - - -

Parameters:

-
    -
  • self - PinKnob - PinKnob -
  • -
  • value - number or nil - The spin speed multiplier. Default: 1 -
  • -
- -

Returns:

-
    - - PinKnob - PinKnob -
- - - - -
-
-

Fields

- -
-
- - druid -
-
- The component druid instance - - - - - - - - -
-
- - is_drag -
-
- Is currently under user control - - -
    -
  • is_drag - boolean - -
  • -
- - - - - -
-
- - node -
-
- The pin node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Progress.html b/docs/modules/Progress.html deleted file mode 100644 index d9fa818..0000000 --- a/docs/modules/Progress.html +++ /dev/null @@ -1,569 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Progress

-

Druid component to handle the progress bars.

-

- # Overview # -

# Notes # -

• Progress Node should be fully filled in your GUI scene node. It will be the progress maximum size -

• Progress correct working with Slice9 nodes, it trying to set size by _set_size_ first, if it is not possible, it set up sizing via _set_scale_ -

• Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene -

• If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles -

- Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
empty(self)Empty a progress bar
fill(self)Fill a progress bar and stop progress animation
get(self)Return current progress bar value
init(self, node, key, init_value)The Progress constructor
set_max_size(self, max_size)Set progress bar max node size
set_steps(self, steps, callback)Set points on progress bar to fire the callback
set_to(self, to)Instant fill progress bar to value
to(self, to, callback)Start animation of a progress bar
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
keyThe progress bar direction.
max_sizeMaximum size of progress bar
nodeProgress bar fill node
on_changeOn progress bar change callback(self, new_value)
scaleCurrent progress bar scale
sizeCurrent progress bar size
sliceProgress bar slice9 settings
- -
-
- - -

Functions

- -
-
- - empty(self) -
-
- Empty a progress bar - - -

Parameters:

- - - - - - -
-
- - fill(self) -
-
- Fill a progress bar and stop progress animation - - -

Parameters:

- - - - - - -
-
- - get(self) -
-
- Return current progress bar value - - -

Parameters:

- - - - - - -
-
- - init(self, node, key, init_value) -
-
- The Progress constructor - - -

Parameters:

-
    -
  • self - Progress - Progress -
  • -
  • node - string or node - Node name or GUI Node itself. -
  • -
  • key - string - Progress bar direction: const.SIDE.X or const.SIDE.Y -
  • -
  • init_value - number or nil - Initial value of progress bar. Default: 1 -
  • -
- - - - - -
-
- - set_max_size(self, max_size) -
-
- Set progress bar max node size - - -

Parameters:

-
    -
  • self - Progress - Progress -
  • -
  • max_size - vector3 - The new node maximum (full) size -
  • -
- -

Returns:

-
    - - Progress - Progress -
- - - - -
-
- - set_steps(self, steps, callback) -
-
- Set points on progress bar to fire the callback - - -

Parameters:

-
    -
  • self - Progress - Progress -
  • -
  • steps - number[] - Array of progress bar values -
  • -
  • callback - function - Callback on intersect step value -
  • -
- - - - -

Usage:

-
    -
    progress:set_steps({0, 0.3, 0.6, 1}, function(self, step) end)
    -
- -
-
- - set_to(self, to) -
-
- Instant fill progress bar to value - - -

Parameters:

-
    -
  • self - Progress - Progress -
  • -
  • to - number - Progress bar value, from 0 to 1 -
  • -
- - - - - -
-
- - to(self, to, callback) -
-
- Start animation of a progress bar - - -

Parameters:

-
    -
  • self - Progress - Progress -
  • -
  • to - number - value between 0..1 -
  • -
  • callback - function or nil - Callback on animation ends -
  • -
- - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • SPEED - number or nil - Progress bas fill rate. More -> faster. Default: 5 -
  • -
  • MIN_DELTA - number or nil - Minimum step to fill progress bar. Default: 0.005 -
  • -
- - - - - -
-
-

Fields

- -
-
- - key -
-
- The progress bar direction. -

The values are: "x" or "y". (const.SIDE.X or const.SIDE.Y) - - -

- - - - - -
-
- - max_size -
-
- Maximum size of progress bar - - -
    -
  • max_size - number - -
  • -
- - - - - -
-
- - node -
-
- Progress bar fill node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_change -
-
- On progress bar change callback(self, new_value) - - - - - - - - -
-
- - scale -
-
- Current progress bar scale - - -
    -
  • scale - vector3 - -
  • -
- - - - - -
-
- - size -
-
- Current progress bar size - - -
    -
  • size - vector3 - -
  • -
- - - - - -
-
- - slice -
-
- Progress bar slice9 settings - - -
    -
  • slice - vector4 - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/RadioGroup.html b/docs/modules/RadioGroup.html deleted file mode 100644 index 41f2b10..0000000 --- a/docs/modules/RadioGroup.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module RadioGroup

-

Radio group module

-

Example Link

- - -

Functions

- - - - - - - - - - - - - -
get_state(self)Return radio group state
init(self, nodes, callback, click_nodes)The RadioGroup constructor
set_state(self, index, is_instant)Set radio group state
-

Fields

- - - - - - - - - -
checkboxesArray of checkbox components
on_radio_clickOn any checkbox click
- -
-
- - -

Functions

- -
-
- - get_state(self) -
-
- Return radio group state - - -

Parameters:

- - -

Returns:

-
    - - number - Index in radio group -
- - - - -
-
- - init(self, nodes, callback, click_nodes) -
-
- The RadioGroup constructor - - -

Parameters:

-
    -
  • self - RadioGroup - RadioGroup -
  • -
  • nodes - node[] - Array of gui node -
  • -
  • callback - function - Radio callback -
  • -
  • click_nodes - node[] or nil - Array of trigger nodes, by default equals to nodes. Default - nodes -
  • -
- - - - - -
-
- - set_state(self, index, is_instant) -
-
- Set radio group state - - -

Parameters:

-
    -
  • self - RadioGroup - RadioGroup -
  • -
  • index - number - Index in radio group -
  • -
  • is_instant - boolean or nil - If is instant state change -
  • -
- - - - - -
-
-

Fields

- -
-
- - checkboxes -
-
- Array of checkbox components - - -
    -
  • checkboxes - Checkbox[] - -
  • -
- - - - - -
-
- - on_radio_click -
-
- On any checkbox click - - - - - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/RichInput.html b/docs/modules/RichInput.html deleted file mode 100644 index 6c5cdf8..0000000 --- a/docs/modules/RichInput.html +++ /dev/null @@ -1,567 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module RichInput

-

Druid Rich Input custom component.

-

- It's wrapper on Input component with cursor and placeholder text

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
get_text(self)Set input field text
init(self, template, nodes)The RichInput constructor
select(self)Select input field
set_allowed_characters(self, characters)Set allowed charaters for input field.
set_font(self, font)Set input field font
set_placeholder(self, placeholder_text)Set placeholder text
set_text(self, text)Set input field text
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cursorOn input field text change to empty string callback(self, input_text)
cursor_positionOn input field text change to empty string callback(self, input_text)
cursor_textOn input field text change to empty string callback(self, input_text)
dragOn input field text change to empty string callback(self, input_text)
druidThe component druid instance
inputOn input field text change callback(self, input_text)
input_textOn input field text change to empty string callback(self, input_text)
placeholderOn input field text change to empty string callback(self, input_text)
rootRoot node
text_positionOn input field text change to empty string callback(self, input_text)
- -
-
- - -

Functions

- -
-
- - get_text(self) -
-
- Set input field text - - -

Parameters:

- - - - - - -
-
- - init(self, template, nodes) -
-
- The RichInput constructor - - -

Parameters:

-
    -
  • self - RichInput - RichInput -
  • -
  • template - string - The template string name -
  • -
  • nodes - table - Nodes table from gui.clone_tree -
  • -
- - - - - -
-
- - select(self) -
-
- Select input field - - -

Parameters:

- - - - - - -
-
- - set_allowed_characters(self, characters) -
-
- Set allowed charaters for input field. - See: https://defold.com/ref/stable/string/ - ex: [%a%d] for alpha and numeric - - -

Parameters:

-
    -
  • self - RichInput - RichInput -
  • -
  • characters - string - Regulax exp. for validate user input -
  • -
- -

Returns:

-
    - - RichInput - Current instance -
- - - - -
-
- - set_font(self, font) -
-
- Set input field font - - -

Parameters:

-
    -
  • self - RichInput - RichInput -
  • -
  • font - hash - The font hash -
  • -
- -

Returns:

-
    - - druid.input - Current input instance -
- - - - -
-
- - set_placeholder(self, placeholder_text) -
-
- Set placeholder text - - -

Parameters:

-
    -
  • self - RichInput - RichInput -
  • -
  • placeholder_text - string - The placeholder text -
  • -
- - - - - -
-
- - set_text(self, text) -
-
- Set input field text - - -

Parameters:

- - -

Returns:

-
    - - druid.input - Current input instance -
- - - - -
-
-

Fields

- -
-
- - cursor -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • cursor - node - -
  • -
- - - - - -
-
- - cursor_position -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • cursor_position - vector3 - -
  • -
- - - - - -
-
- - cursor_text -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • cursor_text - node - -
  • -
- - - - - -
-
- - drag -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • drag - druid.drag - -
  • -
- - - - - -
-
- - druid -
-
- The component druid instance - - - - - - - - -
-
- - input -
-
- On input field text change callback(self, input_text) - - -
    -
  • input - Input - Input -
  • -
- - - - - -
-
- - input_text -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • input_text - druid.text - -
  • -
- - - - - -
-
- - placeholder -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • placeholder - druid.text - -
  • -
- - - - - -
-
- - root -
-
- Root node - - -
    -
  • root - node - -
  • -
- - - - - -
-
- - text_position -
-
- On input field text change to empty string callback(self, input_text) - - -
    -
  • text_position - vector3 - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/RichText.html b/docs/modules/RichText.html deleted file mode 100644 index 075846c..0000000 --- a/docs/modules/RichText.html +++ /dev/null @@ -1,560 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module RichText

-

Druid Rich Text Custom Component.

-

- # Overview # -

This custom component is inspired by defold-richtext by britzl. - It uses a similar syntax for tags but currently supports fewer tags. -

Create Rich Text on your GUI Text Node. All properties of the text node will be used as default for the text. -

# Notes # -

• Nested tags are supported -

Example Link

-

Usage:

-
    -
  • local RichText = require("druid.custom.rich_text.rich_text")
    -...
    -self.rich_text = self.druid:new(RichText, "rich_text")
    -self.rich_text:set_text("Hello, Druid Rich Text!")
    -
  • -
  • type druid.rich_text.word = {
    -  node: Node,
    -  relative_scale: number,
    -  color: vector4,
    -  position: vector3,
    -  offset: vector3,
    -  scale: vector3,
    -  size: vector3,
    -  metrics: druid.rich_text.metrics,
    -  pivot: Pivot,
    -  text: string,
    -  shadow: vector4,
    -  outline: vector4,
    -  font: string,
    -  image: druid.rich_text.image,
    -  br: boolean,
    -  nobr: boolean,
    -}
    -
    -type druid.rich_text.word.image = {
    -  texture: string,
    -  anim: string,
    -  width: number,
    -  height: number,
    -}
    -
    -type druid.rich_text.lines_metrics = {
    -  text_width: number,
    -  text_height: number,
    -  lines: table<number, druid.rich_text.metrics>,
    -}
    -
    -type druid.rich_text.metrics = {
    -  width: number,
    -  height: number,
    -  offset_x: number|nil,
    -  offset_y: number|nil,
    -  node_size: vector3|nil @For images only,
    -}
    -
  • -
- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
characters(self, word)Split a word into it's characters
clear()Clear all created words.
get_line_metric()Get current line metrics
get_text(self)Get current text
get_words()Get all current words.
init(self, text_node, value)The RichText constructor
set_text(self, text)Set text for Rich Text
tagged(self, tag)Get all words, which has a passed tag.
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - -
druidThe component druid instance
rootThe root node of the Rich Text
text_prefabThe text prefab node
- -
-
- - -

Functions

- -
-
- - characters(self, word) -
-
- Split a word into it's characters - - -

Parameters:

-
    -
  • self - RichText - RichText -
  • -
  • word - druid.rich_text.word - -
  • -
- -

Returns:

-
    - - druid.rich_text.word[] - characters -
- - - - -
-
- - clear() -
-
- Clear all created words. - - - - - - - -
-
- - get_line_metric() -
-
- Get current line metrics - - - -

Returns:

-
    - - druid.rich_text.lines_metrics - -
- - - - -
-
- - get_text(self) -
-
- Get current text - - -

Parameters:

- - -

Returns:

-
    - - string - text -
- - - - -
-
- - get_words() -
-
- Get all current words. - - - -

Returns:

-
    - - table - druid.rich_text.word[] -
- - - - -
-
- - init(self, text_node, value) -
-
- The RichText constructor - - -

Parameters:

-
    -
  • self - RichText - RichText -
  • -
  • text_node - node or string - The text node to make Rich Text -
  • -
  • value - string or nil - The initial text value. Default will be gui.get_text(text_node) -
  • -
- - - - - -
-
- - set_text(self, text) -
-
- Set text for Rich Text - - -

Parameters:

-
    -
  • self - RichText - RichText -
  • -
  • text - string or nil - The text to set -
  • -
- -

Returns:

-
    -
  1. - druid.rich_text.word[] - words
  2. -
  3. - druid.rich_text.lines_metrics - line_metrics
  4. -
- - - -

Usage:

-
    -
    • color: Change text color
    -
    -<color=red>Foobar</color>
    -<color=1.0,0,0,1.0>Foobar</color>
    -<color=#ff0000>Foobar</color>
    -<color=#ff0000ff>Foobar</color>
    -
    -• shadow: Change text shadow
    -
    -<shadow=red>Foobar</shadow>
    -<shadow=1.0,0,0,1.0>Foobar</shadow>
    -<shadow=#ff0000>Foobar</shadow>
    -<shadow=#ff0000ff>Foobar</shadow>
    -
    -• outline: Change text shadow
    -
    -<outline=red>Foobar</outline>
    -<outline=1.0,0,0,1.0>Foobar</outline>
    -<outline=#ff0000>Foobar</outline>
    -<outline=#ff0000ff>Foobar</outline>
    -
    -• font: Change font
    -
    -<font=MyCoolFont>Foobar</font>
    -
    -• size: Change text size, relative to default size
    -
    -<size=2>Twice as large</size>
    -
    -• br: Insert a line break
    -
    -<br/>
    -
    -• nobr: Prevent the text from breaking
    -
    -Words <nobr>inside tag</nobr> won't break
    -
    -• img: Display image
    -
    -<img=texture:image/>
    -<img=texture:image,size/>
    -<img=texture:image,width,height/>
    -
- -
-
- - tagged(self, tag) -
-
- Get all words, which has a passed tag. - - -

Parameters:

- - -

Returns:

-
    - - druid.rich_text.word[] - words -
- - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in Druid styles table - or create your own style - - -

Fields:

-
    -
  • COLORS - table or nil - Rich Text color aliases. Default: {} -
  • -
  • ADJUST_STEPS - number or nil - Amount steps of attemps text adjust by height. Default: 20 -
  • -
  • ADJUST_SCALE_DELTA - number or nil - Scale step on each height adjust step. Default: 0.02 -
  • -
- - - - - -
-
-

Fields

- -
-
- - druid -
-
- The component druid instance - - - - - - - - -
-
- - root -
-
- The root node of the Rich Text - - -
    -
  • root - node - -
  • -
- - - - - -
-
- - text_prefab -
-
- The text prefab node - - -
    -
  • text_prefab - node - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Scroll.html b/docs/modules/Scroll.html deleted file mode 100644 index 457f77c..0000000 --- a/docs/modules/Scroll.html +++ /dev/null @@ -1,1183 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Scroll

-

Component to handle scroll content.

-

- # Overview # -

The Scroll component is designed to handle scrollable content and consists of two nodes: the scroll parent and the scroll input. -

The scroll input represents the user input zone and remains static. -

The scroll parent is the movable part of the scroll and changes its position. -

The initial scroll size can be set by adjusting the size of the scroll parent. - If the size of the scroll parent is smaller than the scroll input size, scrolling is not available. -

# Notes # -

• By default, the scroll style includes inertia and extra size for a stretching effect. - These settings can be adjusted using the scroll style settings. - For more details, refer to the scroll style settings. -

• "Points of interest" can be set up for the scroll. - The scroll will always be centered on the closest point of interest. - This feature allows creating a slider without inertia and with points of interest on each scroll element. -

• The scroll content size can be adjusted using the scroll:set_size(node_size) method. - This method sets a new size for the _content node. -

• Inertial scrolling mode can be enabled or disabled using the scroll:set_inert(state) method. -

• The extra stretch size can be adjusted using the scroll:set_extra_stretch_size method. -

• Multitouch is required for scrolling. The scroll component correctly handles - touch ID swaps while dragging the scroll. -

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bind_grid(self, grid)Bind the grid component (Static or Dynamic) to recalculate - scroll size on grid changes
get_percent(self)Return current scroll progress status.
get_scroll_size(self)Return vector of scroll size with width and height.
init(self, view_node, content_node)The Scroll constructor
is_inert(self)Return if scroll have inertion.
is_node_in_view(self, node)Check node if it visible now on scroll.
scroll_to(self, point, is_instant)Start scroll to target point.
scroll_to_index(self, index, skip_cb)Scroll to item in scroll by point index.
scroll_to_percent(self, percent, is_instant)Start scroll to target scroll percent
set_click_zone(self, node)Strict drag scroll area.
set_extra_stretch_size(self, stretch_size)Set extra size for scroll stretching.
set_horizontal_scroll(self, state)Lock or unlock horizontal scroll
set_inert(self, state)Enable or disable scroll inert.
set_points(self, points)Set points of interest.
set_size(self, size, offset)Set scroll content size.
set_vertical_scroll(self, state)Lock or unlock vertical scroll
set_view_size(self, size)Set new scroll view size in case the node size was changed.
update_view_size(self)Refresh scroll view size
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_is_inertFlag, if scroll now moving by inertion
available_posAvailable position for content node: (min_x, max_y, max_x, min_y)
available_sizeSize of available positions: (width, height, 0)
content_nodeScroll content node
dragDrag Druid component
inertionCurrent inert speed
is_animateFlag, if scroll now animating by gui.animate
on_point_scrollOn scroll_to_index function callback(self, index, point)
on_scrollOn scroll move callback(self, position)
on_scroll_toOn scroll_to function callback(self, target, is_instant)
positionCurrent scroll posisition
selectedCurrent index of points of interests
target_positionCurrent scroll target position
view_nodeScroll view node
view_sizeScroll view size
- -
-
- - -

Functions

- -
-
- - bind_grid(self, grid) -
-
- Bind the grid component (Static or Dynamic) to recalculate - scroll size on grid changes - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • grid - StaticGrid - Druid grid component -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - get_percent(self) -
-
- Return current scroll progress status. - Values will be in [0..1] interval - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
- -

Returns:

-
    - - vector3 - New vector with scroll progress values -
- - - - -
-
- - get_scroll_size(self) -
-
- Return vector of scroll size with width and height. - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
- -

Returns:

-
    - - vector3 - Available scroll size -
- - - - -
-
- - init(self, view_node, content_node) -
-
- The Scroll constructor - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • view_node - string or node - GUI view scroll node -
  • -
  • content_node - string or node - GUI content scroll node -
  • -
- - - - - -
-
- - is_inert(self) -
-
- Return if scroll have inertion. - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
- -

Returns:

-
    - - boolean - @If scroll have inertion -
- - - - -
-
- - is_node_in_view(self, node) -
-
- Check node if it visible now on scroll. - Extra border is not affected. Return true for elements in extra scroll zone - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • node - node - The node to check -
  • -
- -

Returns:

-
    - - boolean - True if node in visible scroll area -
- - - - -
-
- - scroll_to(self, point, is_instant) -
-
- Start scroll to target point. - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • point - vector3 - Target point -
  • -
  • is_instant - boolean or nil - Instant scroll flag -
  • -
- - - - -

Usage:

-
    -
  • scroll:scroll_to(vmath.vector3(0, 50, 0))
  • -
  • scroll:scroll_to(vmath.vector3(0), true)
  • -
- -
-
- - scroll_to_index(self, index, skip_cb) -
-
- Scroll to item in scroll by point index. - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • index - number - Point index -
  • -
  • skip_cb - boolean or nil - If true, skip the point callback -
  • -
- - - - - -
-
- - scroll_to_percent(self, percent, is_instant) -
-
- Start scroll to target scroll percent - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • percent - vector3 - target percent -
  • -
  • is_instant - boolean or nil - instant scroll flag -
  • -
- - - - -

Usage:

-
    -
    scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0))
    -
- -
-
- - set_click_zone(self, node) -
-
- Strict drag scroll area. Useful for - restrict events outside stencil node - - -

Parameters:

-
    -
  • self - Drag - -
  • -
  • node - node or string - Gui node -
  • -
- - - - - -
-
- - set_extra_stretch_size(self, stretch_size) -
-
- Set extra size for scroll stretching. - Set 0 to disable stretching effect - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • stretch_size - number or nil - Size in pixels of additional scroll area -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - set_horizontal_scroll(self, state) -
-
- Lock or unlock horizontal scroll - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • state - boolean or nil - True, if horizontal scroll is enabled -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - set_inert(self, state) -
-
- Enable or disable scroll inert. - If disabled, scroll through points (if exist) - If no points, just simple drag without inertion - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • state - boolean or nil - Inert scroll state -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - set_points(self, points) -
-
- Set points of interest. - Scroll will always centered on closer points - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • points - table - Array of vector3 points -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - set_size(self, size, offset) -
-
- Set scroll content size. - It will change content gui node size - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • size - vector3 - The new size for content node -
  • -
  • offset - vector3 or nil - Offset value to set, where content is starts -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - set_vertical_scroll(self, state) -
-
- Lock or unlock vertical scroll - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • state - boolean or nil - True, if vertical scroll is enabled -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - set_view_size(self, size) -
-
- Set new scroll view size in case the node size was changed. - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
  • size - vector3 - The new size for view node -
  • -
- -

Returns:

-
    - - druid.scroll - Current scroll instance -
- - - - -
-
- - update_view_size(self) -
-
- Refresh scroll view size - - -

Parameters:

-
    -
  • self - Scroll - Scroll -
  • -
- - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • FRICT - number or nil - Multiplier for free inertion. Default: 0 -
  • -
  • FRICT_HOLD - number or nil - Multiplier for inertion, while touching. Default: 0 -
  • -
  • INERT_THRESHOLD - number or nil - Scroll speed to stop inertion. Default: 3 -
  • -
  • INERT_SPEED - number or nil - Multiplier for inertion speed. Default: 30 -
  • -
  • POINTS_DEADZONE - number or nil - Speed to check points of interests in no_inertion mode. Default: 20 -
  • -
  • BACK_SPEED - number or nil - Scroll back returning lerp speed. Default: 35 -
  • -
  • ANIM_SPEED - number or nil - Scroll gui.animation speed for scroll_to function. Default: 2 -
  • -
  • EXTRA_STRETCH_SIZE - number or nil - extra size in pixels outside of scroll (stretch effect). Default: 0 -
  • -
  • SMALL_CONTENT_SCROLL - boolean or nil - If true, content node with size less than view node size can be scrolled. Default: false -
  • -
  • WHEEL_SCROLL_SPEED - boolean or nil - The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 -
  • -
  • WHEEL_SCROLL_INVERTED - boolean or nil - If true, invert direction for touchpad and mouse wheel scroll. Default: false -
  • -
  • WHEEL_SCROLL_BY_INERTION - boolean or nil - If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false -
  • -
- - - - - -
-
-

Fields

- -
-
- - _is_inert -
-
- Flag, if scroll now moving by inertion - - -
    -
  • _is_inert - boolean - -
  • -
- - - - - -
-
- - available_pos -
-
- Available position for content node: (min_x, max_y, max_x, min_y) - - -
    -
  • available_pos - vector4 - -
  • -
- - - - - -
-
- - available_size -
-
- Size of available positions: (width, height, 0) - - -
    -
  • available_size - vector3 - -
  • -
- - - - - -
-
- - content_node -
-
- Scroll content node - - -
    -
  • content_node - node - -
  • -
- - - - - -
-
- - drag -
-
- Drag Druid component - - -
    -
  • drag - Drag - Drag -
  • -
- - - - - -
-
- - inertion -
-
- Current inert speed - - -
    -
  • inertion - vector3 - -
  • -
- - - - - -
-
- - is_animate -
-
- Flag, if scroll now animating by gui.animate - - -
    -
  • is_animate - boolean - -
  • -
- - - - - -
-
- - on_point_scroll -
-
- On scroll_to_index function callback(self, index, point) - - - - - - - - -
-
- - on_scroll -
-
- On scroll move callback(self, position) - - - - - - - - -
-
- - on_scroll_to -
-
- On scroll_to function callback(self, target, is_instant) - - - - - - - - -
-
- - position -
-
- Current scroll posisition - - -
    -
  • position - vector3 - -
  • -
- - - - - -
-
- - selected -
-
- Current index of points of interests - - -
    -
  • selected - number or nil - -
  • -
- - - - - -
-
- - target_position -
-
- Current scroll target position - - -
    -
  • target_position - vector3 - -
  • -
- - - - - -
-
- - view_node -
-
- Scroll view node - - -
    -
  • view_node - node - -
  • -
- - - - - -
-
- - view_size -
-
- Scroll view size - - -
    -
  • view_size - vector3 - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Slider.html b/docs/modules/Slider.html deleted file mode 100644 index 45ce723..0000000 --- a/docs/modules/Slider.html +++ /dev/null @@ -1,531 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Slider

-

Druid slider component

-

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - -
init(self, node, end_pos, callback)The Slider constructor
is_enabled(self)Check if Slider component is enabled
set(self, value, is_silent)Set value for slider
set_enabled(self, is_enabled)Set Slider input enabled or disabled
set_input_node(self, input_node)Set input zone for slider.
set_steps(self, steps)Set slider steps.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
distLength between start and end position
end_posEnd pin node position
is_dragCurrent drag state
nodeSlider pin node
on_change_valueOn change value callback(self, value)
posCurrent pin node position
start_posStart pin node position
target_posTarger pin node position
valueCurrent slider value
- -
-
- - -

Functions

- -
-
- - init(self, node, end_pos, callback) -
-
- The Slider constructor - - -

Parameters:

-
    -
  • self - Slider - Slider -
  • -
  • node - node - Gui pin node -
  • -
  • end_pos - vector3 - The end position of slider -
  • -
  • callback - function or nil - On slider change callback -
  • -
- - - - - -
-
- - is_enabled(self) -
-
- Check if Slider component is enabled - - -

Parameters:

-
    -
  • self - Slider - Slider -
  • -
- -

Returns:

-
    - - boolean - -
- - - - -
-
- - set(self, value, is_silent) -
-
- Set value for slider - - -

Parameters:

-
    -
  • self - Slider - Slider -
  • -
  • value - number - Value from 0 to 1 -
  • -
  • is_silent - boolean or nil - Don't trigger event if true -
  • -
- - - - - -
-
- - set_enabled(self, is_enabled) -
-
- Set Slider input enabled or disabled - - -

Parameters:

-
    -
  • self - Slider - Slider -
  • -
  • is_enabled - boolean - -
  • -
- - - - - -
-
- - set_input_node(self, input_node) -
-
- Set input zone for slider. - User can touch any place of node, pin instantly will - move at this position and node drag will start. - This function require the Defold version 1.3.0+ - - -

Parameters:

- - -

Returns:

-
    - - Slider - Slider -
- - - - -
-
- - set_steps(self, steps) -
-
- Set slider steps. Pin node will - apply closest step position - - -

Parameters:

-
    -
  • self - Slider - Slider -
  • -
  • steps - number[] - Array of steps -
  • -
- -

Returns:

-
    - - Slider - Slider -
- - - -

Usage:

-
    -
    slider:set_steps({0, 0.2, 0.6, 1})
    -
- -
-
-

Fields

- -
-
- - dist -
-
- Length between start and end position - - -
    -
  • dist - vector3 - -
  • -
- - - - - -
-
- - end_pos -
-
- End pin node position - - -
    -
  • end_pos - vector3 - -
  • -
- - - - - -
-
- - is_drag -
-
- Current drag state - - -
    -
  • is_drag - boolean - -
  • -
- - - - - -
-
- - node -
-
- Slider pin node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_change_value -
-
- On change value callback(self, value) - - - - - - - - -
-
- - pos -
-
- Current pin node position - - -
    -
  • pos - vector3 - -
  • -
- - - - - -
-
- - start_pos -
-
- Start pin node position - - -
    -
  • start_pos - vector3 - -
  • -
- - - - - -
-
- - target_pos -
-
- Targer pin node position - - -
    -
  • target_pos - vector3 - -
  • -
- - - - - -
-
- - value -
-
- Current slider value - - -
    -
  • value - number - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/StaticGrid.html b/docs/modules/StaticGrid.html deleted file mode 100644 index 5281ef5..0000000 --- a/docs/modules/StaticGrid.html +++ /dev/null @@ -1,1094 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module StaticGrid

-

Component to handle component's position by row and columns.

-

- # Overview # -

The Static Grid component allows for positioning components in rows and columns. - It provides a static grid layout with constant node sizes, allowing for pre-calculated - node positions and the option to include gaps between nodes. -

# Notes # -

• In a static grid, the node size remains constant, enabling the calculation of node - positions before placement. If you want add gaps between nodes, increase the root prefab size, - including the padding and margin. -

• The static grid can automatically shift elements when nodes are added or removed. -

• When a node is added, the grid will set the node's parent to the specified parent_node. -

• You can obtain an array of positions for each element, which can be used to set - points of interest in a scroll component. -

• The size of all elements can be retrieved for setting up the size in a scroll component. -

• The grid can be bound to a scroll component for automatic resizing of the scroll content size. -

• The pivot of the parent_node affects the node placement within the grid. -

• A prefab node is used to determine the node size and anchor. -

• You can specify a position_function for animations using the - _static_grid:set_position_function(node, pos) callback. The default position function is gui.set_position(). -

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
add(self, item, index, shift_policy, is_instant)Add new item to the grid
clear(self)Clear grid nodes array.
get_all_pos(self)Return array of all node positions
get_borders(self)Return grid content borders
get_index(self, pos)Return index for grid pos
get_index_by_node(self, node)Return grid index by node
get_offset(self)Return StaticGrid offset, where StaticGrid content starts.
get_pos(self, index)Return pos for grid node index
get_size(self)Return grid content size
init(self, parent, element, in_row)The StaticGrid constructor
refresh(self)Update grid content
remove(self, index, shift_policy, is_instant)Remove the item from the grid.
set_anchor(self, anchor)Set grid anchor.
set_in_row(self, in_row)Set new in_row elements for grid
set_item_size(self[, width[, height]])Set new node size for grid
set_items(self, nodes[, is_instant=false])Set new items to the grid.
set_position_function(self, callback)Change set position function for grid nodes.
sort_nodes(self, comparator)Sort grid nodes by custom comparator function
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
anchorItem anchor [0..1]
borderThe size of item content
first_indexThe first index of node in grid
last_indexThe last index of node in grid
node_sizeItem size
nodesList of all grid nodes
on_add_itemOn item add callback(self, node, index)
on_change_itemsOn item add, remove or change in_row callback(self, index|nil)
on_clearOn grid clear callback(self)
on_remove_itemOn item remove callback(self, index)
on_update_positionsOn update item positions callback(self)
parentParent gui node
pivotItem pivot [-0.5..0.5]
- -
-
- - -

Functions

- -
-
- - add(self, item, index, shift_policy, is_instant) -
-
- Add new item to the grid - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • item - node - GUI node -
  • -
  • index - number or nil - The item position. By default add as last item -
  • -
  • shift_policy - number or nil - How shift nodes, if required. Default: const.SHIFT.RIGHT -
  • -
  • is_instant - boolean or nil - If true, update node positions instantly -
  • -
- - - - - -
-
- - clear(self) -
-
- Clear grid nodes array. GUI nodes will be not deleted! - If you want to delete GUI nodes, use static_grid.nodes array before grid:clear - - -

Parameters:

- - -

Returns:

-
    - - druid.static_grid - Current grid instance -
- - - - -
-
- - get_all_pos(self) -
-
- Return array of all node positions - - -

Parameters:

- - -

Returns:

-
    - - vector3[] - All grid node positions -
- - - - -
-
- - get_borders(self) -
-
- Return grid content borders - - -

Parameters:

- - -

Returns:

-
    - - vector3 - The grid content borders -
- - - - -
-
- - get_index(self, pos) -
-
- Return index for grid pos - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • pos - vector3 - The node position in the grid -
  • -
- -

Returns:

-
    - - number - The node index -
- - - - -
-
- - get_index_by_node(self, node) -
-
- Return grid index by node - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • node - node - The gui node in the grid -
  • -
- -

Returns:

-
    - - number - The node index -
- - - - -
-
- - get_offset(self) -
-
- Return StaticGrid offset, where StaticGrid content starts. - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid The StaticGrid instance -
  • -
- -

Returns:

-
    - - vector3 - The StaticGrid offset -
- - - - -
-
- - get_pos(self, index) -
-
- Return pos for grid node index - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • index - number - The grid element index -
  • -
- -

Returns:

-
    - - vector3 - @Node position -
- - - - -
-
- - get_size(self) -
-
- Return grid content size - - -

Parameters:

- - -

Returns:

-
    - - vector3 - The grid content size -
- - - - -
-
- - init(self, parent, element, in_row) -
-
- The StaticGrid constructor - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • parent - string or node - The GUI Node container, where grid's items will be placed -
  • -
  • element - node - Element prefab. Need to get it size -
  • -
  • in_row - number or nil - How many nodes in row can be placed. By default 1 -
  • -
- - - - - -
-
- - refresh(self) -
-
- Update grid content - - -

Parameters:

- - - - - - -
-
- - remove(self, index, shift_policy, is_instant) -
-
- Remove the item from the grid. Note that gui node will be not deleted - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • index - number - The grid node index to remove -
  • -
  • shift_policy - number or nil - How shift nodes, if required. Default: const.SHIFT.RIGHT -
  • -
  • is_instant - boolean or nil - If true, update node positions instantly -
  • -
- -

Returns:

-
    - - node - The deleted gui node from grid -
- - - - -
-
- - set_anchor(self, anchor) -
-
- Set grid anchor. Default anchor is equal to anchor of grid parent node - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • anchor - vector3 - Anchor -
  • -
- - - - - -
-
- - set_in_row(self, in_row) -
-
- Set new in_row elements for grid - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • in_row - number - The new in_row value -
  • -
- -

Returns:

-
    - - druid.static_grid - Current grid instance -
- - - - -
-
- - set_item_size(self[, width[, height]]) -
-
- Set new node size for grid - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • width - number - The new node width - (optional) -
  • -
  • height - number - The new node height - (optional) -
  • -
- -

Returns:

-
    - - druid.static_grid - Current grid instance -
- - - - -
-
- - set_items(self, nodes[, is_instant=false]) -
-
- Set new items to the grid. All previous items will be removed - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • nodes - node[] - The new grid nodes -
  • -
  • is_instant - boolean - If true, update node positions instantly - (default false) -
  • -
- - - - - -
-
- - set_position_function(self, callback) -
-
- Change set position function for grid nodes. It will call on - update poses on grid elements. Default: gui.set_position - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • callback - function - Function on node set position -
  • -
- -

Returns:

-
    - - druid.static_grid - Current grid instance -
- - - - -
-
- - sort_nodes(self, comparator) -
-
- Sort grid nodes by custom comparator function - - -

Parameters:

-
    -
  • self - StaticGrid - StaticGrid -
  • -
  • comparator - function - The comparator function. (a, b) -> boolean -
  • -
- -

Returns:

-
    - - druid.static_grid - Current grid instance -
- - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • IS_DYNAMIC_NODE_POSES - boolean or nil - If true, always center grid content as grid pivot sets. Default: false -
  • -
  • IS_ALIGN_LAST_ROW - boolean or nil - If true, always align last row of the grid as grid pivot sets. Default: false -
  • -
- - - - - -
-
-

Fields

- -
-
- - anchor -
-
- Item anchor [0..1] - - -
    -
  • anchor - vector3 - -
  • -
- - - - - -
-
- - border -
-
- The size of item content - - -
    -
  • border - vector4 - -
  • -
- - - - - -
-
- - first_index -
-
- The first index of node in grid - - -
    -
  • first_index - number - -
  • -
- - - - - -
-
- - last_index -
-
- The last index of node in grid - - -
    -
  • last_index - number - -
  • -
- - - - - -
-
- - node_size -
-
- Item size - - -
    -
  • node_size - vector3 - -
  • -
- - - - - -
-
- - nodes -
-
- List of all grid nodes - - -
    -
  • nodes - node[] - -
  • -
- - - - - -
-
- - on_add_item -
-
- On item add callback(self, node, index) - - - - - - - - -
-
- - on_change_items -
-
- On item add, remove or change in_row callback(self, index|nil) - - - - - - - - -
-
- - on_clear -
-
- On grid clear callback(self) - - - - - - - - -
-
- - on_remove_item -
-
- On item remove callback(self, index) - - - - - - - - -
-
- - on_update_positions -
-
- On update item positions callback(self) - - -
    -
  • on_update_positions - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - parent -
-
- Parent gui node - - -
    -
  • parent - node - -
  • -
- - - - - -
-
- - pivot -
-
- Item pivot [-0.5..0.5] - - -
    -
  • pivot - vector3 - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Swipe.html b/docs/modules/Swipe.html deleted file mode 100644 index 9b7a2a9..0000000 --- a/docs/modules/Swipe.html +++ /dev/null @@ -1,288 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Swipe

-

Component to handle swipe gestures on node.

-

- Swipe will be triggered, if swipe was started and - ended on one node -

Example Link

- - -

Functions

- - - - - - - - - -
init(self, node, on_swipe_callback)The Swipe constructor
set_click_zone(self, zone)Strict swipe click area.
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - -
click_zoneRestriction zone
nodeSwipe node
on_swipeTrigger on swipe event(self, swipe_side, dist, delta_time)
- -
-
- - -

Functions

- -
-
- - init(self, node, on_swipe_callback) -
-
- The Swipe constructor - - -

Parameters:

-
    -
  • self - Swipe - Swipe -
  • -
  • node - node - Gui node -
  • -
  • on_swipe_callback - function - Swipe callback for on_swipe_end event -
  • -
- - - - - -
-
- - set_click_zone(self, zone) -
-
- Strict swipe click area. Useful for - restrict events outside stencil node - - -

Parameters:

- - - - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • SWIPE_TIME - number or nil - Maximum time for swipe trigger. Default: 0.4 -
  • -
  • SWIPE_THRESHOLD - number or nil - Minimum distance for swipe trigger. Default: 50 -
  • -
  • SWIPE_TRIGGER_ON_MOVE - boolean or nil - If true, trigger on swipe moving, not only release action. Default: false -
  • -
- - - - - -
-
-

Fields

- -
-
- - click_zone -
-
- Restriction zone - - -
    -
  • click_zone - node or nil - -
  • -
- - - - - -
-
- - node -
-
- Swipe node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_swipe -
-
- Trigger on swipe event(self, swipe_side, dist, delta_time) - - - - - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Text.html b/docs/modules/Text.html deleted file mode 100644 index bcf6e6c..0000000 --- a/docs/modules/Text.html +++ /dev/null @@ -1,942 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Text

-

Component for Wrapping GUI Text Nodes: Druid Text -

## Overview ## -

Druid Text is a component that provides various adjustment modes for text nodes.

-

It allows text to be scaled down to fit within the size of the text node. -

## Notes ## -

• The text pivot can be changed using the text:set_pivot method. - The anchoring will be inside the text node's area size. -

• There are several text adjustment types available. The default is DOWNSCALE. - You can change the default adjustment type in the Text style. Refer to the example below to see all available adjustment types: -

- const.TEXT_ADJUST.DOWNSCALE: Changes the text's scale to fit within the text node's size. -

- const.TEXT_ADJUST.TRIM: Trims the text with a postfix (default: "...", can be overridden in styles) - to fit within the text node's size. -

- const.TEXT_ADJUST.NO_ADJUST: No adjustment is applied, similar - to the default Defold Text Node behavior. -

- const.TEXT_ADJUST.DOWNSCALE_LIMITED: Changes the text's scale - with a limited downscale. You can set the minimum scale using the text:set_minimal_scale() function. -

- const.TEXT_ADJUST.SCROLL: Changes the text's pivot to imitate scrolling within the text box. - For better effect, use with a stencil node. -

- const.TEXT_ADJUST.SCALE_THEN_SCROLL: Combines two modes: limited downscale first, then scroll. -

Example Link

- - -

Functions

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
get_text_adjust(self, adjust_type)Return current text adjust type
get_text_index_by_width(self, width)Get chars count by width
get_text_size(self, text)Calculate text width with font with respect to trailing space
init(self, node, value, adjust_type)The Text constructor
is_multiline(self)Return true, if text with line break
set_alpha(self, alpha)Set alpha
set_color(self, color)Set color
set_minimal_scale(self, minimal_scale)Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types
set_pivot(self, pivot)Set text pivot.
set_scale(self, scale)Set scale
set_size(self, size)Set text area size
set_text_adjust(self, adjust_type, minimal_scale)Set text adjust, refresh the current text visuals, if needed
set_to(self, set_to)Set text to text field
-

Tables

- - - - - -
styleComponent style params.
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
adjust_typeCurrent text size adjust settings
colorCurrent text color
last_valueThe last text value
nodeText node
node_idThe node id of text node
on_set_pivotOn change pivot callback(self, pivot)
on_set_textOn set text callback(self, text)
on_update_text_scaleOn adjust text size callback(self, new_scale, text_metrics)
posCurrent text position
scaleCurrent text node scale
start_scaleInitial text node scale
start_sizeInitial text node size
text_areaCurrent text node available are
- -
-
- - -

Functions

- -
-
- - get_text_adjust(self, adjust_type) -
-
- Return current text adjust type - - -

Parameters:

-
    -
  • self - -
  • -
  • adjust_type - -
  • -
- -

Returns:

-
    - - number - The current text adjust type -
- - - - -
-
- - get_text_index_by_width(self, width) -
-
- Get chars count by width - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • width - number - -
  • -
- -

Returns:

-
    - - number - Chars count -
- - - - -
-
- - get_text_size(self, text) -
-
- Calculate text width with font with respect to trailing space - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • text - string - |nil -
  • -
- -

Returns:

-
    -
  1. - number - Width
  2. -
  3. - number - Height
  4. -
- - - - -
-
- - init(self, node, value, adjust_type) -
-
- The Text constructor - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • node - string or node - Node name or GUI Text Node itself -
  • -
  • value - string or nil - Initial text. Default value is node text from GUI scene. Default: nil -
  • -
  • adjust_type - string or nil - Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE -
  • -
- - - - - -
-
- - is_multiline(self) -
-
- Return true, if text with line break - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
- -

Returns:

-
    - - boolean - Is text node with line break -
- - - - -
-
- - set_alpha(self, alpha) -
-
- Set alpha - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • alpha - number - Alpha for node -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_color(self, color) -
-
- Set color - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • color - vector4 - Color for node -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_minimal_scale(self, minimal_scale) -
-
- Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • minimal_scale - number - If pass nil - not use minimal scale -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_pivot(self, pivot) -
-
- Set text pivot. Text will re-anchor inside text area - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • pivot - number - The gui.PIVOT_* constant -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_scale(self, scale) -
-
- Set scale - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • scale - vector3 - Scale for node -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_size(self, size) -
-
- Set text area size - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • size - vector3 - The new text area size -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_text_adjust(self, adjust_type, minimal_scale) -
-
- Set text adjust, refresh the current text visuals, if needed - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • adjust_type - string or nil - See const.TEXT_ADJUST. If pass nil - use current adjust type -
  • -
  • minimal_scale - number or nil - If pass nil - not use minimal scale -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
- - set_to(self, set_to) -
-
- Set text to text field - - -

Parameters:

-
    -
  • self - Text - Text -
  • -
  • set_to - string - Text for node -
  • -
- -

Returns:

-
    - - Text - Current text instance -
- - - - -
-
-

Tables

- -
-
- - style -
-
- Component style params. - You can override this component styles params in druid styles table - or create your own style - - -

Fields:

-
    -
  • TRIM_POSTFIX - string or nil - The postfix for TRIM adjust type. Default: ... -
  • -
  • DEFAULT_ADJUST - string or nil - The default adjust type for any text component. Default: DOWNSCALE -
  • -
  • ADJUST_STEPS - string or nil - Amount of iterations for text adjust by height. Default: 20 -
  • -
  • ADJUST_SCALE_DELTA - string or nil - Scale step on each height adjust step. Default: 0.02 -
  • -
- - - - - -
-
-

Fields

- -
-
- - adjust_type -
-
- Current text size adjust settings - - -
    -
  • adjust_type - number - -
  • -
- - - - - -
-
- - color -
-
- Current text color - - -
    -
  • color - vector3 - -
  • -
- - - - - -
-
- - last_value -
-
- The last text value - - - - - - - - -
-
- - node -
-
- Text node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - node_id -
-
- The node id of text node - - -
    -
  • node_id - hash - -
  • -
- - - - - -
-
- - on_set_pivot -
-
- On change pivot callback(self, pivot) - - - - - - - - -
-
- - on_set_text -
-
- On set text callback(self, text) - - - - - - - - -
-
- - on_update_text_scale -
-
- On adjust text size callback(self, new_scale, text_metrics) - - -
    -
  • on_update_text_scale - DruidEvent - DruidEvent -
  • -
- - - - - -
-
- - pos -
-
- Current text position - - -
    -
  • pos - vector3 - -
  • -
- - - - - -
-
- - scale -
-
- Current text node scale - - -
    -
  • scale - vector3 - -
  • -
- - - - - -
-
- - start_scale -
-
- Initial text node scale - - -
    -
  • start_scale - vector3 - -
  • -
- - - - - -
-
- - start_size -
-
- Initial text node size - - -
    -
  • start_size - vector3 - -
  • -
- - - - - -
-
- - text_area -
-
- Current text node available are - - -
    -
  • text_area - vector3 - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/Timer.html b/docs/modules/Timer.html deleted file mode 100644 index 7fabb1b..0000000 --- a/docs/modules/Timer.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module Timer

-

Component to handle GUI timers.

-

- Timer updating by game delta time. If game is not focused - - timer will be not updated.

- - -

Functions

- - - - - - - - - - - - - - - - - -
init(self, node, seconds_from, seconds_to, callback)The Timer constructor
set_interval(self, from, to)Set time interval
set_state(self, is_on)Called when update
set_to(self, set_to)Set text to text field
-

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fromInitial timer value
nodeTrigger node
on_set_enabledOn timer change enabled state callback(self, is_enabled)
on_tickOn timer tick.
on_timer_endOn timer end callback
targetTarget timer value
valueCurrent timer value
- -
-
- - -

Functions

- -
-
- - init(self, node, seconds_from, seconds_to, callback) -
-
- The Timer constructor - - -

Parameters:

-
    -
  • self - Timer - Timer -
  • -
  • node - node - Gui text node -
  • -
  • seconds_from - number or nil - Start timer value in seconds -
  • -
  • seconds_to - number or nil - End timer value in seconds -
  • -
  • callback - function or nil - Function on timer end -
  • -
- - - - - -
-
- - set_interval(self, from, to) -
-
- Set time interval - - -

Parameters:

-
    -
  • self - Timer - Timer -
  • -
  • from - number - Start time in seconds -
  • -
  • to - number - Target time in seconds -
  • -
- - - - - -
-
- - set_state(self, is_on) -
-
- Called when update - - -

Parameters:

-
    -
  • self - Timer - Timer -
  • -
  • is_on - boolean or nil - Timer enable state -
  • -
- - - - - -
-
- - set_to(self, set_to) -
-
- Set text to text field - - -

Parameters:

-
    -
  • self - Timer - Timer -
  • -
  • set_to - number - Value in seconds -
  • -
- - - - - -
-
-

Fields

- -
-
- - from -
-
- Initial timer value - - -
    -
  • from - number - -
  • -
- - - - - -
-
- - node -
-
- Trigger node - - -
    -
  • node - node - -
  • -
- - - - - -
-
- - on_set_enabled -
-
- On timer change enabled state callback(self, is_enabled) - - - - - - - - -
-
- - on_tick -
-
- On timer tick. Fire every second callback(self, value) - - - - - - - - -
-
- - on_timer_end -
-
- On timer end callback - - -
    -
  • on_timer_end - DruidEvent - (self, Timer) DruidEvent -
  • -
- - - - - -
-
- - target -
-
- Target timer value - - -
    -
  • target - number - -
  • -
- - - - - -
-
- - value -
-
- Current timer value - - -
    -
  • value - number - -
  • -
- - - - - -
-
- - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/druid.extended.layout.html b/docs/modules/druid.extended.layout.html deleted file mode 100644 index 4f01fd5..0000000 --- a/docs/modules/druid.extended.layout.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module druid.extended.layout

-

Druid layout module -

# Overview # -

Layout component works like Dynamic Grid before - for aligning elements in a row or column.

-

Works like a Figma layout. -

# Notes

- - - -
-
- - - - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs/modules/druid.system.utf8.html b/docs/modules/druid.system.utf8.html deleted file mode 100644 index 0582106..0000000 --- a/docs/modules/druid.system.utf8.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - Defold Druid UI Framework - - - - -
- -
- -
-
-
- - -
- - - - - - -
- -

Module druid.system.utf8

-

-

- - - -
-
- - - - -
-
-
-generated by LDoc TESTING -Last updated 2015-01-01 12:00:00 -
-
- - diff --git a/docs_md/01-components.md b/docs_md/01-components.md deleted file mode 100644 index ce33f02..0000000 --- a/docs_md/01-components.md +++ /dev/null @@ -1,372 +0,0 @@ -# Druid components - - -## Button -[Button API here](https://insality.github.io/druid/modules/Button.html) - -### Overview -Basic Druid input component. Handle input on node and provide different callbacks on touch events. - -### Setup -Create button with druid: `button = druid:new_button(node_name, callback, [params], [animation_node])` -Where node name is name of node from GUI scene. You can use `node_name` as input trigger zone and point another node for animation via `animation_node` - -### Usecase -_fill example usecases_ - -### Notes -- Button callback have next params: (self, params, button_instance) - - **self** - Druid self context - - **params** - Additional params, specified on button creating - - **button_instance** - button itself -- You can set _params_ on button callback on button creating: `druid:new_button("node_name", callback, params)`. This _params_ will pass in callback as second argument -- Button have next events: - - **on_click** - basic button callback - - **on_repeated_click** - repeated click callback, while holding the button, don't trigger if callback is empty - - **on_long_click** - callback on long button tap, don't trigger if callback is empty - - **on_hold_click** - hold callback, before long_click trigger, don't trigger if callback is empty - - **on_double_click** - different callback, if tap button 2+ in row, don't trigger if callback is empty -- Click event will not trigger, if between pressed and released state cursor was outside of node zone -- If button have double click event and it is triggered, usual callback will be not invoked -- If you have stencil on buttons and you don't want trigger them outside of stencil node, you can use `button:set_click_zone` to restrict button click zone -- Button can have key trigger to use then by key: `button:set_key_trigger` -- Animation node can be used for example to animate small icon on big panel. Node name of trigger zone will be `big panel` and animation node will be `small icon` - - -## Text -[Text API here](https://insality.github.io/druid/modules/Text.html) - -### Overview -Basic Druid text component. Text components by default have the text size adjusting. - -### Setup -Create text node with druid: `text = druid:new_text(node_name, [initial_value], [text_adjust_type])` - -### Notes -- Text component by default have auto adjust text sizing. Text never will be bigger, than text node size, which you can setup in GUI scene. It can be disabled on component creating by settings argument `is_no_adjust` to _true_ - -![](../media/text_autosize.png) - -- Text pivot can be changed with `text:set_pivot`, and text will save their position inside their text size box: - -![](../media/text_anchor.gif) - -- There is several text adjust types. Default Downscale. You can change the default adjust type in the text style table. - - **const.TEXT_ADJUST.DOWNSCALE** - Change text's scale to fit in the text node size - - **const.TEXT_ADJUST.TRIM** - Trim the text with postfix (default - "...", override in styles) to fit in the text node size - - **const.TEXT_ADJUST.NO_ADJUST** - No any adjust, like default Defold text node - - **const.TEXT_ADJUST.DOWNSCALE_LIMITED** - Change text's scale list downscale, but there is limit for text's scale - - **const.TEXT_ADJUST.SCROLL** - Change text's pivot to imitate scrolling in the text box. Use with stencil node for better effect. - - **const.TEXT_ADJUST.SCALE_THEN_SCROLL** - Combine two modes: first limited downscale, then scroll - - -## Blocker -[Blocker API here](https://insality.github.io/druid/modules/Blocker.html) - -### Overview -Druid component for block input. Use it to block input in special zone. - -### Setup -Create blocker component with druid: `druid:new_blocker(node_name)` - -### Notes -Explanation: -![](../media/blocker_scheme.png) - -Blue zone is **button** with close_window callback - -Yellow zone is blocker with window content - -So you can do the safe zones, when you have the big buttons - - -## Back Handler -[Back handler API here](https://insality.github.io/druid/modules/BackHandler.html) - -### Overview -Component to handle back button. It handle Android back button and Backspace key. Key triggers in `input.binding` should be setup for correct working. - -### Setup -Setup callback with `druid:new_back_handler(callback)` - -### Notes - - -## Lang text -[Lang text API here](https://insality.github.io/druid/modules/LangText.html) - -### Overview -Wrap on Text component to handle localization. It uses druid get_text_function to set text by it's id - -### Setup -Create lang text component with druid `text = druid:new_lang_text(node_name, locale_id)` - -### Notes - - -## Scroll -[Scroll API here](https://insality.github.io/druid/modules/Scroll.html) - -### Overview -Basic Druid scroll component. Handle all scrolling stuff in druid GUI - -### Setup -Create scroll component with druid: `scroll = druid:new_scroll(view_node, content_node)`. - -_View_node_ - is static part. It capturing user input and recognize scrolling touches - -_Content_node_ - is dynamic part. This node will change position by scroll system - -Initial scroll size will be equal to _content_node_ node size. The initial view box will be equal to _view_node_ node size - -Usually, Place _view_node_ and as children add _content_node_: -![](../media/scroll_scheme.png) -![](../media/scroll_outline.png) - -*Here content_node below view_node, in game content_node be able to scroll left until end* - -### Notes -- Scroll by default style have inertion and extra size for strecthing effect. It can be adjust via scroll [style settings](https://insality.github.io/druid/modules/Scroll.html#Style) -- You can setup "points of interest". Scroll always will be centered on closes point of interest. It is able to create slider without inertion and points of interest on each scroll element. -- Scroll have next events: - - *on_scroll* (self, position) On scroll move callback - - *on_scroll_to* (self, position, is_instant) On scroll_to function callback - - *on_point_scroll* (self, item_index, position) On scroll_to_index function callback -- You can adjust scroll content size by `scroll:set_size(node_size)`. It will setup new size to _content node_ -- You can enabled or disable inertion mode via `scroll:set_inert(state)` -- You can adjust extra stretch size via `scroll:set_extra_stretch_size` -- Multitouch is required for scroll. Scroll is correctly handling touch_id swap while dragging scroll - - -## Progress -[Progress API here](https://insality.github.io/druid/modules/Progress.html) - -### Overview -Basic Druid progress bar component - -### Setup -Create progress bar component with druid: `progress = druid:new_progress(node_name, key, init_value)` - -Node name should have maximum node size, so in GUI scene, node_name should be fully filled. -Key is value from druid const: const.SIDE.X (or just "x") or const.SIDE.Y (or just "y") - -### Notes -- Progress correct working with 9slice nodes, it trying to set size by _set_size_ first, if it is not possible, it set up sizing via _set_scale_ -- Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene -- If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles - - -## Slider -[Slider API here](https://insality.github.io/druid/modules/Slider.html) - -### Overview -Basic Druid slider component - -### Setup -Create slider component with druid: `slider = druid:new_slider(node_name, end_pos, callback)` - -Pin node (node_name in params) should be placed in zero position (initial). It will be available to mode Pin node between start pos and end pos. - -### Notes -- You can setup points of interests on slider via `slider:set_steps`. If steps are exist, slider values will be only from this steps (notched slider) -- For now, start pos and end pos should be on vertical or horizontal line (their x or y value should be equal) - - -## Input -[Input API here](https://insality.github.io/druid/modules/Input.html) - -### Overview -Basic Druid text input component - -### Setup -Create input component with druid: `input = druid:new_input(button_node_name, text_node_name, keyboard_type)` - -### Notes -- Input component handle user text input. Input contains from button and text components. Button needed for selecting/unselecting input field -- Long click on input field for clear and select input field (clearing can be disable via styles) -- Click outside of button to unselect input field -- On focus lost (game minimized) input field will be unselected -- You can setup max length of the text -- You can setup allowed characters. On add not allowed characters `on_input_wrong` will be called. By default it cause simple shake animation -- The keyboard for input will not show on mobile HTML5. So input field in mobile HTML5 is not working now -- To make work different keyboard type, make sure value in game.project Android:InputMethod set to HidderInputField (https://defold.com/manuals/project-settings/#input-method) - - -## Timer -[Timer API here](https://insality.github.io/druid/modules/Timer.html) - -### Overview -Handle timer work on gui text node - -### Setup -Create timer component with druid: `timer = druid:new_timer(text_node, from_seconds, to_seconds, callback)` - -### Notes -- Timer fires callback, when timer value equals to _to_seconds_ -- Timer will set text node with current timer value -- Timer uses update function to handle time - - -## Static Grid -[Static Grid API here](https://insality.github.io/druid/modules/StaticGrid.html) - -### Overview -Component for manage node positions. -Static grid have constant node size, so it possible to calculate node positions before placement. Nodes can be placed with gaps. -Static grid can shift elements on add/remove functions. - -### Setup -Create component with druid: `grid = druid:new_grid(parent_node, prefab_node, max_in_row_elements)` - -### Notes -- On _add node_ grid will set nodeup parent to _parent_node_ -- You can get array of position of every element for setup points of interest in scroll component -- You can get size of all elements for setup size in scroll component -- You can also bind the grid to the scroll component for auto resize scroll content size -- Pivot of parent_node matter for node placement -- _Prefab node_ used to get node size and anchor -- You can point *position_function* for animations with _static_grid:set_position_function(node, pos)_ callback. Default - *gui.set_position()* - -## Data List -[Data List API here](https://insality.github.io/druid/modules/DataList.html) - -### Overview -Component to manage data for huge dataset in scroll. DataList create elements only in scroll view. -It requires Druid Scroll and Druid Grid (Static or Dynamic) components - - -### Setup -Create component with druid: `grid = druid:new_data_list(scroll, grid, create_callback)` -- scroll - already created Scroll component -- grid - already created StaticGrid or DynamicGrid component -- create_function - your function to create node instances. This callback have next parameters: fun(self, data, index, data_list) - - self - Script/Druid context - - data- your element data - - index - element index - - data_list - current DataList component - -Create function should return root node and optionaly, Druid component. It’s required to manage create/remove lifecycle. - -### Notes -- Set data with `data_list:set_data({...})` after component initialize -- You can use `data_list:scroll_to_index()` function to show data element - - -## Hover -[Hover API here](https://insality.github.io/druid/modules/Hover.html) - -### Overview -System Druid component, handle hover node state. - -### Setup -Create hover component with druid: `hover = druid:new_hover(node, callback)` - -### Notes -- By default, hover handles _hover event_ with pressed touch action_id. So it's mean, what mouse or touch have to be pressed -- On desktop platforms there is _on_mouse_hover_ event. It's event on mouse hover without any action id -- By default, assume what node is on not hovered state (both _hover_ and _mouse_hover_) - - -## Swipe -[Swipe API here](https://insality.github.io/druid/modules/Swipe.html) - -### Overview -System Druid component, handle swipe actions on node - -### Setup -Create swipe component with druid: `hover = druid:new_swipe(node, swipe_callback)` - -### Notes -- Swipe callback have next params: (self, swipe_side, distance, time) - - **self** - Druid self context - - **swipe_side**: *string* - values from ["up", "down", "left", "right"] - - **distance**: *number* - in pixels, distance of swipe - - **time**: *number* - in seconds, time of swiping -- Swipe trigger only, if all input actions was on swipe node. If action will be outside of node, swipe status will be reseted -- In swipe style table you can adjust minimal distance and maximum time to trigg- Hover state trigger only with touch on mobile devices or button mouse holding. Just mouse over swipe -- In swipe style table you can toggle type of swipe triggering. if SWIPE_TRIGGER_ON_MOVE setup to true - swipe will trigger as swipe can be triggered. If setup to false - swipe will trigger only on released action -- If you have stencil on swipe node and you don't want trigger it outside of stencil node, you can use `swipe:set_click_zone` to restrict swipe zonethout buttons is now not allowed. - - -## Drag -[Drag API here](https://insality.github.io/druid/modules/Drag.html) - -### Overview -System Druid component, handle drag actions on node - -### Setup -Create drag component with druid: `hover = druid:new_drag(node, drag_callback)` - -### Notes -- Drag callback have next params: (self, dx, dy, total_x, total_y) - - **self**: Druid self context - - **dx**: *number* - delta x position - - **dy**: *number* - delta y position - - **total_x**: *number* - total delta x position - - **total_y**: *number* - total delta y position -- In styles, you can point the drag start deadzone. Default value is 10 pixels -- Drag correctly process multitouch. You can switch touch_id, while dragging on node with correct _dx_ and _dy_ values (made for correct scrolling) -- You can restrict horizontal or vertical dragging by setting `drag.can_x` or `drag.can_y` to _false_ value -- You can get info about current drag state: - - _is_touch_ - Is currently node touching - - _is_drag_ - Is currently node is dragging - - _x_ and _y_ - Current touch position - - _touch_start_pos_ - Touch stat positions -- Drag have next events: - - _on_touch_start_ (self) - Event on touch start - - _on_touch_end_ (self) - Event on touch end - - _on_drag_start_ (self) - Event on drag start - - _on_drag_ (self, dx, dy) - Event on drag process - - _on_drag_end_ (self) - Event on drag end -- Drag node zone can be restricted via `drag:set_click_zone(node)` - - -## Hotkey -[Hotkey API here](https://insality.github.io/druid/modules/Hotkey.html) - -### Overview -Druid component to handle keyboard hotkeys with key modificators - -### Setup -This is extended component. Before use it, you should register it: -``` -local druid = require("druid.druid") -local hotkey = require("druid.extended.hotkey") -druid.register("hotkey", hotkey) -``` -Create hotkey component with druid: `hotkey = druid:new_hotkey(keys_array, callback, [callback_argument])` - -### Notes -- Hotkey callback is similar with button callback: (self, callback_argument) - - **self**: Druid self context - - **callback_argument**: *value* - Any value passed at component constructor -- In styles, you can point the array of modificator keys. This keys should be pressed with main key to trigger the callback -- The keys_arrays should contains one action key and any amount of modificator keys -- You can add additional hotkeys to hotkey component with `hotkey:add_hotkey(keys_array, callback_argument)` - - -## Layout -[Layout API here](https://insality.github.io/druid/modules/Layout.html) - -### Overview -Component to arrange nodes inside layout node with margin/paddings settings. Works with different node sizes and pivots. Works in the same way as Figma AutoLayout - -### Setup -This is extended component. Before use it, you should register it: -``` -local druid = require("druid.druid") -local layout = require("druid.extended.layout") -druid.register("layout", layout) -``` -Create layout component with druid: `layout = druid:new_layout(node, layout_mode)` - - -### Notes -- Layout mode can be next: - - `horizontal` - arrange nodes in horizontal line - - `vertical` - arrange nodes in vertical line - - `horizontal_wrap` - arrange nodes in horizontal line with wrap to next line -- You can setup margin and padding for layout nodes -- You can set "justify" alignment to place nodes with the same margin between layout node borders -- You can set "hug" by content. This option will set layout node size by content size. Can be setup separately for width and height - diff --git a/docs_md/FAQ.md b/docs_md/FAQ.md deleted file mode 100644 index 4812a91..0000000 --- a/docs_md/FAQ.md +++ /dev/null @@ -1,36 +0,0 @@ -# Druid FAQ - -Welcome to the Druid FAQ! Here are answers to some common questions you may have: - -### Q: How do I remove a Druid component instance? -**A:** To remove a created Druid component, use the `druid:remove` function. You can find more information in the [API reference](https://insality.github.io/druid/modules/druid_instance.html#druid:remove). - -### Q: How does Druid process input? -**A:** Input processing in Druid follows a Last-In-First-Out (LIFO) queue. Buttons added later have higher priority than those added earlier. To ensure correct button behavior, place your buttons from back to front in most cases. - -### Q: What is the purpose of the Blocker component? -**A:** The Blocker component is used to block input in a specific zone. It is useful for creating unclickable zones within buttons or for creating a panel of buttons on top of another button (e.g., closing windows by clicking on the window background). You can find more information about the Blocker component [here](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#notes-2). - -### Q: What can I do with custom components? -**A:** With custom components in Druid, the possibilities are endless! Custom components allow you to separate component placement and game logic from other elements, making them reusable and easier to test and develop. Custom components can be used for scroll elements with buttons, custom GUI widgets, or even components with custom game logic. Templates often accompany custom components, allowing you to create multiple visual variations for a single component module. You can find some examples of custom components [here](https://github.com/Insality/druid-assets). - -### Q: How does `self:get_node()` work? -**A:** The `self:get_node()` function in a Druid component searches for nodes in the GUI directly or in cloned nodes created using `gui.clone_tree()`. It also considers nodes placed as templates, with the full node ID composed of the template name and node name (including cloned nodes). To ensure correct usage of `self:get_node()`, set up the component nodes using `self:set_template()` and `self:set_component_nodes()` before calling `self:get_node()`. It's best to pass the string name of the node, rather than the GUI node itself. - -### Q: My button in a scroll is clickable outside the stencil node. How can I fix this? -**A:** When using Druid, the stencil node does not prevent buttons from being clickable outside its bounds. To address this, you can set up an additional click zone on your buttons using the `button:set_click_zone()` function. After adding a button to the scroll, you can use the following code: -```lua --- Assuming the scroll view node is the stencil node -button:set_click_zone(scroll.view_node) -``` - -### Q: How do I use EmmyLua annotations? (from Druid 0.6.0) -**A:** EmmyLua annotations are used for better autocompletion and type inference in editors. To use the generated EmmyLua annotations, copy the `druid/annotations.lua` file to your project. After copying, you may need to restart the EmmyLua server to ensure the changes take effect. Once the annotations are processed, you can specify the type of Druid in your code: -```lua ----@type druid -local druid = require("druid.druid") - --- Autocomplete and type information should now work -``` - -Feel free to ask any additional questions you have about Druid! diff --git a/docs_md/api_reference/druid_button.md b/docs_md/api_reference/druid_button.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs_md/quick_api_reference.md b/docs_md/quick_api_reference.md deleted file mode 100644 index e53c5d1..0000000 --- a/docs_md/quick_api_reference.md +++ /dev/null @@ -1,74 +0,0 @@ -# Quick API Reference - -## Druid -```lua -local druid = require("druid.druid") - -druid.init_window_listener() -druid.on_language_change() -druid.on_window_callback(window_event) -druid.set_default_style(style) -druid.set_sound_function(callback) -druid.set_text_function(callback) - -self.druid = druid.new(context, [style]) -``` - -## Druid Instance -```lua -self.druid:final() -self.druid:update(dt) -self.druid:on_input(action_id, action) -self.druid:on_message(message_id, message, sender) - -self.druid:new(component, ...) -self.druid:new_back_handler([callback], [params]) -self.druid:new_blocker(node) -self.druid:new_button(node, [callback], [params], [anim_node]) -self.druid:new_container(node, [mode], [callback]) -self.druid:new_data_list(druid_scroll, druid_grid, create_function) -self.druid:new_drag(node, [on_drag_callback]) -self.druid:new_grid(parent_node, item, [in_row]) -self.druid:new_hotkey(keys_array, [callback], [callback_argument]) -self.druid:new_hover(node, [on_hover_callback], [on_mouse_hover_callback]) -self.druid:new_input(click_node, text_node, [keyboard_type]) -self.druid:new_lang_text(node, [locale_id], [adjust_type]) -self.druid:new_layout(node, [mode]) -self.druid:new_progress(node, key, [init_value]) -self.druid:new_rich_input(template, [nodes]) -self.druid:new_rich_text(text_node, [value]) -self.druid:new_scroll(view_node, content_node) -self.druid:new_slider(pin_node, end_pos, [callback]) -self.druid:new_swipe(node, [on_swipe_callback]) -self.druid:new_text(node, [value], [no_adjust]) -self.druid:new_timer(node, [seconds_from], [seconds_to], [callback]) -self.druid:new_widget(widget, [template], [nodes], ...) -self.druid:on_window_event([window_event]) -self.druid:remove(component) -self.druid:set_blacklist(blacklist_components) -self.druid:set_whitelist(whitelist_components) -``` - -## Components -### Base Component -### Blocker -### Button -### Container -### Data List -### Drag -### Grid -### Hotkey -### Hover -### Input -### Lang Text -### Layout -### Progress -### Rich Input -### Rich Text -### Scroll -### Slider -### Swipe -### Text -### Timer - -## Helper diff --git a/druid.code-workspace b/druid.code-workspace deleted file mode 100644 index ac43fbc..0000000 --- a/druid.code-workspace +++ /dev/null @@ -1,31 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "files.exclude": { - "**/.git": true, // this is a default value - "**/.DS_Store": true, // this is a default value - - "**/node_modules": true, // this excludes all folders - // named "node_modules" from - // the explore tree - - // alternative version - "node_modules": true, // this excludes the folder - // only from the root of - // your workspace - ".internal": true, - "bundle": true, - "input": true, - "media": true, - "build": true, - "docs": true, - ".github": true, - ".deployer_cache": true, - "dist": true - } - } -} diff --git a/druid/base/back_handler.lua b/druid/base/back_handler.lua index 534eae7..22b459d 100644 --- a/druid/base/back_handler.lua +++ b/druid/base/back_handler.lua @@ -2,28 +2,35 @@ local event = require("event.event") local const = require("druid.const") local component = require("druid.component") ----@class druid.back_handler: druid.base_component +---Component to handle back button. It handles Android back button and Backspace key. +--- +---### Setup +---Create back handler component with druid: `druid:new_back_handler(callback)` +--- +---### Notes +---- Key triggers in `input.binding` should be setup for correct working +---- It uses a key_back and key_backspace action ids +---@class druid.back_handler: druid.component ---@field on_back event Trigger on back handler action, fun(self, params) ---@field params any|nil Custom args to pass in the callback local M = component.create("back_handler") ----@param callback function|nil ----@param params any|nil +---The Back Handler constructor +---@param callback function|nil The callback to call when the back handler is triggered +---@param params any? Custom args to pass in the callback function M:init(callback, params) self.params = params self.on_back = event.create(callback) end ----@param action_id string ----@param action table +---@private +---@param action_id hash The action id +---@param action table The action table +---@return boolean is_consumed True if the input was consumed function M:on_input(action_id, action) - if not action.released then - return false - end - - if action_id == const.ACTION_BACK or action_id == const.ACTION_BACKSPACE then + if action.released and (action_id == const.ACTION_BACK or action_id == const.ACTION_BACKSPACE) then self.on_back:trigger(self:get_context(), self.params) return true end diff --git a/druid/base/blocker.lua b/druid/base/blocker.lua index bbd1890..f2190cb 100644 --- a/druid/base/blocker.lua +++ b/druid/base/blocker.lua @@ -1,21 +1,33 @@ local const = require("druid.const") local component = require("druid.component") ----@class druid.blocker: druid.base_component ----@field node node ----@field private _is_enabled boolean +---Druid component for block input. Use it to block input in special zone. +--- +---### Setup +---Create blocker component with druid: `druid:new_blocker(node_name)` +--- +---### Notes +---- Blocker can be used to create safe zones, where you have big buttons +---- Blocker will capture all input events that hit the node, preventing them from reaching other components +---- Blocker works placed as usual component in stack, so any other component can be placed on top of it and will work as usual +---@class druid.blocker: druid.component +---@field node node The node that will block input +---@field private _is_enabled boolean Whether blocker is enabled local M = component.create("blocker") ----@param node node +---The Blocker constructor +---@param node node|string The node to use as a blocker function M:init(node) self.node = self:get_node(node) self._is_enabled = gui.is_enabled(self.node, true) end ----@param action_id string ----@param action table +---@private +---@param action_id string The action id +---@param action table The action table +---@return boolean is_consumed True if the input was consumed function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH and @@ -40,8 +52,8 @@ end ---Set blocker enabled state ----@param state boolean ----@return druid.blocker self +---@param state boolean The new enabled state +---@return druid.blocker self The blocker instance function M:set_enabled(state) self._is_enabled = state @@ -50,7 +62,7 @@ end ---Get blocker enabled state ----@return boolean +---@return boolean is_enabled True if the blocker is enabled function M:is_enabled() return self._is_enabled end diff --git a/druid/base/button.lua b/druid/base/button.lua index f1c48dc..7799863 100755 --- a/druid/base/button.lua +++ b/druid/base/button.lua @@ -1,288 +1,10 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid Component for Handling User Click Interactions: Click, Long Click, Double Click, and More. --- --- # Overview # --- --- This component provides a versatile solution for handling user click interactions. --- It allows you to make any GUI node clickable and define various callbacks for different types of clicks. --- --- # Notes # --- --- • The click callback will not trigger if the cursor moves outside the node's --- area between the pressed and released states. --- --- • If a button has a double click event subscriber and the double click event is triggered, --- the regular click callback will not be triggered. --- --- • Buttons can be triggered using a keyboard key by calling the button:set_key_trigger method. --- --- • To animate a small icon on a big button panel, you can use an animation node. --- The trigger node name should be set as "big panel," and the animation node should be set as "small icon." --- --- Example Link --- @usage --- local function on_button_click(self, args, button) --- print("Button has clicked with params: " .. args) --- print("Also the button component is passed in callback params") --- end --- --- local custom_args = "Any variable to pass inside callback" --- local button = self.druid:new_button("button_name", on_button_click, custom_args) --- --- @module Button --- @within BaseComponent --- @alias druid.button - - ---- The event: Event on successful release action over button. --- @usage --- -- Custom args passed in Button constructor --- button.on_click:subscribe(function(self, custom_args, button_instance) --- print("On button click!") --- end) --- @tfield event on_click event - - ---- The event: Event on repeated action over button. --- --- This callback will be triggered if user hold the button. The repeat rate pick from `input.repeat_interval` in game.project --- @usage --- -- Custom args passed in Button constructor --- button.on_repeated_click:subscribe(function(self, custom_args, button_instance, click_count) --- print("On repeated Button click!") --- end) --- @tfield event on_repeated_click event - - ---- The event: Event on long tap action over button. --- --- This callback will be triggered if user pressed the button and hold the some amount of time. --- The amount of time picked from button style param: LONGTAP_TIME --- @usage --- -- Custom args passed in Button constructor --- button.on_long_click:subscribe(function(self, custom_args, button_instance, hold_time) --- print("On long Button click!") --- end) --- @tfield event on_long_click event - - ---- The event: Event on double tap action over button. --- --- If secondary click was too fast after previous one, the double --- click will be called instead usual click (if on_double_click subscriber exists) --- @usage --- -- Custom args passed in Button constructor --- button.on_double_click:subscribe(function(self, custom_args, button_instance, click_amount) --- print("On double Button click!") --- end) --- @tfield event on_double_click event - - ---- The event: Event calls every frame before on_long_click event. --- --- If long_click subscriber exists, the on_hold_callback will be called before long_click trigger. --- --- Usecase: Animate button progress of long tap --- @usage --- -- Custom args passed in Button constructor --- button.on_double_click:subscribe(function(self, custom_args, button_instance, time) --- print("On hold Button callback!") --- end) --- @tfield event on_hold_callback event - - ---- The event: Event calls if click event was outside of button. --- --- This event will be triggered for each button what was not clicked on user click action --- --- Usecase: Hide the popup when click outside --- @usage --- -- Custom args passed in Button constructor --- button.on_click_outside:subscribe(function(self, custom_args, button_instance) --- print("On click Button outside!") --- end) --- @tfield event on_click_outside event - - ---- The event: Event triggered if button was pressed by user. --- @usage --- -- Custom args passed in Button constructor --- button.on_pressed:subscribe(function(self, custom_args, button_instance) --- print("On Button pressed!") --- end) --- @tfield event on_pressed event - ---- Button trigger node --- @tfield node node - ----The GUI node id from button node --- @tfield hash node_id - ---- Button animation node. --- In default case equals to clickable node. --- --- Usecase: You have the big clickable panel, but want to animate only one small icon on it. --- @tfield node|nil anim_node Default node - ----Custom args for any Button event. Setup in Button constructor --- @tfield any params - ---- The Hover: Button Hover component --- @tfield Hover hover Hover - ---- Additional button click area, defined by another GUI node --- @tfield node|nil click_zone - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") ----Clickable node with various interaction callbacks ----@class druid.button: druid.base_component ----@field on_click event function(self, custom_args, button_instance) ----@field on_pressed event ----@field on_repeated_click event ----@field on_long_click event ----@field on_double_click event ----@field on_hold_callback event ----@field on_click_outside event ----@field node node ----@field node_id hash ----@field anim_node node ----@field params any ----@field hover druid.hover ----@field click_zone node|nil ----@field start_scale vector3 ----@field start_pos vector3 ----@field disabled boolean ----@field key_trigger hash ----@field style table -local M = component.create("button") - - -local function is_input_match(self, action_id) - if action_id == const.ACTION_TOUCH or action_id == const.ACTION_MULTITOUCH then - return true - end - - if self.key_trigger and action_id == self.key_trigger then - return true - end - - return false -end - - -local function on_button_hover(self, hover_state) - self.style.on_hover(self, self.anim_node, hover_state) -end - - -local function on_button_mouse_hover(self, hover_state) - self.style.on_mouse_hover(self, self.anim_node, hover_state) -end - - -local function on_button_click(self) - if self._is_html5_mode then - self._is_html5_listener_set = false - html5.set_interaction_listener(nil) - end - self.click_in_row = 1 - self.on_click:trigger(self:get_context(), self.params, self) - self.style.on_click(self, self.anim_node) -end - - -local function on_button_repeated_click(self) - if not self.is_repeated_started then - self.click_in_row = 0 - self.is_repeated_started = true - end - - self.click_in_row = self.click_in_row + 1 - self.on_repeated_click:trigger(self:get_context(), self.params, self, self.click_in_row) - self.style.on_click(self, self.anim_node) -end - - -local function on_button_long_click(self) - self.click_in_row = 1 - local time = socket.gettime() - self.last_pressed_time - self.on_long_click:trigger(self:get_context(), self.params, self, time) - self.style.on_click(self, self.anim_node) -end - - -local function on_button_double_click(self) - self.click_in_row = self.click_in_row + 1 - self.on_double_click:trigger(self:get_context(), self.params, self, self.click_in_row) - self.style.on_click(self, self.anim_node) -end - - -local function on_button_hold(self, press_time) - self.on_hold_callback:trigger(self:get_context(), self.params, self, press_time) -end - - ----@param self druid.button -local function on_button_release(self) - if self.is_repeated_started then - return false - end - - local check_function_result = true - if self._check_function then - check_function_result = self._check_function(self:get_context()) - end - - if self.disabled then - self.style.on_click_disabled(self, self.anim_node) - return true - elseif not check_function_result then - if self._failure_callback then - self._failure_callback(self:get_context()) - end - return true - else - if self.can_action and not self._is_html5_mode then - self.can_action = false - - local time = socket.gettime() - local is_long_click = (time - self.last_pressed_time) >= self.style.LONGTAP_TIME - is_long_click = is_long_click and not self.on_long_click:is_empty() - - local is_double_click = (time - self.last_released_time) < self.style.DOUBLETAP_TIME - is_double_click = is_double_click and not self.on_double_click:is_empty() - - if is_long_click then - local is_hold_complete = (time - self.last_pressed_time) >= self.style.AUTOHOLD_TRIGGER - if is_hold_complete then - on_button_long_click(self) - else - self.on_click_outside:trigger(self:get_context(), self.params, self) - end - elseif is_double_click then - on_button_double_click(self) - else - on_button_click(self) - end - - self.last_released_time = time - end - return true - end -end - - ---- Component style params. ----You can override this component styles params in Druid styles table ----or create your own style +---Button style params. +---You can override this component styles params in Druid styles table or create your own style ---@class druid.button.style ---@field LONGTAP_TIME number|nil Minimum time to trigger on_hold_callback. Default: 0.4 ---@field AUTOHOLD_TRIGGER number|nil Maximum hold time to trigger button release while holding. Default: 0.8 @@ -293,26 +15,49 @@ end ---@field on_mouse_hover fun(self, node, hover_state)|nil ---@field on_set_enabled fun(self, node, enabled_state)|nil ----@param style druid.button.style -function M:on_style_change(style) - self.style = {} - self.style.LONGTAP_TIME = style.LONGTAP_TIME or 0.4 - self.style.AUTOHOLD_TRIGGER = style.AUTOHOLD_TRIGGER or 0.8 - self.style.DOUBLETAP_TIME = style.DOUBLETAP_TIME or 0.4 - - self.style.on_click = style.on_click or function(_, node) end - self.style.on_click_disabled = style.on_click_disabled or function(_, node) end - self.style.on_mouse_hover = style.on_mouse_hover or function(_, node, state) end - self.style.on_hover = style.on_hover or function(_, node, state) end - self.style.on_set_enabled = style.on_set_enabled or function(_, node, state) end -end +---Basic Druid input component. Handle input on node and provide different callbacks on touch events. +--- +---### Setup +---Create button with druid: `button = druid:new_button(node_name, callback, [params], [animation_node])` +---Where node_name is name of node from GUI scene. You can use `node_name` as input trigger zone and point another node for animation via `animation_node` +--- +---### Notes +---- Button callback have next params: (self, params, button_instance) +---- - **self** - Druid self context +---- - **params** - Additional params, specified on button creating +---- - **button_instance** - button itself +---- You can set _params_ on button callback on button creating: `druid:new_button("node_name", callback, params)`. +---- Button have several events like on_click, on_repeated_click, on_long_click, on_hold_click, on_double_click +---- Click event will not trigger if between pressed and released state cursor was outside of node zone +---- Button can have key trigger to use them by key: `button:set_key_trigger` +---- +---@class druid.button: druid.component +---@field on_click event function(self, custom_args, button_instance) +---@field on_pressed event function(self, custom_args, button_instance) +---@field on_repeated_click event function(self, custom_args, button_instance, click_count) Repeated click callback, while holding the button +---@field on_long_click event function(self, custom_args, button_instance, hold_time) Callback on long button tap +---@field on_double_click event function(self, custom_args, button_instance, click_amount) Different callback, if tap button 2+ in row +---@field on_hold_callback event function(self, custom_args, button_instance, press_time) Hold callback, before long_click trigger +---@field on_click_outside event function(self, custom_args, button_instance) +---@field node node Clickable node +---@field node_id hash Node id +---@field anim_node node Animation node. In default case equals to clickable node +---@field params any Custom arguments for any Button event +---@field hover druid.hover Hover component for this button +---@field click_zone node|nil Click zone node to restrict click area +---@field start_scale vector3 Start scale of the button +---@field start_pos vector3 Start position of the button +---@field disabled boolean Is button disabled +---@field key_trigger hash Key trigger for this button +---@field style table Style for this button +local M = component.create("button") ----Button constructor ----@param node_or_node_id node|string Node name or GUI Node itself. +---The constructor for the button component +---@param node_or_node_id node|string Node name or GUI Node itself ---@param callback fun()|nil Callback on button click ----@param custom_args any|nil Custom args for any Button event ----@param anim_node node|string|nil Node to animate instead of trigger node. +---@param custom_args any|nil Custom args for any Button event, will be passed to callbacks +---@param anim_node node|string|nil Node to animate instead of trigger node, useful for animating small icons on big panels function M:init(node_or_node_id, callback, custom_args, anim_node) self.druid = self:get_druid() self.node = self:get_node(node_or_node_id) @@ -322,8 +67,8 @@ function M:init(node_or_node_id, callback, custom_args, anim_node) self.start_scale = gui.get_scale(self.anim_node) self.start_pos = gui.get_position(self.anim_node) self.params = custom_args - self.hover = self.druid:new_hover(node_or_node_id, on_button_hover) - self.hover.on_mouse_hover:subscribe(on_button_mouse_hover) + self.hover = self.druid:new_hover(node_or_node_id, self._on_button_hover) + self.hover.on_mouse_hover:subscribe(self._on_button_mouse_hover) self.click_zone = nil self.is_repeated_started = false self.last_pressed_time = 0 @@ -347,6 +92,39 @@ function M:init(node_or_node_id, callback, custom_args, anim_node) end +---@private +---@param style druid.button.style +function M:on_style_change(style) + self.style = { + LONGTAP_TIME = style.LONGTAP_TIME or 0.4, + AUTOHOLD_TRIGGER = style.AUTOHOLD_TRIGGER or 0.8, + DOUBLETAP_TIME = style.DOUBLETAP_TIME or 0.4, + + on_click = style.on_click or function(_, node) end, + on_click_disabled = style.on_click_disabled or function(_, node) end, + on_mouse_hover = style.on_mouse_hover or function(_, node, state) end, + on_hover = style.on_hover or function(_, node, state) end, + on_set_enabled = style.on_set_enabled or function(_, node, state) end, + } +end + + +---Remove default button style animations +---@return druid.button self The current button instance +function M:set_animations_disabled() + local empty_function = function() end + + self.style.on_click = empty_function + self.style.on_hover = empty_function + self.style.on_mouse_hover = empty_function + self.style.on_set_enabled = empty_function + self.style.on_click_disabled = empty_function + + return self +end + + +---@private function M:on_late_init() if not self.click_zone then local stencil_node = helper.get_closest_stencil_node(self.node) @@ -357,8 +135,12 @@ function M:on_late_init() end +---@private +---@param action_id hash The action id +---@param action table The action table +---@return boolean is_consumed True if the input was consumed function M:on_input(action_id, action) - if not is_input_match(self, action_id) then + if not self:_is_input_match(action_id) then return false end @@ -402,7 +184,7 @@ function M:on_input(action_id, action) if self._is_html5_mode then self._is_html5_listener_set = true html5.set_interaction_listener(function() - on_button_click(self) + self:_on_button_click() end) end return is_consume @@ -411,25 +193,25 @@ function M:on_input(action_id, action) -- While hold button, repeat rate pick from input.repeat_interval if action.repeated then if not self.on_repeated_click:is_empty() and self.can_action then - on_button_repeated_click(self) + self:_on_button_repeated_click() return is_consume end end if action.released then - return on_button_release(self) and is_consume + return self:_on_button_release() and is_consume end if self.can_action and not self.on_long_click:is_empty() then local press_time = socket.gettime() - self.last_pressed_time if self.style.AUTOHOLD_TRIGGER <= press_time then - on_button_release(self) + self:_on_button_release() return is_consume end if press_time >= self.style.LONGTAP_TIME then - on_button_hold(self, press_time) + self:_on_button_hold(press_time) return is_consume end end @@ -438,6 +220,7 @@ function M:on_input(action_id, action) end +---@private function M:on_input_interrupt() self.can_action = false self.hover:set_hover(false) @@ -445,11 +228,11 @@ function M:on_input_interrupt() end ---- Set button enabled state. --- The style.on_set_enabled will be triggered. --- Disabled button is not clickable. +---Set button enabled state. +---The style.on_set_enabled will be triggered. +---Disabled button is not clickable. ---@param state boolean|nil Enabled state ----@return druid.button self +---@return druid.button self The current button instance function M:set_enabled(state) self.disabled = not state self.hover:set_enabled(state) @@ -459,21 +242,19 @@ function M:set_enabled(state) end ---- Get button enabled state. --- --- By default all Buttons is enabled on creating. ----@return boolean @True, if button is enabled now, False overwise +---Get button enabled state. +---By default all Buttons is enabled on creating. +---@return boolean is_enabled True, if button is enabled now, False overwise function M:is_enabled() return not self.disabled end ---- Set additional button click area. --- Useful to restrict click outside out stencil node or scrollable content. --- --- This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check +---Set additional button click area. +---Useful to restrict click outside out stencil node or scrollable content. +---If button node placed inside stencil node, it will be automatically set to this stencil node. ---@param zone node|string|nil Gui node ----@return druid.button self +---@return druid.button self The current button instance function M:set_click_zone(zone) self.click_zone = zone and self:get_node(zone) or nil self.hover:set_click_zone(zone) @@ -484,7 +265,7 @@ end ---Set key name to trigger this button by keyboard. ---@param key hash|string The action_id of the input key. Example: "key_space" ----@return druid.button self +---@return druid.button self The current button instance function M:set_key_trigger(key) if type(key) == "string" then self.key_trigger = hash(key) @@ -496,7 +277,7 @@ function M:set_key_trigger(key) end ---- Get current key name to trigger this button. +---Get current key name to trigger this button. ---@return hash key_trigger The action_id of the input key function M:get_key_trigger() return self.key_trigger @@ -506,7 +287,7 @@ end ---Set function for additional check for button click availability ---@param check_function function|nil Should return true or false. If true - button can be pressed. ---@param failure_callback function|nil Function will be called on button click, if check function return false ----@return druid.button self +---@return druid.button self The current button instance function M:set_check_function(check_function, failure_callback) self._check_function = check_function self._failure_callback = failure_callback @@ -522,11 +303,131 @@ end --- ---If the game is not HTML, html mode will be not enabled ---@param is_web_mode boolean|nil If true - button will be called inside html5 callback ----@return druid.button self +---@return druid.button self The current button instance function M:set_web_user_interaction(is_web_mode) self._is_html5_mode = not not (is_web_mode and html5) return self end +---@param action_id hash The action id +---@return boolean is_match True if the input matches the button +function M:_is_input_match(action_id) + if action_id == const.ACTION_TOUCH or action_id == const.ACTION_MULTITOUCH then + return true + end + + if self.key_trigger and action_id == self.key_trigger then + return true + end + + return false +end + + +---@param hover_state boolean True if the hover state is active +function M:_on_button_hover(hover_state) + self.style.on_hover(self, self.anim_node, hover_state) +end + + +---@param hover_state boolean True if the hover state is active +function M:_on_button_mouse_hover(hover_state) + self.style.on_mouse_hover(self, self.anim_node, hover_state) +end + + +function M:_on_button_click() + if self._is_html5_mode then + self._is_html5_listener_set = false + html5.set_interaction_listener(nil) + end + self.click_in_row = 1 + self.on_click:trigger(self:get_context(), self.params, self) + self.style.on_click(self, self.anim_node) +end + + +function M:_on_button_repeated_click() + if not self.is_repeated_started then + self.click_in_row = 0 + self.is_repeated_started = true + end + + self.click_in_row = self.click_in_row + 1 + self.on_repeated_click:trigger(self:get_context(), self.params, self, self.click_in_row) + self.style.on_click(self, self.anim_node) +end + + +function M:_on_button_long_click() + self.click_in_row = 1 + local time = socket.gettime() - self.last_pressed_time + self.on_long_click:trigger(self:get_context(), self.params, self, time) + self.style.on_click(self, self.anim_node) +end + + +function M:_on_button_double_click() + self.click_in_row = self.click_in_row + 1 + self.on_double_click:trigger(self:get_context(), self.params, self, self.click_in_row) + self.style.on_click(self, self.anim_node) +end + + +---@param press_time number Amount of time the button was held +function M:_on_button_hold(press_time) + self.on_hold_callback:trigger(self:get_context(), self.params, self, press_time) +end + + +function M:_on_button_release() + if self.is_repeated_started then + return false + end + + local check_function_result = true + if self._check_function then + check_function_result = self._check_function(self:get_context()) + end + + if self.disabled then + self.style.on_click_disabled(self, self.anim_node) + return true + elseif not check_function_result then + if self._failure_callback then + self._failure_callback(self:get_context()) + end + return true + else + if self.can_action and not self._is_html5_mode then + self.can_action = false + + local time = socket.gettime() + local is_long_click = (time - self.last_pressed_time) >= self.style.LONGTAP_TIME + is_long_click = is_long_click and not self.on_long_click:is_empty() + + local is_double_click = (time - self.last_released_time) < self.style.DOUBLETAP_TIME + is_double_click = is_double_click and not self.on_double_click:is_empty() + + if is_long_click then + local is_hold_complete = (time - self.last_pressed_time) >= self.style.AUTOHOLD_TRIGGER + if is_hold_complete then + self:_on_button_long_click() + else + self.on_click_outside:trigger(self:get_context(), self.params, self) + end + elseif is_double_click then + self:_on_button_double_click() + else + self:_on_button_click() + end + + self.last_released_time = time + end + return true + end +end + + return M diff --git a/druid/base/drag.lua b/druid/base/drag.lua index ee5a3dc..65a3674 100644 --- a/druid/base/drag.lua +++ b/druid/base/drag.lua @@ -1,62 +1,3 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle drag action on node. --- Drag have correct handling for multitouch and swap --- touched while dragging. Drag will be processed even --- the cursor is outside of node, if drag is already started --- --- Example Link --- @module Drag --- @within BaseComponent --- @alias druid.drag - ---- Drag node --- @tfield node node - ---- Event on touch start callback(self) --- @tfield event on_touch_start event - ---- Event on touch end callback(self) --- @tfield event on_touch_end event - ---- Event on drag start callback(self, touch) --- @tfield event on_drag_start event - ---- on drag progress callback(self, dx, dy, total_x, total_y, touch) --- @tfield event on_drag Event event - ---- Event on drag end callback(self, total_x, total_y, touch) --- @tfield event on_drag_end event - ---- Is component now touching --- @tfield boolean is_touch - ---- Is component now dragging --- @tfield boolean is_drag - ---- Is drag component process vertical dragging. Default - true --- @tfield boolean can_x - ---- Is drag component process horizontal. Default - true --- @tfield boolean can_y - ---- Current touch x position --- @tfield number x - ---- Current touch y position --- @tfield number y - ---- Current touch x screen position --- @tfield number screen_x - ---- Current touch y screen position --- @tfield number screen_y - ---- Touch start position --- @tfield vector3 touch_start_pos - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") @@ -66,156 +7,37 @@ local component = require("druid.component") ---@field DRAG_DEADZONE number Distance in pixels to start dragging. Default: 10 ---@field NO_USE_SCREEN_KOEF boolean If screen aspect ratio affects on drag values. Default: false ----@class druid.drag: druid.base_component ----@field node node ----@field on_touch_start event ----@field on_touch_end event ----@field on_drag_start event ----@field on_drag event ----@field on_drag_end event ----@field style druid.drag.style ----@field click_zone node|nil ----@field is_touch boolean ----@field is_drag boolean ----@field can_x boolean ----@field can_y boolean ----@field dx number ----@field dy number ----@field touch_id number ----@field x number ----@field y number ----@field screen_x number ----@field screen_y number ----@field touch_start_pos vector3 ----@field private _is_enabled boolean ----@field private _x_koef number ----@field private _y_koef number +---A component that allows you to subscribe to drag events over a node +---@class druid.drag: druid.component +---@field node node The node to subscribe to drag events over +---@field on_touch_start event fun(self, touch) The event triggered when a touch starts +---@field on_touch_end event fun(self, touch) The event triggered when a touch ends +---@field on_drag_start event fun(self, touch) The event triggered when a drag starts +---@field on_drag event fun(self, touch) The event triggered when a drag occurs +---@field on_drag_end event fun(self, touch) The event triggered when a drag ends +---@field style druid.drag.style The style of Drag component +---@field click_zone node|nil The click zone of Drag component +---@field is_touch boolean True if a touch is active +---@field is_drag boolean True if a drag is active +---@field can_x boolean True if Drag can move horizontally +---@field can_y boolean True if Drag can move vertically +---@field dx number The horizontal drag distance +---@field dy number The vertical drag distance +---@field touch_id number The touch id +---@field x number The current x position +---@field y number The current y position +---@field screen_x number The current screen x position +---@field screen_y number The current screen y position +---@field touch_start_pos vector3 The touch start position +---@field private _is_enabled boolean True if Drag component is enabled +---@field private _x_koef number The x koef +---@field private _y_koef number The y koef local M = component.create("drag", const.PRIORITY_INPUT_HIGH) -local function start_touch(self, touch) - self.is_touch = true - self.is_drag = false - - self.touch_start_pos.x = touch.x - self.touch_start_pos.y = touch.y - - self.x = touch.x - self.y = touch.y - - self.screen_x = touch.screen_x - self.screen_y = touch.screen_y - - self._scene_scale = helper.get_scene_scale(self.node) - - self.on_touch_start:trigger(self:get_context(), touch) -end - - -local function end_touch(self, touch) - if self.is_drag then - self.on_drag_end:trigger( - self:get_context(), - self.x - self.touch_start_pos.x, - self.y - self.touch_start_pos.y, - touch - ) - end - - self.is_drag = false - if self.is_touch then - self.is_touch = false - self.on_touch_end:trigger(self:get_context(), touch) - end - self:reset_input_priority() - self.touch_id = 0 -end - - -local function process_touch(self, touch) - if not self.can_x then - self.touch_start_pos.x = touch.x - end - - if not self.can_y then - self.touch_start_pos.y = touch.y - end - - local distance = helper.distance(touch.x, touch.y, self.touch_start_pos.x, self.touch_start_pos.y) - if not self.is_drag and distance >= self.style.DRAG_DEADZONE then - self.is_drag = true - self.on_drag_start:trigger(self:get_context(), touch) - self:set_input_priority(const.PRIORITY_INPUT_MAX, true) - end -end - - ---- Return current touch action from action input data --- If touch_id stored - return exact this touch action -local function find_touch(action_id, action, touch_id) - local act = helper.is_mobile() and const.ACTION_MULTITOUCH or const.ACTION_TOUCH - - if action_id ~= act then - return - end - - if action.touch then - local touch = action.touch - for i = 1, #touch do - if touch[i].id == touch_id then - return touch[i] - end - end - return touch[1] - else - return action - end -end - - ---- Process on touch release. We should to find, if any other --- touches exists to switch to another touch. -local function on_touch_release(self, action_id, action) - if #action.touch >= 2 then - -- Find next unpressed touch - local next_touch - for i = 1, #action.touch do - if not action.touch[i].released then - next_touch = action.touch[i] - break - end - end - - if next_touch then - self.x = next_touch.x - self.y = next_touch.y - self.touch_id = next_touch.id - else - end_touch(self) - end - elseif #action.touch == 1 then - end_touch(self) - end -end - - ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield number|nil DRAG_DEADZONE Distance in pixels to start dragging. Default: 10 --- @tfield boolean|nil NO_USE_SCREEN_KOEF If screen aspect ratio affects on drag values. Default: false -function M:on_style_change(style) - self.style = { - DRAG_DEADZONE = style.DRAG_DEADZONE or 10, - NO_USE_SCREEN_KOEF = style.NO_USE_SCREEN_KOEF or false, - } -end - - ----Drag constructor ----@param node_or_node_id node|string ----@param on_drag_callback function +---The constructor for Drag component +---@param node_or_node_id node|string The node to subscribe to drag events over +---@param on_drag_callback fun(self, touch) The callback to call when a drag occurs function M:init(node_or_node_id, on_drag_callback) self.druid = self:get_druid() self.node = self:get_node(node_or_node_id) @@ -250,8 +72,18 @@ function M:init(node_or_node_id, on_drag_callback) end +---@private +---@param style druid.drag.style The style of Drag component +function M:on_style_change(style) + self.style = { + DRAG_DEADZONE = style.DRAG_DEADZONE or 10, + NO_USE_SCREEN_KOEF = style.NO_USE_SCREEN_KOEF or false, + } +end + + ---Set Drag component enabled state. ----@param is_enabled boolean +---@param is_enabled boolean True if Drag component is enabled function M:set_drag_cursors(is_enabled) if defos and is_enabled then self.hover.style.ON_HOVER_CURSOR = defos.CURSOR_CROSSHAIR @@ -263,6 +95,7 @@ function M:set_drag_cursors(is_enabled) end +---@private function M:on_late_init() if not self.click_zone then local stencil_node = helper.get_closest_stencil_node(self.node) @@ -273,6 +106,7 @@ function M:on_late_init() end +---@private function M:on_window_resized() local x_koef, y_koef = helper.get_screen_aspect_koef() self._x_koef = x_koef @@ -281,16 +115,18 @@ function M:on_window_resized() end +---@private function M:on_input_interrupt() if self.is_drag or self.is_touch then - end_touch(self) + self:_end_touch() end end ----@local ----@param action_id string ----@param action table +---@private +---@param action_id hash Action id from on_input +---@param action table Action from on_input +---@return boolean is_consumed True if the input was consumed function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= const.ACTION_MULTITOUCH then return false @@ -302,12 +138,12 @@ function M:on_input(action_id, action) local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone) if not is_pick and not self.is_drag then - end_touch(self) + self:_end_touch() return false end - local touch = find_touch(action_id, action, self.touch_id) + local touch = self:_find_touch(action_id, action, self.touch_id) if not touch then return false end @@ -320,24 +156,24 @@ function M:on_input(action_id, action) self.dy = 0 if touch.pressed and not self.is_touch then - start_touch(self, touch) + self:_start_touch(touch) end if touch.released and self.is_touch then if action.touch then -- Mobile - on_touch_release(self, action_id, action) + self:_on_touch_release(action_id, action) else -- PC - end_touch(self, touch) + self:_end_touch(touch) end end if self.is_touch then - process_touch(self, touch) + self:_process_touch(touch) end - local touch_modified = find_touch(action_id, action, self.touch_id) + local touch_modified = self:_find_touch(action_id, action, self.touch_id) if touch_modified and self.is_drag then self.dx = touch_modified.x - self.x self.dy = touch_modified.y - self.y @@ -369,7 +205,7 @@ end ---Set Drag click zone ----@param node node|string|nil +---@param node node|string|nil Node or node id ---@return druid.drag self Current instance function M:set_click_zone(node) self.click_zone = node and self:get_node(node) or nil @@ -388,11 +224,125 @@ function M:set_enabled(is_enabled) end ----Check if Drag component is enabled ----@return boolean +---Check if Drag component is capture input +---@return boolean is_enabled True if Drag component is enabled function M:is_enabled() return self._is_enabled end +function M:_start_touch(touch) + self.is_touch = true + self.is_drag = false + + self.touch_start_pos.x = touch.x + self.touch_start_pos.y = touch.y + + self.x = touch.x + self.y = touch.y + + self.screen_x = touch.screen_x + self.screen_y = touch.screen_y + + self._scene_scale = helper.get_scene_scale(self.node) + + self.on_touch_start:trigger(self:get_context(), touch) +end + + +---@param touch touch|nil +function M:_end_touch(touch) + if self.is_drag then + self.on_drag_end:trigger( + self:get_context(), + self.x - self.touch_start_pos.x, + self.y - self.touch_start_pos.y, + touch + ) + end + + self.is_drag = false + if self.is_touch then + self.is_touch = false + self.on_touch_end:trigger(self:get_context(), touch) + end + self:reset_input_priority() + self.touch_id = 0 +end + + +---@param touch touch Touch action +function M:_process_touch(touch) + if not self.can_x then + self.touch_start_pos.x = touch.x + end + + if not self.can_y then + self.touch_start_pos.y = touch.y + end + + local distance = helper.distance(touch.x, touch.y, self.touch_start_pos.x, self.touch_start_pos.y) + if not self.is_drag and distance >= self.style.DRAG_DEADZONE then + self.is_drag = true + self.on_drag_start:trigger(self:get_context(), touch) + self:set_input_priority(const.PRIORITY_INPUT_MAX, true) + end +end + + +---Return current touch action from action input data +---If touch_id stored - return exact this touch action +---@param action_id hash Action id from on_input +---@param action table Action from on_input +---@param touch_id number Touch id +---@return table|nil touch Touch action +function M:_find_touch(action_id, action, touch_id) + local act = helper.is_mobile() and const.ACTION_MULTITOUCH or const.ACTION_TOUCH + + if action_id ~= act then + return + end + + if action.touch then + local touch = action.touch + for i = 1, #touch do + if touch[i].id == touch_id then + return touch[i] + end + end + return touch[1] + else + return action + end +end + + +---Process on touch release. We should to find, if any other +---touches exists to switch to another touch. +---@param action_id hash Action id from on_input +---@param action table Action from on_input +function M:_on_touch_release(action_id, action) + if #action.touch >= 2 then + -- Find next unpressed touch + local next_touch + for i = 1, #action.touch do + if not action.touch[i].released then + next_touch = action.touch[i] + break + end + end + + if next_touch then + self.x = next_touch.x + self.y = next_touch.y + self.touch_id = next_touch.id + else + self:_end_touch() + end + elseif #action.touch == 1 then + self:_end_touch() + end +end + + return M diff --git a/druid/base/hover.lua b/druid/base/hover.lua index 4ca0849..315316d 100644 --- a/druid/base/hover.lua +++ b/druid/base/hover.lua @@ -1,40 +1,27 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle hover node interaction --- @module Hover --- @within BaseComponent --- @alias druid.hover - ---- Hover node --- @tfield node node - ---- On hover callback(self, state, hover_instance) --- @tfield event on_hover event - ---- On mouse hover callback(self, state, hover_instance) --- @tfield event on_mouse_hover event - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") ----@class druid.hover: druid.base_component ----@field node node ----@field on_hover event ----@field on_mouse_hover event ----@field style table ----@field click_zone node ----@field private _is_hovered boolean|nil ----@field private _is_mouse_hovered boolean|nil ----@field private _is_enabled boolean|nil ----@field private _is_mobile boolean +---@class druid.hover.style +---@field ON_HOVER_CURSOR string|nil Mouse hover style on node hover +---@field ON_MOUSE_HOVER_CURSOR string|nil Mouse hover style on node mouse hover + +---The component for handling hover events on a node +---@class druid.hover: druid.component +---@field node node Gui node +---@field on_hover event fun(self: druid.hover, is_hover: boolean) Hover event +---@field on_mouse_hover event fun(self: druid.hover, is_hover: boolean) Mouse hover event +---@field style druid.hover.style Style of the hover component +---@field click_zone node Click zone of the hover component +---@field private _is_hovered boolean|nil True if the node is hovered +---@field private _is_mouse_hovered boolean|nil True if the node is mouse hovered +---@field private _is_enabled boolean|nil True if the hover component is enabled +---@field private _is_mobile boolean True if the platform is mobile local M = component.create("hover") ---- The Hover constructor +---The constructor for the hover component ---@param node node Gui node ---@param on_hover_callback function Hover callback ---@param on_mouse_hover function On mouse hover callback @@ -51,6 +38,7 @@ function M:init(node, on_hover_callback, on_mouse_hover) end +---@private function M:on_late_init() if not self.click_zone then local stencil_node = helper.get_closest_stencil_node(self.node) @@ -61,12 +49,8 @@ function M:on_late_init() end ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield[opt] string ON_HOVER_CURSOR Mouse hover style on node hover --- @tfield[opt] string ON_MOUSE_HOVER_CURSOR Mouse hover style on node mouse hover +---@private +---@param style druid.hover.style function M:on_style_change(style) self.style = {} self.style.ON_HOVER_CURSOR = style.ON_HOVER_CURSOR or nil @@ -74,6 +58,10 @@ function M:on_style_change(style) end +---@private +---@param action_id hash Action id from on_input +---@param action table Action from on_input +---@return boolean is_consumed True if the input was consumed function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH and action_id ~= nil then return false @@ -108,12 +96,13 @@ function M:on_input(action_id, action) end +---@private function M:on_input_interrupt() self:set_hover(false) end ---- Set hover state +---Set hover state ---@param state boolean|nil The hover state function M:set_hover(state) if self._is_hovered == state then @@ -129,14 +118,14 @@ function M:set_hover(state) end ---- Return current hover state. True if touch action was on the node at current time ----@return boolean The current hovered state +---Return current hover state. True if touch action was on the node at current time +---@return boolean is_hovered The current hovered state function M:is_hovered() return self._is_hovered end ---- Set mouse hover state +---Set mouse hover state ---@param state boolean|nil The mouse hover state function M:set_mouse_hover(state) if self._is_mouse_hovered == state then @@ -152,15 +141,14 @@ function M:set_mouse_hover(state) end ---- Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time +---Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time ---@return boolean The current hovered state function M:is_mouse_hovered() return self._is_mouse_hovered end ---- Strict hover click area. Useful for --- no click events outside stencil node +---Strict hover click area. Useful for no click events outside stencil node ---@param zone node|string|nil Gui node function M:set_click_zone(zone) if not zone then @@ -172,9 +160,9 @@ function M:set_click_zone(zone) end ---- Set enable state of hover component. --- If hover is not enabled, it will not generate --- any hover events +---Set enable state of hover component. +---If hover is not enabled, it will not generate +---any hover events ---@param state boolean|nil The hover enabled state function M:set_enabled(state) self._is_enabled = state @@ -190,7 +178,7 @@ function M:set_enabled(state) end ---- Return current hover enabled state +---Return current hover enabled state ---@return boolean The hover enabled state function M:is_enabled() return self._is_enabled diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua index 4bd7f75..b382496 100755 --- a/druid/base/scroll.lua +++ b/druid/base/scroll.lua @@ -1,101 +1,46 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle scroll content. --- # Overview # --- --- The Scroll component is designed to handle scrollable content and consists of two nodes: the scroll parent and the scroll input. --- --- The scroll input represents the user input zone and remains static. --- --- The scroll parent is the movable part of the scroll and changes its position. --- --- The initial scroll size can be set by adjusting the size of the scroll parent. --- If the size of the scroll parent is smaller than the scroll input size, scrolling is not available. --- --- # Notes # --- --- • By default, the scroll style includes inertia and extra size for a stretching effect. --- These settings can be adjusted using the scroll style settings. --- For more details, refer to the scroll style settings. --- --- • "Points of interest" can be set up for the scroll. --- The scroll will always be centered on the closest point of interest. --- This feature allows creating a slider without inertia and with points of interest on each scroll element. --- --- • The scroll content size can be adjusted using the scroll:set_size(node_size) method. --- This method sets a new size for the _content node. --- --- • Inertial scrolling mode can be enabled or disabled using the scroll:set_inert(state) method. --- --- • The extra stretch size can be adjusted using the scroll:set_extra_stretch_size method. --- --- • Multitouch is required for scrolling. The scroll component correctly handles --- touch ID swaps while dragging the scroll. --- --- Example Link --- @module Scroll --- @within BaseComponent --- @alias druid.scroll - - ---- On scroll move callback(self, position) --- @tfield event on_scroll event - ---- On scroll_to function callback(self, target, is_instant) --- @tfield event on_scroll_to event - ---- On scroll_to_index function callback(self, index, point) --- @tfield event on_point_scroll event - ---- Scroll view node --- @tfield node view_node - ---- Scroll view size --- @tfield vector3 view_size - ---- Scroll content node --- @tfield node content_node - ---- Flag, if scroll now moving by inertion --- @tfield boolean _is_inert - ---- Current inert speed --- @tfield vector3 inertion - ---- Current scroll posisition --- @tfield vector3 position - ---- Current scroll target position --- @tfield vector3 target_position - ---- Available position for content node: (min_x, max_y, max_x, min_y) --- @tfield vector4 available_pos - ---- Size of available positions: (width, height, 0) --- @tfield vector3 available_size - ---- Drag Druid component --- @tfield Drag drag Drag - ---- Current index of points of interests --- @tfield number|nil selected - ---- Flag, if scroll now animating by gui.animate --- @tfield boolean is_animate - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") ----@class druid.scroll: druid.base_component +---Scroll style parameters +---@class druid.scroll.style +---@field FRICT number|nil Multiplier for free inertion. Default: 0 +---@field FRICT_HOLD number|nil Multiplier for inertion, while touching. Default: 0 +---@field INERT_THRESHOLD number|nil Scroll speed to stop inertion. Default: 3 +---@field INERT_SPEED number|nil Multiplier for inertion speed. Default: 30 +---@field POINTS_DEADZONE number|nil Speed to check points of interests in no_inertion mode. Default: 20 +---@field BACK_SPEED number|nil Scroll back returning lerp speed. Default: 35 +---@field ANIM_SPEED number|nil Scroll gui.animation speed for scroll_to function. Default: 2 +---@field EXTRA_STRETCH_SIZE number|nil extra size in pixels outside of scroll (stretch effect). Default: 0 +---@field SMALL_CONTENT_SCROLL boolean|nil If true, content node with size less than view node size can be scrolled. Default: false +---@field WHEEL_SCROLL_SPEED number|nil The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 +---@field WHEEL_SCROLL_INVERTED boolean|nil If true, invert direction for touchpad and mouse wheel scroll. Default: false +---@field WHEEL_SCROLL_BY_INERTION boolean|nil If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false + +---Basic Druid scroll component. Handles all scrolling behavior in Druid GUI. +--- +---### Setup +---Create scroll component with druid: `druid:new_scroll(view_node, content_node)` +--- +---### Notes +---- View_node is the static part that captures user input and recognizes scrolling touches +---- Content_node is the dynamic part that will change position according to the scroll system +---- Initial scroll size will be equal to content_node size +---- The initial view box will be equal to view_node size +---- Scroll by default style has inertia and extra size for stretching effect +---- You can setup "points of interest" to make scroll always center on closest point +---- Scroll events: +---- - on_scroll(self, position): On scroll move callback +---- - on_scroll_to(self, position, is_instant): On scroll_to function callback +---- - on_point_scroll(self, item_index, position): On scroll_to_index function callback +---- Multitouch is required for scroll. Scroll correctly handles touch_id swap while dragging +---@class druid.scroll: druid.component ---@field node node The root node ---@field click_zone node|nil Optional click zone to restrict scroll area ----@field on_scroll event Triggered on scroll move with (self, position) ----@field on_scroll_to event Triggered on scroll_to with (self, target, is_instant) ----@field on_point_scroll event Triggered on scroll_to_index with (self, index, point) +---@field on_scroll event Triggered on scroll move with fun(self, position) +---@field on_scroll_to event Triggered on scroll_to with fun(self, target, is_instant) +---@field on_point_scroll event Triggered on scroll_to_index with fun(self, index, point) ---@field view_node node The scroll view node (static part) ---@field view_border vector4 The scroll view borders ---@field content_node node The scroll content node (moving part) @@ -107,6 +52,7 @@ local component = require("druid.component") ---@field drag druid.drag The drag component instance ---@field selected number|nil Current selected point of interest index ---@field is_animate boolean True if scroll is animating +---@field style druid.scroll.style Component style parameters ---@field private _is_inert boolean True if inertial scrolling is enabled ---@field private inertion vector3 Current inertial movement vector ---@field private _is_horizontal_scroll boolean True if horizontal scroll enabled @@ -114,81 +60,12 @@ local component = require("druid.component") ---@field private _grid_on_change event Grid items change event ---@field private _grid_on_change_callback function Grid change callback ---@field private _offset vector3 Content start offset ----@field private style table Component style parameters local M = component.create("scroll") -local function inverse_lerp(min, max, current) - return helper.clamp((current - min) / (max - min), 0, 1) -end - - ---- Update vector with next conditions: --- Field x have to <= field z --- Field y have to <= field w -local function get_border_vector(vector, offset) - if vector.x > vector.z then - vector.x, vector.z = vector.z, vector.x - end - if vector.y > vector.w then - vector.y, vector.w = vector.w, vector.y - end - vector.x = vector.x - offset.x - vector.z = vector.z - offset.x - vector.y = vector.y - offset.y - vector.w = vector.w - offset.y - return vector -end - - ---- Return size from scroll border vector4 -local function get_size_vector(vector) - return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0) -end - - ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield number|nil FRICT Multiplier for free inertion. Default: 0 --- @tfield number|nil FRICT_HOLD Multiplier for inertion, while touching. Default: 0 --- @tfield number|nil INERT_THRESHOLD Scroll speed to stop inertion. Default: 3 --- @tfield number|nil INERT_SPEED Multiplier for inertion speed. Default: 30 --- @tfield number|nil POINTS_DEADZONE Speed to check points of interests in no_inertion mode. Default: 20 --- @tfield number|nil BACK_SPEED Scroll back returning lerp speed. Default: 35 --- @tfield number|nil ANIM_SPEED Scroll gui.animation speed for scroll_to function. Default: 2 --- @tfield number|nil EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect). Default: 0 --- @tfield boolean|nil SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled. Default: false --- @tfield boolean|nil WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0 --- @tfield boolean|nil WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll. Default: false --- @tfield boolean|nil WHEEL_SCROLL_BY_INERTION If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false -function M:on_style_change(style) - self.style = {} - self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0 - self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2 - self.style.BACK_SPEED = style.BACK_SPEED or 0.35 - - self.style.FRICT = style.FRICT or 0 - self.style.FRICT_HOLD = style.FRICT_HOLD or 0 - - self.style.INERT_THRESHOLD = style.INERT_THRESHOLD or 3 - self.style.INERT_SPEED = style.INERT_SPEED or 30 - self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20 - self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false - self.style.WHEEL_SCROLL_SPEED = style.WHEEL_SCROLL_SPEED or 0 - self.style.WHEEL_SCROLL_INVERTED = style.WHEEL_SCROLL_INVERTED or false - self.style.WHEEL_SCROLL_BY_INERTION = style.WHEEL_SCROLL_BY_INERTION or false - - self._is_inert = not (self.style.FRICT == 0 or - self.style.FRICT_HOLD == 0 or - self.style.INERT_SPEED == 0) -end - - ---- The Scroll constructor ----@param view_node string|node GUI view scroll node ----@param content_node string|node GUI content scroll node +---The Scroll constructor +---@param view_node string|node GUI view scroll node - the static part that captures user input +---@param content_node string|node GUI content scroll node - the dynamic part that will change position function M:init(view_node, content_node) self.druid = self:get_druid() @@ -227,6 +104,32 @@ function M:init(view_node, content_node) end +---@private +---@param style druid.scroll.style +function M:on_style_change(style) + self.style = {} + self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0 + self.style.ANIM_SPEED = style.ANIM_SPEED or 0.2 + self.style.BACK_SPEED = style.BACK_SPEED or 0.35 + + self.style.FRICT = style.FRICT or 0 + self.style.FRICT_HOLD = style.FRICT_HOLD or 0 + + self.style.INERT_THRESHOLD = style.INERT_THRESHOLD or 3 + self.style.INERT_SPEED = style.INERT_SPEED or 30 + self.style.POINTS_DEADZONE = style.POINTS_DEADZONE or 20 + self.style.SMALL_CONTENT_SCROLL = style.SMALL_CONTENT_SCROLL or false + self.style.WHEEL_SCROLL_SPEED = style.WHEEL_SCROLL_SPEED or 0 + self.style.WHEEL_SCROLL_INVERTED = style.WHEEL_SCROLL_INVERTED or false + self.style.WHEEL_SCROLL_BY_INERTION = style.WHEEL_SCROLL_BY_INERTION or false + + self._is_inert = not (self.style.FRICT == 0 or + self.style.FRICT_HOLD == 0 or + self.style.INERT_SPEED == 0) +end + + +---@private function M:on_late_init() if not self.click_zone then local stencil_node = helper.get_closest_stencil_node(self.node) @@ -237,11 +140,13 @@ function M:on_late_init() end +---@private function M:on_layout_change() gui.set_position(self.content_node, self.position) end +---@private function M:update(dt) if self.is_animate then self.position.x = gui.get(self.content_node, "position.x") --[[@as number]] @@ -257,21 +162,21 @@ function M:update(dt) end +---@private function M:on_input(action_id, action) return self:_process_scroll_wheel(action_id, action) end +---@private function M:on_remove() self:bind_grid(nil) end ---- Start scroll to target point. +---Start scroll to target point. ---@param point vector3 Target point ---@param is_instant boolean|nil Instant scroll flag --- @usage scroll:scroll_to(vmath.vector3(0, 50, 0)) --- @usage scroll:scroll_to(vmath.vector3(0), true) function M:scroll_to(point, is_instant) local b = self.available_pos local target = vmath.vector3( @@ -300,7 +205,7 @@ function M:scroll_to(point, is_instant) end ---- Scroll to item in scroll by point index. +---Scroll to item in scroll by point index. ---@param index number Point index ---@param skip_cb boolean|nil If true, skip the point callback function M:scroll_to_index(index, skip_cb) @@ -322,10 +227,9 @@ function M:scroll_to_index(index, skip_cb) end ---- Start scroll to target scroll percent +---Start scroll to target scroll percent ---@param percent vector3 target percent ---@param is_instant boolean|nil instant scroll flag --- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0)) function M:scroll_to_percent(percent, is_instant) local border = self.available_pos @@ -346,22 +250,22 @@ function M:scroll_to_percent(percent, is_instant) end ---- Return current scroll progress status. +---Return current scroll progress status. -- Values will be in [0..1] interval ---@return vector3 New vector with scroll progress values function M:get_percent() - local x_perc = 1 - inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x) - local y_perc = inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y) + local x_perc = 1 - self:_inverse_lerp(self.available_pos.x, self.available_pos.z, self.position.x) + local y_perc = self:_inverse_lerp(self.available_pos.w, self.available_pos.y, self.position.y) return vmath.vector3(x_perc, y_perc, 0) end ---- Set scroll content size. +---Set scroll content size. -- It will change content gui node size ---@param size vector3 The new size for content node ---@param offset vector3|nil Offset value to set, where content is starts ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_size(size, offset) if offset then self._offset = offset @@ -373,9 +277,9 @@ function M:set_size(size, offset) end ---- Set new scroll view size in case the node size was changed. +---Set new scroll view size in case the node size was changed. ---@param size vector3 The new size for view node ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_view_size(size) gui.set_size(self.view_node, size) self.view_size = size @@ -386,7 +290,8 @@ function M:set_view_size(size) end ---- Refresh scroll view size +---Refresh scroll view size, used when view node size is changed +---@return druid.scroll self Current scroll instance function M:update_view_size() self.view_size = helper.get_scaled_size(self.view_node) self.view_border = helper.get_border(self.view_node) @@ -396,11 +301,11 @@ function M:update_view_size() end ---- Enable or disable scroll inert. +---Enable or disable scroll inert -- If disabled, scroll through points (if exist) -- If no points, just simple drag without inertion ---@param state boolean Inert scroll state ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_inert(state) self._is_inert = state @@ -408,17 +313,17 @@ function M:set_inert(state) end ---- Return if scroll have inertion. ----@return boolean @If scroll have inertion +---Return if scroll have inertion +---@return boolean is_inert If scroll have inertion function M:is_inert() return self._is_inert end ---- Set extra size for scroll stretching. +---Set extra size for scroll stretching -- Set 0 to disable stretching effect ---@param stretch_size number|nil Size in pixels of additional scroll area ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_extra_stretch_size(stretch_size) self.style.EXTRA_STRETCH_SIZE = stretch_size or 0 self:_update_size() @@ -427,17 +332,17 @@ function M:set_extra_stretch_size(stretch_size) end ---- Return vector of scroll size with width and height. +---Return vector of scroll size with width and height. ---@return vector3 Available scroll size function M:get_scroll_size() return self.available_size end ---- Set points of interest. +---Set points of interest. -- Scroll will always centered on closer points ---@param points table Array of vector3 points ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_points(points) self.points = points @@ -451,9 +356,9 @@ function M:set_points(points) end ---- Lock or unlock horizontal scroll +---Lock or unlock horizontal scroll ---@param state boolean True, if horizontal scroll is enabled ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_horizontal_scroll(state) self._is_horizontal_scroll = state self.drag.can_x = self.available_size.x > 0 and state or false @@ -461,9 +366,9 @@ function M:set_horizontal_scroll(state) end ---- Lock or unlock vertical scroll +---Lock or unlock vertical scroll ---@param state boolean True, if vertical scroll is enabled ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:set_vertical_scroll(state) self._is_vertical_scroll = state self.drag.can_y = self.available_size.y > 0 and state or false @@ -471,7 +376,7 @@ function M:set_vertical_scroll(state) end ---- Check node if it visible now on scroll. +---Check node if it visible now on scroll. -- Extra border is not affected. Return true for elements in extra scroll zone ---@param node node The node to check ---@return boolean True if node in visible scroll area @@ -511,10 +416,10 @@ function M:is_node_in_view(node) end ---- Bind the grid component (Static or Dynamic) to recalculate +---Bind the grid component (Static or Dynamic) to recalculate -- scroll size on grid changes ---@param grid druid.grid|nil Druid grid component ----@return druid.scroll Current scroll instance +---@return druid.scroll self Current scroll instance function M:bind_grid(grid) if self._grid_on_change then self._grid_on_change:unsubscribe(self._grid_on_change_callback) @@ -540,7 +445,7 @@ function M:bind_grid(grid) end ---- Strict drag scroll area. Useful for +---Strict drag scroll area. Useful for -- restrict events outside stencil node ---@param node node|string Gui node function M:set_click_zone(node) @@ -560,11 +465,11 @@ function M:_on_scroll_drag(dx, dy) -- Right border (minimum x) if t.x < b.x and dx < 0 then - x_perc = inverse_lerp(eb.x, b.x, t.x) + x_perc = self:_inverse_lerp(eb.x, b.x, t.x) end -- Left border (maximum x) if t.x > b.z and dx > 0 then - x_perc = inverse_lerp(eb.z, b.z, t.x) + x_perc = self:_inverse_lerp(eb.z, b.z, t.x) end -- Disable x scroll if not self.drag.can_x then @@ -573,11 +478,11 @@ function M:_on_scroll_drag(dx, dy) -- Top border (minimum y) if t.y < b.y and dy < 0 then - y_perc = inverse_lerp(eb.y, b.y, t.y) + y_perc = self:_inverse_lerp(eb.y, b.y, t.y) end -- Bot border (maximum y) if t.y > b.w and dy > 0 then - y_perc = inverse_lerp(eb.w, b.w, t.y) + y_perc = self:_inverse_lerp(eb.w, b.w, t.y) end -- Disable y scroll if not self.drag.can_y then @@ -647,7 +552,7 @@ function M:_set_scroll_position(position_x, position_y) end ---- Find closer point of interest +---Find closer point of interest -- if no inert, scroll to next point by scroll direction -- if inert, find next point by scroll director ---@private @@ -782,8 +687,8 @@ function M:_update_size() local content_border = helper.get_border(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) + self.available_pos = self:_get_border_vector(self.view_border - content_border, self._offset) + self.available_size = self:_get_size_vector(self.available_pos) self.drag.can_x = self.available_size.x > 0 and self._is_horizontal_scroll self.drag.can_y = self.available_size.y > 0 and self._is_vertical_scroll @@ -807,8 +712,8 @@ function M:_update_size() self.drag.can_y = content_size.y > self.view_size.y and self._is_vertical_scroll end - self.available_pos_extra = get_border_vector(self.view_border - content_border_extra, self._offset) - self.available_size_extra = get_size_vector(self.available_pos_extra) + self.available_pos_extra = self:_get_border_vector(self.view_border - content_border_extra, self._offset) + self.available_size_extra = self:_get_size_vector(self.available_pos_extra) self:_set_scroll_position(self.position.x, self.position.y) self.target_position.x = self.position.x @@ -860,4 +765,38 @@ function M:_on_mouse_hover(state) end +function M:_inverse_lerp(min, max, current) + return helper.clamp((current - min) / (max - min), 0, 1) +end + + +---Update vector with next conditions: +---Field x have to <= field z +---Field y have to <= field w +---@param vector vector4 +---@param offset vector3 +---@return vector4 +function M:_get_border_vector(vector, offset) + if vector.x > vector.z then + vector.x, vector.z = vector.z, vector.x + end + if vector.y > vector.w then + vector.y, vector.w = vector.w, vector.y + end + vector.x = vector.x - offset.x + vector.z = vector.z - offset.x + vector.y = vector.y - offset.y + vector.w = vector.w - offset.y + return vector +end + + +---Return size from scroll border vector4 +---@param vector vector4 +---@return vector3 +function M:_get_size_vector(vector) + return vmath.vector3(vector.z - vector.x, vector.w - vector.y, 0) +end + + return M diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua index a138fe2..155dd18 100644 --- a/druid/base/static_grid.lua +++ b/druid/base/static_grid.lua @@ -1,133 +1,33 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle component's position by row and columns. --- # Overview # --- --- The Static Grid component allows for positioning components in rows and columns. --- It provides a static grid layout with constant node sizes, allowing for pre-calculated --- node positions and the option to include gaps between nodes. --- --- # Notes # --- --- • In a static grid, the node size remains constant, enabling the calculation of node --- positions before placement. If you want add gaps between nodes, increase the root prefab size, --- including the padding and margin. --- --- • The static grid can automatically shift elements when nodes are added or removed. --- --- • When a node is added, the grid will set the node's parent to the specified parent_node. --- --- • You can obtain an array of positions for each element, which can be used to set --- points of interest in a scroll component. --- --- • The size of all elements can be retrieved for setting up the size in a scroll component. --- --- • The grid can be bound to a scroll component for automatic resizing of the scroll content size. --- --- • The pivot of the parent_node affects the node placement within the grid. --- --- • A prefab node is used to determine the node size and anchor. --- --- • You can specify a position_function for animations using the --- _static_grid:set_position_function(node, pos) callback. The default position function is gui.set_position(). --- --- Example Link --- @module StaticGrid --- @within BaseComponent --- @alias druid.grid - ---- On item add callback(self, node, index) --- @tfield event on_add_item event - ---- On item remove callback(self, index) --- @tfield event on_remove_item event - ---- On item add, remove or change in_row callback(self, index|nil) --- @tfield event on_change_items event - ---- On grid clear callback(self) --- @tfield event on_clear event - ---- On update item positions callback(self) --- @tfield event on_update_positions event - ---- Parent gui node --- @tfield node parent - ---- List of all grid nodes --- @tfield node[] nodes - ---- The first index of node in grid --- @tfield number first_index - ---- The last index of node in grid --- @tfield number last_index - ---- Item anchor [0..1] --- @tfield vector3 anchor - ---- Item pivot [-0.5..0.5] --- @tfield vector3 pivot - ---- Item size --- @tfield vector3 node_size - ---- The size of item content --- @tfield vector4 border - ---- - local const = require("druid.const") local event = require("event.event") local helper = require("druid.helper") local component = require("druid.component") ----@class druid.grid: druid.base_component ----@field on_add_item event ----@field on_remove_item event ----@field on_change_items event ----@field on_clear event ----@field on_update_positions event ----@field parent node ----@field nodes node[] ----@field first_index number ----@field last_index number ----@field anchor vector3 ----@field pivot vector3 ----@field node_size vector3 ----@field border vector4 ----@field in_row number ----@field style table -local M = component.create("static_grid") +---@class druid.grid.style +---@field IS_DYNAMIC_NODE_POSES boolean|nil If true, always center grid content as grid pivot sets. Default: false +---@field IS_ALIGN_LAST_ROW boolean|nil If true, always align last row of the grid as grid pivot sets. Default: false + +---The component for manage the nodes position in the grid with various options +---@class druid.grid: druid.component +---@field on_add_item event Trigger on add item event, fun(self, item, index) +---@field on_remove_item event Trigger on remove item event, fun(self, index) +---@field on_change_items event Trigger on change items event, fun(self, index) +---@field on_clear event Trigger on clear event, fun(self) +---@field on_update_positions event Trigger on update positions event, fun(self) +---@field parent node Parent node +---@field nodes node[] Nodes array +---@field first_index number First index +---@field last_index number Last index +---@field anchor vector3 Anchor +---@field pivot vector3 Pivot +---@field node_size vector3 Node size +---@field border vector4 Border +---@field in_row number In row +---@field style druid.grid.style Style +local M = component.create("grid") -local function _extend_border(border, pos, size, pivot) - local left = pos.x - size.x/2 - (size.x * pivot.x) - local right = pos.x + size.x/2 - (size.x * pivot.x) - local top = pos.y + size.y/2 - (size.y * pivot.y) - local bottom = pos.y - size.y/2 - (size.y * pivot.y) - - border.x = math.min(border.x, left) - border.y = math.max(border.y, top) - border.z = math.max(border.z, right) - border.w = math.min(border.w, bottom) -end - - ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield boolean|nil IS_DYNAMIC_NODE_POSES If true, always center grid content as grid pivot sets. Default: false --- @tfield boolean|nil IS_ALIGN_LAST_ROW If true, always align last row of the grid as grid pivot sets. Default: false -function M:on_style_change(style) - self.style = {} - self.style.IS_DYNAMIC_NODE_POSES = style.IS_DYNAMIC_NODE_POSES or false - self.style.IS_ALIGN_LAST_ROW = style.IS_ALIGN_LAST_ROW or false -end - - ---- The StaticGrid constructor +---The constructor for the grid component ---@param parent string|node The GUI Node container, where grid's items will be placed ---@param element node Element prefab. Need to get it size ---@param in_row number|nil How many nodes in row can be placed. By default 1 @@ -162,10 +62,20 @@ function M:init(parent, element, in_row) end +---@private +---@param style druid.grid.style +function M:on_style_change(style) + self.style = { + IS_DYNAMIC_NODE_POSES = style.IS_DYNAMIC_NODE_POSES or false, + IS_ALIGN_LAST_ROW = style.IS_ALIGN_LAST_ROW or false, + } +end + + local _temp_pos = vmath.vector3(0) ---- Return pos for grid node index +---Return pos for grid node index ---@param index number The grid element index ----@return vector3 @Node position +---@return vector3 position Node position function M:get_pos(index) local row = math.ceil(index / self.in_row) - 1 local col = (index - row * self.in_row) - 1 @@ -180,9 +90,9 @@ function M:get_pos(index) end ---- Return index for grid pos +---Return grid index by position ---@param pos vector3 The node position in the grid ----@return number The node index +---@return number index The node index function M:get_index(pos) -- Offset to left-top corner from node pivot local node_offset_x = self.node_size.x * (-0.5 + self.node_pivot.x) @@ -199,7 +109,7 @@ function M:get_index(pos) end ---- Return grid index by node +---Return grid index by node ---@param node node The gui node in the grid ---@return number|nil index The node index function M:get_index_by_node(node) @@ -213,12 +123,13 @@ function M:get_index_by_node(node) end +---@private function M:on_layout_change() self:_update(true) end ---- Set grid anchor. Default anchor is equal to anchor of grid parent node +---Set grid anchor. Default anchor is equal to anchor of grid parent node ---@param anchor vector3 Anchor function M:set_anchor(anchor) self.anchor = anchor @@ -226,23 +137,24 @@ function M:set_anchor(anchor) end ---- Update grid content +---Instantly update the grid content +---@return druid.grid self Current grid instance function M:refresh() self:_update(true) + + return self end +---Set grid pivot +---@param pivot constant The new pivot +---@return druid.grid self Current grid instance function M:set_pivot(pivot) local prev_pivot = helper.get_pivot_offset(gui.get_pivot(self.parent)) self.pivot = helper.get_pivot_offset(pivot) local width = gui.get(self.parent, "size.x") local height = gui.get(self.parent, "size.y") - --local pos_offset = vmath.vector3( - -- width * (self.pivot.x - prev_pivot.x), - -- height * (self.pivot.y - prev_pivot.y), - -- 0 - --) local position = gui.get_position(self.parent) position.x = position.x + width * (self.pivot.x - prev_pivot.x) @@ -260,14 +172,17 @@ function M:set_pivot(pivot) ) self:_update(true) + + return self end ---- Add new item to the grid +---Add new item to the grid ---@param item node GUI node ---@param index number|nil The item position. By default add as last item ---@param shift_policy number|nil How shift nodes, if required. Default: const.SHIFT.RIGHT ---@param is_instant boolean|nil If true, update node positions instantly +---@return druid.grid self Current grid instance function M:add(item, index, shift_policy, is_instant) index = index or ((self.last_index or 0) + 1) @@ -284,12 +199,15 @@ function M:add(item, index, shift_policy, is_instant) self.on_add_item:trigger(self:get_context(), item, index) self.on_change_items:trigger(self:get_context(), index) + + return self end ---- Set new items to the grid. All previous items will be removed +---Set new items to the grid. All previous items will be removed ---@param nodes node[] The new grid nodes --- @tparam[opt=false] boolean is_instant If true, update node positions instantly +---@param is_instant boolean|nil If true, update node positions instantly +---@return druid.grid self Current grid instance function M:set_items(nodes, is_instant) self.nodes = nodes for index = 1, #nodes do @@ -300,14 +218,16 @@ function M:set_items(nodes, is_instant) self:_update(is_instant) self.on_change_items:trigger(self:get_context()) + + return self end ---- Remove the item from the grid. Note that gui node will be not deleted +---Remove the item from the grid. Note that gui node will be not deleted ---@param index number The grid node index to remove ---@param shift_policy number|nil How shift nodes, if required. Default: const.SHIFT.RIGHT ---@param is_instant boolean|nil If true, update node positions instantly ----@return node The deleted gui node from grid +---@return node node The deleted gui node from grid function M:remove(index, shift_policy, is_instant) assert(self.nodes[index], "No grid item at given index " .. index) @@ -323,8 +243,8 @@ function M:remove(index, shift_policy, is_instant) end ---- Return grid content size ----@return vector3 The grid content size +---Return grid content size +---@return vector3 size The grid content size function M:get_size() return vmath.vector3( self.border.z - self.border.x, @@ -333,6 +253,9 @@ function M:get_size() end +---Return grid content size for given count of nodes +---@param count number The count of nodes +---@return vector3 size The grid content size function M:get_size_for(count) if not count or count == 0 then return vmath.vector3(0) @@ -342,10 +265,10 @@ function M:get_size_for(count) local size = self.node_size local pivot = self.node_pivot - _extend_border(border, self:get_pos(1), size, pivot) - _extend_border(border, self:get_pos(count), size, pivot) + self:_extend_border(border, self:get_pos(1), size, pivot) + self:_extend_border(border, self:get_pos(count), size, pivot) if count >= self.in_row then - _extend_border(border, self:get_pos(self.in_row), size, pivot) + self:_extend_border(border, self:get_pos(self.in_row), size, pivot) end return vmath.vector3( @@ -355,15 +278,15 @@ function M:get_size_for(count) end ---- Return grid content borders ----@return vector4 The grid content borders +---Return grid content borders +---@return vector4 borders The grid content borders function M:get_borders() return self.border end ---- Return array of all node positions ----@return vector3[] All grid node positions +---Return array of all node positions +---@return vector3[] positions All grid node positions function M:get_all_pos() local result = {} for i, node in pairs(self.nodes) do @@ -374,10 +297,10 @@ function M:get_all_pos() end ---- Change set position function for grid nodes. It will call on +---Change set position function for grid nodes. It will call on -- update poses on grid elements. Default: gui.set_position ---@param callback function Function on node set position ----@return druid.grid Current grid instance +---@return druid.grid self Current grid instance function M:set_position_function(callback) self._set_position_function = callback or gui.set_position @@ -385,9 +308,9 @@ function M:set_position_function(callback) end ---- Clear grid nodes array. GUI nodes will be not deleted! +---Clear grid nodes array. GUI nodes will be not deleted! -- If you want to delete GUI nodes, use static_grid.nodes array before grid:clear ----@return druid.grid Current grid instance +---@return druid.grid self Current grid instance function M:clear() self.border.x = 0 self.border.y = 0 @@ -404,8 +327,8 @@ function M:clear() end ---- Return StaticGrid offset, where StaticGrid content starts. ----@return vector3 The StaticGrid offset +---Return StaticGrid offset, where StaticGrid content starts. +---@return vector3 offset The StaticGrid offset function M:get_offset() local borders = self:get_borders() local size = self:get_size() @@ -419,9 +342,9 @@ function M:get_offset() end ---- Set new in_row elements for grid +---Set new in_row elements for grid ---@param in_row number The new in_row value ----@return druid.grid Current grid instance +---@return druid.grid self Current grid instance function M:set_in_row(in_row) self.in_row = in_row self._grid_horizonal_offset = self.node_size.x * (self.in_row - 1) * self.anchor.x @@ -437,10 +360,10 @@ function M:set_in_row(in_row) end ---- Set new node size for grid --- @tparam[opt] number width The new node width --- @tparam[opt] number height The new node height ----@return druid.grid Current grid instance +---Set new node size for grid +---@param width number|nil The new node width +---@param height number|nil The new node height +---@return druid.grid self Current grid instance function M:set_item_size(width, height) if width then self.node_size.x = width @@ -461,7 +384,7 @@ function M:set_item_size(width, height) end ---- Sort grid nodes by custom comparator function +---Sort grid nodes by custom comparator function ---@param comparator function The comparator function. (a, b) -> boolean ---@return druid.grid self Current grid instance function M:sort_nodes(comparator) @@ -472,7 +395,7 @@ function M:sort_nodes(comparator) end ---- Update grid inner state +---Update grid inner state ---@param is_instant boolean|nil If true, node position update instantly, otherwise with set_position_function callback ---@private function M:_update(is_instant) @@ -482,7 +405,7 @@ function M:_update(is_instant) end ---- Update first and last indexes of grid nodes +---Update first and last indexes of grid nodes ---@private function M:_update_indexes() self.first_index = nil @@ -497,7 +420,7 @@ function M:_update_indexes() end ---- Update grid content borders, recalculate min and max values +---Update grid content borders, recalculate min and max values ---@private function M:_update_borders() if not self.first_index then @@ -510,12 +433,12 @@ function M:_update_borders() local size = self.node_size local pivot = self.node_pivot for index, node in pairs(self.nodes) do - _extend_border(self.border, self:get_pos(index), size, pivot) + self:_extend_border(self.border, self:get_pos(index), size, pivot) end end ---- Update grid nodes position +---Update grid nodes position ---@param is_instant boolean|nil If true, node position update instantly, otherwise with set_position_function callback ---@private function M:_update_pos(is_instant) @@ -537,8 +460,8 @@ function M:_update_pos(is_instant) end ---- Return elements offset for correct posing nodes. Correct posing at --- parent pivot node (0:0) with adjusting of node sizes and anchoring +---Return elements offset for correct posing nodes. Correct posing at +---parent pivot node (0:0) with adjusting of node sizes and anchoring ---@return vector3 The offset vector ---@private function M:_get_zero_offset() @@ -555,7 +478,7 @@ function M:_get_zero_offset() end ---- Return offset x for last row in grid. Used to align this row accorting to grid's anchor +---Return offset x for last row in grid. Used to align this row accorting to grid's anchor ---@return number The offset x value ---@private function M:_get_zero_offset_x(row_index) @@ -576,4 +499,21 @@ function M:_get_zero_offset_x(row_index) end +---@param border vector4 Will be updated with new border values +---@param pos vector3 +---@param size vector3 +---@param pivot vector3 +function M:_extend_border(border, pos, size, pivot) + local left = pos.x - size.x/2 - (size.x * pivot.x) + local right = pos.x + size.x/2 - (size.x * pivot.x) + local top = pos.y + size.y/2 - (size.y * pivot.y) + local bottom = pos.y - size.y/2 - (size.y * pivot.y) + + border.x = math.min(border.x, left) + border.y = math.max(border.y, top) + border.z = math.max(border.z, right) + border.w = math.min(border.w, bottom) +end + + return M diff --git a/druid/base/text.lua b/druid/base/text.lua index a0cd877..f84423f 100755 --- a/druid/base/text.lua +++ b/druid/base/text.lua @@ -1,81 +1,3 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component for Wrapping GUI Text Nodes: Druid Text --- --- ## Overview ## --- --- Druid Text is a component that provides various adjustment modes for text nodes. It allows text to be scaled down to fit within the size of the text node. --- --- ## Notes ## --- --- • The text pivot can be changed using the text:set_pivot method. --- The anchoring will be inside the text node's area size. --- --- • There are several text adjustment types available. The default is DOWNSCALE. --- You can change the default adjustment type in the Text style. Refer to the example below to see all available adjustment types: --- --- - const.TEXT_ADJUST.DOWNSCALE: Changes the text's scale to fit within the text node's size. --- --- - const.TEXT_ADJUST.TRIM: Trims the text with a postfix (default: "...", can be overridden in styles) --- to fit within the text node's size. --- --- - const.TEXT_ADJUST.NO_ADJUST: No adjustment is applied, similar --- to the default Defold Text Node behavior. --- --- - const.TEXT_ADJUST.DOWNSCALE_LIMITED: Changes the text's scale --- with a limited downscale. You can set the minimum scale using the text:set_minimal_scale() function. --- --- - const.TEXT_ADJUST.SCROLL: Changes the text's pivot to imitate scrolling within the text box. --- For better effect, use with a stencil node. --- --- - const.TEXT_ADJUST.SCALE_THEN_SCROLL: Combines two modes: limited downscale first, then scroll. --- --- Example Link --- @module Text --- @within BaseComponent --- @alias druid.text - ---- On set text callback(self, text) --- @tfield event on_set_text event - ---- On adjust text size callback(self, new_scale, text_metrics) --- @tfield event on_update_text_scale event - ---- On change pivot callback(self, pivot) --- @tfield event on_set_pivot event - ---- Text node --- @tfield node node - ---- The node id of text node --- @tfield hash node_id - ---- Current text position --- @tfield vector3 pos - ---- The last text value --- @tfield string last_value - ---- Initial text node scale --- @tfield vector3 start_scale - ---- Current text node scale --- @tfield vector3 scale - ---- Initial text node size --- @tfield vector3 start_size - ---- Current text node available are --- @tfield vector3 text_area - ---- Current text size adjust settings --- @tfield number adjust_type - ---- Current text color --- @tfield vector3 color - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") @@ -83,249 +5,48 @@ local utf8_lua = require("druid.system.utf8") local component = require("druid.component") local utf8 = utf8 or utf8_lua --[[@as utf8]] ----@class druid.text: druid.base_component ----@field node node ----@field on_set_text event ----@field on_update_text_scale event ----@field on_set_pivot event ----@field style table ----@field private start_pivot userdata ----@field private start_scale vector3 ----@field private scale vector3 +---@class druid.text.style +---@field TRIM_POSTFIX string|nil The postfix for TRIM adjust type. Default: ... +---@field DEFAULT_ADJUST string|nil The default adjust type for any text component. Default: DOWNSCALE +---@field ADJUST_STEPS number|nil Amount of iterations for text adjust by height. Default: 20 +---@field ADJUST_SCALE_DELTA number|nil Scale step on each height adjust step. Default: 0.02 + +---@alias druid.text.adjust_type "downscale"|"trim"|"no_adjust"|"downscale_limited"|"scroll"|"scale_then_scroll"|"trim_left"|"scale_then_trim"|"scale_then_trim_left" + +---Basic Druid text component. Text components by default have the text size adjusting. +--- +---### Setup +---Create text node with druid: `text = druid:new_text(node_name, [initial_value], [text_adjust_type])` +--- +---### Notes +---- Text component by default have auto adjust text sizing. Text never will be bigger, than text node size, which you can setup in GUI scene. +---- Text pivot can be changed with `text:set_pivot`, and text will save their position inside their text size box +---- There are several text adjust types: +---- - **"downscale"** - Change text's scale to fit in the text node size (default) +---- - **"trim"** - Trim the text with postfix (default - "...") to fit in the text node size +---- - **"no_adjust"** - No any adjust, like default Defold text node +---- - **"downscale_limited"** - Change text's scale like downscale, but there is limit for text's scale +---- - **"scroll"** - Change text's pivot to imitate scrolling in the text box. Use with stencil node for better effect. +---- - **"scale_then_scroll"** - Combine two modes: first limited downscale, then scroll +---- - **"trim_left"** - Trim the text with postfix (default - "...") to fit in the text node size +---- - **"scale_then_trim"** - Combine two modes: first limited downscale, then trim +---- - **"scale_then_trim_left"** - Combine two modes: first limited downscale, then trim left +---@class druid.text: druid.component +---@field node node The text node +---@field on_set_text event fun(self, text) The event triggered when the text is set +---@field on_update_text_scale event fun(self, scale, metrics) The event triggered when the text scale is updated +---@field on_set_pivot event fun(self, pivot) The event triggered when the text pivot is set +---@field style druid.text.style The style of the text +---@field private start_pivot userdata The start pivot of the text +---@field private start_scale vector3 The start scale of the text +---@field private scale vector3 The current scale of the text local M = component.create("text") -local function update_text_size(self) - if self.scale.x == 0 or self.scale.y == 0 then - return - end - if self.start_scale.x == 0 or self.start_scale.y == 0 then - return - end - local size = vmath.vector3( - self.start_size.x * (self.start_scale.x / self.scale.x), - self.start_size.y * (self.start_scale.y / self.scale.y), - self.start_size.z - ) - gui.set_size(self.node, size) -end - - ---- Reset initial scale for text -local function reset_default_scale(self) - self.scale.x = self.start_scale.x - self.scale.y = self.start_scale.y - self.scale.z = self.start_scale.z - gui.set_scale(self.node, self.start_scale) - gui.set_size(self.node, self.start_size) -end - - -local function is_fit_info_area(self, metrics) - return metrics.width * self.scale.x <= self.text_area.x and - metrics.height * self.scale.y <= self.text_area.y -end - - ---- Setup scale x, but can only be smaller, than start text scale -local function update_text_area_size(self) - reset_default_scale(self) - - local metrics = helper.get_text_metrics_from_node(self.node) - - if metrics.width == 0 then - reset_default_scale(self) - self.on_update_text_scale:trigger(self:get_context(), self.start_scale, metrics) - return - end - - local text_area_width = self.text_area.x - local text_area_height = self.text_area.y - - -- Adjust by width - local scale_modifier = text_area_width / metrics.width - - -- Adjust by height - if self:is_multiline() then - -- Approximate scale by height to start adjust scale - scale_modifier = math.sqrt(text_area_height / metrics.height) - if metrics.width * scale_modifier > text_area_width then - scale_modifier = text_area_width / metrics.width - end - - -- #RMME - if self._minimal_scale then - scale_modifier = math.max(scale_modifier, self._minimal_scale) - end - -- Limit max scale by initial scale - scale_modifier = math.min(scale_modifier, self.start_scale.x) - -- #RMME - - local is_fit = is_fit_info_area(self, metrics) - local step = is_fit and self.style.ADJUST_SCALE_DELTA or -self.style.ADJUST_SCALE_DELTA - - for i = 1, self.style.ADJUST_STEPS do - -- Grow down to check if we fit - if step < 0 and is_fit then - break - end - -- Grow up to check if we still fit - if step > 0 and not is_fit then - break - end - - scale_modifier = scale_modifier + step - - if self._minimal_scale then - scale_modifier = math.max(scale_modifier, self._minimal_scale) - end - -- Limit max scale by initial scale - scale_modifier = math.min(scale_modifier, self.start_scale.x) - - self.scale.x = scale_modifier - self.scale.y = scale_modifier - self.scale.z = self.start_scale.z - gui.set_scale(self.node, self.scale) - update_text_size(self) - metrics = helper.get_text_metrics_from_node(self.node) - is_fit = is_fit_info_area(self, metrics) - end - end - - if self._minimal_scale then - scale_modifier = math.max(scale_modifier, self._minimal_scale) - end - - -- Limit max scale by initial scale - scale_modifier = math.min(scale_modifier, self.start_scale.x) - - self.scale.x = scale_modifier - self.scale.y = scale_modifier - self.scale.z = self.start_scale.z - gui.set_scale(self.node, self.scale) - update_text_size(self) - - self.on_update_text_scale:trigger(self:get_context(), self.scale, metrics) -end - - ----@param self druid.text ----@param trim_postfix string -local function update_text_with_trim(self, trim_postfix) - local max_width = self.text_area.x - local text_width = self:get_text_size() - - if text_width > max_width then - local text_length = utf8.len(self.last_value) - local new_text = self.last_value - while text_width > max_width do - text_length = text_length - 1 - new_text = utf8.sub(self.last_value, 1, text_length) - text_width = self:get_text_size(new_text .. trim_postfix) - if text_length == 0 then - break - end - end - - gui.set_text(self.node, new_text .. trim_postfix) - else - gui.set_text(self.node, self.last_value) - end -end - -local function update_text_with_trim_left(self, trim_postfix) - local max_width = self.text_area.x - local text_width = self:get_text_size() - local text_length = utf8.len(self.last_value) - local trim_index = 1 - - if text_width > max_width then - local new_text = self.last_value - while text_width > max_width and trim_index < text_length do - trim_index = trim_index + 1 - new_text = trim_postfix .. utf8.sub(self.last_value, trim_index, text_length) - text_width = self:get_text_size(new_text) - end - - gui.set_text(self.node, new_text) - end -end - - -local function update_text_with_anchor_shift(self) - if self:get_text_size() >= self.text_area.x then - self:set_pivot(const.REVERSE_PIVOTS[self.start_pivot]) - else - self:set_pivot(self.start_pivot) - end -end - - ----@param self druid.text -local function update_adjust(self) - if not self.adjust_type or self.adjust_type == const.TEXT_ADJUST.NO_ADJUST then - reset_default_scale(self) - return - end - - if self.adjust_type == const.TEXT_ADJUST.DOWNSCALE then - update_text_area_size(self) - end - - if self.adjust_type == const.TEXT_ADJUST.TRIM then - update_text_with_trim(self, self.style.TRIM_POSTFIX) - end - - if self.adjust_type == const.TEXT_ADJUST.TRIM_LEFT then - update_text_with_trim_left(self, self.style.TRIM_POSTFIX) - end - - if self.adjust_type == const.TEXT_ADJUST.DOWNSCALE_LIMITED then - update_text_area_size(self) - end - - if self.adjust_type == const.TEXT_ADJUST.SCROLL then - update_text_with_anchor_shift(self) - end - - if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_SCROLL then - update_text_area_size(self) - update_text_with_anchor_shift(self) - end - - if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_TRIM then - update_text_area_size(self) - update_text_with_trim(self, self.style.TRIM_POSTFIX) - end - - if self.adjust_type == const.TEXT_ADJUST.SCALE_THEN_TRIM_LEFT then - update_text_area_size(self) - update_text_with_trim_left(self, self.style.TRIM_POSTFIX) - end -end - - ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield string|nil TRIM_POSTFIX The postfix for TRIM adjust type. Default: ... --- @tfield string|nil DEFAULT_ADJUST The default adjust type for any text component. Default: DOWNSCALE --- @tfield string|nil ADJUST_STEPS Amount of iterations for text adjust by height. Default: 20 --- @tfield string|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02 -function M:on_style_change(style) - self.style = {} - self.style.TRIM_POSTFIX = style.TRIM_POSTFIX or "..." - self.style.DEFAULT_ADJUST = style.DEFAULT_ADJUST or const.TEXT_ADJUST.DOWNSCALE - self.style.ADJUST_STEPS = style.ADJUST_STEPS or 20 - self.style.ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02 -end - - ---- The Text constructor +---The Text constructor ---@param node string|node Node name or GUI Text Node itself ---@param value string|nil Initial text. Default value is node text from GUI scene. Default: nil ----@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE +---@param adjust_type druid.text.adjust_type|nil Adjust type for text. By default is "downscale". Options: "downscale", "trim", "no_adjust", "downscale_limited", "scroll", "scale_then_scroll", "trim_left", "scale_then_trim", "scale_then_trim_left" function M:init(node, value, adjust_type) self.node = self:get_node(node) self.pos = gui.get_position(self.node) @@ -348,19 +69,31 @@ function M:init(node, value, adjust_type) self.on_update_text_scale = event.create() self:set_text(value or gui.get_text(self.node)) - return self end +---@private +---@param style druid.text.style +function M:on_style_change(style) + self.style = { + TRIM_POSTFIX = style.TRIM_POSTFIX or "...", + DEFAULT_ADJUST = style.DEFAULT_ADJUST or "downscale", + ADJUST_STEPS = style.ADJUST_STEPS or 20, + ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02 + } +end + + +---@private function M:on_layout_change() self:set_text(self.last_value) end ---- Calculate text width with font with respect to trailing space ----@param text string|nil ----@return number Width ----@return number Height +---Calculate text width with font with respect to trailing space +---@param text string|nil The text to calculate the size of, if nil - use current text +---@return number width The text width +---@return number height The text height function M:get_text_size(text) text = text or self.last_value local font_name = gui.get_font(self.node) @@ -381,9 +114,9 @@ function M:get_text_size(text) end ---- Get chars count by width ----@param width number ----@return number Chars count +---Get chars count by width +---@param width number The width to get the chars count of +---@return number index The chars count function M:get_text_index_by_width(width) local text = self.last_value local font_name = gui.get_font(self.node) @@ -414,10 +147,10 @@ function M:get_text_index_by_width(width) end ---- Set text to text field +---Set text to text field ---@deprecated ---@param set_to string Text for node ----@return druid.text Current text instance +---@return druid.text self Current text instance function M:set_to(set_to) set_to = tostring(set_to or "") @@ -426,7 +159,7 @@ function M:set_to(set_to) self.on_set_text:trigger(self:get_context(), set_to) - update_adjust(self) + self:_update_adjust() return self end @@ -443,7 +176,7 @@ function M:get_text() end ---- Set text area size +---Set text area size ---@param size vector3 The new text area size ---@return druid.text self Current text instance function M:set_size(size) @@ -451,15 +184,15 @@ function M:set_size(size) self.text_area = vmath.vector3(size) self.text_area.x = self.text_area.x * self.start_scale.x self.text_area.y = self.text_area.y * self.start_scale.y - update_adjust(self) + self:_update_adjust() return self end ---- Set color +---Set color ---@param color vector4 Color for node ----@return druid.text Current text instance +---@return druid.text self Current text instance function M:set_color(color) self.color = color gui.set_color(self.node, color) @@ -468,9 +201,9 @@ function M:set_color(color) end ---- Set alpha +---Set alpha ---@param alpha number Alpha for node ----@return druid.text Current text instance +---@return druid.text self Current text instance function M:set_alpha(alpha) self.color.w = alpha gui.set_color(self.node, self.color) @@ -479,9 +212,9 @@ function M:set_alpha(alpha) end ---- Set scale +---Set scale ---@param scale vector3 Scale for node ----@return druid.text Current text instance +---@return druid.text self Current text instance function M:set_scale(scale) self.last_scale = scale gui.set_scale(self.node, scale) @@ -490,9 +223,9 @@ function M:set_scale(scale) end ---- Set text pivot. Text will re-anchor inside text area +---Set text pivot. Text will re-anchor inside text area ---@param pivot userdata The gui.PIVOT_* constant ----@return druid.text Current text instance +---@return druid.text self Current text instance function M:set_pivot(pivot) local prev_pivot = gui.get_pivot(self.node) local prev_offset = const.PIVOTS[prev_pivot] @@ -523,9 +256,7 @@ end ---Set text adjust, refresh the current text visuals, if needed ----Values are: "downscale", "trim", "no_adjust", "downscale_limited", ----"scroll", "scale_then_scroll", "trim_left", "scale_then_trim", "scale_then_trim_left" ----@param adjust_type string|nil See const.TEXT_ADJUST. If pass nil - use current adjust type +---@param adjust_type druid.text.adjust_type|nil The adjust type to set, values: "downscale", "trim", "no_adjust", "downscale_limited", "scroll", "scale_then_scroll", "trim_left", "scale_then_trim", "scale_then_trim_left" ---@param minimal_scale number|nil To remove minimal scale, use `text:set_minimal_scale(nil)`, if pass nil - not change minimal scale ---@return druid.text self Current text instance function M:set_text_adjust(adjust_type, minimal_scale) @@ -537,9 +268,9 @@ function M:set_text_adjust(adjust_type, minimal_scale) end ---- Set minimal scale for DOWNSCALE_LIMITED or SCALE_THEN_SCROLL adjust types +---Set minimal scale for "downscale_limited" or "scale_then_scroll" adjust types ---@param minimal_scale number If pass nil - not use minimal scale ----@return druid.text Current text instance +---@return druid.text self Current text instance function M:set_minimal_scale(minimal_scale) self._minimal_scale = minimal_scale @@ -547,11 +278,232 @@ function M:set_minimal_scale(minimal_scale) end ---- Return current text adjust type +---Return current text adjust type ---@return string adjust_type The current text adjust type function M:get_text_adjust() return self.adjust_type end +---@private +function M:_update_text_size() + if self.scale.x == 0 or self.scale.y == 0 then + return + end + if self.start_scale.x == 0 or self.start_scale.y == 0 then + return + end + + local size = vmath.vector3( + self.start_size.x * (self.start_scale.x / self.scale.x), + self.start_size.y * (self.start_scale.y / self.scale.y), + self.start_size.z + ) + gui.set_size(self.node, size) +end + + +---Reset initial scale for text +---@private +function M:_reset_default_scale() + self.scale.x = self.start_scale.x + self.scale.y = self.start_scale.y + self.scale.z = self.start_scale.z + gui.set_scale(self.node, self.start_scale) + gui.set_size(self.node, self.start_size) +end + + +---@private +---@param metrics table +---@return boolean +function M:_is_fit_info_area(metrics) + return metrics.width * self.scale.x <= self.text_area.x and + metrics.height * self.scale.y <= self.text_area.y +end + + +---Setup scale x, but can only be smaller, than start text scale +---@private +function M:_update_text_area_size() + self:_reset_default_scale() + + local metrics = helper.get_text_metrics_from_node(self.node) + + if metrics.width == 0 then + self:_reset_default_scale() + self.on_update_text_scale:trigger(self:get_context(), self.start_scale, metrics) + return + end + + local text_area_width = self.text_area.x + local text_area_height = self.text_area.y + + -- Adjust by width + local scale_modifier = text_area_width / metrics.width + + -- Adjust by height + if self:is_multiline() then + -- Approximate scale by height to start adjust scale + scale_modifier = math.sqrt(text_area_height / metrics.height) + if metrics.width * scale_modifier > text_area_width then + scale_modifier = text_area_width / metrics.width + end + + -- #RMME + if self._minimal_scale then + scale_modifier = math.max(scale_modifier, self._minimal_scale) + end + -- Limit max scale by initial scale + scale_modifier = math.min(scale_modifier, self.start_scale.x) + -- #RMME + + local is_fit = self:_is_fit_info_area(metrics) + local step = is_fit and self.style.ADJUST_SCALE_DELTA or -self.style.ADJUST_SCALE_DELTA + + for i = 1, self.style.ADJUST_STEPS do + -- Grow down to check if we fit + if step < 0 and is_fit then + break + end + -- Grow up to check if we still fit + if step > 0 and not is_fit then + break + end + + scale_modifier = scale_modifier + step + + if self._minimal_scale then + scale_modifier = math.max(scale_modifier, self._minimal_scale) + end + -- Limit max scale by initial scale + scale_modifier = math.min(scale_modifier, self.start_scale.x) + + self.scale.x = scale_modifier + self.scale.y = scale_modifier + self.scale.z = self.start_scale.z + gui.set_scale(self.node, self.scale) + self:_update_text_size() + metrics = helper.get_text_metrics_from_node(self.node) + is_fit = self:_is_fit_info_area(metrics) + end + end + + if self._minimal_scale then + scale_modifier = math.max(scale_modifier, self._minimal_scale) + end + + -- Limit max scale by initial scale + scale_modifier = math.min(scale_modifier, self.start_scale.x) + + self.scale.x = scale_modifier + self.scale.y = scale_modifier + self.scale.z = self.start_scale.z + gui.set_scale(self.node, self.scale) + self:_update_text_size() + + self.on_update_text_scale:trigger(self:get_context(), self.scale, metrics) +end + + +---@private +---@param trim_postfix string +function M:_update_text_with_trim(trim_postfix) + local max_width = self.text_area.x + local text_width = self:get_text_size() + + if text_width > max_width then + local text_length = utf8.len(self.last_value) + local new_text = self.last_value + while text_width > max_width do + text_length = text_length - 1 + new_text = utf8.sub(self.last_value, 1, text_length) + text_width = self:get_text_size(new_text .. trim_postfix) + if text_length == 0 then + break + end + end + + gui.set_text(self.node, new_text .. trim_postfix) + else + gui.set_text(self.node, self.last_value) + end +end + + +---@private +---@param trim_postfix string +function M:_update_text_with_trim_left(trim_postfix) + local max_width = self.text_area.x + local text_width = self:get_text_size() + local text_length = utf8.len(self.last_value) + local trim_index = 1 + + if text_width > max_width then + local new_text = self.last_value + while text_width > max_width and trim_index < text_length do + trim_index = trim_index + 1 + new_text = trim_postfix .. utf8.sub(self.last_value, trim_index, text_length) + text_width = self:get_text_size(new_text) + end + + gui.set_text(self.node, new_text) + end +end + + +---@private +function M:_update_text_with_anchor_shift() + if self:get_text_size() >= self.text_area.x then + self:set_pivot(const.REVERSE_PIVOTS[self.start_pivot]) + else + self:set_pivot(self.start_pivot) + end +end + + +---@private +function M:_update_adjust() + if not self.adjust_type or self.adjust_type == "no_adjust" then + self:_reset_default_scale() + return + end + + if self.adjust_type == "downscale" then + self:_update_text_area_size() + end + + if self.adjust_type == "trim" then + self:_update_text_with_trim(self.style.TRIM_POSTFIX) + end + + if self.adjust_type == "trim_left" then + self:_update_text_with_trim_left(self.style.TRIM_POSTFIX) + end + + if self.adjust_type == "downscale_limited" then + self:_update_text_area_size() + end + + if self.adjust_type == "scroll" then + self:_update_text_with_anchor_shift() + end + + if self.adjust_type == "scale_then_scroll" then + self:_update_text_area_size() + self:_update_text_with_anchor_shift() + end + + if self.adjust_type == "scale_then_trim" then + self:_update_text_area_size() + self:_update_text_with_trim(self.style.TRIM_POSTFIX) + end + + if self.adjust_type == "scale_then_trim_left" then + self:_update_text_area_size() + self:_update_text_with_trim_left(self.style.TRIM_POSTFIX) + end +end + + return M diff --git a/druid/bindings.lua b/druid/bindings.lua deleted file mode 100644 index e63a11e..0000000 --- a/druid/bindings.lua +++ /dev/null @@ -1,48 +0,0 @@ -local event = require("event.event") - -local M = {} -local WRAPPED_WIDGETS = {} - ----Set a widget to the current game object. The game object can acquire the widget by calling `bindings.get_widget` ----It wraps with events only top level functions cross-context, so no access to nested widgets functions ----@param widget druid.widget -function M.set_widget(widget) - local object = msg.url() - object.fragment = nil - - -- Make a copy of the widget with all functions wrapped in events - -- It makes available to call gui functions from game objects - local wrapped_widget = setmetatable({}, { __index = widget }) - local parent_table = getmetatable(widget).__index - - -- Go through all functions and wrap them in events - for key, value in pairs(parent_table) do - if type(value) == "function" then - wrapped_widget[key] = event.create(function(_, ...) - return value(widget, ...) - end) - end - end - - WRAPPED_WIDGETS[object.socket] = WRAPPED_WIDGETS[object.socket] or {} - WRAPPED_WIDGETS[object.socket][object.path] = wrapped_widget -end - - ----@param object_url string|userdata|url @root object ----@return druid.widget|nil -function M.get_widget(object_url) - assert(object_url, "You must provide an object_url") - - object_url = msg.url(object_url --[[@as string]]) - - local socket_widgets = WRAPPED_WIDGETS[object_url.socket] - if not socket_widgets then - return nil - end - - return socket_widgets[object_url.path] -end - - -return M diff --git a/druid/color.lua b/druid/color.lua index 8a1ccc9..f7158b8 100644 --- a/druid/color.lua +++ b/druid/color.lua @@ -9,7 +9,7 @@ local COLOR_Z = hash("color.z") local M = {} ----Get color color by id +---Get color color by string (hex or from palette) ---@param color_id string ---@return vector4 function M.get(color_id) @@ -86,32 +86,20 @@ function M.lerp(t, color1, color2) return vmath.vector4(r, g, b, a) end - ---@param hex string ----@param alpha number|nil ----@return number, number, number, number -function M.hex2rgb(hex, alpha) - alpha = alpha or 1 - if alpha > 1 then - alpha = alpha / 100 +---@return number, number, number +function M.hex2rgb(hex) + if not hex or #hex < 3 then + return 0, 0, 0 end - -- Remove leading # - if string.sub(hex, 1, 1) == "#" then - hex = string.sub(hex, 2) - end - - -- Expand 3-digit hex codes to 6 digits + hex = hex:gsub("^#", "") if #hex == 3 then - hex = string.rep(string.sub(hex, 1, 1), 2) .. - string.rep(string.sub(hex, 2, 2), 2) .. - string.rep(string.sub(hex, 3, 3), 2) + hex = hex:gsub("(.)", "%1%1") end - - local r = tonumber("0x" .. string.sub(hex, 1, 2)) / 255 - local g = tonumber("0x" .. string.sub(hex, 3, 4)) / 255 - local b = tonumber("0x" .. string.sub(hex, 5, 6)) / 255 - return r, g, b, alpha + return tonumber("0x" .. hex:sub(1,2)) / 255, + tonumber("0x" .. hex:sub(3,4)) / 255, + tonumber("0x" .. hex:sub(5,6)) / 255 end @@ -119,16 +107,16 @@ end ---@param alpha number|nil ---@return vector4 function M.hex2vector4(hex, alpha) - local r, g, b, a = M.hex2rgb(hex, alpha) - return vmath.vector4(r, g, b, a) + local r, g, b = M.hex2rgb(hex) + return vmath.vector4(r, g, b, alpha or 1) end ---Convert hsb color to rgb color ----@param r number @Red value ----@param g number @Green value ----@param b number @Blue value ----@param alpha number|nil @Alpha value. Default is 1 +---@param r number Red value +---@param g number Green value +---@param b number Blue value +---@param alpha number|nil Alpha value. Default is 1 function M.rgb2hsb(r, g, b, alpha) alpha = alpha or 1 local min, max = math.min(r, g, b), math.max(r, g, b) @@ -155,10 +143,10 @@ end ---Convert hsb color to rgb color ----@param h number @Hue ----@param s number @Saturation ----@param v number @Value ----@param alpha number|nil @Alpha value. Default is 1 +---@param h number Hue +---@param s number Saturation +---@param v number Value +---@param alpha number|nil Alpha value. Default is 1 function M.hsb2rgb(h, s, v, alpha) local r, g, b local i = math.floor(h * 6) @@ -182,9 +170,9 @@ end ---Convert rgb color to hex color ----@param red number @Red value ----@param green number @Green value ----@param blue number @Blue value +---@param red number Red value +---@param green number Green value +---@param blue number Blue value function M.rgb2hex(red, green, blue) local r = string.format("%x", math.floor(red * 255)) local g = string.format("%x", math.floor(green * 255)) @@ -194,7 +182,7 @@ end function M.load_palette() - local PALETTE_PATH = sys.get_config_string("fluid.palette") + local PALETTE_PATH = sys.get_config_string("druid.palette") if PALETTE_PATH then PALETTE_DATA = M.load_json(PALETTE_PATH) --[[@as table>]] end @@ -226,4 +214,4 @@ end M.load_palette() -return M \ No newline at end of file +return M diff --git a/druid/component.lua b/druid/component.lua index 3c82000..1515b4b 100644 --- a/druid/component.lua +++ b/druid/component.lua @@ -1,44 +1,43 @@ local const = require("druid.const") local helper = require("druid.helper") ----@class druid.base_component.meta +---@class druid.component.meta ---@field template string ---@field context table ---@field nodes table|nil ---@field style table|nil ----@field druid druid_instance +---@field druid druid.instance ---@field input_enabled boolean ---@field children table ----@field parent druid.base_component|nil +---@field parent druid.component|nil ---@field instance_class table ----@class druid.base_component.component +---@class druid.component.component ---@field name string ---@field input_priority number ---@field default_input_priority number ---@field _is_input_priority_changed boolean ---@field _uid number ----@class druid.base_component ----@field druid druid_instance Druid instance to create inner components ----@field init fun(self:druid.base_component, ...)|nil ----@field update fun(self:druid.base_component, dt:number)|nil ----@field on_remove fun(self:druid.base_component)|nil ----@field on_input fun(self:druid.base_component, action_id:number, action:table)|nil ----@field on_message fun(self:druid.base_component, message_id:hash, message:table, sender:url)|nil ----@field on_late_init fun(self:druid.base_component)|nil ----@field on_focus_lost fun(self:druid.base_component)|nil ----@field on_focus_gained fun(self:druid.base_component)|nil ----@field on_style_change fun(self:druid.base_component, style: table)|nil ----@field on_layout_change fun(self:druid.base_component)|nil ----@field on_window_resized fun(self:druid.base_component)|nil ----@field on_language_change fun(self:druid.base_component)|nil ----@field private _component druid.base_component.component ----@field private _meta druid.base_component.meta +---@class druid.component +---@field druid druid.instance Druid instance to create inner components +---@field init fun(self:druid.component, ...)|nil Called when component is created +---@field update fun(self:druid.component, dt:number)|nil Called every frame +---@field on_remove fun(self:druid.component)|nil Called when component is removed +---@field on_input fun(self:druid.component, action_id:hash, action:table)|nil Called when input event is triggered +---@field on_input_interrupt fun(self:druid.component, action_id:hash, action:table)|nil Called when input event is consumed before +---@field on_message fun(self:druid.component, message_id:hash, message:table, sender:url)|nil Called when message is received +---@field on_late_init fun(self:druid.component)|nil Called before update once time after GUI init +---@field on_focus_lost fun(self:druid.component)|nil Called when app lost focus +---@field on_focus_gained fun(self:druid.component)|nil Called when app gained focus +---@field on_style_change fun(self:druid.component, style: table)|nil Called when style is changed +---@field on_layout_change fun(self:druid.component)|nil Called when GUI layout is changed +---@field on_window_resized fun(self:druid.component)|nil Called when window is resized +---@field on_language_change fun(self:druid.component)|nil Called when language is changed +---@field private _component druid.component.component +---@field private _meta druid.component.meta local M = {} -local INTERESTS = {} -- Cache interests per component class in runtime - local uid = 0 ---@private @@ -54,7 +53,7 @@ end ---@param druid_style table|nil ---@return T self The component itself for chaining function M:set_style(druid_style) - ---@cast self druid.base_component + ---@cast self druid.component self._meta.style = druid_style or {} local component_style = self._meta.style[self._component.name] or {} @@ -75,7 +74,7 @@ end ---@param template string|nil ---@return T self The component itself for chaining function M:set_template(template) - ---@cast self druid.base_component + ---@cast self druid.component template = template or "" @@ -109,7 +108,7 @@ end ---Set current component nodes, returned from `gui.clone_tree` function. ---@param nodes table ----@return druid.base_component +---@return druid.component function M:set_nodes(nodes) self._meta.nodes = nodes return self @@ -134,10 +133,11 @@ end ---Get Druid instance for inner component creation. ---@param template string|nil ---@param nodes table|nil ----@return druid_instance +---@return druid.instance function M:get_druid(template, nodes) - local context = { _context = self } - local druid_instance = setmetatable(context, { __index = self._meta.druid }) + local druid_instance = setmetatable({ + _context = self + }, { __index = self._meta.druid }) if template then self:set_template(template) @@ -176,19 +176,21 @@ end ---Set component input priority, the bigger number processed first. Default value: 10 ---@param value number ---@param is_temporary boolean|nil If true, the reset input priority will return to previous value ----@return druid.base_component self The component itself for chaining +---@return druid.component self The component itself for chaining function M:set_input_priority(value, is_temporary) assert(value) - if self._component.input_priority == value then + local component = self._component + + if component.input_priority == value then return self end - self._component.input_priority = value - self._component._is_input_priority_changed = true + component.input_priority = value + component._is_input_priority_changed = true if not is_temporary then - self._component.default_input_priority = value + component.default_input_priority = value end local children = self:get_childrens() @@ -201,7 +203,7 @@ end ---Reset component input priority to it's default value, that was set in `create` function or `set_input_priority` ----@return druid.base_component self The component itself for chaining +---@return druid.component self The component itself for chaining function M:reset_input_priority() self:set_input_priority(self._component.default_input_priority) return self @@ -219,7 +221,7 @@ end ---If input is disabled, the component will not receive input events. ---Recursive for all children components. ---@param state boolean ----@return druid.base_component self The component itself for chaining +---@return druid.component self The component itself for chaining function M:set_input_enabled(state) self._meta.input_enabled = state @@ -231,19 +233,26 @@ function M:set_input_enabled(state) end +---Get component input state. By default it's enabled. Can be disabled by `set_input_enabled` function. +---@return boolean +function M:get_input_enabled() + return self._meta.input_enabled +end + + ---Get parent component ----@return druid.base_component|nil parent The parent component if exist or nil +---@return druid.component|nil parent_component The parent component if exist or nil function M:get_parent_component() return self._meta.parent end ---- Setup component context and his style table ----@param druid_instance table The parent druid instance +---Setup component context and his style table +---@param druid_instance druid.instance The parent druid instance ---@param context table Druid context. Usually it is self of script ---@param style table Druid style module ---@param instance_class table The component instance class ----@return druid.base_component BaseComponent itself +---@return druid.component BaseComponent itself ---@private function M:setup_component(druid_instance, context, style, instance_class) self._meta = { @@ -254,7 +263,7 @@ function M:setup_component(druid_instance, context, style, instance_class) druid = druid_instance, input_enabled = true, children = {}, - parent = type(context) ~= "userdata" and context --[[@as druid.base_component]], + parent = type(context) ~= "userdata" and context --[[@as druid.component]], instance_class = instance_class } @@ -269,42 +278,20 @@ function M:setup_component(druid_instance, context, style, instance_class) end ---- Return true, if input priority was changed +---Return true, if input priority was changed ---@private function M:_is_input_priority_changed() return self._component._is_input_priority_changed end ---- Reset is_input_priority_changed field +---Reset is_input_priority_changed field ---@private function M:_reset_input_priority_changed() self._component._is_input_priority_changed = false end ---- Get current component interests ----@return table List of component interests ----@private -function M:__get_interests() - local instance_class = self._meta.instance_class - if INTERESTS[instance_class] then - return INTERESTS[instance_class] - end - - local interests = {} - for index = 1, #const.ALL_INTERESTS do - local interest = const.ALL_INTERESTS[index] - if self[interest] and type(self[interest]) == "function" then - table.insert(interests, interest) - end - end - - INTERESTS[instance_class] = interests - return INTERESTS[instance_class] -end - - ---Get current component nodes ---@return table|nil function M:get_nodes() @@ -319,7 +306,7 @@ end ---Add child to component children list ----@generic T: druid.base_component +---@generic T: druid.component ---@param child T The druid component instance ---@return T self The component itself for chaining ---@private @@ -330,9 +317,8 @@ function M:__add_child(child) end - ---Remove child from component children list ----@generic T: druid.base_component +---@generic T: druid.component ---@param child T The druid component instance ---@return boolean true if child was removed ---@private @@ -348,7 +334,7 @@ function M:__remove_child(child) end ---- Return all children components, recursive +---Return all children components, recursive ---@return table Array of childrens if the Druid component instance function M:get_childrens() local childrens = {} @@ -367,7 +353,7 @@ end ---Сreate a new component class, which will inherit from the base Druid component. ---@param name string|nil The name of the component ---@param input_priority number|nil The input priority. The bigger number processed first. Default value: 10 ----@return druid.base_component +---@return druid.component function M.create(name, input_priority) local new_class = setmetatable({}, { __index = M, @@ -391,4 +377,45 @@ function M.create(name, input_priority) end +local WIDGET_METATABLE = { __index = M } + +---Create the Druid component instance +---@param self druid.instance +---@param widget_class druid.widget +---@param context table +---@return druid.widget +function M.create_widget(self, widget_class, context) + local instance = setmetatable({}, { + __index = setmetatable(widget_class, WIDGET_METATABLE) + }) + + instance._component = { + _uid = M.create_uid(), + name = "Druid Widget", + input_priority = const.PRIORITY_INPUT, + default_input_priority = const.PRIORITY_INPUT, + _is_input_priority_changed = true, -- Default true for sort once time after GUI init + } + instance._meta = { + druid = self, + template = "", + nodes = nil, + context = context, + style = nil, + input_enabled = true, + children = {}, + parent = type(context) ~= "userdata" and context or nil, + instance_class = widget_class + } + + -- Register + if instance._meta.parent then + instance._meta.parent:__add_child(instance) + end + + ---@cast instance druid.widget + return instance +end + + return M diff --git a/druid/const.lua b/druid/const.lua index 46ac38c..0363871 100755 --- a/druid/const.lua +++ b/druid/const.lua @@ -79,8 +79,7 @@ M.LAYOUT_MODE = { STRETCH = gui.ADJUST_STRETCH, } -M.SYS_INFO = sys.get_sys_info() -M.CURRENT_SYSTEM_NAME = M.SYS_INFO.system_name +M.CURRENT_SYSTEM_NAME = sys.get_sys_info().system_name M.OS = { ANDROID = "Android", @@ -114,5 +113,4 @@ M.SIDE = { Y = "y" } - return M diff --git a/druid/custom/rich_input/rich_input.lua b/druid/custom/rich_input/rich_input.lua index fdc5f10..8ee70b6 100644 --- a/druid/custom/rich_input/rich_input.lua +++ b/druid/custom/rich_input/rich_input.lua @@ -1,65 +1,18 @@ --- Copyright (c) 2022 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid Rich Input custom component. --- It's wrapper on Input component with cursor and placeholder text --- @module RichInput --- @alias druid.rich_input - ---- The component druid instance --- @tfield DruidInstance druid DruidInstance - ---- Root node --- @tfield node root - ---- On input field text change callback(self, input_text) --- @tfield Input input Input - ---- On input field text change to empty string callback(self, input_text) --- @tfield node cursor - ---- On input field text change to empty string callback(self, input_text) --- @tfield node cursor_text - ---- On input field text change to empty string callback(self, input_text) --- @tfield vector3 cursor_position - ---- On input field text change to empty string callback(self, input_text) --- @tfield druid.text input_text - ---- On input field text change to empty string callback(self, input_text) --- @tfield druid.drag drag - ---- On input field text change to empty string callback(self, input_text) --- @tfield druid.text placeholder - ---- On input field text change to empty string callback(self, input_text) --- @tfield vector3 text_position - ---- - local component = require("druid.component") local helper = require("druid.helper") local const = require("druid.const") local utf8_lua = require("druid.system.utf8") local utf8 = utf8 or utf8_lua ----@class druid.rich_input: druid.base_component ----@field root node ----@field input druid.input ----@field cursor node ----@field cursor_text node ----@field cursor_position vector3 +---The component that handles a rich text input field, it's a wrapper around the druid.input component +---@class druid.rich_input: druid.component +---@field root node The root node of the rich input +---@field input druid.input The input component +---@field cursor node The cursor node +---@field cursor_text node The cursor text node +---@field cursor_position vector3 The position of the cursor local M = component.create("druid.rich_input") ---local SCHEME = { --- ROOT = "root", --- BUTTON = "button", --- PLACEHOLDER = "placeholder_text", --- INPUT = "input_text", --- CURSOR = "cursor_node", --- CURSOR_TEXT = "cursor_text", ---} - local DOUBLE_CLICK_TIME = 0.35 local function animate_cursor(self) @@ -120,7 +73,7 @@ local function on_unselect(self) end ---- Update selection +---Update selection local function update_selection(self) update_text(self) end @@ -179,7 +132,12 @@ local function on_touch_start_callback(self, touch) end - +---@param self druid.rich_input +---@param dx number The delta x position +---@param dy number The delta y position +---@param x number The x position +---@param y number The y position +---@param touch table The touch table local function on_drag_callback(self, dx, dy, x, y, touch) if not self._last_touch_info.cursor_index then return @@ -233,6 +191,10 @@ function M:init(template, nodes) end +---@private +---@param action_id hash Action id from on_input +---@param action table Action table from on_input +---@return boolean is_consumed True if input was consumed function M:on_input(action_id, action) if action_id == const.ACTION_LSHIFT then if action.pressed then @@ -261,24 +223,29 @@ function M:on_input(action_id, action) return true end end + + return false end ---- Set placeholder text +---Set placeholder text ---@param placeholder_text string The placeholder text +---@return druid.rich_input self Current instance function M:set_placeholder(placeholder_text) self.placeholder:set_text(placeholder_text) return self end ---- Select input field +---Select input field +---@return druid.rich_input self Current instance function M:select() self.input:select() + return self end ---- Set input field text +---Set input field text ---@param text string The input text ---@return druid.rich_input self Current instance function M:set_text(text) @@ -289,7 +256,7 @@ function M:set_text(text) end ---- Set input field font +---Set input field font ---@param font hash The font hash ---@return druid.rich_input self Current instance function M:set_font(font) @@ -300,17 +267,17 @@ function M:set_font(font) end ---- Set input field text +---Set input field text function M:get_text() return self.input:get_text() end ---- Set allowed charaters for input field. +---Set allowed charaters for input field. -- See: https://defold.com/ref/stable/string/ -- ex: [%a%d] for alpha and numeric ---@param characters string Regulax exp. for validate user input ----@return druid.rich_input Current instance +---@return druid.rich_input self Current instance function M:set_allowed_characters(characters) self.input:set_allowed_characters(characters) diff --git a/druid/custom/rich_text/module/rt.lua b/druid/custom/rich_text/module/rt.lua index 8239877..e688f43 100755 --- a/druid/custom/rich_text/module/rt.lua +++ b/druid/custom/rich_text/module/rt.lua @@ -1,3 +1,4 @@ +---@diagnostic disable: inject-field -- Source: https://github.com/britzl/defold-richtext version 5.19.0 -- Author: Britzl -- Modified by: Insality @@ -50,10 +51,10 @@ local function compare_words(one, two) end ---- Get the length of a text ignoring any tags except image tags --- which are treated as having a length of 1 --- @param text String with text or a list of words (from richtext.create) --- @return Length of text +---Get the length of a text ignoring any tags except image tags +---which are treated as having a length of 1 +---@param text string|table String with text or a list of words (from richtext.create) +---@return number Length of text function M.length(text) assert(text) if type(text) == "string" then @@ -152,12 +153,12 @@ end -- Create rich text gui nodes from text ---- @param text string The text to create rich text nodes from ---- @param settings table Optional settings table (refer to documentation for details) ---- @param style druid.rich_text.style ---- @return druid.rich_text.word[] ---- @return druid.rich_text.settings ---- @return druid.rich_text.lines_metrics +---@param text string The text to create rich text nodes from +---@param settings table Optional settings table (refer to documentation for details) +---@param style druid.rich_text.style +---@return druid.rich_text.word[] +---@return druid.rich_text.settings +---@return druid.rich_text.lines_metrics function M.create(text, settings, style) assert(text, "You must provide a text") @@ -424,7 +425,7 @@ function M._update_nodes(lines, settings) gui.set_outline(node, word.outline) gui.set_shadow(node, word.shadow) gui.set_text(node, word.text) - gui.set_color(node, word.color) + gui.set_color(node, word.color or word.text_color) gui.set_font(node, word.font or settings.font) end word.node = node @@ -522,10 +523,10 @@ function M.is_fit_info_area(lines, settings) 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 --- @return Words matching the tag +---Get all words with a specific tag +---@param words druid.rich_text.word[] The words to search (as received from richtext.create) +---@param tag string|nil The tag to search for. Nil to search for words without a tag +---@return druid.rich_text.word[] Words matching the tag function M.tagged(words, tag) local tagged = {} for i = 1, #words do diff --git a/druid/custom/rich_text/module/rt_color.lua b/druid/custom/rich_text/module/rt_color.lua index dd7a725..6729998 100644 --- a/druid/custom/rich_text/module/rt_color.lua +++ b/druid/custom/rich_text/module/rt_color.lua @@ -34,7 +34,7 @@ function M.parse_decimal(dec) local r,g,b,a = dec:match("(%d*%.?%d*),(%d*%.?%d*),(%d*%.?%d*),(%d*%.?%d*)") if r and g and b and a then - local color = vmath.vector4(tonumber(r), tonumber(g), tonumber(b), tonumber(a)) + local color = vmath.vector4(tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0, tonumber(a) or 1) cache[dec] = color return color end diff --git a/druid/custom/rich_text/module/rt_parse.lua b/druid/custom/rich_text/module/rt_parse.lua index 53d42a6..3d019c7 100755 --- a/druid/custom/rich_text/module/rt_parse.lua +++ b/druid/custom/rich_text/module/rt_parse.lua @@ -107,11 +107,11 @@ local function merge_tags(dst, src) end ---- Parse the text into individual words --- @param text The text to parse --- @param default_settings Default settings for each word --- @param color_aliases Color aliases table --- @return List of all words +---Parse the text into individual words +---@param text string The text to parse +---@param default_settings table Default settings for each word +---@param style table Style settings +---@return table List of all words function M.parse(text, default_settings, style) assert(text) assert(default_settings) @@ -184,7 +184,9 @@ function M.parse(text, default_settings, style) end ---- Get the length of a text, excluding any tags (except image and spine tags) +---Get the length of a text, excluding any tags (except image and spine tags) +---@param text string The text to get the length of +---@return number The length of the text function M.length(text) return utf8.len(text:gsub("", " "):gsub("<.->", "")) end diff --git a/druid/custom/rich_text/module/rt_tags.lua b/druid/custom/rich_text/module/rt_tags.lua index 058131e..f061954 100644 --- a/druid/custom/rich_text/module/rt_tags.lua +++ b/druid/custom/rich_text/module/rt_tags.lua @@ -26,12 +26,11 @@ function M.register(tag, fn) end --- Split string at first occurrence of token --- If the token doesn't exist the whole string is returned --- @param s The string to split --- @param token The token to split string on --- @return before The string before the token or the whole string if token doesn't exist --- @return after The string after the token or nul +---Split string at first occurrence of token +---@param s string? The string to split +---@param token string The token to split string on +---@return string? before The string before the token or the whole string if token doesn't exist +---@return string? after The string after the token or nil local function split(s, token) if not s then return nil, nil end local before, after = s:match("(.-)" .. token .. "(.*)") diff --git a/druid/custom/rich_text/rich_text.lua b/druid/custom/rich_text/rich_text.lua index 6e2fb8d..7b38045 100644 --- a/druid/custom/rich_text/rich_text.lua +++ b/druid/custom/rich_text/rich_text.lua @@ -1,78 +1,3 @@ --- Copyright (c) 2022 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid Rich Text Custom Component. --- # Overview # --- --- This custom component is inspired by defold-richtext by britzl. --- It uses a similar syntax for tags but currently supports fewer tags. --- --- Create Rich Text on your GUI Text Node. All properties of the text node will be used as default for the text. --- --- # Notes # --- --- • Nested tags are supported --- --- Example Link --- @usage --- local RichText = require("druid.custom.rich_text.rich_text") --- ... --- self.rich_text = self.druid:new(RichText, "rich_text") --- self.rich_text:set_text("Hello, Druid Rich Text!") --- @usage --- type druid.rich_text.word = { --- node: Node, --- relative_scale: number, --- color: vector4, --- position: vector3, --- offset: vector3, --- scale: vector3, --- size: vector3, --- metrics: druid.rich_text.metrics, --- pivot: Pivot, --- text: string, --- shadow: vector4, --- outline: vector4, --- font: string, --- image: druid.rich_text.image, --- br: boolean, --- nobr: boolean, --- } --- --- type druid.rich_text.word.image = { --- texture: string, --- anim: string, --- width: number, --- height: number, --- } --- --- type druid.rich_text.lines_metrics = { --- text_width: number, --- text_height: number, --- lines: table, --- } --- --- type druid.rich_text.metrics = { --- width: number, --- height: number, --- offset_x: number|nil, --- offset_y: number|nil, --- node_size: vector3|nil @For images only, --- } --- @module RichText --- @within BaseComponent --- @alias druid.rich_text - ---- The component druid instance --- @tfield DruidInstance druid DruidInstance - ---- The root node of the Rich Text --- @tfield node root - ---- The text prefab node --- @tfield node text_prefab - --- - local component = require("druid.component") local rich_text = require("druid.custom.rich_text.module.rt") @@ -102,6 +27,7 @@ local rich_text = require("druid.custom.rich_text.module.rt") ---@field relative_scale number ---@field source_text string ---@field color vector4 +---@field text_color vector4 ---@field position vector3 ---@field offset vector3 ---@field scale vector3 @@ -115,6 +41,7 @@ local rich_text = require("druid.custom.rich_text.module.rt") ---@field image druid.rich_text.word.image ---@field br boolean ---@field nobr boolean +---@field tags table ---@class druid.rich_text.word.image ---@field texture string @@ -126,8 +53,6 @@ local rich_text = require("druid.custom.rich_text.module.rt") ---@field COLORS table ---@field ADJUST_STEPS number ---@field ADJUST_SCALE_DELTA number ----@field ADJUST_TYPE string ----@field ADJUST_SCALE number ---@class druid.rich_text.lines_metrics ---@field text_width number @@ -141,15 +66,15 @@ local rich_text = require("druid.custom.rich_text.module.rt") ---@field offset_y number|nil ---@field node_size vector3|nil ----@class druid.rich_text: druid.base_component ----@field root node ----@field text_prefab node ----@field private _last_value string ----@field private _settings table +---The component that handles a rich text display, allows to custom color, size, font, etc. of the parts of the text +---@class druid.rich_text: druid.component +---@field root node The root node of the rich text +---@field text_prefab node The text prefab node +---@field private _last_value string The last value of the rich text +---@field private _settings table The settings of the rich text local M = component.create("rich_text") ---- The RichText constructor ---@param text_node node|string The text node to make Rich Text ---@param value string|nil The initial text value. Default will be gui.get_text(text_node) function M:init(text_node, value) @@ -167,6 +92,7 @@ function M:init(text_node, value) end +---@private function M:on_layout_change() if self._last_value then self:set_text(self._last_value) @@ -174,68 +100,48 @@ function M:on_layout_change() end ---- Component style params. --- You can override this component styles params in Druid styles table --- or create your own style --- @table style --- @tfield table|nil COLORS Rich Text color aliases. Default: {} --- @tfield number|nil ADJUST_STEPS Amount steps of attemps text adjust by height. Default: 20 --- @tfield number|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02 +---@private +---@param style druid.rich_text.style function M:on_style_change(style) - self.style = {} - self.style.COLORS = style.COLORS or {} - self.style.ADJUST_STEPS = style.ADJUST_STEPS or 20 - self.style.ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02 + self.style = { + COLORS = style.COLORS or {}, + ADJUST_STEPS = style.ADJUST_STEPS or 20, + ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02, + } end ---- Set text for Rich Text +---Set text for Rich Text +--- -- Color +--- rich_text:set_text("<color=red>Foobar</color>") +--- rich_text:set_text("<color=1.0,0,0,1.0>Foobar</color>") +--- rich_text:set_text("<color=#ff0000>Foobar</color>") +--- rich_text:set_text("<color=#ff0000ff>Foobar</color>") +--- -- Shadow +--- rich_text:set_text("<shadow=red>Foobar</shadow>") +--- rich_text:set_text("<shadow=1.0,0,0,1.0>Foobar</shadow>") +--- rich_text:set_text("<shadow=#ff0000>Foobar</shadow>") +--- rich_text:set_text("<shadow=#ff0000ff>Foobar</shadow>") +--- -- Outline +--- rich_text:set_text("<outline=red>Foobar</outline>") +--- rich_text:set_text("<outline=1.0,0,0,1.0>Foobar</outline>") +--- rich_text:set_text("<outline=#ff0000>Foobar</outline>") +--- rich_text:set_text("<outline=#ff0000ff>Foobar</outline>") +--- -- Font +--- rich_text:set_text("<font=MyCoolFont>Foobar</font>") +--- -- Size +--- rich_text:set_text("<size=2>Twice as large</size>") +--- -- Line break +--- rich_text:set_text("<br/>Insert a line break") +--- -- No break +--- rich_text:set_text("<nobr>Prevent the text from breaking") +--- -- Image +--- rich_text:set_text("<img=texture:image>Display image") +--- rich_text:set_text("<img=texture:image,size>Display image with size") +--- rich_text:set_text("<img=texture:image,width,height>Display image with width and height") ---@param text string|nil The text to set ---@return druid.rich_text.word[] words ---@return druid.rich_text.lines_metrics line_metrics --- @usage --- • color: Change text color --- --- Foobar --- Foobar --- Foobar --- Foobar --- --- • shadow: Change text shadow --- --- Foobar --- Foobar --- Foobar --- Foobar --- --- • outline: Change text shadow --- --- Foobar --- Foobar --- Foobar --- Foobar --- --- • font: Change font --- --- Foobar --- --- • size: Change text size, relative to default size --- --- Twice as large --- --- • br: Insert a line break --- ---
--- --- • nobr: Prevent the text from breaking --- --- Words inside tag won't break --- --- • img: Display image --- --- --- --- function M:set_text(text) text = text or "" self:clear() @@ -251,13 +157,14 @@ function M:set_text(text) end ---- Get current text ----@return string text +---Get the current text of the rich text +---@return string text The current text of the rich text function M:get_text() return self._last_value end +---@private function M:on_remove() gui.set_scale(self.root, self._default_scale) gui.set_size(self.root, self._default_size) @@ -265,7 +172,7 @@ function M:on_remove() end ---- Clear all created words. +---Clear all created words. function M:clear() if self._words then rich_text.remove(self._words) @@ -275,9 +182,9 @@ function M:clear() end ---- Get all words, which has a passed tag. ----@param tag string ----@return druid.rich_text.word[] words +---Get all words, which has a passed tag. +---@param tag string The tag to get the words for +---@return druid.rich_text.word[] words The words with the passed tag function M:tagged(tag) if not self._words then return {} @@ -287,28 +194,22 @@ function M:tagged(tag) end ----Split a word into it's characters ----@param word druid.rich_text.word ----@return druid.rich_text.word[] characters -function M:characters(word) - return rich_text.characters(word) -end - - ---- Get all current words. +---Get all current created words, each word is a table that contains the information about the word ---@return druid.rich_text.word[] function M:get_words() return self._words end ---- Get current line metrics -----@return druid.rich_text.lines_metrics +---Get the current line metrics +---@return druid.rich_text.lines_metrics lines_metrics The line metrics of the rich text function M:get_line_metric() return self._line_metrics end +---@private +---@return table settings The settings of the rich text, they are created based on the root node on the GUI scene function M:_create_settings() local root_size = gui.get_size(self.root) local scale = gui.get_scale(self.root) diff --git a/druid/materials/gui_repeat/gui_repeat.fp b/druid/custom/tiling_node/gui_tiling_node.fp similarity index 99% rename from druid/materials/gui_repeat/gui_repeat.fp rename to druid/custom/tiling_node/gui_tiling_node.fp index fb355aa..b18e002 100644 --- a/druid/materials/gui_repeat/gui_repeat.fp +++ b/druid/custom/tiling_node/gui_tiling_node.fp @@ -7,7 +7,6 @@ in vec4 var_color; in vec4 var_uv; in vec4 var_repeat; // [repeat_x, repeat_y, anchor_x, anchor_y] in vec4 var_params; // [margin_x, margin_y, offset_x, offset_y] -in vec4 var_perspective; in vec4 var_uv_rotated; out vec4 color_out; @@ -81,4 +80,4 @@ void main() { lowp vec4 tex = texture(texture_sampler, uv); color_out = tex * var_color; -} \ No newline at end of file +} diff --git a/druid/materials/gui_repeat/gui_repeat.material b/druid/custom/tiling_node/gui_tiling_node.material similarity index 69% rename from druid/materials/gui_repeat/gui_repeat.material rename to druid/custom/tiling_node/gui_tiling_node.material index 213467e..4c0a29e 100644 --- a/druid/materials/gui_repeat/gui_repeat.material +++ b/druid/custom/tiling_node/gui_tiling_node.material @@ -1,7 +1,7 @@ name: "repeat" tags: "gui" -vertex_program: "/druid/materials/gui_repeat/gui_repeat.vp" -fragment_program: "/druid/materials/gui_repeat/gui_repeat.fp" +vertex_program: "/druid/custom/tiling_node/gui_tiling_node.vp" +fragment_program: "/druid/custom/tiling_node/gui_tiling_node.fp" vertex_constants { name: "view_proj" type: CONSTANT_TYPE_VIEWPROJ @@ -28,12 +28,6 @@ vertex_constants { value { } } -vertex_constants { - name: "perspective" - type: CONSTANT_TYPE_USER - value { - } -} vertex_constants { name: "uv_rotated" type: CONSTANT_TYPE_USER diff --git a/druid/materials/gui_repeat/gui_repeat.vp b/druid/custom/tiling_node/gui_tiling_node.vp similarity index 67% rename from druid/materials/gui_repeat/gui_repeat.vp rename to druid/custom/tiling_node/gui_tiling_node.vp index 12c1460..93146f7 100644 --- a/druid/materials/gui_repeat/gui_repeat.vp +++ b/druid/custom/tiling_node/gui_tiling_node.vp @@ -11,7 +11,6 @@ uniform vertex_inputs highp vec4 uv_repeat; // [repeat_x, repeat_y, pivot_x, pivot_y] vec4 uv_rotated; vec4 params; // [margin_x, margin_y, offset_x, offset_y] - vec4 perspective; // [perspective_x, perspective_y, zoom, offset_y] }; out mediump vec2 var_texcoord0; @@ -19,7 +18,6 @@ out lowp vec4 var_color; out highp vec4 var_uv; out highp vec4 var_repeat; out vec4 var_params; -out vec4 var_perspective; out vec4 var_uv_rotated; void main() @@ -29,7 +27,6 @@ void main() var_uv = uv_coord; var_repeat = uv_repeat; var_params = params; - var_perspective = perspective; var_uv_rotated = uv_rotated; mat4 transform = mat4( @@ -39,12 +36,5 @@ void main() 0.0, position.z, 0, 1.0 ); - // Matrix Info = mat4( - // scale_x, skew_x, 0, offset_x, - // skew_y, scale_y, 0, offset_y, - // 0, 0, scale_z, offset_z, - // perspective_x, perspective_y, perspective_z, zoom - //) - gl_Position = view_proj * vec4(position.xyz, 1.0) * transform; } diff --git a/druid/widget/node_repeat/node_repeat.lua b/druid/custom/tiling_node/tiling_node.lua similarity index 55% rename from druid/widget/node_repeat/node_repeat.lua rename to druid/custom/tiling_node/tiling_node.lua index 353517d..2fef09b 100644 --- a/druid/widget/node_repeat/node_repeat.lua +++ b/druid/custom/tiling_node/tiling_node.lua @@ -1,51 +1,71 @@ +local component = require("druid.component") local helper = require("druid.helper") -local event_queue = require("druid.event_queue") +local defer = require("event.defer") ----@class druid.node_repeat: druid.widget +---@class druid.tiling_node: druid.component ---@field animation table ---@field node node ---@field params vector4 ---@field time number -local M = {} +local M = component.create("tiling_node") +M.PROP_SIZE_X = hash("size.x") +M.PROP_SIZE_Y = hash("size.y") +M.PROP_SCALE_X = hash("scale.x") +M.PROP_SCALE_Y = hash("scale.y") + + +---@param node node|string function M:init(node) self.node = self:get_node(node) self.animation = nil - gui.set_material(self.node, hash("gui_repeat")) self.time = 0 self.margin = 0 self.params = gui.get(self.node, "params") --[[@as vector4]] - self:get_atlas_path(function(atlas_path) - self.is_inited = self:init_tiling_animation(atlas_path) - local repeat_x, repeat_y = self:get_repeat() - self:animate(repeat_x, repeat_y) + + self.timer_no_init = timer.delay(0.1, false, function() + print("The druid.script is not found, please add it nearby to the GUI collection", msg.url()) end) - --self.druid.events.on_node_property_changed:subscribe(self.on_node_property_changed, self) + defer.push("druid.get_atlas_path", { + texture_name = gui.get_texture(self.node), + sender = msg.url(), + }, self.on_get_atlas_path, self) end +---@param atlas_path string +function M:on_get_atlas_path(atlas_path) + timer.cancel(self.timer_no_init) + self.is_inited = self:init_tiling_animation(atlas_path) + local repeat_x, repeat_y = self:get_repeat_count_from_node() + self:start_animation(repeat_x, repeat_y) +end + + +---@param node node +---@param property string function M:on_node_property_changed(node, property) if not self.is_inited or node ~= self.node then return end if property == "size" or property == "scale" then - local repeat_x, repeat_y = self:get_repeat() + local repeat_x, repeat_y = self:get_repeat_count_from_node() self:set_repeat(repeat_x, repeat_y) end end -function M:get_repeat() +function M:get_repeat_count_from_node() if not self.is_inited then return 1, 1 end - local size_x = gui.get(self.node, helper.PROP_SIZE_X) - local size_y = gui.get(self.node, helper.PROP_SIZE_Y) - local scale_x = gui.get(self.node, helper.PROP_SCALE_X) - local scale_y = gui.get(self.node, helper.PROP_SCALE_Y) + local size_x = gui.get(self.node, M.PROP_SIZE_X) + local size_y = gui.get(self.node, M.PROP_SIZE_Y) + local scale_x = gui.get(self.node, M.PROP_SCALE_X) + local scale_y = gui.get(self.node, M.PROP_SCALE_Y) local repeat_x = (size_x / self.animation.width) / scale_x local repeat_y = (size_y / self.animation.height) / scale_y @@ -54,11 +74,7 @@ function M:get_repeat() end -function M:get_atlas_path(callback) - event_queue.request("druid.get_atlas_path", callback, gui.get_texture(self.node), msg.url()) -end - - +---@param atlas_path string ---@return boolean function M:init_tiling_animation(atlas_path) if not atlas_path then @@ -71,24 +87,25 @@ function M:init_tiling_animation(atlas_path) return true end + -- Start our repeat shader work --- @param repeat_x -- X factor --- @param repeat_y -- Y factor -function M:animate(repeat_x, repeat_y) +---@param repeat_x number X factor +---@param repeat_y number Y factor +function M:start_animation(repeat_x, repeat_y) if not self.is_inited then return end + self:set_repeat(repeat_x, repeat_y) + local node = self.node local animation = self.animation - local frame = animation.frames[1] gui.set(node, "uv_coord", frame.uv_coord) - self:set_repeat(repeat_x, repeat_y) if #animation.frames > 1 and animation.fps > 0 then animation.handle = - timer.delay(1/animation.fps, true, function(self, handle, time_elapsed) + timer.delay(1/animation.fps, true, function(_, handle, time_elapsed) local next_rame = animation.frames[animation.current_frame] gui.set(node, "uv_coord", next_rame.uv_coord) @@ -110,9 +127,9 @@ function M:final() end --- Update repeat factor values --- @param repeat_x --- @param repeat_y +---Update repeat factor values +---@param repeat_x number? X factor +---@param repeat_y number? Y factor function M:set_repeat(repeat_x, repeat_y) local animation = self.animation animation.v.x = repeat_x or animation.v.x @@ -126,32 +143,8 @@ function M:set_repeat(repeat_x, repeat_y) end -function M:set_perpective(perspective_x, perspective_y) - if perspective_x then - gui.set(self.node, "perspective.x", perspective_x) - end - - if perspective_y then - gui.set(self.node, "perspective.y", perspective_y) - end - - return self -end - - -function M:set_perpective_offset(offset_x, offset_y) - if offset_x then - gui.set(self.node, "perspective.z", offset_x) - end - - if offset_y then - gui.set(self.node, "perspective.w", offset_y) - end - - return self -end - - +---@param offset_perc_x number? X offset +---@param offset_perc_y number? Y offset function M:set_offset(offset_perc_x, offset_perc_y) self.params.z = offset_perc_x or self.params.z self.params.w = offset_perc_y or self.params.w @@ -160,6 +153,8 @@ function M:set_offset(offset_perc_x, offset_perc_y) end +---@param margin_x number? X margin +---@param margin_y number? Y margin function M:set_margin(margin_x, margin_y) self.params.x = margin_x or self.params.x self.params.y = margin_y or self.params.y @@ -170,23 +165,17 @@ end ---@param scale number function M:set_scale(scale) - local current_scale_x = gui.get(self.node, helper.PROP_SCALE_X) - local current_scale_y = gui.get(self.node, helper.PROP_SCALE_Y) - local current_size_x = gui.get(self.node, helper.PROP_SIZE_X) - local current_size_y = gui.get(self.node, helper.PROP_SIZE_Y) + local current_scale_x = gui.get(self.node, M.PROP_SCALE_X) + local current_scale_y = gui.get(self.node, M.PROP_SCALE_Y) + local current_size_x = gui.get(self.node, M.PROP_SIZE_X) + local current_size_y = gui.get(self.node, M.PROP_SIZE_Y) local delta_scale_x = scale / current_scale_x local delta_scale_y = scale / current_scale_y - gui.set(self.node, helper.PROP_SCALE_X, scale) - gui.set(self.node, helper.PROP_SCALE_Y, scale) - gui.set(self.node, helper.PROP_SIZE_X, current_size_x / delta_scale_x) - gui.set(self.node, helper.PROP_SIZE_Y, current_size_y / delta_scale_y) - - --self.druid:on_node_property_changed(self.node, "scale") - --self.druid:on_node_property_changed(self.node, "size") - - --local repeat_x, repeat_y = self:get_repeat() - --self:set_repeat(repeat_x, repeat_y) + gui.set(self.node, M.PROP_SCALE_X, scale) + gui.set(self.node, M.PROP_SCALE_Y, scale) + gui.set(self.node, M.PROP_SIZE_X, current_size_x / delta_scale_x) + gui.set(self.node, M.PROP_SIZE_Y, current_size_y / delta_scale_y) return self end diff --git a/druid/druid.lua b/druid/druid.lua index ce3f034..71c3b54 100644 --- a/druid/druid.lua +++ b/druid/druid.lua @@ -1,9 +1,13 @@ +local event = require("event.event") local events = require("event.events") local settings = require("druid.system.settings") local druid_instance = require("druid.system.druid_instance") local default_style = require("druid.styles.default.style") + +---Entry point for Druid UI Framework. +---Create a new Druid instance and adjust the Druid settings here. ---@class druid local M = {} @@ -11,16 +15,13 @@ local M = {} ---Create a new Druid instance for creating GUI components. ---@param context table The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks. ---@param style table|nil The Druid style table to override style parameters for this Druid instance. ----@return druid_instance druid_instance The new Druid instance +---@return druid.instance druid_instance The new Druid instance function M.new(context, style) if settings.default_style == nil then M.set_default_style(default_style) end - local new_instance = setmetatable({}, { __index = druid_instance }) - new_instance:initialize(context, style) - - return new_instance + return druid_instance.create_druid_instance(context, style) end @@ -31,6 +32,7 @@ end ---The default way to create component is `druid_instance:new(component_class, ...)`. ---@param name string Module name ---@param module table Lua table with component +---@deprecated function M.register(name, module) druid_instance["new_" .. name] = function(self, ...) return druid_instance.new(self, module, ...) @@ -83,4 +85,91 @@ function M.on_language_change() end +local REGISTERED_GUI_WIDGETS = {} + +---Set a widget to the current game object. The game object can acquire the widget by calling `bindings.get_widget` +---It wraps with events only top level functions cross-context, so you will have no access to nested widgets functions +---Only one widget can be set per game object. +---@param widget druid.widget +---@return druid.widget +local function wrap_widget(widget) + -- Make a copy of the widget with all functions wrapped in events + -- It makes available to call gui functions from game objects + local wrapped_widget = setmetatable({}, { __index = widget }) + local parent_table = getmetatable(widget).__index + + -- Go through all functions and wrap them in events + for key, value in pairs(parent_table) do + if type(value) == "function" then + wrapped_widget[key] = event.create(function(_, ...) + return value(widget, ...) + end) + end + end + + return wrapped_widget +end + + +---Get a binded widget to the current game object. +--- msg.url(nil, nil, "go_widget") -- current game object +--- msg.url(nil, object_url, "go_widget") -- other game object +---@generic T: druid.widget +---@param widget_class T The class of the widget to return +---@param gui_url url GUI url +---@return T +function M.get_widget(widget_class, gui_url) + gui_url = gui_url or msg.url() + local guis = REGISTERED_GUI_WIDGETS[gui_url.socket] + if not guis then + return nil + end + + for index = 1, #guis do + local gui = guis[index] + if gui.fragment == gui_url.fragment and gui.path == gui_url.path then + return gui.new_widget:trigger(widget_class) + end + end + + return nil +end + + +---Register a widget to the current game object. +---@param druid druid.instance The druid instance to register +function M.register_druid_as_widget(druid) + local gui_url = msg.url() + REGISTERED_GUI_WIDGETS[gui_url.socket] = REGISTERED_GUI_WIDGETS[gui_url.socket] or {} + table.insert(REGISTERED_GUI_WIDGETS[gui_url.socket], { + path = gui_url.path, + fragment = gui_url.fragment, + new_widget = event.create(function(widget_class) + return wrap_widget(druid:new_widget(widget_class)) + end), + }) +end + + +---Unregister a druid instance from the current game object. +function M.unregister_druid_as_widget() + local gui_url = msg.url() + local socket = gui_url.socket + local path = gui_url.path + local fragment = gui_url.fragment + + for index = 1, #REGISTERED_GUI_WIDGETS[socket] do + local gui = REGISTERED_GUI_WIDGETS[socket][index] + if gui.path == path and gui.fragment == fragment then + table.remove(REGISTERED_GUI_WIDGETS[socket], index) + break + end + end + + if #REGISTERED_GUI_WIDGETS[socket] == 0 then + REGISTERED_GUI_WIDGETS[socket] = nil + end +end + + return M diff --git a/druid/druid.script b/druid/druid.script index 209ba74..8306eff 100644 --- a/druid/druid.script +++ b/druid/druid.script @@ -1,37 +1,42 @@ -- Place this script nearby with the gui component to able make requests -- To the go namespace from GUI with events systems (cross context) -local event_queue = require("druid.event_queue") +local defer = require("event.defer") ----Usage: event_queue.request("druid.get_atlas_path", callback, gui.get_texture(self.node), msg.url()) +---Usage: defer.push("druid.get_atlas_path", { +--- texture_name = gui.get_texture(self.node), +--- sender = msg.url(), +---}, callback, [context]) ---Pass texture name to get atlas info and sender url to check if the request is valid local MESSAGE_GET_ATLAS_PATH = "druid.get_atlas_path" +---@class druid.get_atlas_path_request +---@field texture_name hash +---@field sender hash ----@param texture_name hash The name from gui.get_texture(node) ----@param sender hash Just msg.url from the caller -local function get_atlas_path(texture_name, sender) +---@param request druid.get_atlas_path_request +---@return string? +local function get_atlas_path(self, request) local my_url = msg.url() my_url.fragment = nil - local copy_url = msg.url(sender) + local copy_url = msg.url(request.sender) copy_url.fragment = nil -- This check should works well - local is_my_url = my_url == copy_url - if not is_my_url then + if my_url ~= copy_url then return nil end - return go.get(sender, "textures", { key = texture_name }) + return go.get(request.sender, "textures", { key = request.texture_name }) end function init(self) - event_queue.subscribe(MESSAGE_GET_ATLAS_PATH, get_atlas_path) + defer.subscribe(MESSAGE_GET_ATLAS_PATH, get_atlas_path, self) end function final(self) - event_queue.unsubscribe(MESSAGE_GET_ATLAS_PATH, get_atlas_path) -end \ No newline at end of file + defer.unsubscribe(MESSAGE_GET_ATLAS_PATH, get_atlas_path, self) +end diff --git a/druid/druid_widget.gui_script b/druid/druid_widget.gui_script new file mode 100644 index 0000000..8956239 --- /dev/null +++ b/druid/druid_widget.gui_script @@ -0,0 +1,28 @@ +local druid = require("druid.druid") + + +function init(self) + self.druid = druid.new(self) + druid.register_druid_as_widget(self.druid) +end + + +function final(self) + druid.unregister_druid_as_widget() + 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 diff --git a/druid/editor_scripts/component.lua_template b/druid/editor_scripts/component.lua_template deleted file mode 100644 index 560dc2a..0000000 --- a/druid/editor_scripts/component.lua_template +++ /dev/null @@ -1,22 +0,0 @@ ---- For component interest functions ---- see https://github.com/Insality/druid/blob/master/docs_md/02-creating_custom_components.md ---- Require this component in you gui file: ---- $ local {COMPONENT_NAME} = require("{COMPONENT_PATH}") ---- And create this component via: ---- $ self.{COMPONENT_TYPE} = self.druid:new({COMPONENT_NAME}, template, nodes) - -local component = require("druid.component") - ----@class {COMPONENT_TYPE}: druid.base_component ----@field druid druid_instance{COMPONENT_ANNOTATIONS} -local M = component.create("{COMPONENT_TYPE}") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes){COMPONENT_DEFINE} -end - -{COMPONENT_FUNCTIONS} -return M diff --git a/druid/event_queue.lua b/druid/event_queue.lua deleted file mode 100644 index cdeb7c2..0000000 --- a/druid/event_queue.lua +++ /dev/null @@ -1,84 +0,0 @@ -local event = require("event.event") - ----@class event.queue -local M = {} - -local event_handlers = {} -local pending_callbacks = {} - - ----Request to handle a specified event and processes the queue of callbacks associated with it. ----If event has already been triggered, the callback will be executed immediately. ----If event not triggered yet, callback will be executed when event will be triggered. ----It triggered only once and then removed from the queue. ----@param event_name string The name of the event to trigger. ----@param callback fun() The callback function to execute upon triggering. ----@param ... any Additional arguments for the callback. -function M.request(event_name, callback, ...) - pending_callbacks[event_name] = pending_callbacks[event_name] or {} - table.insert(pending_callbacks[event_name], { event.create(callback), ... }) - - M.process_pending_callbacks(event_name) -end - - ----Subscribes to a specified event and executes a callback when the event is triggered. --- If the event has already been triggered, the callback will be executed immediately. ----@param event_name string The name of the event to subscribe to. ----@param callback fun() The function to call when the event is triggered. -function M.subscribe(event_name, callback) - event_handlers[event_name] = event_handlers[event_name] or event.create() - - if event_handlers[event_name] then - event_handlers[event_name]:subscribe(callback) - end - - M.process_pending_callbacks(event_name) -end - - ----Unsubscribes a callback function from a specified event. ----@param event_name string The name of the event to unsubscribe from. ----@param callback fun() The function to remove from the event's subscription list. -function M.unsubscribe(event_name, callback) - if event_handlers[event_name] then - event_handlers[event_name]:unsubscribe(callback) - end -end - - ----Processes the queue for a given event name, executing callbacks and handling results. ----Processed callbacks are removed from the queue. ----@param event_name string The name of the event for which to process the queue. -function M.process_pending_callbacks(event_name) - local callbacks_to_process = pending_callbacks[event_name] - local event_handler = event_handlers[event_name] - - if not callbacks_to_process or not event_handler then - return - end - - -- Loop through the queue in reverse to prevent index errors during removal - for i = #callbacks_to_process, 1, -1 do - local callback_entry = callbacks_to_process[i] - -- Better to figure out how to make it without 2 unpacks, but ok for all our cases now - local args = { unpack(callback_entry, 2) } - - -- Safely call the event handler and handle errors - local success, result = pcall(event_handler.trigger, event_handler, unpack(args)) - - if success and result then - local callback_function = callback_entry[1] - pcall(callback_function, result) -- Safely invoke the callback, catching any errors - table.remove(callbacks_to_process, i) -- Remove the processed callback from the queue - end - end - - -- Clean up if the callback queue is empty - if #callbacks_to_process == 0 then - pending_callbacks[event_name] = nil - end -end - - -return M diff --git a/druid/extended/container.lua b/druid/extended/container.lua index c9f07c9..a1dbd14 100644 --- a/druid/extended/container.lua +++ b/druid/extended/container.lua @@ -1,4 +1,4 @@ ---- Container component +---Container component -- Container setup in GUI -- parent container - container that contains this container. If not, then it's a window default container or parent node -- container pivot - the point of the parent container that will be used as a pivot point for positioning @@ -15,26 +15,6 @@ local helper = require("druid.helper") local component = require("druid.component") local event = require("event.event") ----@class druid.container: druid.base_component ----@field node node ----@field druid druid_instance ----@field node_offset vector4 ----@field origin_size vector3 ----@field size vector3 ----@field origin_position vector3 ----@field position vector3 ----@field pivot_offset vector3 ----@field center_offset vector3 ----@field mode string ----@field fit_size vector3 ----@field min_size_x number|nil ----@field min_size_y number|nil ----@field on_size_changed event @function on_size_changed(size) ----@field _parent_container druid.container ----@field _containers table ----@field _draggable_corners table -local M = component.create("container") - local abs = math.abs local min = math.min local max = math.max @@ -46,8 +26,45 @@ local CORNER_PIVOTS = { gui.PIVOT_SW, } +---@class druid.container.style +---@field DRAGGABLE_CORNER_SIZE vector3 Size of box node for debug draggable corners +---@field DRAGGABLE_CORNER_COLOR vector4 Color of debug draggable corners ---- The Container init +---Druid component to manage the size and positions with other containers relations to create a adaptable layouts. +--- +---### Setup +---Create container component with druid: `container = druid:new_container(node, mode, callback)` +--- +---### Notes +---- Container can be used to create adaptable layouts that respond to window size changes +---- Container supports different layout modes: FIT, STRETCH, STRETCH_X, STRETCH_Y +---- Container can be nested inside other containers +---- Container supports fixed margins and percentage-based sizing +---- Container can be positioned using pivot points +---- Container supports minimum size constraints +---- Container can be fitted into window or custom size +---@class druid.container: druid.component +---@field node node The gui node +---@field druid druid.instance The druid instance +---@field node_offset vector4 The node offset +---@field origin_size vector3 The origin size +---@field size vector3 The current size +---@field origin_position vector3 The origin position +---@field position vector3 The current position +---@field pivot_offset vector3 The pivot offset +---@field center_offset vector3 The center offset +---@field mode string The layout mode +---@field fit_size vector3 The fit size +---@field min_size_x number|nil The minimum size x +---@field min_size_y number|nil The minimum size y +---@field on_size_changed event fun(self: druid.container, size: vector3) The event triggered when the size changes +---@field _parent_container druid.container The parent container +---@field _containers table The containers +---@field _draggable_corners table The draggable corners +local M = component.create("container") + + +---The Container constructor ---@param node node Gui node ---@param mode string Layout mode ---@param callback fun(self: druid.container, size: vector3)|nil Callback on size changed @@ -90,6 +107,7 @@ function M:init(node, mode, callback) end +---@private function M:on_late_init() if not gui.get_parent(self.node) then -- TODO: Scale issue here, in fit into window! @@ -98,11 +116,13 @@ function M:on_late_init() end +---@private function M:on_remove() self:clear_draggable_corners() end +---Refresh the origins of the container, origins is the size and position of the container when it was created function M:refresh_origins() self.origin_size = gui.get_size(self.node) self.origin_position = gui.get_position(self.node) @@ -110,7 +130,8 @@ function M:refresh_origins() end ----@param pivot constant +---Set the pivot of the container +---@param pivot constant The pivot to set function M:set_pivot(pivot) gui.set_pivot(self.node, pivot) self.pivot_offset = helper.get_pivot_offset(pivot) @@ -118,22 +139,19 @@ function M:set_pivot(pivot) end ---- Component style params. --- You can override this component styles params in Druid styles table --- or create your own style --- @table style --- @tfield[opt=vector3(24, 24, 0)] vector3 DRAGGABLE_CORNER_SIZE Size of box node for debug draggable corners --- @tfield[opt=vector4(1)] vector4 DRAGGABLE_CORNER_COLOR Color of debug draggable corners +---@private +---@param style druid.container.style function M:on_style_change(style) - self.style = {} - self.style.DRAGGABLE_CORNER_SIZE = style.DRAGGABLE_CORNER_SIZE or vmath.vector3(24, 24, 0) - self.style.DRAGGABLE_CORNER_COLOR = style.DRAGGABLE_CORNER_COLOR or vmath.vector4(10) + self.style = { + DRAGGABLE_CORNER_SIZE = style.DRAGGABLE_CORNER_SIZE or vmath.vector3(24, 24, 0), + DRAGGABLE_CORNER_COLOR = style.DRAGGABLE_CORNER_COLOR or vmath.vector4(10) + } end ---- Set new size of layout node ----@param width number|nil ----@param height number|nil +---Set new size of layout node +---@param width number|nil The width to set +---@param height number|nil The height to set ---@param anchor_pivot constant|nil If set will keep the corner possition relative to the new size ---@return druid.container Container function M:set_size(width, height, anchor_pivot) @@ -175,13 +193,16 @@ function M:set_size(width, height, anchor_pivot) end +---Get the position of the container +---@return vector3 position The position of the container function M:get_position() return self._position end ----@param pos_x number ----@param pos_y number +---Set the position of the container +---@param pos_x number The x position to set +---@param pos_y number The y position to set function M:set_position(pos_x, pos_y) if self._position.x == pos_x and self._position.y == pos_y then return @@ -193,23 +214,23 @@ function M:set_position(pos_x, pos_y) end ----Get current size of layout node ----@return vector3 size +---Get the current size of the layout node +---@return vector3 size The current size of the layout node function M:get_size() return vmath.vector3(self.size) end ----Get current scale of layout node ----@return vector3 scale +---Get the current scale of the layout node +---@return vector3 scale The current scale of the layout node function M:get_scale() return helper.get_scene_scale(self.node, true) --[[@as vector3]] end ---- Set size for layout node to fit inside it ----@param target_size vector3 ----@return druid.container Container +---Set size for layout node to fit inside it +---@param target_size vector3 The target size to fit into +---@return druid.container self Current container instance function M:fit_into_size(target_size) self.fit_size = target_size self:refresh() @@ -218,13 +239,14 @@ function M:fit_into_size(target_size) end ---- Set current size for layout node to fit inside it ----@return druid.container Container +---Set current size for layout node to fit inside it +---@return druid.container self Current container instance function M:fit_into_window() return self:fit_into_size(vmath.vector3(gui.get_width(), gui.get_height(), 0)) end +---@private function M:on_window_resized() local x_koef, y_koef = helper.get_screen_aspect_koef() self.x_koef = x_koef @@ -236,7 +258,7 @@ function M:on_window_resized() end ----@param node_or_container node|string|druid.container|table +---@param node_or_container node|string|druid.container|table The node or container to add ---@param mode string|nil stretch, fit, stretch_x, stretch_y. Default: Pick from node, "fit" or "stretch" ---@param on_resize_callback fun(self: userdata, size: vector3)|nil ---@return druid.container Container New created layout instance @@ -245,13 +267,14 @@ function M:add_container(node_or_container, mode, on_resize_callback) local node = node_or_container -- Check it's a container components instead of node - if type(node_or_container) == "table" and node_or_container._component then + if type(node_or_container) == "table" and node_or_container.add_container then node = node_or_container.node container = node_or_container mode = mode or container.mode end -- Covert node_id to node if needed + ---@cast node node node = self:get_node(node) container = container or self.druid:new(M, node, mode) @@ -387,7 +410,7 @@ function M:refresh() stretch_side_y = parent.size.y - (abs(self.node_offset.y) + abs(self.node_offset.w)) end - ---- Size Update (for stretch) + ----Size Update (for stretch) if self.mode == const.LAYOUT_MODE.STRETCH then self:set_size( abs(stretch_side_x * self.node_fill_x), @@ -440,7 +463,7 @@ function M:update_child_containers() end ----@return druid.container Container +---@return druid.container self Current container instance function M:create_draggable_corners() self:clear_draggable_corners() @@ -470,7 +493,7 @@ function M:create_draggable_corners() end ----@return druid.container Container +---@return druid.container self Current container instance function M:clear_draggable_corners() for index = 1, #self._draggable_corners do local drag_component = self._draggable_corners[index] @@ -521,9 +544,9 @@ function M:_on_corner_drag(x, y, corner_offset) end ---- Set node for layout node to fit inside it. Pass nil to reset +---Set node for layout node to fit inside it. Pass nil to reset ---@param node string|node The node_id or gui.get_node(node_id) ----@return druid.container Layout +---@return druid.container self Current container instance function M:fit_into_node(node) self._fit_node = self:get_node(node) self:refresh_scale() @@ -531,8 +554,10 @@ function M:fit_into_node(node) end ----@param min_size_x number|nil ----@param min_size_y number|nil +---Set the minimum size of the container +---@param min_size_x number|nil The minimum size x +---@param min_size_y number|nil The minimum size y +---@return druid.container self Current container instance function M:set_min_size(min_size_x, min_size_y) self.min_size_x = min_size_x or self.min_size_x self.min_size_y = min_size_y or self.min_size_y diff --git a/druid/extended/data_list.lua b/druid/extended/data_list.lua index c7ece01..0bebccf 100644 --- a/druid/extended/data_list.lua +++ b/druid/extended/data_list.lua @@ -1,63 +1,40 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to manage data for huge dataset in scroll. --- It requires Druid Scroll and Druid Grid (Static or Dynamic) components --- --- Example Link --- @module DataList --- @within BaseComponent --- @alias druid.data_list - - ---- The Druid scroll component --- @tfield Scroll scroll Scroll - ---- The Druid Grid component --- @tfield StaticGrid grid StaticGrid}, @{DynamicGrid - ---- The current progress of scroll posititon --- @tfield number scroll_progress - ---- The current top index of visual elements --- @tfield number top_index - ---- The current last index of visual elements --- @tfield number last_index - ---- Event triggered when scroll progress is changed; event(self, progress_value) --- @tfield event on_scroll_progress_change event - ----On DataList visual element created Event callback(self, index, node, instance) --- @tfield event on_element_add event - ----On DataList visual element created Event callback(self, index) --- @tfield event on_element_remove event - ---- - local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") local event = require("event.event") ----@class druid.data_list: druid.base_component ----@field scroll druid.scroll ----@field grid druid.grid ----@field on_scroll_progress_change event ----@field on_element_add event ----@field on_element_remove event ----@field private _create_function function ----@field private _is_use_cache boolean ----@field private _cache table ----@field private _data table ----@field private _data_visual table ----@field top_index number +---Druid component to manage a list of data with a scrollable view, used to manage huge list data and render only visible elements. +--- +---### Setup +---Create data list component with druid: `data_list = druid:new_data_list(scroll, grid, create_function)` +--- +---### Notes +---- Data List uses a scroll component for scrolling and a grid component for layout +---- Data List only renders visible elements for better performance +---- Data List supports caching of elements for better performance +---- Data List supports adding, removing and updating elements +---- Data List supports scrolling to specific elements +---- Data List supports custom element creation and cleanup +---@class druid.data_list: druid.component +---@field scroll druid.scroll The scroll instance for Data List component +---@field grid druid.grid The StaticGrid or DynamicGrid instance for Data List component +---@field on_scroll_progress_change event The event triggered when the scroll progress changes +---@field on_element_add event The event triggered when a new element is added +---@field on_element_remove event The event triggered when an element is removed +---@field top_index number The top index of the visible elements +---@field last_index number The last index of the visible elements +---@field scroll_progress number The scroll progress +---@field private _create_function function The create function callback(self, data, index, data_list). Function should return (node, [component]) +---@field private _is_use_cache boolean Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove +---@field private _cache table The cache table +---@field private _data table The data table +---@field private _data_visual table The data visual table local M = component.create("data_list") ---- The DataList constructor +---The DataList constructor ---@param scroll druid.scroll The Scroll instance for Data List component ----@param grid druid.grid The StaticGrid} or @{DynamicGrid instance for Data List component +---@param grid druid.grid The StaticGrid instance for Data List component ---@param create_function function The create function callback(self, data, index, data_list). Function should return (node, [component]) function M:init(scroll, grid, create_function) self.scroll = scroll @@ -85,25 +62,25 @@ function M:init(scroll, grid, create_function) end ---- Druid System on_remove function +---@private function M:on_remove() self:clear() self.scroll.on_scroll:unsubscribe(self._refresh, self) end ---- Set refresh function for DataList component ----@param is_use_cache boolean Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove ----@return druid.data_list Current DataList instance +---Set use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove +---@param is_use_cache boolean Use cache version of DataList +---@return druid.data_list self Current DataList instance function M:set_use_cache(is_use_cache) self._is_use_cache = is_use_cache return self end ---- Set new data set for DataList component +---Set new data set for DataList component ---@param data table The new data array ----@return druid.data_list Current DataList instance +---@return druid.data_list self Current DataList instance function M:set_data(data) self._data = data or {} self:_refresh() @@ -112,55 +89,67 @@ function M:set_data(data) end ---- Return current data from DataList component ----@return table The current data array +---Return current data from DataList component +---@return table data The current data array function M:get_data() return self._data end ---- Add element to DataList. Currenly untested ----@param data table ----@param index number|nil +---Add element to DataList +---@param data table The data to add +---@param index number|nil The index to add the data at ---@param shift_policy number|nil The constant from const.SHIFT.* +---@return druid.data_list self Current DataList instance function M:add(data, index, shift_policy) index = index or #self._data + 1 shift_policy = shift_policy or const.SHIFT.RIGHT helper.insert_with_shift(self._data, data, index, shift_policy) self:_refresh() + + return self end ---- Remove element from DataList. Currenly untested ----@param index number|nil +---Remove element from DataList +---@param index number|nil The index to remove the data at ---@param shift_policy number|nil The constant from const.SHIFT.* +---@return druid.data_list self Current DataList instance function M:remove(index, shift_policy) helper.remove_with_shift(self._data, index, shift_policy) self:_refresh() + + return self end ---- Remove element from DataList by data value. Currenly untested ----@param data table +---Remove element from DataList by data value +---@param data table The data to remove ---@param shift_policy number|nil The constant from const.SHIFT.* +---@return druid.data_list self Current DataList instance function M:remove_by_data(data, shift_policy) local index = helper.contains(self._data, data) if index then helper.remove_with_shift(self._data, index, shift_policy) self:_refresh() end + + return self end ---- Clear the DataList and refresh visuals +---Clear the DataList and refresh visuals +---@return druid.data_list self Current DataList instance function M:clear() self._data = {} self:_refresh() + + return self end ---- Return index for data value +---Return index for data value ---@param data table function M:get_index(data) for index, value in pairs(self._data) do @@ -173,7 +162,7 @@ function M:get_index(data) end ---- Return all currenly created nodes in DataList +---Return all currenly created nodes in DataList ---@return node[] List of created nodes function M:get_created_nodes() local nodes = {} @@ -186,8 +175,8 @@ function M:get_created_nodes() end ---- Return all currenly created components in DataList ----@return druid.base_component[] List of created nodes +---Return all currenly created components in DataList +---@return druid.component[] components List of created components function M:get_created_components() local components = {} @@ -199,16 +188,16 @@ function M:get_created_components() end ---- Instant scroll to element with passed index ----@param index number +---Instant scroll to element with passed index +---@param index number The index to scroll to function M:scroll_to_index(index) local pos = self.grid:get_pos(index) self.scroll:scroll_to(pos) end ---- Add element at passed index using cache or create new ----@param index number +---Add element at passed index using cache or create new +---@param index number The index to add the element at ---@private function M:_add_at(index) if self._data_visual[index] then @@ -240,8 +229,8 @@ function M:_add_at(index) end ---- Remove element from passed index and add it to cache if applicable ----@param index number +---Remove element from passed index and add it to cache if applicable +---@param index number The index to remove the element at ---@private function M:_remove_at(index) self.grid:remove(index, const.SHIFT.NO_SHIFT) @@ -269,8 +258,7 @@ function M:_remove_at(index) end - ---- Refresh all elements in DataList +---Refresh all elements in DataList ---@private function M:_refresh() self.scroll:set_size(self.grid:get_size_for(#self._data)) diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua index b06f1fe..0671e1c 100644 --- a/druid/extended/hotkey.lua +++ b/druid/extended/hotkey.lua @@ -1,43 +1,32 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid hotkey component --- --- Example Link --- @module Hotkey --- @within BaseComponent --- @alias druid.hotkey - ---- On hotkey released callback(self, argument) --- @tfield event on_hotkey_pressed event - ---- On hotkey released callback(self, argument) --- @tfield event on_hotkey_released event - ---- Visual node --- @tfield node node - ---- Button trigger node --- @tfield node|nil click_node - ---- Button component from click_node --- @tfield Button button Button - ---- - +local event = require("event.event") local helper = require("druid.helper") local component = require("druid.component") -local event = require("event.event") ----@class druid.hotkey: druid.base_component ----@field on_hotkey_pressed event ----@field on_hotkey_released event ----@field style table ----@field private _hotkeys table ----@field private _modificators table +---@class druid.hotkey.style +---@field MODIFICATORS string[]|hash[] The list of action_id as hotkey modificators + +---Druid component to manage hotkeys and trigger callbacks when hotkeys are pressed. +--- +---### Setup +---Create hotkey component with druid: `hotkey = druid:new_hotkey(keys, callback, callback_argument)` +--- +---### Notes +---- Hotkey can be triggered by pressing a single key or a combination of keys +---- Hotkey supports modificator keys (e.g. Ctrl, Shift, Alt) +---- Hotkey can be triggered on key press, release or repeat +---- Hotkey can be added or removed at runtime +---- Hotkey can be enabled or disabled +---- Hotkey can be set to repeat on key hold +---@class druid.hotkey: druid.component +---@field on_hotkey_pressed event fun(self, context, callback_argument) The event triggered when a hotkey is pressed +---@field on_hotkey_released event fun(self, context, callback_argument) The event triggered when a hotkey is released +---@field style druid.hotkey.style The style of the hotkey component +---@field private _hotkeys table The list of hotkeys +---@field private _modificators table The list of modificators local M = component.create("hotkey") ---- The Hotkey constructor +---The Hotkey constructor ---@param keys string[]|string The keys to be pressed for trigger callback. Should contains one key and any modificator keys ---@param callback function The callback function ---@param callback_argument any|nil The argument to pass into the callback function @@ -56,25 +45,26 @@ function M:init(keys, callback, callback_argument) end ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield string[] MODIFICATORS The list of action_id as hotkey modificators +---@private +---@param style druid.hotkey.style function M:on_style_change(style) - self.style = {} - self.style.MODIFICATORS = style.MODIFICATORS or {} + self.style = { + MODIFICATORS = style.MODIFICATORS or {}, + } for index = 1, #style.MODIFICATORS do - self.style.MODIFICATORS[index] = hash(self.style.MODIFICATORS[index]) + local modificator = style.MODIFICATORS[index] + if type(modificator) == "string" then + self.style.MODIFICATORS[index] = hash(modificator) + end end end ---- Add hotkey for component callback +---Add hotkey for component callback ---@param keys string[]|hash[]|string|hash that have to be pressed before key pressed to activate ---@param callback_argument any|nil The argument to pass into the callback function ----@return druid.hotkey Current instance +---@return druid.hotkey self Current instance function M:add_hotkey(keys, callback_argument) keys = keys or {} if type(keys) == "string" then @@ -84,6 +74,7 @@ function M:add_hotkey(keys, callback_argument) local modificators = {} local key = nil + ---@cast keys string[] for index = 1, #keys do local key_hash = hash(keys[index]) if #keys > 1 and helper.contains(self.style.MODIFICATORS, key_hash) then @@ -105,8 +96,9 @@ function M:add_hotkey(keys, callback_argument) }) -- Current hotkey status - for index = 1, #self.style.MODIFICATORS do - local modificator = hash(self.style.MODIFICATORS[index]) + local mods = self.style.MODIFICATORS ---@type string[] + for index = 1, #mods do + local modificator = hash(mods[index]) self._modificators[modificator] = self._modificators[modificator] or false end @@ -125,6 +117,7 @@ function M:is_processing() end +---@private function M:on_focus_gained() for k, v in pairs(self._modificators) do self._modificators[k] = false @@ -132,6 +125,10 @@ function M:on_focus_gained() end +---@private +---@param action_id hash|nil The action id +---@param action action The action +---@return boolean is_consume True if the action is consumed function M:on_input(action_id, action) if not action_id then return false @@ -186,9 +183,9 @@ function M:on_input(action_id, action) end ---- If true, the callback will be triggered on action.repeated ----@param is_enabled_repeated bool The flag value ----@return druid.hotkey +---If true, the callback will be triggered on action.repeated +---@param is_enabled_repeated boolean The flag value +---@return druid.hotkey self Current instance function M:set_repeat(is_enabled_repeated) self._is_process_repeated = is_enabled_repeated return self diff --git a/druid/extended/input.lua b/druid/extended/input.lua index ae243a2..3f18ea8 100755 --- a/druid/extended/input.lua +++ b/druid/extended/input.lua @@ -1,85 +1,3 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid input text component. --- Carry on user text input --- --- Example Link --- @author Part of code from Britzl gooey input component --- @module Input --- @within BaseComponent --- @alias druid.input - ---- On input field select callback(self, input_instance) --- @tfield event on_input_select event - ---- On input field unselect callback(self, input_text, input_instance) --- @tfield event on_input_unselect event - ---- On input field text change callback(self, input_text) --- @tfield event on_input_text event - ---- On input field text change to empty string callback(self, input_text) --- @tfield event on_input_empty event - ---- On input field text change to max length string callback(self, input_text) --- @tfield event on_input_full event - ---- On trying user input with not allowed character callback(self, params, input_text) --- @tfield event on_input_wrong event - ---- On cursor position change callback(self, cursor_index, start_index, end_index) --- @tfield event on_select_cursor_change event - ---- The cursor index. The index of letter cursor after. Leftmost cursor - 0 --- @tfield number cursor_index - ---- The selection start index. The index of letter cursor after. Leftmost selection - 0 --- @tfield number start_index - ---- Theselection end index. The index of letter cursor before. Rightmost selection - #text --- @tfield number end_index - ---- Text component --- @tfield Text text Text - ---- Current input value --- @tfield string value - ---- Previous input value --- @tfield string previous_value - ---- Current input value with marked text --- @tfield string current_value - ---- Marked text for input field. Info: https://defold.com/manuals/input-key-and-text/#marked-text --- @tfield string marked_value - ---- Text width --- @tfield number text_width - ---- Marked text width --- @tfield number marked_text_width - ---- Button component --- @tfield Button button Button - ---- Is current input selected now --- @tfield boolean is_selected - ---- Is current input is empty now --- @tfield boolean is_empty - ---- Max length for input text --- @tfield number|nil max_length - ---- Pattern matching for user input --- @tfield string|nil allowerd_characters - ---- Gui keyboard type for input field --- @tfield number keyboard_type - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") @@ -87,18 +5,38 @@ local component = require("druid.component") local utf8_lua = require("druid.system.utf8") local utf8 = utf8 or utf8_lua ----@class druid.input: druid.base_component ----@field on_input_select event ----@field on_input_unselect event ----@field on_input_text event ----@field on_input_empty event ----@field on_input_full event ----@field on_input_wrong event ----@field on_select_cursor_change event ----@field style table ----@field text druid.text +---@class druid.input.style +---@field MASK_DEFAULT_CHAR string Default character mask for password input +---@field IS_LONGTAP_ERASE boolean Is long tap will erase current input data +---@field IS_UNSELECT_ON_RESELECT boolean If true, call unselect on select selected input +---@field on_select fun(self: druid.input, button_node: node) Callback on input field selecting +---@field on_unselect fun(self: druid.input, button_node: node) Callback on input field unselecting +---@field on_input_wrong fun(self: druid.input, button_node: node) Callback on wrong user input + +---Basic Druid text input component. Handles user text input via component with button and text. +--- +---### Setup +---Create input component with druid: `input = druid:new_input(button_node_name, text_node_name, keyboard_type)` +--- +---### Notes +---- Input component handles user text input. Input contains button and text components +---- Button needed for selecting/unselecting input field +---- Click outside of button to unselect input field +---- On focus lost (game minimized) input field will be unselected +---- You can setup max length of the text +---- You can setup allowed characters. On add not allowed characters `on_input_wrong` will be called +---@class druid.input: druid.component +---@field on_input_select event fun(self: druid.input, input: druid.input) The event triggered when the input field is selected +---@field on_input_unselect event fun(self: druid.input, text: string, input: druid.input) The event triggered when the input field is unselected +---@field on_input_text event fun(self: druid.input) The event triggered when the input field is changed +---@field on_input_empty event fun(self: druid.input) The event triggered when the input field is empty +---@field on_input_full event fun(self: druid.input) The event triggered when the input field is full +---@field on_input_wrong event fun(self: druid.input) The event triggered when the input field is wrong +---@field on_select_cursor_change event fun(self: druid.input, cursor_index: number, start_index: number, end_index: number) The event triggered when the cursor index is changed +---@field style druid.input.style The style of the input component local M = component.create("input") +---@private M.ALLOWED_ACTIONS = { [const.ACTION_TOUCH] = true, [const.ACTION_TEXT] = true, @@ -108,7 +46,7 @@ M.ALLOWED_ACTIONS = { [const.ACTION_ESC] = true, } ---- Mask text by replacing every character with a mask character +---Mask text by replacing every character with a mask character ---@param text string ---@param mask string ---@return string Masked text @@ -132,33 +70,9 @@ local function clear_and_select(self) end ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield boolean IS_LONGTAP_ERASE Is long tap will erase current input data. Default: false --- @tfield string MASK_DEFAULT_CHAR Default character mask for password input. Default: *] --- @tfield boolean IS_UNSELECT_ON_RESELECT If true, call unselect on select selected input. Default: false --- @tfield function on_select (self, button_node) Callback on input field selecting --- @tfield function on_unselect (self, button_node) Callback on input field unselecting --- @tfield function on_input_wrong (self, button_node) Callback on wrong user input -function M:on_style_change(style) - self.style = {} - - self.style.IS_LONGTAP_ERASE = style.IS_LONGTAP_ERASE or false - self.style.MASK_DEFAULT_CHAR = style.MASK_DEFAULT_CHAR or "*" - self.style.IS_UNSELECT_ON_RESELECT = style.IS_UNSELECT_ON_RESELECT or false - - self.style.on_select = style.on_select or function(_, button_node) end - self.style.on_unselect = style.on_unselect or function(_, button_node) end - self.style.on_input_wrong = style.on_input_wrong or function(_, button_node) end -end - - ---- The Input constructor ---@param click_node node Node to enabled input component ---@param text_node node|druid.text Text node what will be changed on user input. You can pass text component instead of text node name Text ----@param keyboard_type number|nil Gui keyboard type for input field +---@param keyboard_type constant|nil Gui keyboard type for input field function M:init(click_node, text_node, keyboard_type) self.druid = self:get_druid() @@ -210,6 +124,25 @@ function M:init(click_node, text_node, keyboard_type) end +---@private +---@param style druid.input.style +function M:on_style_change(style) + self.style = { + IS_LONGTAP_ERASE = style.IS_LONGTAP_ERASE or false, + MASK_DEFAULT_CHAR = style.MASK_DEFAULT_CHAR or "*", + IS_UNSELECT_ON_RESELECT = style.IS_UNSELECT_ON_RESELECT or false, + + on_select = style.on_select or function(_, button_node) end, + on_unselect = style.on_unselect or function(_, button_node) end, + on_input_wrong = style.on_input_wrong or function(_, button_node) end, + } +end + + +---@private +---@param action_id hash|nil The action id +---@param action action The action +---@return boolean is_consume True if the action is consumed function M:on_input(action_id, action) if not (action_id == nil or M.ALLOWED_ACTIONS[action_id]) then return false @@ -308,11 +241,13 @@ function M:on_input(action_id, action) end +---@private function M:on_focus_lost() self:unselect() end +---@private function M:on_input_interrupt() --self:unselect() end @@ -326,9 +261,10 @@ function M:get_text_selected() return utf8.sub(self.value, self.start_index + 1, self.end_index) end ---- Replace selected text with new text + +---Replace selected text with new text ---@param text string The text to replace selected text ----@return string New input text +---@return string new_text New input text function M:get_text_selected_replaced(text) local left_part = utf8.sub(self.value, 1, self.start_index) local right_part = utf8.sub(self.value, self.end_index + 1, utf8.len(self.value)) @@ -343,8 +279,8 @@ function M:get_text_selected_replaced(text) end ---- Set text for input field ----@param input_text string The string to apply for input field +---Set text for input field +---@param input_text string? The string to apply for input field, if nil - will be set to empty string function M:set_text(input_text) input_text = tostring(input_text or "") @@ -391,7 +327,7 @@ function M:set_text(input_text) end ---- Select input field. It will show the keyboard and trigger on_select events +---Select input field. It will show the keyboard and trigger on_select events function M:select() gui.reset_keyboard() self.marked_value = "" @@ -415,7 +351,7 @@ function M:select() end ---- Remove selection from input. It will hide the keyboard and trigger on_unselect events +---Remove selection from input. It will hide the keyboard and trigger on_unselect events function M:unselect() gui.reset_keyboard() self.marked_value = "" @@ -433,8 +369,8 @@ function M:unselect() end ---- Return current input field text ----@return string The current input field text +---Return current input field text +---@return string text The current input field text function M:get_text() if self.marked_value ~= "" then return self.value .. self.marked_value @@ -444,29 +380,31 @@ function M:get_text() end ---- Set maximum length for input field. --- Pass nil to make input field unliminted (by default) +---Set maximum length for input field. +---Pass nil to make input field unliminted (by default) ---@param max_length number Maximum length for input text field ----@return druid.input Current input instance +---@return druid.input self Current input instance function M:set_max_length(max_length) self.max_length = max_length return self end ---- Set allowed charaters for input field. --- See: https://defold.com/ref/stable/string/ --- ex: [%a%d] for alpha and numeric ----@param characters string Regulax exp. for validate user input ----@return druid.input Current input instance +---Set allowed charaters for input field. +---See: https://defold.com/ref/stable/string/ +---ex: [%a%d] for alpha and numeric +---ex: [abcdef] to allow only these characters +---ex: [^%s] to allow only non-space characters +---@param characters string Regular expression for validate user input +---@return druid.input self Current input instance function M:set_allowed_characters(characters) self.allowed_characters = characters return self end ---- Reset current input selection and return previous value ----@return druid.input Current input instance +---Reset current input selection and return previous value +---@return druid.input self Current input instance function M:reset_changes() self:set_text(self.previous_value) self:unselect() @@ -474,11 +412,11 @@ function M:reset_changes() end ---- Set cursor position in input field +---Set cursor position in input field ---@param cursor_index number|nil Cursor index for cursor position, if nil - will be set to the end of the text ---@param start_index number|nil Start index for cursor position, if nil - will be set to the end of the text ---@param end_index number|nil End index for cursor position, if nil - will be set to the start_index ----@return druid.input Current input instance +---@return druid.input self Current input instance function M:select_cursor(cursor_index, start_index, end_index) local len = utf8.len(self.value) @@ -496,10 +434,11 @@ function M:select_cursor(cursor_index, start_index, end_index) end ---- Change cursor position by delta +---Change cursor position by delta ---@param delta number side for cursor position, -1 for left, 1 for right ---@param is_add_to_selection boolean (Shift key) ---@param is_move_to_end boolean (Ctrl key) +---@return druid.input self Current input instance function M:move_selection(delta, is_add_to_selection, is_move_to_end) local len = utf8.len(self.value) local cursor_index = self.cursor_index @@ -555,6 +494,8 @@ function M:move_selection(delta, is_add_to_selection, is_move_to_end) end self:select_cursor(cursor_index, start_index, end_index) + + return self end diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua index d0745c9..b065104 100755 --- a/druid/extended/lang_text.lua +++ b/druid/extended/lang_text.lua @@ -1,49 +1,28 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to wrap over GUI Text nodes with localization helpers --- --- # Overview # --- --- • The initialization of druid.set_text_function is required to enable localization --- using the localization ID. --- --- • The LangText component supports up to 7 string format parameters. --- This limitation exists due to certain issues with using ... arguments. --- --- # Notes # --- --- Example Link --- @module LangText --- @within BaseComponent --- @alias druid.lang_text - ---- On change text callback --- @tfield event on_change event - ---- The text component --- @tfield Text text Text - ---- Text node --- @tfield node node - ---- - local event = require("event.event") -local settings = require("druid.system.settings") local component = require("druid.component") +local settings = require("druid.system.settings") ----@class druid.lang_text: druid.base_component ----@field text druid.text ----@field node node ----@field on_change event ----@field private last_locale_args table ----@field private last_locale string +---The component used for displaying localized text, can automatically update text when locale is changed. +---It wraps the Text component to handle localization using druid's get_text_function to set text by its id. +--- +---### Setup +---Create lang text component with druid: `text = druid:new_lang_text(node_name, locale_id)` +--- +---### Notes +---- Component automatically updates text when locale is changed +---- Uses druid's get_text_function to get localized text by id +---- Supports string formatting with additional parameters +---@class druid.lang_text: druid.component +---@field text druid.text The text component +---@field node node The node of the text component +---@field on_change event The event triggered when the text is changed +---@field private last_locale_args table The last locale arguments +---@field private last_locale string The last locale local M = component.create("lang_text") ---- The LangText constructor ---@param node string|node The node_id or gui.get_node(node_id) ----@param locale_id string|nil Default locale id or text from node as default +---@param locale_id string|nil Default locale id or text from node as default. If not provided, will use text from the node ---@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference function M:init(node, locale_id, adjust_type) self.druid = self:get_druid() @@ -60,6 +39,7 @@ function M:init(node, locale_id, adjust_type) end +---@private function M:on_language_change() if self.last_locale then self:translate(self.last_locale, unpack(self.last_locale_args)) @@ -67,9 +47,9 @@ function M:on_language_change() end ---- Setup raw text to lang_text component +---Setup raw text to lang_text component. This will clear any locale settings. ---@param text string Text for text node ----@return druid.lang_text Current instance +---@return druid.lang_text self Current instance function M:set_to(text) self.last_locale = nil self.text:set_text(text) @@ -79,47 +59,36 @@ function M:set_to(text) end ---- Setup raw text to lang_text component +---Setup raw text to lang_text component. This will clear any locale settings. ---@param text string Text for text node ----@return druid.lang_text Current instance +---@return druid.lang_text self Current instance function M:set_text(text) return self:set_to(text) end ---- Translate the text by locale_id ----@param locale_id string Locale id ----@param a string|nil Optional param to string.format ----@param b string|nil Optional param to string.format ----@param c string|nil Optional param to string.format ----@param d string|nil Optional param to string.format ----@param e string|nil Optional param to string.format ----@param f string|nil Optional param to string.format ----@param g string|nil Optional param to string.format ----@return druid.lang_text Current instance -function M:translate(locale_id, a, b, c, d, e, f, g) - self.last_locale_args = { a, b, c, d, e, f, g } +---Translate the text by locale_id. The text will be automatically updated when locale changes. +---@param locale_id string Locale id to get text from +---@param ... string Optional params for string.format +---@return druid.lang_text self Current instance +function M:translate(locale_id, ...) + self.last_locale_args = { ... } self.last_locale = locale_id or self.last_locale - self.text:set_text(settings.get_text(self.last_locale, a, b, c, d, e, f, g) or "") + self.text:set_text(settings.get_text(self.last_locale, ...) or "") return self end ---- Format string with new text params on localized text ----@param a string|nil Optional param to string.format ----@param b string|nil Optional param to string.format ----@param c string|nil Optional param to string.format ----@param d string|nil Optional param to string.format ----@param e string|nil Optional param to string.format ----@param f string|nil Optional param to string.format ----@param g string|nil Optional param to string.format ----@return druid.lang_text Current instance -function M:format(a, b, c, d, e, f, g) - self.last_locale_args = { a, b, c, d, e, f, g } - self.text:set_text(settings.get_text(self.last_locale, a, b, c, d, e, f, g) or "") +---Format string with new text params on localized text. Keeps the current locale but updates the format parameters. +---@param ... string Optional params for string.format +---@return druid.lang_text self Current instance +function M:format(...) + self.last_locale_args = { ... } + self.text:set_text(settings.get_text(self.last_locale, ...) or "") return self end + return M diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua index 52c0582..e5e5085 100644 --- a/druid/extended/layout.lua +++ b/druid/extended/layout.lua @@ -2,7 +2,7 @@ local event = require("event.event") local helper = require("druid.helper") local component = require("druid.component") ----@alias druid.layout.mode "horizontal"|"vertical"|"horizontal_wrap" +---@alias druid.layout.type "horizontal"|"vertical"|"horizontal_wrap" ---@class event.on_size_changed: event ---@field subscribe fun(_, callback: fun(new_size: vector3), context: any|nil) @@ -19,24 +19,35 @@ local component = require("druid.component") ---@field nodes_height table ---@field rows druid.layout.row_data[]> ----@class druid.layout: druid.base_component ----@field node node +---Druid component to manage the layout of nodes, placing them inside the node size with respect to the size and pivot of each node. +--- +---### Setup +---Create layout component with druid: `layout = druid:new_layout(node, layout_type)` +--- +---### Notes +---- Layout can be horizontal, vertical or horizontal with wrapping +---- Layout can resize parent node to fit content +---- Layout can justify content +---- Layout supports margins and padding +---- Layout automatically updates when nodes are added or removed +---- Layout can be manually updated by calling set_dirty() +---@class druid.layout: druid.component +---@field node node The node to manage the layout of ---@field rows_data druid.layout.rows_data Last calculated rows data ----@field is_dirty boolean ----@field entities node[] ----@field margin {x: number, y: number} ----@field padding vector4 ----@field type string ----@field is_resize_width boolean ----@field is_resize_height boolean ----@field is_justify boolean ----@field on_size_changed event.on_size_changed +---@field is_dirty boolean True if layout needs to be updated +---@field entities node[] The entities to manage the layout of +---@field margin {x: number, y: number} The margin of the layout +---@field padding vector4 The padding of the layout +---@field type string The type of the layout +---@field is_resize_width boolean True if the layout should resize the width of the node +---@field is_resize_height boolean True if the layout should resize the height of the node +---@field is_justify boolean True if the layout should justify the nodes +---@field on_size_changed event.on_size_changed The event triggered when the size of the layout is changed local M = component.create("layout") ----Layout component constructor ----@local ----@param node_or_node_id node|string ----@param layout_type druid.layout.mode + +---@param node_or_node_id node|string The node to manage the layout of +---@param layout_type druid.layout.type The type of layout (horizontal, vertical, horizontal_wrap) function M:init(node_or_node_id, layout_type) self.node = self:get_node(node_or_node_id) @@ -60,7 +71,6 @@ function M:init(node_or_node_id, layout_type) end ----@local function M:update() if not self.is_dirty then return @@ -70,11 +80,15 @@ function M:update() end +---@return node[] entities The entities to manage the layout of function M:get_entities() return self.entities end +---@param node node The node to set the index of +---@param index number The index to set the node to +---@return druid.layout self for chaining function M:set_node_index(node, index) for i = 1, #self.entities do if self.entities[i] == node then @@ -83,12 +97,15 @@ function M:set_node_index(node, index) break end end + + return self end ----@param margin_x number|nil ----@param margin_y number|nil ----@return druid.layout +---Set the margin of the layout +---@param margin_x number|nil The margin x +---@param margin_y number|nil The margin y +---@return druid.layout self Current layout instance function M:set_margin(margin_x, margin_y) self.margin.x = margin_x or self.margin.x self.margin.y = margin_y or self.margin.y @@ -98,11 +115,11 @@ function M:set_margin(margin_x, margin_y) end ----@param padding_x number|nil ----@param padding_y number|nil ----@param padding_z number|nil ----@param padding_w number|nil ----@return druid.layout +---@param padding_x number|nil The padding x +---@param padding_y number|nil The padding y +---@param padding_z number|nil The padding z +---@param padding_w number|nil The padding w +---@return druid.layout self Current layout instance function M:set_padding(padding_x, padding_y, padding_z, padding_w) self.padding.x = padding_x or self.padding.x self.padding.y = padding_y or self.padding.y @@ -114,7 +131,7 @@ function M:set_padding(padding_x, padding_y, padding_z, padding_w) end ----@return druid.layout +---@return druid.layout self Current layout instance function M:set_dirty() self.is_dirty = true @@ -123,7 +140,7 @@ end ---@param is_justify boolean ----@return druid.layout +---@return druid.layout self Current layout instance function M:set_justify(is_justify) self.is_justify = is_justify self.is_dirty = true @@ -132,10 +149,10 @@ function M:set_justify(is_justify) end ----@param type string The layout type: "horizontal", "vertical", "horizontal_wrap" ----@return druid.layout -function M:set_type(type) - self.type = type +---@param layout_type druid.layout.type +---@return druid.layout self Current layout instance +function M:set_type(layout_type) + self.type = layout_type self.is_dirty = true return self @@ -144,7 +161,7 @@ end ---@param is_hug_width boolean ---@param is_hug_height boolean ----@return druid.layout +---@return druid.layout self Current layout instance function M:set_hug_content(is_hug_width, is_hug_height) self.is_resize_width = is_hug_width or false self.is_resize_height = is_hug_height or false @@ -156,7 +173,7 @@ end ---Add node to layout ---@param node_or_node_id node|string node_or_node_id ----@return druid.layout +---@return druid.layout self Current layout instance function M:add(node_or_node_id) -- Acquire node from entity or by id local node = node_or_node_id @@ -209,7 +226,7 @@ function M:get_content_size() end ----@return druid.layout +---@return druid.layout self Current layout instance function M:refresh_layout() local layout_node = self.node @@ -288,7 +305,7 @@ function M:refresh_layout() local new_row_width = width * (0.5 - layout_pivot_offset.x) -- Compare with eps due the float loss and element flickering - if current_x + node_width - new_row_width > 0.0001 then + if current_x + node_width - new_row_width > 0.00001 then current_y = current_y - row.height - margin.y if row_index < #rows then @@ -297,6 +314,7 @@ function M:refresh_layout() end current_x = -row.width * (0.5 + layout_pivot_offset.x) + if is_justify and row.count > 1 then current_x = -max_width * (0.5 + layout_pivot_offset.x) end @@ -350,7 +368,7 @@ function M:refresh_layout() end ----@return druid.layout +---@return druid.layout self Current layout instance function M:clear_layout() for index = #self.entities, 1, -1 do self.entities[index] = nil @@ -363,7 +381,8 @@ end ---@param node node ----@return number, number +---@return number width The width of the node +---@return number height The height of the node function M:get_node_size(node) if not gui.is_enabled(node, false) then return 0, 0 diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua index bac6d3c..e29be6d 100644 --- a/druid/extended/progress.lua +++ b/druid/extended/progress.lua @@ -1,64 +1,188 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid component to handle the progress bars. --- # Overview # --- --- # Notes # --- --- • Progress Node should be fully filled in your GUI scene node. It will be the progress maximum size --- --- • Progress correct working with Slice9 nodes, it trying to set size by _set_size_ first, if it is not possible, it set up sizing via _set_scale_ --- --- • Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene --- --- • If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles --- --- --- Example Link --- @module Progress --- @within BaseComponent --- @alias druid.progress - ---- On progress bar change callback(self, new_value) --- @tfield event on_change event - ---- Progress bar fill node --- @tfield node node - ---- The progress bar direction. --- --- The values are: "x" or "y". (const.SIDE.X or const.SIDE.Y) --- @tfield string key - ---- Current progress bar scale --- @tfield vector3 scale - ---- Current progress bar size --- @tfield vector3 size - ---- Maximum size of progress bar --- @tfield number max_size - ---- Progress bar slice9 settings --- @tfield vector4 slice - ---- - local event = require("event.event") -local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") ----@class druid.progress: druid.base_component ----@field node node ----@field on_change event ----@field style table ----@field key string ----@field prop hash +---@class druid.progress.style +---@field SPEED number|nil Progress bas fill rate. More -> faster. Default: 5 +---@field MIN_DELTA number|nil Minimum step to fill progress bar. Default: 0.005 + +---Basic Druid progress bar component. Changes the size or scale of a node to represent progress. +--- +---### Setup +---Create progress bar component with druid: `progress = druid:new_progress(node_name, key, init_value)` +--- +---### Notes +---- Node should have maximum node size in GUI scene, it's represent the progress bar maximum size +---- Key is value from druid const: "x" or "y" +---- Progress works correctly with 9slice nodes, it tries to set size by _set_size_ first, until minimum size is reached, then it sizing via _set_scale_ +---- Progress bar can fill only by vertical or horizontal size. For diagonal progress bar, just rotate node in GUI scene +---- If you have glitchy or dark texture bugs with progress bar, try to disable mipmaps in your texture profiles +---@class druid.progress: druid.component +---@field node node The progress bar node +---@field on_change event Event triggered when progress value changes +---@field style druid.progress.style Component style parameters +---@field key string Progress bar direction: "x" or "y" +---@field prop hash Property for scaling the progress bar local M = component.create("progress") -local function check_steps(self, from, to, exactly) +---@param node string|node Node name or GUI Node itself. +---@param key string Progress bar direction: "x" or "y" +---@param init_value number|nil Initial value of progress bar (0 to 1). Default: 1 +function M:init(node, key, init_value) + assert(key == "x" or key == "y", "Progress bar key should be 'x' or 'y'") + + self.key = key + self.prop = hash("scale." .. self.key) + + self._init_value = init_value or 1 + self.node = self:get_node(node) + self.scale = gui.get_scale(self.node) + self.size = gui.get_size(self.node) + self.max_size = gui.get_size(self.node) + self.slice = gui.get_slice9(self.node) + self.last_value = self._init_value + + self.slice_size = vmath.vector3( + self.slice.x + self.slice.z, + self.slice.y + self.slice.w, + 0 + ) + + self.on_change = event.create() + + self:set_to(self.last_value) +end + + +---@private +---@param style druid.progress.style +function M:on_style_change(style) + self.style = { + SPEED = style.SPEED or 5, + MIN_DELTA = style.MIN_DELTA or 0.005, + } +end + + +---@private +function M:on_layout_change() + self:set_to(self.last_value) +end + + +---@private +function M:on_remove() + gui.set_size(self.node, self.max_size) +end + + +---@param dt number Delta time +function M:update(dt) + if self.target then + local prev_value = self.last_value + local step = math.abs(self.last_value - self.target) * (self.style.SPEED * dt) + step = math.max(step, self.style.MIN_DELTA) + self:set_to(helper.step(self.last_value, self.target, step)) + + if self.last_value == self.target then + self:_check_steps(prev_value, self.target, self.target) + + if self.target_callback then + self.target_callback(self:get_context(), self.target) + end + + self.target = nil + end + end +end + + +---Fill the progress bar +---@return druid.progress self Current progress instance +function M:fill() + self:_set_bar_to(1, true) + + return self +end + + +---Empty the progress bar +---@return druid.progress self Current progress instance +function M:empty() + self:_set_bar_to(0, true) + + return self +end + + +---Instant fill progress bar to value +---@param to number Progress bar value, from 0 to 1 +---@return druid.progress self Current progress instance +function M:set_to(to) + to = helper.clamp(to, 0, 1) + self:_set_bar_to(to) + + return self +end + + +---Return the current value of the progress bar +---@return number value The current value of the progress bar +function M:get() + return self.last_value +end + + +---Set points on progress bar to fire the callback +---@param steps number[] Array of progress bar values +---@param callback function Callback on intersect step value +---@return druid.progress self Current progress instance +function M:set_steps(steps, callback) + self.steps = steps + self.step_callback = callback + + return self +end + + +---Start animation of a progress bar +---@param to number value between 0..1 +---@param callback function|nil Callback on animation ends +---@return druid.progress self Current progress instance +function M:to(to, callback) + to = helper.clamp(to, 0, 1) + -- cause of float error + local value = helper.round(to, 5) + if value ~= self.last_value then + self.target = value + self.target_callback = callback + else + if callback then + callback(self:get_context(), to) + end + end + + return self +end + + +---Set progress bar max node size +---@param max_size vector3 The new node maximum (full) size +---@return druid.progress self Current progress instance +function M:set_max_size(max_size) + self.max_size[self.key] = max_size[self.key] + self:set_to(self.last_value) + + return self +end + + +---@private +---@param from number The start value +---@param to number The end value +---@param exactly number|nil The exact value +function M:_check_steps(from, to, exactly) if not self.steps then return end @@ -80,9 +204,11 @@ local function check_steps(self, from, to, exactly) end -local function set_bar_to(self, set_to, is_silent) +---@private +---@param set_to number The value to set the progress bar to +function M:_set_bar_to(set_to, is_silent) local prev_value = self.last_value - local other_side = self.key == const.SIDE.X and const.SIDE.Y or const.SIDE.X + local other_side = self.key == "x" and "y" or "x" self.last_value = set_to local total_width = set_to * self.max_size[self.key] @@ -109,148 +235,12 @@ local function set_bar_to(self, set_to, is_silent) gui.set_size(self.node, self.size) if not is_silent then - check_steps(self, prev_value, set_to) + self:_check_steps(prev_value, set_to) if prev_value ~= self.last_value then self.on_change:trigger(self:get_context(), self.last_value) end end -end - ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style --- @table style --- @tfield number|nil SPEED Progress bas fill rate. More -> faster. Default: 5 --- @tfield number|nil MIN_DELTA Minimum step to fill progress bar. Default: 0.005 -function M:on_style_change(style) - self.style = {} - self.style.SPEED = style.SPEED or 5 - self.style.MIN_DELTA = style.MIN_DELTA or 0.005 -end - - ---- The Progress constructor ----@param node string|node Node name or GUI Node itself. ----@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y ----@param init_value number|nil Initial value of progress bar. Default: 1 -function M:init(node, key, init_value) - assert(key == const.SIDE.X or const.SIDE.Y, "Progress bar key should be 'x' or 'y'") - - self.key = key - self.prop = hash("scale." .. self.key) - - self._init_value = init_value or 1 - self.node = self:get_node(node) - self.scale = gui.get_scale(self.node) - self.size = gui.get_size(self.node) - self.max_size = gui.get_size(self.node) - self.slice = gui.get_slice9(self.node) - self.last_value = self._init_value - - self.slice_size = vmath.vector3( - self.slice.x + self.slice.z, - self.slice.y + self.slice.w, - 0 - ) - - self.on_change = event.create() - - self:set_to(self.last_value) -end - - -function M:on_layout_change() - self:set_to(self.last_value) -end - - -function M:on_remove() - -- Return default size - gui.set_size(self.node, self.max_size) -end - - -function M:update(dt) - if self.target then - local prev_value = self.last_value - local step = math.abs(self.last_value - self.target) * (self.style.SPEED*dt) - step = math.max(step, self.style.MIN_DELTA) - self:set_to(helper.step(self.last_value, self.target, step)) - - if self.last_value == self.target then - check_steps(self, prev_value, self.target, self.target) - - if self.target_callback then - self.target_callback(self:get_context(), self.target) - end - - self.target = nil - end - end -end - - ---- Fill a progress bar and stop progress animation -function M:fill() - set_bar_to(self, 1, true) -end - - ---- Empty a progress bar -function M:empty() - set_bar_to(self, 0, true) -end - - ---- Instant fill progress bar to value ----@param to number Progress bar value, from 0 to 1 -function M:set_to(to) - to = helper.clamp(to, 0, 1) - set_bar_to(self, to) -end - - ---- Return current progress bar value -function M:get() - return self.last_value -end - - ---- Set points on progress bar to fire the callback ----@param steps number[] Array of progress bar values ----@param callback function Callback on intersect step value --- @usage progress:set_steps({0, 0.3, 0.6, 1}, function(self, step) end) -function M:set_steps(steps, callback) - self.steps = steps - self.step_callback = callback -end - - ---- Start animation of a progress bar ----@param to number value between 0..1 ----@param callback function|nil Callback on animation ends -function M:to(to, callback) - to = helper.clamp(to, 0, 1) - -- cause of float error - local value = helper.round(to, 5) - if value ~= self.last_value then - self.target = value - self.target_callback = callback - else - if callback then - callback(self:get_context(), to) - end - end -end - - ---- Set progress bar max node size ----@param max_size vector3 The new node maximum (full) size ----@return druid.progress Progress -function M:set_max_size(max_size) - self.max_size[self.key] = max_size[self.key] - self:set_to(self.last_value) return self end diff --git a/druid/extended/slider.lua b/druid/extended/slider.lua index 197d57f..c1796d2 100644 --- a/druid/extended/slider.lua +++ b/druid/extended/slider.lua @@ -1,76 +1,37 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Druid slider component --- --- Example Link --- @module Slider --- @within BaseComponent --- @alias druid.slider - ---- On change value callback(self, value) --- @tfield event on_change_value event - ---- Slider pin node --- @tfield node node - ---- Start pin node position --- @tfield vector3 start_pos - ---- Current pin node position --- @tfield vector3 pos - ---- Targer pin node position --- @tfield vector3 target_pos - ---- End pin node position --- @tfield vector3 end_pos - ---- Length between start and end position --- @tfield vector3 dist - ---- Current drag state --- @tfield boolean is_drag - ---- Current slider value --- @tfield number value - ---- - - local event = require("event.event") local helper = require("druid.helper") local const = require("druid.const") local component = require("druid.component") ----@class druid.slider: druid.base_component ----@field node node ----@field on_change_value event ----@field style table ----@field private start_pos vector3 ----@field private pos vector3 ----@field private target_pos vector3 ----@field private end_pos vector3 ----@field private dist vector3 ----@field private is_drag boolean ----@field private value number ----@field private steps number[] +---Basic Druid slider component. Creates a draggable node over a line with progress reporting. +--- +---### Setup +---Create slider component with druid: `slider = druid:new_slider(node_name, end_pos, callback)` +--- +---### Notes +---- Pin node should be placed in initial position at zero progress +---- It will be available to move Pin node between start pos and end pos +---- You can setup points of interests on slider via `slider:set_steps`. If steps exist, slider values will be only from these steps (notched slider) +---- Start pos and end pos should be on vertical or horizontal line (their x or y value should be equal) +---- To catch input across all slider, you can setup input node via `slider:set_input_node` +---@class druid.slider: druid.component +---@field node node The node to manage the slider +---@field on_change_value event The event triggered when the slider value changes +---@field style table The style of the slider +---@field private start_pos vector3 The start position of the slider +---@field private pos vector3 The current position of the slider +---@field private target_pos vector3 The target position of the slider +---@field private end_pos vector3 The end position of the slider +---@field private dist vector3 The distance between the start and end positions of the slider +---@field private is_drag boolean True if the slider is being dragged +---@field private value number The current value of the slider +---@field private steps number[] The steps of the slider local M = component.create("slider", const.PRIORITY_INPUT_HIGH) -local function on_change_value(self) - self.on_change_value:trigger(self:get_context(), self.value) -end - - -local function set_position(self, value) - value = helper.clamp(value, 0, 1) - gui.set_position(self.node, self.start_pos + self.dist * value) -end - - ---- The Slider constructor ----@param node node Gui pin node ----@param end_pos vector3 The end position of slider +---The Slider constructor +---@param node node GUI node to drag as a slider +---@param end_pos vector3 The end position of slider, should be on the same axis as the node ---@param callback function|nil On slider change callback function M:init(node, end_pos, callback) self.node = self:get_node(node) @@ -92,17 +53,20 @@ function M:init(node, end_pos, callback) end +---@private function M:on_layout_change() self:set(self.value) end +---@private function M:on_remove() -- Return pin to start position gui.set_position(self.node, self.start_pos) end +---@private function M:on_window_resized() local x_koef, y_koef = helper.get_screen_aspect_koef() self._x_koef = x_koef @@ -111,6 +75,10 @@ function M:on_window_resized() end +---@private +---@param action_id hash Action id from on_input +---@param action table Action table from on_input +---@return boolean is_consumed True if input was consumed function M:on_input(action_id, action) if action_id ~= const.ACTION_TOUCH then return false @@ -180,11 +148,11 @@ function M:on_input(action_id, action) end if prev_value ~= self.value then - on_change_value(self) + self:_on_change_value() end end - set_position(self, self.value) + self:_set_position(self.value) end if action.released then @@ -195,36 +163,38 @@ function M:on_input(action_id, action) end ---- Set value for slider +---Set value for slider ---@param value number Value from 0 to 1 ---@param is_silent boolean|nil Don't trigger event if true +---@return druid.slider self Current slider instance function M:set(value, is_silent) value = helper.clamp(value, 0, 1) - set_position(self, value) + self:_set_position(value) self.value = value if not is_silent then - on_change_value(self) + self:_on_change_value() end + + return self end ---- Set slider steps. Pin node will --- apply closest step position +---Set slider steps. Pin node will +---apply closest step position ---@param steps number[] Array of steps --- @usage slider:set_steps({0, 0.2, 0.6, 1}) ----@return druid.slider Slider +---@return druid.slider self Current slider instance function M:set_steps(steps) self.steps = steps return self end ---- Set input zone for slider. --- User can touch any place of node, pin instantly will --- move at this position and node drag will start. --- This function require the Defold version 1.3.0+ +---Set input zone for slider. +---User can touch any place of node, pin instantly will +---move at this position and node drag will start. +---This function require the Defold version 1.3.0+ ---@param input_node node|string|nil ----@return druid.slider Slider +---@return druid.slider self Current slider instance function M:set_input_node(input_node) if not input_node then self._input_node = nil @@ -236,18 +206,34 @@ function M:set_input_node(input_node) end ---- Set Slider input enabled or disabled ----@param is_enabled boolean +---Set Slider input enabled or disabled +---@param is_enabled boolean True if slider is enabled +---@return druid.slider self Current slider instance function M:set_enabled(is_enabled) self._is_enabled = is_enabled + + return self end ---- Check if Slider component is enabled ----@return boolean +---Check if Slider component is enabled +---@return boolean is_enabled True if slider is enabled function M:is_enabled() return self._is_enabled end +---@private +function M:_on_change_value() + self.on_change_value:trigger(self:get_context(), self.value) +end + + +---@private +function M:_set_position(value) + value = helper.clamp(value, 0, 1) + gui.set_position(self.node, self.start_pos + self.dist * value) +end + + return M diff --git a/druid/extended/swipe.lua b/druid/extended/swipe.lua index fb65293..203126e 100644 --- a/druid/extended/swipe.lua +++ b/druid/extended/swipe.lua @@ -1,56 +1,135 @@ --- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license - ---- Component to handle swipe gestures on node. --- Swipe will be triggered, if swipe was started and --- ended on one node --- --- Example Link --- @module Swipe --- @within BaseComponent --- @alias druid.swipe - ---- Swipe node ---@param node node - ---- Restriction zone ---@param click_zone node|nil - ---- Trigger on swipe event(self, swipe_side, dist, delta_time) ---@param event event on_swipe - ---- - local event = require("event.event") local const = require("druid.const") local helper = require("druid.helper") local component = require("druid.component") ----@class druid.swipe: druid.base_component ----@field node node ----@field on_swipe event function(side, dist, dt), side - "left", "right", "up", "down" ----@field style table ----@field click_zone node ----@field private _trigger_on_move boolean ----@field private _swipe_start_time number ----@field private _start_pos vector3 ----@field private _is_enabled boolean ----@field private _is_mobile boolean +---@class druid.swipe.style +---@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4 +---@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50 +---@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false + +---The component to manage swipe events over a node +---@class druid.swipe: druid.component +---@field node node The node to manage the swipe +---@field on_swipe event fun(context, side, dist, dt) The event triggered when a swipe is detected +---@field style druid.swipe.style The style of the swipe +---@field click_zone node The click zone of the swipe +---@field private _trigger_on_move boolean True if the swipe should trigger on move +---@field private _swipe_start_time number The time the swipe started +---@field private _start_pos vector3 The start position of the swipe +---@field private _is_enabled boolean True if the swipe is enabled +---@field private _is_mobile boolean True if the swipe is on a mobile device local M = component.create("swipe") -local function start_swipe(self, action) +---@param node_or_node_id node|string +---@param on_swipe_callback function +function M:init(node_or_node_id, on_swipe_callback) + self._trigger_on_move = self.style.SWIPE_TRIGGER_ON_MOVE + self.node = self:get_node(node_or_node_id) + + self._swipe_start_time = 0 + self._start_pos = vmath.vector3(0) + + self.click_zone = nil + self.on_swipe = event.create(on_swipe_callback) +end + + +---@private +function M:on_late_init() + if not self.click_zone then + local stencil_node = helper.get_closest_stencil_node(self.node) + if stencil_node then + self:set_click_zone(stencil_node) + end + end +end + + +---@private +---@param style druid.swipe.style +function M:on_style_change(style) + self.style = { + SWIPE_TIME = style.SWIPE_TIME or 0.4, + SWIPE_THRESHOLD = style.SWIPE_THRESHOLD or 50, + SWIPE_TRIGGER_ON_MOVE = style.SWIPE_TRIGGER_ON_MOVE or false, + } +end + + +---@private +---@param action_id hash The action id +---@param action action The action table +---@return boolean is_consumed True if the input was consumed +function M:on_input(action_id, action) + if action_id ~= const.ACTION_TOUCH then + return false + end + + if not gui.is_enabled(self.node, true) then + return false + end + + local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone) + if not is_pick then + self:_reset_swipe() + return false + end + + if self._swipe_start_time ~= 0 and (self._trigger_on_move or action.released) then + self:_check_swipe(action) + end + + if action.pressed then + self:_start_swipe(action) + end + + if action.released then + self:_reset_swipe() + end + + return true +end + + +---@private +function M:on_input_interrupt() + self:_reset_swipe() +end + + +---Set the click zone for the swipe, useful for restricting events outside stencil node +---@param zone node|string|nil Gui node +function M:set_click_zone(zone) + if not zone then + self.click_zone = nil + return + end + + self.click_zone = self:get_node(zone) +end + + +---Start swipe event +---@param action action The action table +function M:_start_swipe(action) self._swipe_start_time = socket.gettime() self._start_pos.x = action.x self._start_pos.y = action.y end -local function reset_swipe(self, action) +---Reset swipe event +function M:_reset_swipe() self._swipe_start_time = 0 end -local function check_swipe(self, action) +---Check swipe event +---@param self druid.swipe +---@param action action +function M:_check_swipe(action) local dx = action.x - self._start_pos.x local dy = action.y - self._start_pos.y local dist = helper.distance(self._start_pos.x, self._start_pos.y, action.x, action.y) @@ -75,102 +154,9 @@ local function check_swipe(self, action) end self.on_swipe:trigger(self:get_context(), swipe_side, dist, delta_time) - reset_swipe(self) + self:_reset_swipe() end end ---- Component style params. --- You can override this component styles params in druid styles table --- or create your own style ----@class druid.swipe.style ----@field SWIPE_TIME number|nil Maximum time for swipe trigger. Default: 0.4 ----@field SWIPE_THRESHOLD number|nil Minimum distance for swipe trigger. Default: 50 ----@field SWIPE_TRIGGER_ON_MOVE boolean|nil If true, trigger on swipe moving, not only release action. Default: false - ----@param style druid.swipe.style -function M:on_style_change(style) - self.style = {} - self.style.SWIPE_TIME = style.SWIPE_TIME or 0.4 - self.style.SWIPE_THRESHOLD = style.SWIPE_THRESHOLD or 50 - self.style.SWIPE_TRIGGER_ON_MOVE = style.SWIPE_TRIGGER_ON_MOVE or false -end - - ----Swipe constructor ----@param node_or_node_id node|string ----@param on_swipe_callback function -function M:init(node_or_node_id, on_swipe_callback) - self._trigger_on_move = self.style.SWIPE_TRIGGER_ON_MOVE - self.node = self:get_node(node_or_node_id) - - self._swipe_start_time = 0 - self._start_pos = vmath.vector3(0) - - self.click_zone = nil - self.on_swipe = event.create(on_swipe_callback) -end - - -function M:on_late_init() - if not self.click_zone then - local stencil_node = helper.get_closest_stencil_node(self.node) - if stencil_node then - self:set_click_zone(stencil_node) - end - end -end - - ----@param action_id hash ----@param action action -function M:on_input(action_id, action) - if action_id ~= const.ACTION_TOUCH then - return false - end - - if not gui.is_enabled(self.node, true) then - return false - end - - local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone) - if not is_pick then - reset_swipe(self, action) - return false - end - - if self._swipe_start_time ~= 0 and (self._trigger_on_move or action.released) then - check_swipe(self, action) - end - - if action.pressed then - start_swipe(self, action) - end - - if action.released then - reset_swipe(self, action) - end - - return true -end - - -function M:on_input_interrupt() - reset_swipe(self) -end - - ---- Strict swipe click area. Useful for --- restrict events outside stencil node ----@param zone node|string|nil Gui node -function M:set_click_zone(zone) - if not zone then - self.click_zone = nil - return - end - - self.click_zone = self:get_node(zone) -end - - return M diff --git a/druid/extended/timer.lua b/druid/extended/timer.lua index e4e95c4..833e465 100644 --- a/druid/extended/timer.lua +++ b/druid/extended/timer.lua @@ -2,31 +2,31 @@ local event = require("event.event") local helper = require("druid.helper") local component = require("druid.component") ----@class druid.timer: druid.base_component ----@field on_tick event ----@field on_set_enabled event ----@field on_timer_end event ----@field style table ----@field node node ----@field from number ----@field target number ----@field value number ----@field is_on boolean|nil +---Druid component to handle timer work on gui text node. Displays time in a formatted way. +--- +---### Setup +---Create timer component with druid: `timer = druid:new_timer(text_node, from_seconds, to_seconds, callback)` +--- +---### Notes +---- Timer fires callback when timer value equals to _to_seconds_ +---- Timer will set text node with current timer value +---- Timer uses update function to handle time +---@class druid.timer: druid.component +---@field on_tick event fun(context, value) The event triggered when the timer ticks +---@field on_set_enabled event fun(context, is_on) The event triggered when the timer is enabled +---@field on_timer_end event fun(context) The event triggered when the timer ends +---@field node node The node to display the timer +---@field from number The start time of the timer +---@field target number The target time of the timer +---@field value number The current value of the timer +---@field is_on boolean|nil True if the timer is on local M = component.create("timer") -local function second_string_min(sec) - local mins = math.floor(sec / 60) - local seconds = math.floor(sec - mins * 60) - return string.format("%.2d:%.2d", mins, seconds) -end - - ----The Timer constructor ---@param node node Gui text node ---@param seconds_from number|nil Start timer value in seconds ---@param seconds_to number|nil End timer value in seconds ----@param callback function|nil Function on timer end +---@param callback function|nil Function that triggers when timer value equals to seconds_to function M:init(node, seconds_from, seconds_to, callback) self.node = self:get_node(node) seconds_to = math.max(seconds_to or 0, 0) @@ -50,6 +50,7 @@ function M:init(node, seconds_from, seconds_to, callback) end +---@private function M:update(dt) if not self.is_on then return @@ -73,23 +74,26 @@ function M:update(dt) end +---@private function M:on_layout_change() self:set_to(self.last_value) end +---Set the timer to a specific value ---@param set_to number Value in seconds ----@return druid.timer self +---@return druid.timer self Current timer instance function M:set_to(set_to) self.last_value = set_to - gui.set_text(self.node, second_string_min(set_to)) + gui.set_text(self.node, self:_second_string_min(set_to)) return self end +---Set the timer to a specific value ---@param is_on boolean|nil Timer enable state ----@return druid.timer self +---@return druid.timer self Current timer instance function M:set_state(is_on) self.is_on = is_on self.on_set_enabled:trigger(self:get_context(), is_on) @@ -98,9 +102,10 @@ function M:set_state(is_on) end +---Set the timer interval ---@param from number Start time in seconds ---@param to number Target time in seconds ----@return druid.timer self +---@return druid.timer self Current timer instance function M:set_interval(from, to) self.from = from self.value = from @@ -113,4 +118,14 @@ function M:set_interval(from, to) end +---@private +---@param sec number Seconds to convert +---@return string The formatted time string +function M:_second_string_min(sec) + local mins = math.floor(sec / 60) + local seconds = math.floor(sec - mins * 60) + return string.format("%.2d:%.2d", mins, seconds) +end + + return M diff --git a/druid/fonts/druid_text_bold.font b/druid/fonts/druid_text_bold.font index a8546d6..a72449e 100644 --- a/druid/fonts/druid_text_bold.font +++ b/druid/fonts/druid_text_bold.font @@ -7,4 +7,4 @@ shadow_alpha: 1.0 shadow_blur: 2 output_format: TYPE_DISTANCE_FIELD render_mode: MODE_MULTI_LAYER -characters: "\302\241\302\253\302\273\302\277\303\200\303\202\303\206\303\207\303\210\303\211\303\212\303\213\303\216\303\217\303\224\303\231\303\233\303\234\303\237\303\240\303\241\303\242\303\243\303\244\303\246\303\247\303\250\303\251\303\252\303\253\303\255\303\256\303\257\303\261\303\262\303\263\303\264\303\265\303\266\303\271\303\273\303\274\303\277\305\222\305\223\305\270\320\201\320\220\320\221\320\222\320\223\320\224\320\225\320\226\320\227\320\230\320\231\320\232\320\233\320\234\320\235\320\236\320\237\320\240\320\241\320\242\320\243\320\244\320\245\320\246\320\247\320\250\320\251\320\252\320\253\320\254\320\255\320\256\320\257\320\260\320\261\320\262\320\263\320\264\320\265\320\266\320\267\320\270\320\271\320\272\320\273\320\274\320\275\320\276\320\277\321\200\321\201\321\202\321\203\321\204\321\205\321\206\321\207\321\210\321\211\321\212\321\213\321\214\321\215\321\216\321\217\321\221\342\200\224\343\200\201\343\200\202\343\200\214\343\200\215\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212\343\201\213\343\201\214\343\201\215\343\201\217\343\201\223\343\201\225\343\201\227\343\201\230\343\201\231\343\201\233\343\201\237\343\201\240\343\201\244\343\201\246\343\201\247\343\201\250\343\201\251\343\201\252\343\201\253\343\201\256\343\201\257\343\201\263\343\201\276\343\202\200\343\202\201\343\202\202\343\202\210\343\202\211\343\202\212\343\202\213\343\202\214\343\202\222\343\202\223\343\202\241\343\202\242\343\202\243\343\202\244\343\202\246\343\202\250\343\202\251\343\202\254\343\202\255\343\202\257\343\202\260\343\202\261\343\202\262\343\202\263\343\202\265\343\202\267\343\202\270\343\202\271\343\202\272\343\202\273\343\202\277\343\203\200\343\203\201\343\203\203\343\203\206\343\203\207\343\203\210\343\203\211\343\203\213\343\203\215\343\203\216\343\203\220\343\203\221\343\203\224\343\203\225\343\203\226\343\203\227\343\203\231\343\203\233\343\203\234\343\203\235\343\203\236\343\203\240\343\203\241\343\203\242\343\203\243\343\203\245\343\203\247\343\203\251\343\203\252\343\203\253\343\203\254\343\203\255\343\203\257\343\203\263\343\203\274\344\270\200\344\270\207\344\270\212\344\270\213\344\270\215\344\270\216\344\270\241\344\270\244\344\270\252\344\270\255\344\270\272\344\271\211\344\271\260\344\272\213\344\272\216\344\273\213\344\273\216\344\273\230\344\273\243\344\273\245\344\273\254\344\273\266\344\275\206\344\275\223\344\275\225\344\275\234\344\275\240\344\275\277\344\276\213\344\277\241\345\200\244\345\200\274\345\201\234\345\205\203\345\205\205\345\205\245\345\205\266\345\206\205\345\207\246\345\207\272\345\207\273\345\210\206\345\210\227\345\210\233\345\210\235\345\210\240\345\210\245\345\210\260\345\210\266\345\211\212\345\211\215\345\211\252\345\212\233\345\212\237\345\212\240\345\212\250\345\212\271\345\214\272\345\215\225\345\215\230\345\217\214\345\217\221\345\217\226\345\217\243\345\217\246\345\217\257\345\220\210\345\220\214\345\220\221\345\220\227\345\220\253\345\220\257\345\222\214\345\231\250\345\233\236\345\234\250\345\235\227\345\236\202\345\236\213\345\237\237\345\237\272\345\240\261\345\241\253\345\244\204\345\244\232\345\244\247\345\245\275\345\246\202\345\247\213\345\255\227\345\255\230\345\256\203\345\256\232\345\257\206\345\257\214\345\257\271\345\260\206\345\260\217\345\260\261\345\261\200\345\261\217\345\261\236\345\267\245\345\270\203\345\270\246\345\271\225\345\271\263\345\271\266\345\272\246\345\273\272\345\274\200\345\274\271\345\276\227\345\277\205\345\277\253\346\200\201\346\200\247\346\201\257\346\202\254\346\203\205\346\210\217\346\210\220\346\211\200\346\211\213\346\212\236\346\212\274\346\213\226\346\213\251\346\214\201\346\214\211\346\215\256\346\215\267\346\216\247\346\217\203\346\220\255\346\221\270\346\223\215\346\224\257\346\224\276\346\225\210\346\225\260\346\225\264\346\226\207\346\226\271\346\227\245\346\227\266\346\230\216\346\230\257\346\230\276\346\233\264\346\234\200\346\234\211\346\234\254\346\235\206\346\235\241\346\236\220\346\237\204\346\237\245\346\240\207\346\240\274\346\243\200\346\251\237\346\254\241\346\255\244\346\255\245\346\260\264\346\261\275\346\262\241\346\263\225\346\264\262\346\265\213\346\266\210\346\267\267\346\267\273\346\270\205\346\270\270\346\273\221\346\273\232\347\202\271\347\211\210\347\216\207\347\220\206\347\224\250\347\224\273\347\225\260\347\231\276\347\232\204\347\233\264\347\233\270\347\234\213\347\240\201\347\241\200\347\241\256\347\242\272\347\244\272\347\247\222\347\247\273\347\252\227\347\253\257\347\255\276\347\256\200\347\260\241\347\261\273\347\264\224\347\264\240\347\264\271\347\272\265\347\273\204\347\273\215\347\273\221\347\274\223\347\274\251\347\275\221\347\275\256\347\276\216\347\276\251\350\203\275\350\211\257\350\211\262\350\212\202\350\216\267\350\241\214\350\241\250\350\243\201\350\244\207\350\246\201\350\246\213\350\247\246\350\250\200\350\250\255\350\252\215\350\252\236\350\252\254\350\252\277\350\256\241\350\256\244\350\256\276\350\257\225\350\257\255\350\257\264\350\257\267\350\260\203\350\261\271\350\263\274\350\264\255\350\267\235\350\273\212\350\273\270\350\275\246\350\275\264\350\276\223\350\276\271\350\277\207\350\277\231\350\277\233\350\277\275\351\200\211\351\200\232\351\201\270\351\205\215\351\207\214\351\222\256\351\224\256\351\225\267\351\225\277\351\231\244\351\234\200\351\235\231\351\235\242\351\240\230\351\242\204\351\242\234\351\252\244\351\253\230\351\274\240\351\275\220\352\260\200\352\260\204\352\260\222\352\260\231\352\260\234\352\261\260\352\262\203\352\262\214\352\262\240\352\263\204\352\263\240\352\263\274\352\265\254\352\265\255\352\267\270\352\270\200\352\270\260\352\271\214\352\273\230\352\274\264\353\202\230\353\202\264\353\204\214\353\205\270\353\206\223\353\210\204\353\212\224\353\212\245\353\213\210\353\213\244\353\213\250\353\213\254\353\213\271\353\214\200\353\215\224\353\215\260\353\217\204\353\217\231\353\220\230\353\220\234\353\220\251\353\221\220\353\223\234\353\223\244\353\224\251\353\225\214\353\226\273\353\235\274\353\236\230\353\236\265\353\237\254\353\240\210\353\240\244\353\240\245\353\240\254\353\241\234\353\241\235\353\241\244\353\245\264\353\245\270\353\245\274\353\246\254\353\246\255\353\247\210\353\247\214\353\247\216\353\247\244\353\250\270\353\251\224\353\251\264\353\252\205\353\252\250\353\252\251\353\260\200\353\260\217\353\260\224\353\260\233\353\260\251\353\260\260\353\260\261\353\262\204\353\262\210\353\262\225\353\262\227\353\262\244\353\263\264\353\263\270\353\270\224\353\271\204\354\202\254\354\203\201\354\203\211\354\204\234\354\204\240\354\204\244\354\204\261\354\204\270\354\205\230\354\206\214\354\206\215\354\210\230\354\212\244\354\212\254\354\212\265\354\213\234\354\213\240\354\213\255\354\225\204\354\225\240\354\226\221\354\226\264\354\226\270\354\227\206\354\227\220\354\227\254\354\227\255\354\230\201\354\230\210\354\230\244\354\230\254\354\231\200\354\232\224\354\232\251\354\232\260\354\233\203\354\234\204\354\234\210\354\234\240\354\234\250\354\234\274\354\235\200\354\235\204\354\235\214\354\235\230\354\235\264\354\235\270\354\235\274\354\236\204\354\236\205\354\236\210\354\236\220\354\236\221\354\236\230\354\236\245\354\240\201\354\240\204\354\240\225\354\240\234\354\241\260\354\242\213\354\244\221\354\247\200\354\247\201\354\247\204\354\247\210\354\260\250\354\260\275\354\262\230\354\264\210\354\265\234\354\266\224\354\266\225\354\266\234\354\267\250\354\271\230\354\272\220\354\273\250\354\273\264\354\274\200\354\275\224\354\275\234\355\201\254\355\201\264\355\202\244\355\203\200\355\203\204\355\203\234\355\203\235\355\204\260\355\205\214\355\205\215\355\212\270\355\212\274\355\213\261\355\214\214\355\214\250\355\214\254\355\217\211\355\217\254\355\221\234\355\224\204\355\224\274\355\225\204\355\225\221\355\225\230\355\225\234\355\225\240\355\225\250\355\225\251\355\225\264\355\226\211\355\230\225\355\230\270\355\230\274\355\231\224\355\231\225\355\231\234\355\232\250\357\274\201\357\274\214\357\274\237 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}" +characters: "\302\241\302\253\302\273\302\277\303\200\303\202\303\206\303\207\303\210\303\211\303\212\303\213\303\216\303\217\303\224\303\231\303\233\303\234\303\237\303\240\303\241\303\242\303\243\303\244\303\246\303\247\303\250\303\251\303\252\303\253\303\255\303\256\303\257\303\261\303\262\303\263\303\264\303\265\303\266\303\271\303\273\303\274\303\277\305\222\305\223\305\270\320\201\320\220\320\221\320\222\320\223\320\224\320\225\320\226\320\227\320\230\320\231\320\232\320\233\320\234\320\235\320\236\320\237\320\240\320\241\320\242\320\243\320\244\320\245\320\246\320\247\320\250\320\251\320\252\320\253\320\254\320\255\320\256\320\257\320\260\320\261\320\262\320\263\320\264\320\265\320\266\320\267\320\270\320\271\320\272\320\273\320\274\320\275\320\276\320\277\321\200\321\201\321\202\321\203\321\204\321\205\321\206\321\207\321\210\321\211\321\212\321\213\321\214\321\215\321\216\321\217\321\221\342\200\224\343\200\201\343\200\202\343\200\214\343\200\215\357\274\201\357\274\214\357\274\237 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}" diff --git a/druid/fonts/druid_text_regular.font b/druid/fonts/druid_text_regular.font index ec01934..eafbcfd 100644 --- a/druid/fonts/druid_text_regular.font +++ b/druid/fonts/druid_text_regular.font @@ -5,4 +5,4 @@ outline_alpha: 1.0 outline_width: 2.0 output_format: TYPE_DISTANCE_FIELD render_mode: MODE_MULTI_LAYER -characters: "\302\241\302\253\302\273\302\277\303\200\303\202\303\206\303\207\303\210\303\211\303\212\303\213\303\216\303\217\303\224\303\231\303\233\303\234\303\237\303\240\303\241\303\242\303\243\303\244\303\246\303\247\303\250\303\251\303\252\303\253\303\255\303\256\303\257\303\261\303\262\303\263\303\264\303\265\303\266\303\271\303\273\303\274\303\277\305\222\305\223\305\270\320\201\320\220\320\221\320\222\320\223\320\224\320\225\320\226\320\227\320\230\320\231\320\232\320\233\320\234\320\235\320\236\320\237\320\240\320\241\320\242\320\243\320\244\320\245\320\246\320\247\320\250\320\251\320\252\320\253\320\254\320\255\320\256\320\257\320\260\320\261\320\262\320\263\320\264\320\265\320\266\320\267\320\270\320\271\320\272\320\273\320\274\320\275\320\276\320\277\321\200\321\201\321\202\321\203\321\204\321\205\321\206\321\207\321\210\321\211\321\212\321\213\321\214\321\215\321\216\321\217\321\221\342\200\224\343\200\201\343\200\202\343\200\214\343\200\215\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212\343\201\213\343\201\214\343\201\215\343\201\217\343\201\223\343\201\225\343\201\227\343\201\230\343\201\231\343\201\233\343\201\237\343\201\240\343\201\244\343\201\246\343\201\247\343\201\250\343\201\251\343\201\252\343\201\253\343\201\256\343\201\257\343\201\263\343\201\276\343\202\200\343\202\201\343\202\202\343\202\210\343\202\211\343\202\212\343\202\213\343\202\214\343\202\222\343\202\223\343\202\241\343\202\242\343\202\243\343\202\244\343\202\246\343\202\250\343\202\251\343\202\254\343\202\255\343\202\257\343\202\260\343\202\261\343\202\262\343\202\263\343\202\265\343\202\267\343\202\270\343\202\271\343\202\272\343\202\273\343\202\277\343\203\200\343\203\201\343\203\203\343\203\206\343\203\207\343\203\210\343\203\211\343\203\213\343\203\215\343\203\216\343\203\220\343\203\221\343\203\224\343\203\225\343\203\226\343\203\227\343\203\231\343\203\233\343\203\234\343\203\235\343\203\236\343\203\240\343\203\241\343\203\242\343\203\243\343\203\245\343\203\247\343\203\251\343\203\252\343\203\253\343\203\254\343\203\255\343\203\257\343\203\263\343\203\274\344\270\200\344\270\207\344\270\212\344\270\213\344\270\215\344\270\216\344\270\241\344\270\244\344\270\252\344\270\255\344\270\272\344\271\211\344\271\260\344\272\213\344\272\216\344\273\213\344\273\216\344\273\230\344\273\243\344\273\245\344\273\254\344\273\266\344\275\206\344\275\223\344\275\225\344\275\234\344\275\240\344\275\277\344\276\213\344\277\241\345\200\244\345\200\274\345\201\234\345\205\203\345\205\205\345\205\245\345\205\266\345\206\205\345\207\246\345\207\272\345\207\273\345\210\206\345\210\227\345\210\233\345\210\235\345\210\240\345\210\245\345\210\260\345\210\266\345\211\212\345\211\215\345\211\252\345\212\233\345\212\237\345\212\240\345\212\250\345\212\271\345\214\272\345\215\225\345\215\230\345\217\214\345\217\221\345\217\226\345\217\243\345\217\246\345\217\257\345\220\210\345\220\214\345\220\221\345\220\227\345\220\253\345\220\257\345\222\214\345\231\250\345\233\236\345\234\250\345\235\227\345\236\202\345\236\213\345\237\237\345\237\272\345\240\261\345\241\253\345\244\204\345\244\232\345\244\247\345\245\275\345\246\202\345\247\213\345\255\227\345\255\230\345\256\203\345\256\232\345\257\206\345\257\214\345\257\271\345\260\206\345\260\217\345\260\261\345\261\200\345\261\217\345\261\236\345\267\245\345\270\203\345\270\246\345\271\225\345\271\263\345\271\266\345\272\246\345\273\272\345\274\200\345\274\271\345\276\227\345\277\205\345\277\253\346\200\201\346\200\247\346\201\257\346\202\254\346\203\205\346\210\217\346\210\220\346\211\200\346\211\213\346\212\236\346\212\274\346\213\226\346\213\251\346\214\201\346\214\211\346\215\256\346\215\267\346\216\247\346\217\203\346\220\255\346\221\270\346\223\215\346\224\257\346\224\276\346\225\210\346\225\260\346\225\264\346\226\207\346\226\271\346\227\245\346\227\266\346\230\216\346\230\257\346\230\276\346\233\264\346\234\200\346\234\211\346\234\254\346\235\206\346\235\241\346\236\220\346\237\204\346\237\245\346\240\207\346\240\274\346\243\200\346\251\237\346\254\241\346\255\244\346\255\245\346\260\264\346\261\275\346\262\241\346\263\225\346\264\262\346\265\213\346\266\210\346\267\267\346\267\273\346\270\205\346\270\270\346\273\221\346\273\232\347\202\271\347\211\210\347\216\207\347\220\206\347\224\250\347\224\273\347\225\260\347\231\276\347\232\204\347\233\264\347\233\270\347\234\213\347\240\201\347\241\200\347\241\256\347\242\272\347\244\272\347\247\222\347\247\273\347\252\227\347\253\257\347\255\276\347\256\200\347\260\241\347\261\273\347\264\224\347\264\240\347\264\271\347\272\265\347\273\204\347\273\215\347\273\221\347\274\223\347\274\251\347\275\221\347\275\256\347\276\216\347\276\251\350\203\275\350\211\257\350\211\262\350\212\202\350\216\267\350\241\214\350\241\250\350\243\201\350\244\207\350\246\201\350\246\213\350\247\246\350\250\200\350\250\255\350\252\215\350\252\236\350\252\254\350\252\277\350\256\241\350\256\244\350\256\276\350\257\225\350\257\255\350\257\264\350\257\267\350\260\203\350\261\271\350\263\274\350\264\255\350\267\235\350\273\212\350\273\270\350\275\246\350\275\264\350\276\223\350\276\271\350\277\207\350\277\231\350\277\233\350\277\275\351\200\211\351\200\232\351\201\270\351\205\215\351\207\214\351\222\256\351\224\256\351\225\267\351\225\277\351\231\244\351\234\200\351\235\231\351\235\242\351\240\230\351\242\204\351\242\234\351\252\244\351\253\230\351\274\240\351\275\220\352\260\200\352\260\204\352\260\222\352\260\231\352\260\234\352\261\260\352\262\203\352\262\214\352\262\240\352\263\204\352\263\240\352\263\274\352\265\254\352\265\255\352\267\270\352\270\200\352\270\260\352\271\214\352\273\230\352\274\264\353\202\230\353\202\264\353\204\214\353\205\270\353\206\223\353\210\204\353\212\224\353\212\245\353\213\210\353\213\244\353\213\250\353\213\254\353\213\271\353\214\200\353\215\224\353\215\260\353\217\204\353\217\231\353\220\230\353\220\234\353\220\251\353\221\220\353\223\234\353\223\244\353\224\251\353\225\214\353\226\273\353\235\274\353\236\230\353\236\265\353\237\254\353\240\210\353\240\244\353\240\245\353\240\254\353\241\234\353\241\235\353\241\244\353\245\264\353\245\270\353\245\274\353\246\254\353\246\255\353\247\210\353\247\214\353\247\216\353\247\244\353\250\270\353\251\224\353\251\264\353\252\205\353\252\250\353\252\251\353\260\200\353\260\217\353\260\224\353\260\233\353\260\251\353\260\260\353\260\261\353\262\204\353\262\210\353\262\225\353\262\227\353\262\244\353\263\264\353\263\270\353\270\224\353\271\204\354\202\254\354\203\201\354\203\211\354\204\234\354\204\240\354\204\244\354\204\261\354\204\270\354\205\230\354\206\214\354\206\215\354\210\230\354\212\244\354\212\254\354\212\265\354\213\234\354\213\240\354\213\255\354\225\204\354\225\240\354\226\221\354\226\264\354\226\270\354\227\206\354\227\220\354\227\254\354\227\255\354\230\201\354\230\210\354\230\244\354\230\254\354\231\200\354\232\224\354\232\251\354\232\260\354\233\203\354\234\204\354\234\210\354\234\240\354\234\250\354\234\274\354\235\200\354\235\204\354\235\214\354\235\230\354\235\264\354\235\270\354\235\274\354\236\204\354\236\205\354\236\210\354\236\220\354\236\221\354\236\230\354\236\245\354\240\201\354\240\204\354\240\225\354\240\234\354\241\260\354\242\213\354\244\221\354\247\200\354\247\201\354\247\204\354\247\210\354\260\250\354\260\275\354\262\230\354\264\210\354\265\234\354\266\224\354\266\225\354\266\234\354\267\250\354\271\230\354\272\220\354\273\250\354\273\264\354\274\200\354\275\224\354\275\234\355\201\254\355\201\264\355\202\244\355\203\200\355\203\204\355\203\234\355\203\235\355\204\260\355\205\214\355\205\215\355\212\270\355\212\274\355\213\261\355\214\214\355\214\250\355\214\254\355\217\211\355\217\254\355\221\234\355\224\204\355\224\274\355\225\204\355\225\221\355\225\230\355\225\234\355\225\240\355\225\250\355\225\251\355\225\264\355\226\211\355\230\225\355\230\270\355\230\274\355\231\224\355\231\225\355\231\234\355\232\250\357\274\201\357\274\214\357\274\237 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}" +characters: "\302\241\302\253\302\273\302\277\303\200\303\202\303\206\303\207\303\210\303\211\303\212\303\213\303\216\303\217\303\224\303\231\303\233\303\234\303\237\303\240\303\241\303\242\303\243\303\244\303\246\303\247\303\250\303\251\303\252\303\253\303\255\303\256\303\257\303\261\303\262\303\263\303\264\303\265\303\266\303\271\303\273\303\274\303\277\305\222\305\223\305\270\320\201\320\220\320\221\320\222\320\223\320\224\320\225\320\226\320\227\320\230\320\231\320\232\320\233\320\234\320\235\320\236\320\237\320\240\320\241\320\242\320\243\320\244\320\245\320\246\320\247\320\250\320\251\320\252\320\253\320\254\320\255\320\256\320\257\320\260\320\261\320\262\320\263\320\264\320\265\320\266\320\267\320\270\320\271\320\272\320\273\320\274\320\275\320\276\320\277\321\200\321\201\321\202\321\203\321\204\321\205\321\206\321\207\321\210\321\211\321\212\321\213\321\214\321\215\321\216\321\217\321\221\342\200\224\343\200\201\343\200\202\343\200\214\343\200\215\357\274\201\357\274\214\357\274\237 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}" diff --git a/druid/helper.lua b/druid/helper.lua index 9f5c5c2..c4f49ee 100644 --- a/druid/helper.lua +++ b/druid/helper.lua @@ -5,18 +5,15 @@ local gui_get_node = gui.get_node local gui_get = gui.get local gui_pick_node = gui.pick_node ----@class druid.system.helper +---The helper module contains various functions that are used in the Druid library. +---You can use these functions in your projects as well. +---@class druid.helper local M = {} local POSITION_X = hash("position.x") local SCALE_X = hash("scale.x") local SIZE_X = hash("size.x") -M.PROP_SIZE_X = hash("size.x") -M.PROP_SIZE_Y = hash("size.y") -M.PROP_SCALE_X = hash("scale.x") -M.PROP_SCALE_Y = hash("scale.y") - local function get_text_width(text_node) if text_node then local text_metrics = M.get_text_metrics_from_node(text_node) @@ -42,15 +39,15 @@ local function is_text_node(node) end ---- Text node or icon node can be nil +---Text node or icon node can be nil local function get_width(node) return is_text_node(node) and get_text_width(node) or get_icon_width(node) end ---Center two nodes. ---Nodes will be center around 0 x position ---text_node will be first (at left side) +---Nodes will be center around 0 x position +---text_node will be first (at left side) ---@param text_node node|nil Gui text node ---@param icon_node node|nil Gui box node ---@param margin number Offset between nodes @@ -61,8 +58,8 @@ end ---Center two nodes. ---Nodes will be center around 0 x position ---icon_node will be first (at left side) +---Nodes will be center around 0 x position +---icon_node will be first (at left side) ---@param icon_node node|nil Gui box node ---@param text_node node|nil Gui text node ---@param margin number|nil Offset between nodes @@ -113,8 +110,8 @@ end ---@param node_id string|node ----@param template string|nil @Full Path to the template ----@param nodes table|nil @Nodes what created with gui.clone_tree +---@param template string|nil Full Path to the template +---@param nodes table|nil Nodes what created with gui.clone_tree ---@return node function M.get_node(node_id, template, nodes) if type(node_id) ~= "string" then @@ -175,7 +172,7 @@ function M.step(current, target, step) end ----Clamp value between min and max +---Clamp value between min and max. Works with nil values and swap min and max if needed. ---@param value number Value ---@param v1 number|nil Min value. If nil, value will be clamped to positive infinity ---@param v2 number|nil Max value If nil, value will be clamped to negative infinity @@ -204,7 +201,7 @@ end ---@param y1 number First point y ---@param x2 number Second point x ---@param y2 number Second point y ----@return number Distance +---@return number distance function M.distance(x1, y1, x2, y2) return math.sqrt((x2 - x1) ^ 2 + (y2 - y1) ^ 2) end @@ -245,6 +242,7 @@ end ---Check if value contains in array ---@param array any[] Array to check ---@param value any Value +---@return number|nil index Index of value in array or nil if value not found function M.contains(array, value) for index = 1, #array do if array[index] == value then @@ -296,7 +294,7 @@ end ---@param node node ---@param x number ---@param y number ----@param node_click_area node|nil +---@param node_click_area node|nil Additional node to check for click area. If nil, only node will be checked ---@local function M.pick_node(node, x, y, node_click_area) local is_pick = gui_pick_node(node, x, y) @@ -369,6 +367,14 @@ function M.get_pivot_offset(pivot_or_node) end +---Check if device is desktop +---@return boolean +function M.is_desktop() + return const.CURRENT_SYSTEM_NAME == const.OS.WINDOWS or const.CURRENT_SYSTEM_NAME == const.OS.MAC or const.CURRENT_SYSTEM_NAME == const.OS.LINUX +end + + + ---Check if device is native mobile (Android or iOS) ---@return boolean Is mobile function M.is_mobile() @@ -431,10 +437,10 @@ function M.get_border(node, offset) local pivot_offset = M.get_pivot_offset(pivot) 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), - size.x*(0.5 - pivot_offset.x), - -size.y*(0.5 + pivot_offset.y) + -size.x * (0.5 + pivot_offset.x), + size.y * (0.5 - pivot_offset.y), + size.x * (0.5 - pivot_offset.x), + -size.y * (0.5 + pivot_offset.y) ) if offset then @@ -448,15 +454,20 @@ function M.get_border(node, offset) end +local TEXT_METRICS_OPTIONS = { + line_break = false, + tracking = 0, + leading = 0, + width = 0, +} + ---Get text metric from GUI node. ---@param text_node node ---@return GUITextMetrics function M.get_text_metrics_from_node(text_node) - local font_resource = gui.get_font_resource(gui.get_font(text_node)) - local options = { - tracking = gui.get_tracking(text_node), - line_break = gui.get_line_break(text_node), - } + local options = TEXT_METRICS_OPTIONS + options.tracking = gui.get_tracking(text_node) + options.line_break = gui.get_line_break(text_node) -- Gather other options only if it used in node if options.line_break then @@ -464,6 +475,7 @@ function M.get_text_metrics_from_node(text_node) options.leading = gui.get_leading(text_node) end + local font_resource = gui.get_font_resource(gui.get_font(text_node)) return resource.get_text_metrics(font_resource, gui.get_text(text_node), options) end @@ -545,18 +557,18 @@ function M.get_full_position(node, root) end ----@class druid.animation_data ----@field frames table> @List of frames with uv coordinates and size ----@field width number @Width of the animation ----@field height number @Height of the animation ----@field fps number @Frames per second ----@field current_frame number @Current frame ----@field node node @Node with flipbook animation ----@field v vector4 @Vector with UV coordinates and size +---@class druid.system.animation_data +---@field frames table> List of frames with uv coordinates and size +---@field width number Width of the animation +---@field height number Height of the animation +---@field fps number Frames per second +---@field current_frame number Current frame +---@field node node Node with flipbook animation +---@field v vector4 Vector with UV coordinates and size ---@param node node ----@param atlas_path string @Path to the atlas ----@return druid.animation_data +---@param atlas_path string Path to the atlas +---@return druid.system.animation_data function M.get_animation_data_from_node(node, atlas_path) local atlas_data = resource.get_atlas(atlas_path) local tex_info = resource.get_texture_info(atlas_data.texture) diff --git a/druid/materials/gui_world/gui_world.fp b/druid/materials/gui_world/gui_world.fp deleted file mode 100644 index aeddd5d..0000000 --- a/druid/materials/gui_world/gui_world.fp +++ /dev/null @@ -1,10 +0,0 @@ -varying mediump vec2 var_texcoord0; -varying lowp vec4 var_color; - -uniform lowp sampler2D texture_sampler; - -void main() -{ - lowp vec4 tex = texture2D(texture_sampler, var_texcoord0.xy); - gl_FragColor = tex * var_color; -} diff --git a/druid/materials/gui_world/gui_world.material b/druid/materials/gui_world/gui_world.material index f609d2e..62671ac 100644 --- a/druid/materials/gui_world/gui_world.material +++ b/druid/materials/gui_world/gui_world.material @@ -1,7 +1,7 @@ name: "gui_world" tags: "tile" -vertex_program: "/druid/materials/gui_world/gui_world.vp" -fragment_program: "/druid/materials/gui_world/gui_world.fp" +vertex_program: "/builtins/materials/gui.vp" +fragment_program: "/builtins/materials/gui.fp" vertex_constants { name: "view_proj" type: CONSTANT_TYPE_VIEWPROJ diff --git a/druid/materials/gui_world/gui_world.vp b/druid/materials/gui_world/gui_world.vp deleted file mode 100644 index 5e71498..0000000 --- a/druid/materials/gui_world/gui_world.vp +++ /dev/null @@ -1,16 +0,0 @@ -uniform highp mat4 view_proj; - -// positions are in world space -attribute highp vec3 position; -attribute mediump vec2 texcoord0; -attribute lowp vec4 color; - -varying mediump vec2 var_texcoord0; -varying lowp vec4 var_color; - -void main() -{ - var_texcoord0 = texcoord0; - var_color = vec4(color.rgb * color.a, color.a); - gl_Position = view_proj * vec4(position.xyz, 1.0); -} diff --git a/druid/materials/skew/gui_skew.fp b/druid/materials/skew/gui_skew.fp deleted file mode 100644 index c3d593d..0000000 --- a/druid/materials/skew/gui_skew.fp +++ /dev/null @@ -1,18 +0,0 @@ -#version 140 - -uniform sampler2D texture_sampler; - -in vec2 var_texcoord0; -in vec4 var_color; - -out vec4 color_out; - -void main() { - lowp vec4 tex = texture(texture_sampler, var_texcoord0.xy); - if (tex.a < 0.5) { - discard; - } - - // Final color of stencil texture - color_out = tex * var_color; -} \ No newline at end of file diff --git a/druid/materials/skew/gui_skew.material b/druid/materials/skew/gui_skew.material deleted file mode 100644 index 5575ae1..0000000 --- a/druid/materials/skew/gui_skew.material +++ /dev/null @@ -1,8 +0,0 @@ -name: "repeat" -tags: "gui" -vertex_program: "/druid/materials/stencil/gui_stencil.vp" -fragment_program: "/druid/materials/stencil/gui_stencil.fp" -vertex_constants { - name: "view_proj" - type: CONSTANT_TYPE_VIEWPROJ -} diff --git a/druid/materials/skew/gui_skew.vp b/druid/materials/skew/gui_skew.vp deleted file mode 100644 index 382c88b..0000000 --- a/druid/materials/skew/gui_skew.vp +++ /dev/null @@ -1,20 +0,0 @@ -#version 140 - -uniform vertex_inputs { - highp mat4 view_proj; -}; - -// positions are in world space -in mediump vec3 position; -in mediump vec2 texcoord0; -in lowp vec4 color; - -out mediump vec2 var_texcoord0; -out lowp vec4 var_color; - -void main() -{ - var_texcoord0 = texcoord0; - var_color = vec4(color.rgb * color.a, color.a); - gl_Position = view_proj * vec4(position.xyz, 1.0); -} diff --git a/druid/materials/stencil/gui_stencil.fp b/druid/materials/stencil/gui_stencil.fp index c3d593d..cc58610 100644 --- a/druid/materials/stencil/gui_stencil.fp +++ b/druid/materials/stencil/gui_stencil.fp @@ -9,10 +9,10 @@ out vec4 color_out; void main() { lowp vec4 tex = texture(texture_sampler, var_texcoord0.xy); + if (tex.a < 0.5) { discard; } - // Final color of stencil texture color_out = tex * var_color; -} \ No newline at end of file +} diff --git a/druid/materials/stencil/gui_stencil.material b/druid/materials/stencil/gui_stencil.material index 5575ae1..e994c21 100644 --- a/druid/materials/stencil/gui_stencil.material +++ b/druid/materials/stencil/gui_stencil.material @@ -1,6 +1,6 @@ name: "repeat" tags: "gui" -vertex_program: "/druid/materials/stencil/gui_stencil.vp" +vertex_program: "/builtins/materials/gui.vp" fragment_program: "/druid/materials/stencil/gui_stencil.fp" vertex_constants { name: "view_proj" diff --git a/druid/materials/stencil/gui_stencil.vp b/druid/materials/stencil/gui_stencil.vp deleted file mode 100644 index 382c88b..0000000 --- a/druid/materials/stencil/gui_stencil.vp +++ /dev/null @@ -1,20 +0,0 @@ -#version 140 - -uniform vertex_inputs { - highp mat4 view_proj; -}; - -// positions are in world space -in mediump vec3 position; -in mediump vec2 texcoord0; -in lowp vec4 color; - -out mediump vec2 var_texcoord0; -out lowp vec4 var_color; - -void main() -{ - var_texcoord0 = texcoord0; - var_color = vec4(color.rgb * color.a, color.a); - gl_Position = view_proj * vec4(position.xyz, 1.0); -} diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua index 7398c74..08c3195 100644 --- a/druid/styles/default/style.lua +++ b/druid/styles/default/style.lua @@ -1,4 +1,3 @@ -local const = require("druid.const") local settings = require("druid.system.settings") local M = {} @@ -130,7 +129,7 @@ M["input"] = { M["text"] = { TRIM_POSTFIX = "...", - DEFAULT_ADJUST = const.TEXT_ADJUST.DOWNSCALE + DEFAULT_ADJUST = "downscale" } diff --git a/druid/system/druid_annotations.lua b/druid/system/druid_annotations.lua index a08b449..2e30ddf 100644 --- a/druid/system/druid_annotations.lua +++ b/druid/system/druid_annotations.lua @@ -1,6 +1,12 @@ ----@class druid.widget: druid.base_component ----@field druid druid_instance Ready to use druid instance ----@field root node +---@class druid.widget: druid.component +---@field druid druid.instance Ready to use druid instance + +---@class druid.logger +---@field trace fun(message: string, context: any) +---@field debug fun(message: string, context: any) +---@field info fun(message: string, context: any) +---@field warn fun(message: string, context: any) +---@field error fun(message: string, context: any) ---@class GUITextMetrics ---@field width number @@ -27,3 +33,34 @@ ---@field lower fun() ---@field upper fun() ---@field rep fun() + +-- This one should be a part of Defold annotations +---@class action +---@field value number The amount of input given by the user. This is usually 1 for buttons and 0-1 for analogue inputs. This is not present for mouse movement. +---@field pressed boolean If the input was pressed this frame. This is not present for mouse movement. +---@field released boolean If the input was released this frame. This is not present for mouse movement. +---@field repeated boolean If the input was repeated this frame. This is similar to how a key on a keyboard is repeated when you hold it down. This is not present for mouse movement. +---@field x number The x value of a pointer device, if present. +---@field y number The y value of a pointer device, if present. +---@field screen_x number The screen space x value of a pointer device, if present. +---@field screen_y number The screen space y value of a pointer device, if present. +---@field dx number The change in x value of a pointer device, if present. +---@field dy number The change in y value of a pointer device, if present. +---@field screen_dx number The change in screen space x value of a pointer device, if present. +---@field screen_dy number The change in screen space y value of a pointer device, if present. +---@field gamepad number The index of the gamepad device that provided the input. +---@field touch touch[] List of touch input, one element per finger, if present. See table below about touch input +---@field text string The text input. + +---@class touch +---@field id number A number identifying the touch input during its duration. +---@field pressed boolean True if the finger was pressed this frame. +---@field released boolean True if the finger was released this frame. +---@field tap_count number Number of taps, one for single, two for double-tap, etc +---@field x number The x touch location. +---@field y number The y touch location. +---@field dx number The change in x value. +---@field dy number The change in y value. +---@field acc_x number|nil Accelerometer x value (if present). +---@field acc_y number|nil Accelerometer y value (if present). +---@field acc_z number|nil Accelerometer z value (if present). diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua index beca2d1..cf74975 100755 --- a/druid/system/druid_instance.lua +++ b/druid/system/druid_instance.lua @@ -1,28 +1,28 @@ +-- Hello, Defolder! Wish you a good day! + local events = require("event.events") local const = require("druid.const") local helper = require("druid.helper") local settings = require("druid.system.settings") -local base_component = require("druid.component") +local druid_component = require("druid.component") ----@class druid_instance ----@field components_all druid.base_component[] All created components ----@field components_interest table All components sorted by interest ----@field url url ----@field private _context table Druid context ----@field private _style table Druid style table ----@field private _deleted boolean ----@field private _is_late_remove_enabled boolean ----@field private _late_remove druid.base_component[] ----@field private _input_blacklist druid.base_component[]|nil ----@field private _input_whitelist druid.base_component[]|nil ----@field private input_inited boolean ----@field private _late_init_timer_id number ----@field private _input_components druid.base_component[] +---The Druid Factory used to create components +---@class druid.instance +---@field package input_inited boolean Used to check if input is initialized +---@field package components_all druid.component[] All created components +---@field package components_interest table All components sorted by interest +---@field package _context table Druid context, usually a self of gui script +---@field package _style table Druid style table +---@field package _late_init_timer_id number Timer id for late init +---@field package _late_remove druid.component[] Components to be removed on late update +---@field package _is_late_remove_enabled boolean Used to check if components should be removed on late update +---@field package _input_blacklist druid.component[]|nil Components that should not receive input +---@field package _input_whitelist druid.component[]|nil Components that should receive input local M = {} -local MSG_ADD_FOCUS = hash("acquire_input_focus") -local MSG_REMOVE_FOCUS = hash("release_input_focus") local IS_NO_AUTO_INPUT = sys.get_config_int("druid.no_auto_input", 0) == 1 +local INTERESTS_CACHE = {} -- Cache interests per component class in runtime + local function set_input_state(self, is_input_inited) if IS_NO_AUTO_INPUT or (self.input_inited == is_input_inited) then @@ -30,21 +30,23 @@ local function set_input_state(self, is_input_inited) end self.input_inited = is_input_inited - msg.post(".", is_input_inited and MSG_ADD_FOCUS or MSG_REMOVE_FOCUS) + msg.post(".", is_input_inited and "acquire_input_focus" or "release_input_focus") end --- The a and b - two Druid components ---@private -local function sort_input_comparator(a, b) - local a_priority = a:get_input_priority() - local b_priority = b:get_input_priority() +---@param component_a druid.component +---@param component_b druid.component +---@return boolean +local function sort_input_comparator(component_a, component_b) + local a_priority = component_a:get_input_priority() + local b_priority = component_b:get_input_priority() if a_priority ~= b_priority then return a_priority < b_priority end - return a:get_uid() < b:get_uid() + return component_a:get_uid() < component_b:get_uid() end @@ -58,71 +60,69 @@ local function sort_input_stack(self) end --- 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) +---Get current component interests +---@param instance druid.component +---@return table interest_list List of component interests +local function get_component_interests(instance) + ---@diagnostic disable-next-line: invisible + local instance_class = instance._meta.instance_class + if INTERESTS_CACHE[instance_class] then + return INTERESTS_CACHE[instance_class] + end + local interests = {} + for index = 1, #const.ALL_INTERESTS do + local interest = const.ALL_INTERESTS[index] + if instance[interest] and type(instance[interest]) == "function" then + table.insert(interests, interest) + end + end + + INTERESTS_CACHE[instance_class] = interests + return INTERESTS_CACHE[instance_class] +end + + +---@private +---@param self druid.instance +---@param instance druid.component +local function register_interests(self, instance) table.insert(self.components_all, instance) - - local register_to = instance:__get_interests() - for i = 1, #register_to do - local interest = register_to[i] + local interest_list = get_component_interests(instance) + for i = 1, #interest_list do + local interest = interest_list[i] table.insert(self.components_interest[interest], instance) end +end + + +---Create the Druid component instance +---@param self druid.instance +---@param instance_class druid.component +---@return druid.component +local function create(self, instance_class) + local instance = instance_class() + instance:setup_component(self, self:get_context(), self:get_style(), instance_class) + register_interests(self, instance) return instance end -local WIDGET_METATABLE = { __index = base_component } - ----Create the Druid component instance ----@param self druid_instance ----@param widget_class druid.base_component +---@private +---@param self druid.instance +---@param widget_class druid.widget +---@return druid.widget local function create_widget(self, widget_class) - local instance = setmetatable({}, { - __index = setmetatable(widget_class, WIDGET_METATABLE) - }) - - instance._component = { - _uid = base_component.create_uid(), - name = "Druid Widget", - input_priority = const.PRIORITY_INPUT, - default_input_priority = const.PRIORITY_INPUT, - _is_input_priority_changed = true, -- Default true for sort once time after GUI init - } - instance._meta = { - druid = self, - template = "", - nodes = nil, - context = self._context, - style = nil, - input_enabled = true, - children = {}, - parent = type(self._context) ~= "userdata" and self._context, - instance_class = widget_class - } - - -- Register - if instance._meta.parent then - instance._meta.parent:__add_child(instance) - end - - table.insert(self.components_all, instance) - - local register_to = instance:__get_interests() - for i = 1, #register_to do - local interest = register_to[i] - table.insert(self.components_interest[interest], instance) - end + local instance = druid_component.create_widget(self, widget_class, self:get_context()) + register_interests(self, instance) return instance end ---Before processing any input check if we need to update input stack ----@param self druid_instance +---@param self druid.instance ---@param components table[] local function check_sort_input_stack(self, components) if not components or #components == 0 then @@ -146,8 +146,8 @@ end ---Check whitelists and blacklists for input components ----@param component druid.base_component ----@return boolean +---@param component druid.component The component to check +---@return boolean is_can_use True if component can be processed on input step function M:_can_use_input_component(component) local can_by_whitelist = true local can_by_blacklist = true @@ -164,27 +164,6 @@ function M:_can_use_input_component(component) end -function M:_process_input(action_id, action, components) - local is_input_consumed = false - - for i = #components, 1, -1 do - local component = components[i] - local meta = component._meta - if meta.input_enabled and self:_can_use_input_component(component) then - if not is_input_consumed then - is_input_consumed = component:on_input(action_id, action) or false - else - if component.on_input_interrupt then - component:on_input_interrupt(action_id, action) - end - end - end - end - - return is_input_consumed -end - - local function schedule_late_init(self) if self._late_init_timer_id then return @@ -197,13 +176,15 @@ local function schedule_late_init(self) end ---- Druid class constructor +---Druid class constructor which used to create a Druid's components ---@param context table Druid context. Usually it is self of gui script ---@param style table? Druid style table -function M:initialize(context, style) +---@return druid.instance instance The new Druid instance +function M.create_druid_instance(context, style) + local self = setmetatable({}, { __index = M }) + self._context = context self._style = style or settings.default_style - self._deleted = false self._is_late_remove_enabled = false self._late_remove = {} @@ -218,20 +199,23 @@ function M:initialize(context, style) events.subscribe("druid.window_event", self.on_window_event, self) events.subscribe("druid.language_change", self.on_language_change, self) + + return self end ---Create new Druid component instance ----@generic T: druid.base_component ----@param component T ----@vararg any ----@return T +---@generic T: druid.component +---@param component T The component class to create +---@vararg any Additional arguments to pass to the component's init function +---@return T instance The new ready to use component function M:new(component, ...) local instance = create(self, component) if instance.init then instance:init(...) end + if instance.on_late_init or (not self.input_inited and instance.on_input) then schedule_late_init(self) end @@ -240,7 +224,7 @@ function M:new(component, ...) end ---- Call this in gui_script final function. +---Call this in gui_script final function. function M:final() local components = self.components_all @@ -250,8 +234,6 @@ function M:final() end end - self._deleted = true - set_input_state(self, false) events.unsubscribe("druid.window_event", self.on_window_event, self) @@ -259,12 +241,12 @@ function M:final() end ---- Remove created component from Druid instance. --- --- Component `on_remove` function will be invoked, if exist. ----@generic T: druid.base_component +---Remove created component from Druid instance. +--- +---Component `on_remove` function will be invoked, if exist. +---@generic T: druid.component ---@param component T Component instance ----@return boolean True if component was removed +---@return boolean is_removed True if component was removed function M:remove(component) if self._is_late_remove_enabled then table.insert(self._late_remove, component) @@ -296,9 +278,9 @@ function M:remove(component) end end - local interests = component:__get_interests() - for i = 1, #interests do - local interest = interests[i] + local interest_list = get_component_interests(component) + for i = 1, #interest_list do + local interest = interest_list[i] local components = self.components_interest[interest] for j = #components, 1, -1 do if components[j] == component then @@ -311,9 +293,25 @@ function M:remove(component) end ---- Druid late update function called after initialization and before the regular update step --- This function is used to check the GUI state and perform actions after all components and nodes have been created. --- An example use case is performing an auto stencil check in the GUI hierarchy for input components. +---Get a context of Druid instance (usually a self of gui script) +---@package +---@return any context The Druid context +function M:get_context() + return self._context +end + + +---Get a style of Druid instance +---@package +---@return table style The Druid style table +function M:get_style() + return self._style +end + + +---Druid late update function called after initialization and before the regular update step. +---This function is used to check the GUI state and perform actions after all components and nodes have been created. +---An example use case is performing an auto stencil check in the GUI hierarchy for input components. ---@private function M:late_init() local late_init_components = self.components_interest[const.ON_LATE_INIT] @@ -347,13 +345,29 @@ end ---Call this in gui_script on_input function. ---@param action_id hash Action_id from on_input ---@param action table Action from on_input ----@return boolean The boolean value is input was consumed +---@return boolean is_input_consumed The boolean value is input was consumed function M:on_input(action_id, action) self._is_late_remove_enabled = true local components = self.components_interest[const.ON_INPUT] check_sort_input_stack(self, components) - local is_input_consumed = self:_process_input(action_id, action, components) + + local is_input_consumed = false + + for i = #components, 1, -1 do + local component = components[i] + local input_enabled = component:get_input_enabled() + + if input_enabled and self:_can_use_input_component(component) then + if not is_input_consumed then + is_input_consumed = component:on_input(action_id, action) or false + else + if component.on_input_interrupt then + component:on_input_interrupt(action_id, action) + end + end + end + end self._is_late_remove_enabled = false self:_clear_late_remove() @@ -362,7 +376,7 @@ function M:on_input(action_id, action) end ---- Call this in gui_script on_message function. +---Call this in gui_script on_message function. ---@param message_id hash Message_id from on_message ---@param message table Message from on_message ---@param sender url Sender from on_message @@ -383,6 +397,8 @@ function M:on_message(message_id, message, sender) end +---Called when the window event occurs +---@param window_event number The window event function M:on_window_event(window_event) if window_event == window.WINDOW_EVENT_FOCUS_LOST then local components = self.components_interest[const.ON_FOCUS_LOST] @@ -403,9 +419,9 @@ function M:on_window_event(window_event) end ---- Calls the on_language_change function in all related components --- This one called by global druid.on_language_change, but can be --- call manualy to update all translations +---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 ---@private function M:on_language_change() local components = self.components_interest[const.ON_LANGUAGE_CHANGE] @@ -418,8 +434,8 @@ 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 whitelist_components table|druid.base_component[] The array of component to whitelist ----@return druid_instance +---@param whitelist_components table|druid.component[] The array of component to whitelist +---@return druid.instance self The Druid instance function M:set_whitelist(whitelist_components) if whitelist_components and whitelist_components._component then whitelist_components = { whitelist_components } @@ -438,8 +454,8 @@ 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 DruidInstance ----@param blacklist_components table|druid.base_component[] The array of component to blacklist ----@return druid_instance +---@param blacklist_components table|druid.component[] The array of component to blacklist +---@return druid.instance self The Druid instance function M:set_blacklist(blacklist_components) if blacklist_components and blacklist_components._component then blacklist_components = { blacklist_components } @@ -455,7 +471,7 @@ function M:set_blacklist(blacklist_components) end ---- Remove all components on late remove step DruidInstance +---Remove all components on late remove step DruidInstance ---@private function M:_clear_late_remove() if #self._late_remove == 0 then @@ -470,15 +486,18 @@ end ---Create new Druid widget instance ----@generic T: druid.base_component ----@param widget T +---@generic T: druid.component +---@param widget T The widget class to create ---@param template string|nil The template name used by widget ----@param nodes table|node|nil The nodes table from gui.clone_tree or prefab node to use for clone ----@vararg any ----@return T +---@param nodes table|node|string|nil The nodes table from gui.clone_tree or prefab node to use for clone or node id to clone +---@vararg any Additional arguments to pass to the widget's init function +---@return T widget The new ready to use widget function M:new_widget(widget, template, nodes, ...) local instance = create_widget(self, widget) + if type(nodes) == "string" then + nodes = gui.get_node(nodes) + end if type(nodes) == "userdata" then nodes = gui.clone_tree(nodes) --[[@as table]] end @@ -499,10 +518,10 @@ end local button = require("druid.base.button") ---Create Button component ---@param node string|node The node_id or gui.get_node(node_id) ----@param callback function|nil Button callback +---@param callback function|event|nil Button callback ---@param params any|nil Button callback params ---@param anim_node node|string|nil Button anim node (node, if not provided) ----@return druid.button Button component +---@return druid.button button The new button component function M:new_button(node, callback, params, anim_node) return self:new(button, node, callback, params, anim_node) end @@ -511,7 +530,7 @@ end local blocker = require("druid.base.blocker") ---Create Blocker component ---@param node string|node The node_id or gui.get_node(node_id) ----@return druid.blocker component Blocker component +---@return druid.blocker blocker The new blocker component function M:new_blocker(node) return self:new(blocker, node) end @@ -519,9 +538,9 @@ end local back_handler = require("druid.base.back_handler") ---Create BackHandler component ----@param callback function|nil The callback(self, custom_args) to call on back event +---@param callback function|event|nil The callback(self, custom_args) to call on back event ---@param params any|nil Callback argument ----@return druid.back_handler component BackHandler component +---@return druid.back_handler back_handler The new back handler component function M:new_back_handler(callback, params) return self:new(back_handler, callback, params) end @@ -532,7 +551,7 @@ local hover = require("druid.base.hover") ---@param node string|node The node_id or gui.get_node(node_id) ---@param on_hover_callback function|nil Hover callback ---@param on_mouse_hover_callback function|nil Mouse hover callback ----@return druid.hover component Hover component +---@return druid.hover hover The new hover component function M:new_hover(node, on_hover_callback, on_mouse_hover_callback) return self:new(hover, node, on_hover_callback, on_mouse_hover_callback) end @@ -540,10 +559,10 @@ end local text = require("druid.base.text") ---Create Text component ----@param node string|node The node_id or gui.get_node(node_id) +---@param node string|node|druid.text The node_id or gui.get_node(node_id) ---@param value string|nil Initial text. Default value is node text from GUI scene. ---@param adjust_type string|nil Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference ----@return druid.text component Text component +---@return druid.text text The new text component function M:new_text(node, value, adjust_type) return self:new(text, node, value, adjust_type) end @@ -554,7 +573,7 @@ local static_grid = require("druid.base.static_grid") ---@param parent_node string|node The node_id or gui.get_node(node_id). Parent of all Grid items. ---@param item string|node Item prefab. Required to get grid's item size. Can be adjusted separately. ---@param in_row number|nil How many nodes in row can be placed ----@return druid.grid component Grid component +---@return druid.grid grid The new grid component function M:new_grid(parent_node, item, in_row) return self:new(static_grid, parent_node, item, in_row) end @@ -564,7 +583,7 @@ local scroll = require("druid.base.scroll") ---Create Scroll component ---@param view_node string|node The node_id or gui.get_node(node_id). Will used as user input node. ---@param content_node string|node The node_id or gui.get_node(node_id). Will used as scrollable node inside view_node. ----@return druid.scroll component Scroll component +---@return druid.scroll scroll The new scroll component function M:new_scroll(view_node, content_node) return self:new(scroll, view_node, content_node) end @@ -574,7 +593,7 @@ local drag = require("druid.base.drag") ---Create Drag component ---@param node string|node The node_id or gui.get_node(node_id). Will used as user input node. ---@param on_drag_callback function|nil Callback for on_drag_event(self, dx, dy) ----@return druid.drag component Drag component +---@return druid.drag drag The new drag component function M:new_drag(node, on_drag_callback) return self:new(drag, node, on_drag_callback) end @@ -584,7 +603,7 @@ local swipe = require("druid.extended.swipe") ---Create Swipe component ---@param node string|node The node_id or gui.get_node(node_id). Will used as user input node. ---@param on_swipe_callback function|nil Swipe callback for on_swipe_end event ----@return druid.swipe component Swipe component +---@return druid.swipe swipe The new swipe component function M:new_swipe(node, on_swipe_callback) return self:new(swipe, node, on_swipe_callback) end @@ -594,8 +613,8 @@ local lang_text = require("druid.extended.lang_text") ---Create LangText component ---@param node string|node The_node id or gui.get_node(node_id) ---@param locale_id string|nil Default locale id or text from node as default ----@param adjust_type string|nil Adjust type for text node. Default: const.TEXT_ADJUST.DOWNSCALE ----@return druid.lang_text component LangText component +---@param adjust_type string|nil Adjust type for text node. Default: "downscale" +---@return druid.lang_text lang_text The new lang text component function M:new_lang_text(node, locale_id, adjust_type) return self:new(lang_text, node, locale_id, adjust_type) end @@ -606,7 +625,7 @@ local slider = require("druid.extended.slider") ---@param pin_node string|node The_node id or gui.get_node(node_id). ---@param end_pos vector3 The end position of slider ---@param callback function|nil On slider change callback ----@return druid.slider component Slider component +---@return druid.slider slider The new slider component function M:new_slider(pin_node, end_pos, callback) return self:new(slider, pin_node, end_pos, callback) end @@ -617,7 +636,7 @@ local input = require("druid.extended.input") ---@param click_node string|node Button node to enabled input component ---@param text_node string|node|druid.text Text node what will be changed on user input ---@param keyboard_type number|nil Gui keyboard type for input field ----@return druid.input component Input component +---@return druid.input input The new input component function M:new_input(click_node, text_node, keyboard_type) return self:new(input, click_node, text_node, keyboard_type) end @@ -626,9 +645,9 @@ end local data_list = require("druid.extended.data_list") ---Create DataList component ---@param druid_scroll druid.scroll The Scroll instance for Data List component ----@param druid_grid druid.grid The StaticGrid} or @{DynamicGrid instance for Data List component +---@param druid_grid druid.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 component DataList component +---@return druid.data_list data_list The new data list component function M:new_data_list(druid_scroll, druid_grid, create_function) return self:new(data_list, druid_scroll, druid_grid, create_function) end @@ -640,7 +659,7 @@ local timer_component = require("druid.extended.timer") ---@param seconds_from number|nil Start timer value in seconds ---@param seconds_to number|nil End timer value in seconds ---@param callback function|nil Function on timer end ----@return druid.timer component Timer component +---@return druid.timer timer The new timer component function M:new_timer(node, seconds_from, seconds_to, callback) return self:new(timer_component, node, seconds_from, seconds_to, callback) end @@ -649,9 +668,9 @@ end local progress = require("druid.extended.progress") ---Create Progress component ---@param node string|node Progress bar fill node or node name ----@param key string Progress bar direction: const.SIDE.X or const.SIDE.Y +---@param key string Progress bar direction: "x" or "y" ---@param init_value number|nil Initial value of progress bar. Default: 1 ----@return druid.progress component Progress component +---@return druid.progress progress The new progress component function M:new_progress(node, key, init_value) return self:new(progress, node, key, init_value) end @@ -661,7 +680,7 @@ local layout = require("druid.extended.layout") ---Create Layout component ---@param node string|node The_node id or gui.get_node(node_id). ---@param mode string|nil vertical|horizontal|horizontal_wrap. Default: horizontal ----@return druid.layout component Layout component +---@return druid.layout layout The new layout component function M:new_layout(node, mode) return self:new(layout, node, mode) end @@ -672,7 +691,7 @@ local container = require("druid.extended.container") ---@param node string|node The_node id or gui.get_node(node_id). ---@param mode string|nil Layout mode ---@param callback fun(self: druid.container, size: vector3)|nil Callback on size changed ----@return druid.container container component +---@return druid.container container The new container component function M:new_container(node, mode, callback) return self:new(container, node, mode, callback) end @@ -681,9 +700,9 @@ end local hotkey = require("druid.extended.hotkey") ---Create Hotkey component ---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys ----@param callback function|nil The callback function +---@param callback function|event|nil The callback function ---@param callback_argument any|nil The argument to pass into the callback function ----@return druid.hotkey component Hotkey component +---@return druid.hotkey hotkey The new hotkey component function M:new_hotkey(keys_array, callback, callback_argument) return self:new(hotkey, keys_array, callback, callback_argument) end @@ -693,7 +712,7 @@ local rich_text = require("druid.custom.rich_text.rich_text") ---Create RichText component. ---@param text_node string|node The text node to make Rich Text ---@param value string|nil The initial text value. Default will be gui.get_text(text_node) ----@return druid.rich_text component RichText component +---@return druid.rich_text rich_text The new rich text component function M:new_rich_text(text_node, value) return self:new(rich_text, text_node, value) end @@ -701,10 +720,10 @@ end local rich_input = require("druid.custom.rich_input.rich_input") ---Create RichInput component. --- As a template please check rich_input.gui layout. +---As a template please check rich_input.gui layout. ---@param template string The template string name ---@param nodes table|nil Nodes table from gui.clone_tree ----@return druid.rich_input component RichInput component +---@return druid.rich_input rich_input The new rich input component function M:new_rich_input(template, nodes) return self:new(rich_input, template, nodes) end diff --git a/druid/system/settings.lua b/druid/system/settings.lua index ea8f8b6..e0b2c21 100755 --- a/druid/system/settings.lua +++ b/druid/system/settings.lua @@ -4,12 +4,14 @@ local M = {} M.default_style = nil ---@param text_id string ----@vararg any +---@param ... string Optional params for string.format function M.get_text(text_id, ...) return "[Druid]: locales not inited" end + function M.play_sound(sound_id) end + return M diff --git a/druid/templates/component.template.lua b/druid/templates/component.template.lua index 202cd42..d2c2e03 100644 --- a/druid/templates/component.template.lua +++ b/druid/templates/component.template.lua @@ -1,4 +1,4 @@ ----@class widget.TEMPLATE: druid.widget +---@class druid.widget.TEMPLATE: druid.widget local M = {} diff --git a/druid/templates/component_full.template.lua b/druid/templates/component_full.template.lua index 81fd322..e657798 100644 --- a/druid/templates/component_full.template.lua +++ b/druid/templates/component_full.template.lua @@ -1,6 +1,6 @@ local component = require("druid.component") ----@class new_component: druid.base_component +---@class new_component: druid.component local M = component.create("new_component") -- Component constructor. Template name and nodes are optional. Pass it if you use it in your component diff --git a/druid/widget/fps_panel/fps_panel.lua b/druid/widget/fps_panel/fps_panel.lua index c86c66b..0ce5589 100644 --- a/druid/widget/fps_panel/fps_panel.lua +++ b/druid/widget/fps_panel/fps_panel.lua @@ -1,7 +1,7 @@ local helper = require("druid.helper") local mini_graph = require("druid.widget.mini_graph.mini_graph") ----@class widget.fps_panel: druid.widget +---@class druid.widget.fps_panel: druid.widget ---@field root node local M = {} @@ -10,6 +10,7 @@ if TARGET_FPS == 0 then TARGET_FPS = 60 end + function M:init() self.root = self:get_node("root") @@ -40,8 +41,11 @@ function M:init() self:push_fps_value() end) - self.container = self.druid:new_container(self.root) - self.container:add_container(self.mini_graph.container) + --self.container = self.druid:new_container(self.root) + --self.container:add_container(self.mini_graph.container) + --local container_content = self.container:add_container("content") + --container_content:add_container("text_min_fps") + --container_content:add_container("text_fps") end @@ -98,4 +102,4 @@ function M:push_fps_value() end -return M \ No newline at end of file +return M diff --git a/druid/widget/memory_panel/memory_panel.gui b/druid/widget/memory_panel/memory_panel.gui index 80b3b4a..1892972 100644 --- a/druid/widget/memory_panel/memory_panel.gui +++ b/druid/widget/memory_panel/memory_panel.gui @@ -117,6 +117,7 @@ nodes { y: 1.0 z: 1.0 } + adjust_mode: ADJUST_MODE_STRETCH parent: "content" inherit_alpha: true outline_alpha: 0.0 @@ -155,6 +156,7 @@ nodes { y: 1.0 z: 1.0 } + adjust_mode: ADJUST_MODE_STRETCH parent: "content" inherit_alpha: true outline_alpha: 0.0 diff --git a/druid/widget/memory_panel/memory_panel.lua b/druid/widget/memory_panel/memory_panel.lua index 3a72ae0..fafdd01 100644 --- a/druid/widget/memory_panel/memory_panel.lua +++ b/druid/widget/memory_panel/memory_panel.lua @@ -1,10 +1,11 @@ local helper = require("druid.helper") local mini_graph = require("druid.widget.mini_graph.mini_graph") ----@class widget.memory_panel: druid.widget +---@class druid.widget.memory_panel: druid.widget ---@field root node local M = {} + function M:init() self.root = self:get_node("root") self.delta_time = 0.1 @@ -38,8 +39,11 @@ function M:init() self:push_next_value() end) - self.container = self.druid:new_container(self.root) - self.container:add_container(self.mini_graph.container) + --self.container = self.druid:new_container(self.root) + --self.container:add_container(self.mini_graph.container) + --local container_content = self.container:add_container("content") + --container_content:add_container("text_max_value") + --container_content:add_container("text_per_second") end @@ -93,4 +97,4 @@ function M:update_text_memory() end -return M \ No newline at end of file +return M diff --git a/druid/widget/mini_graph/mini_graph.gui b/druid/widget/mini_graph/mini_graph.gui index 11ad730..ed5fa6d 100644 --- a/druid/widget/mini_graph/mini_graph.gui +++ b/druid/widget/mini_graph/mini_graph.gui @@ -23,6 +23,7 @@ nodes { type: TYPE_BOX texture: "druid/ui_circle_16" id: "root" + adjust_mode: ADJUST_MODE_STRETCH inherit_alpha: true slice9 { x: 8.0 @@ -120,6 +121,7 @@ nodes { texture: "druid/ui_circle_16" id: "content" pivot: PIVOT_S + adjust_mode: ADJUST_MODE_STRETCH parent: "root" inherit_alpha: true slice9 { diff --git a/druid/widget/mini_graph/mini_graph.lua b/druid/widget/mini_graph/mini_graph.lua index 3cebd5b..10a5237 100644 --- a/druid/widget/mini_graph/mini_graph.lua +++ b/druid/widget/mini_graph/mini_graph.lua @@ -1,7 +1,12 @@ local color = require("druid.color") local helper = require("druid.helper") ----@class widget.mini_graph: druid.widget +---Widget to display a several lines with different height in a row +---Init, set amount of samples and max value of value means that the line will be at max height +---Use `push_line_value` to add a new value to the line +---Or `set_line_value` to set a value to the line by index +---Setup colors inside template file (at minimum and maximum) +---@class druid.widget.mini_graph: druid.widget local M = {} local SIZE_Y = hash("size.y") @@ -11,6 +16,7 @@ function M:init() self.root = self:get_node("root") self.text_header = self.druid:new_text("text_header") + self.icon_drag = self:get_node("icon_drag") self.druid:new_drag("header", self.on_drag_widget) self.druid:new_button("icon_drag", self.toggle_hide) :set_style(nil) @@ -34,7 +40,11 @@ function M:init() self.values = {} self.container = self.druid:new_container(self.root) - self.container:add_container("header") + local container_header = self.container:add_container("header", "stretch_x") + container_header:add_container("text_header") + container_header:add_container("icon_drag") + + self.container:add_container("content", "stretch_x") self.default_size = self.container:get_size() end @@ -75,9 +85,9 @@ end ---Set normalized to control the color of the line ---- for index = 1, mini_graph:get_samples() do ---- mini_graph:set_line_value(index, math.random()) ---- end +--- for index = 1, mini_graph:get_samples() do +--- mini_graph:set_line_value(index, math.random()) +--- end ---@param index number ---@param value number The normalized value from 0 to 1 function M:set_line_value(index, value) @@ -141,6 +151,10 @@ end function M:on_drag_widget(dx, dy) + if not gui.is_enabled(self.icon_drag) then + return + end + local position = self.container:get_position() self.container:set_position(position.x + dx, position.y + dy) end @@ -159,4 +173,4 @@ function M:toggle_hide() end -return M \ No newline at end of file +return M diff --git a/druid/widget/properties_panel/properties/property_button.lua b/druid/widget/properties_panel/properties/property_button.lua index eefa866..cce90fb 100644 --- a/druid/widget/properties_panel/properties/property_button.lua +++ b/druid/widget/properties_panel/properties/property_button.lua @@ -1,14 +1,15 @@ local color = require("druid.color") ----@class widget.property_button: druid.widget +---@class druid.widget.property_button: druid.widget ---@field root node ---@field container druid.container ---@field text_name druid.text ---@field button druid.button ---@field text_button druid.text ----@field druid druid_instance +---@field druid druid.instance local M = {} + function M:init() self.root = self:get_node("root") self.text_name = self.druid:new_text("text_name") @@ -35,7 +36,7 @@ end ---@param text string ----@return widget.property_button +---@return druid.widget.property_button function M:set_text_property(text) self.text_name:set_text(text) return self @@ -43,7 +44,7 @@ end ---@param text string ----@return widget.property_button +---@return druid.widget.property_button function M:set_text_button(text) self.text_button:set_text(text) return self diff --git a/druid/widget/properties_panel/properties/property_checkbox.lua b/druid/widget/properties_panel/properties/property_checkbox.lua index a0fc7ea..71179c3 100644 --- a/druid/widget/properties_panel/properties/property_checkbox.lua +++ b/druid/widget/properties_panel/properties/property_checkbox.lua @@ -1,8 +1,8 @@ local event = require("event.event") ----@class widget.property_checkbox: druid.widget +---@class druid.widget.property_checkbox: druid.widget ---@field root node ----@field druid druid_instance +---@field druid druid.instance ---@field text_name druid.text ---@field button druid.button ---@field selected node @@ -59,14 +59,14 @@ function M:on_click() end ---- Set the text property of the checkbox +---Set the text property of the checkbox ---@param text string function M:set_text_property(text) self.text_name:set_text(text) end ---- Set the callback function for when the checkbox value changes +---Set the callback function for when the checkbox value changes ---@param callback function function M:on_change(callback) self.on_change_value:subscribe(callback) diff --git a/druid/widget/properties_panel/properties/property_input.lua b/druid/widget/properties_panel/properties/property_input.lua index e09b1f0..c33bb1b 100644 --- a/druid/widget/properties_panel/properties/property_input.lua +++ b/druid/widget/properties_panel/properties/property_input.lua @@ -1,9 +1,9 @@ ----@class widget.property_input: druid.widget +---@class druid.widget.property_input: druid.widget ---@field root node ---@field container druid.container ---@field text_name druid.text ---@field button druid.button ----@field druid druid_instance +---@field druid druid.instance local M = {} function M:init() @@ -23,21 +23,23 @@ end ---@param text string ----@return widget.property_input +---@return druid.widget.property_input function M:set_text_property(text) self.text_name:set_text(text) return self end ----@param text string ----@return widget.property_input +---@param text string|number +---@return druid.widget.property_input function M:set_text_value(text) - self.rich_input:set_text(text) + self.rich_input:set_text(tostring(text)) return self end +---@param callback fun(self: druid.widget.property_input, text: string) +---@param callback_context any function M:on_change(callback, callback_context) self.rich_input.input.on_input_unselect:subscribe(callback, callback_context) end diff --git a/druid/widget/properties_panel/properties/property_left_right_selector.lua b/druid/widget/properties_panel/properties/property_left_right_selector.lua index 6cb79b5..2f3dd5d 100644 --- a/druid/widget/properties_panel/properties/property_left_right_selector.lua +++ b/druid/widget/properties_panel/properties/property_left_right_selector.lua @@ -1,8 +1,8 @@ local event = require("event.event") ----@class widget.property_left_right_selector: druid.widget +---@class druid.widget.property_left_right_selector: druid.widget ---@field root node ----@field druid druid_instance +---@field druid druid.instance ---@field text_name druid.text ---@field button druid.button ---@field selected node diff --git a/druid/widget/properties_panel/properties/property_slider.lua b/druid/widget/properties_panel/properties/property_slider.lua index 844cb94..38114b6 100644 --- a/druid/widget/properties_panel/properties/property_slider.lua +++ b/druid/widget/properties_panel/properties/property_slider.lua @@ -1,13 +1,14 @@ local event = require("event.event") local helper = require("druid.helper") ----@class widget.property_slider: druid.widget +---@class druid.widget.property_slider: druid.widget ---@field root node ---@field container druid.container ----@field druid druid_instance +---@field druid druid.instance ---@field text_name druid.text ---@field text_value druid.text ---@field slider druid.slider +---@field on_change_value event fun(value:number) local M = {} @@ -47,14 +48,14 @@ function M:set_text_function(callback) end ---- Sets the text property of the slider +---Sets the text property of the slider ---@param text string function M:set_text_property(text) self.text_name:set_text(text) end ---- Sets the callback function for when the slider value changes +---Sets the callback function for when the slider value changes ---@param callback fun(value:number) function M:on_change(callback) self.on_change_value:subscribe(callback) diff --git a/druid/widget/properties_panel/properties/property_text.lua b/druid/widget/properties_panel/properties/property_text.lua index cb73678..ef2ed48 100644 --- a/druid/widget/properties_panel/properties/property_text.lua +++ b/druid/widget/properties_panel/properties/property_text.lua @@ -1,4 +1,4 @@ ----@class widget.property_text: druid.widget +---@class druid.widget.property_text: druid.widget ---@field root node ---@field container druid.container ---@field text_name druid.text @@ -8,10 +8,10 @@ local M = {} function M:init() self.root = self:get_node("root") self.text_name = self.druid:new_text("text_name") - :set_text_adjust("scale_when_trim_left", 0.3) + :set_text_adjust("scale_then_trim_left", 0.3) self.text_right = self.druid:new_text("text_right", "") - --:set_text_adjust("scale_when_trim_left", 0.3) -- TODO: not works? why? + --:set_text_adjust("scale_then_trim_left", 0.3) -- TODO: not works? why? self.container = self.druid:new_container(self.root) self.container:add_container("text_name", nil, function(_, size) @@ -24,7 +24,7 @@ end ---@param text string ----@return widget.property_text +---@return druid.widget.property_text function M:set_text_property(text) self.text_name:set_text(text) return self @@ -32,7 +32,7 @@ end ---@param text string|nil ----@return widget.property_text +---@return druid.widget.property_text function M:set_text_value(text) self.text_right:set_text(text or "") return self diff --git a/druid/widget/properties_panel/properties/property_vector3.lua b/druid/widget/properties_panel/properties/property_vector3.lua index 56ccf9d..820ccbd 100644 --- a/druid/widget/properties_panel/properties/property_vector3.lua +++ b/druid/widget/properties_panel/properties/property_vector3.lua @@ -1,12 +1,12 @@ local event = require("event.event") ----@class widget.property_vector3: druid.widget +---@class druid.widget.property_vector3: druid.widget ---@field root node ---@field container druid.container ---@field text_name druid.text ---@field button druid.button ----@field druid druid_instance +---@field druid druid.instance local M = {} function M:init() @@ -53,7 +53,7 @@ end ---@param text string ----@return widget.property_vector3 +---@return druid.widget.property_vector3 function M:set_text_property(text) self.text_name:set_text(text) return self @@ -63,7 +63,7 @@ end ---@param x number ---@param y number ---@param z number ----@return widget.property_vector3 +---@return druid.widget.property_vector3 function M:set_value(x, y, z) self.rich_input_x:set_text(tostring(x)) self.rich_input_y:set_text(tostring(y)) diff --git a/druid/widget/properties_panel/properties_panel.gui b/druid/widget/properties_panel/properties_panel.gui index 7ba5a5c..43dbf4c 100644 --- a/druid/widget/properties_panel/properties_panel.gui +++ b/druid/widget/properties_panel/properties_panel.gui @@ -13,7 +13,7 @@ textures { nodes { size { x: 400.0 - y: 240.0 + y: 400.0 } color { x: 0.173 @@ -23,6 +23,7 @@ nodes { type: TYPE_BOX texture: "druid/ui_circle_16" id: "root" + pivot: PIVOT_N inherit_alpha: true slice9 { x: 8.0 @@ -32,9 +33,6 @@ nodes { } } nodes { - position { - y: 120.0 - } size { x: 400.0 y: 40.0 @@ -105,15 +103,15 @@ nodes { } nodes { position { - y: -120.0 + y: -50.0 } size { x: 400.0 - y: 190.0 + y: 350.0 } type: TYPE_BOX id: "content" - pivot: PIVOT_S + pivot: PIVOT_N parent: "root" inherit_alpha: true size_mode: SIZE_MODE_AUTO @@ -122,11 +120,10 @@ nodes { nodes { position { x: -200.0 - y: 190.0 } size { x: 400.0 - y: 190.0 + y: 350.0 } type: TYPE_BOX texture: "druid/empty" @@ -141,7 +138,7 @@ nodes { nodes { size { x: 400.0 - y: 190.0 + y: 350.0 } type: TYPE_BOX texture: "druid/pixel" @@ -159,7 +156,7 @@ nodes { } nodes { position { - y: 170.0 + y: -10.0 } type: TYPE_BOX texture: "druid/empty" diff --git a/druid/widget/properties_panel/properties_panel.lua b/druid/widget/properties_panel/properties_panel.lua index cae5d3f..6ec0230 100644 --- a/druid/widget/properties_panel/properties_panel.lua +++ b/druid/widget/properties_panel/properties_panel.lua @@ -6,7 +6,7 @@ local property_text = require("druid.widget.properties_panel.properties.property local property_left_right_selector = require("druid.widget.properties_panel.properties.property_left_right_selector") local property_vector3 = require("druid.widget.properties_panel.properties.property_vector3") ----@class widget.properties_panel: druid.widget +---@class druid.widget.properties_panel: druid.widget ---@field root node ---@field scroll druid.scroll ---@field layout druid.layout @@ -14,8 +14,9 @@ local property_vector3 = require("druid.widget.properties_panel.properties.prope ---@field container_content druid.container ---@field container_scroll_view druid.container ---@field contaienr_scroll_content druid.container +---@field button_hidden druid.button ---@field text_header druid.text ----@field paginator widget.property_left_right_selector +---@field paginator druid.widget.property_left_right_selector ---@field properties druid.widget[] List of created properties ---@field properties_constructors fun()[] List of properties functions to create a new widget. Used to not spawn non-visible widgets but keep the reference local M = {} @@ -47,8 +48,9 @@ function M:init() self.layout.on_size_changed:subscribe(self.on_size_changed, self) self.druid:new_drag("header", self.on_drag_widget) - self.druid:new_button("icon_drag", self.toggle_hide) - :set_style(nil) + self.button_hidden = self.druid:new_button("icon_drag", function() + self:set_hidden(not self._is_hidden) + end):set_style(nil) self.property_checkbox_prefab = self:get_node("property_checkbox/root") gui.set_enabled(self.property_checkbox_prefab, false) @@ -100,13 +102,16 @@ end function M:clear_created_properties() for index = 1, #self.properties do local property = self.properties[index] + local root = property.root --[[@as node]] - -- If prefab used clone nodes we can remove it - if property:get_nodes() then - gui.delete_node(property.root) - else - -- Probably we have component placed on scene directly - gui.set_enabled(property.root, false) + if root then + -- If prefab used clone nodes we can remove it + if property:get_nodes() then + gui.delete_node(root) + else + -- Probably we have component placed on scene directly + gui.set_enabled(root, false) + end end self.druid:remove(self.properties[index]) @@ -130,15 +135,16 @@ function M:on_size_changed(new_size) self.container_content:set_size(new_size.x, new_size.y, gui.PIVOT_N) self.default_size = vmath.vector3(new_size.x, new_size.y + 50, 0) - if not self.is_hidden then + if not self._is_hidden then self.container:set_size(self.default_size.x, self.default_size.y, gui.PIVOT_N) end local width = self.layout:get_size().x - self.layout.padding.x - self.layout.padding.z for index = 1, #self.properties do local property = self.properties[index] - if property.container then - property.container:set_size(width) + local container = property.container --[[@as druid.container]] + if container then + container:set_size(width) end end self.paginator.container:set_size(width) @@ -170,47 +176,47 @@ function M:update(dt) end ----@param on_create fun(checkbox: widget.property_checkbox)|nil ----@return widget.properties_panel +---@param on_create fun(checkbox: druid.widget.property_checkbox)|nil +---@return druid.widget.properties_panel function M:add_checkbox(on_create) return self:add_inner_widget(property_checkbox, "property_checkbox", self.property_checkbox_prefab, on_create) end ----@param on_create fun(slider: widget.property_slider)|nil ----@return widget.properties_panel +---@param on_create fun(slider: druid.widget.property_slider)|nil +---@return druid.widget.properties_panel function M:add_slider(on_create) return self:add_inner_widget(property_slider, "property_slider", self.property_slider_prefab, on_create) end ----@param on_create fun(button: widget.property_button)|nil ----@return widget.properties_panel +---@param on_create fun(button: druid.widget.property_button)|nil +---@return druid.widget.properties_panel function M:add_button(on_create) return self:add_inner_widget(property_button, "property_button", self.property_button_prefab, on_create) end ----@param on_create fun(input: widget.property_input)|nil ----@return widget.properties_panel +---@param on_create fun(input: druid.widget.property_input)|nil +---@return druid.widget.properties_panel function M:add_input(on_create) return self:add_inner_widget(property_input, "property_input", self.property_input_prefab, on_create) end ----@param on_create fun(text: widget.property_text)|nil +---@param on_create fun(text: druid.widget.property_text)|nil function M:add_text(on_create) return self:add_inner_widget(property_text, "property_text", self.property_text_prefab, on_create) end ----@param on_create fun(selector: widget.property_left_right_selector)|nil +---@param on_create fun(selector: druid.widget.property_left_right_selector)|nil function M:add_left_right_selector(on_create) return self:add_inner_widget(property_left_right_selector, "property_left_right_selector", self.property_left_right_selector_prefab, on_create) end ----@param on_create fun(vector3: widget.property_vector3)|nil +---@param on_create fun(vector3: druid.widget.property_vector3)|nil function M:add_vector3(on_create) return self:add_inner_widget(property_vector3, "property_vector3", self.property_vector3_prefab, on_create) end @@ -221,7 +227,7 @@ end ---@param template string|nil ---@param nodes table|node|nil ---@param on_create fun(widget: T)|nil ----@return widget.properties_panel +---@return druid.widget.properties_panel function M:add_inner_widget(widget_class, template, nodes, on_create) table.insert(self.properties_constructors, function() local widget = self.druid:new_widget(widget_class, template, nodes) @@ -239,7 +245,7 @@ end ---@param create_widget_callback fun(): druid.widget ----@return widget.properties_panel +---@return druid.widget.properties_panel function M:add_widget(create_widget_callback) table.insert(self.properties_constructors, function() local widget = create_widget_callback() @@ -292,15 +298,19 @@ function M:remove(widget) end -function M:toggle_hide() - self.is_hidden = not self.is_hidden +function M:set_hidden(is_hidden) + self._is_hidden = is_hidden local hidden_size = gui.get_size(self:get_node("header")) - local new_size = self.is_hidden and hidden_size or self.default_size + local new_size = self._is_hidden and hidden_size or self.default_size self.container:set_size(new_size.x, new_size.y, gui.PIVOT_N) - gui.set_enabled(self.content, not self.is_hidden) - return self + gui.set_enabled(self.content, not self._is_hidden) +end + + +function M:is_hidden() + return self._is_hidden end diff --git a/example/components/druid_logo/druid_logo.lua b/example/components/druid_logo/druid_logo.lua index c2eb7d2..5f70ba0 100644 --- a/example/components/druid_logo/druid_logo.lua +++ b/example/components/druid_logo/druid_logo.lua @@ -3,10 +3,10 @@ local component = require("druid.component") local druid_logo_panthera = require("example.components.druid_logo.druid_logo_panthera") ----@class druid_logo: druid.base_component +---@class examples.druid_logo: druid.component ---@field root druid.container ---@field text_description druid.text ----@field druid druid_instance +---@field druid druid.instance local DruidLogo = component.create("druid_logo") diff --git a/example/components/example_scene/example_scene.lua b/example/components/example_scene/example_scene.lua index 394ccc1..f8751b3 100644 --- a/example/components/example_scene/example_scene.lua +++ b/example/components/example_scene/example_scene.lua @@ -1,10 +1,10 @@ local component = require("druid.component") ----@class example_scene: druid.base_component +---@class examples.example_scene: druid.component ---@field root druid.container ---@field text_debug_info druid.text ---@field text_gui_path druid.text ----@field druid druid_instance +---@field druid druid.instance local M = component.create("example_scene") diff --git a/example/components/examples_list_view/examples_list_view.gui b/example/components/examples_list_view/examples_list_view.gui index cadc473..af607e7 100644 --- a/example/components/examples_list_view/examples_list_view.gui +++ b/example/components/examples_list_view/examples_list_view.gui @@ -106,6 +106,36 @@ nodes { inherit_alpha: true template: "/example/components/examples_list_view/examples_list_view_item.gui" } +nodes { + type: TYPE_BOX + id: "examples_list_view_item/root" + parent: "examples_list_view_item" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "examples_list_view_item/panel_highlight" + parent: "examples_list_view_item/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "examples_list_view_item/panel_selected" + parent: "examples_list_view_item/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "examples_list_view_item/icon" + parent: "examples_list_view_item/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "examples_list_view_item/text" + parent: "examples_list_view_item/root" + template_node_child: true +} layers { name: "druid" } diff --git a/example/components/examples_list_view/examples_list_view.lua b/example/components/examples_list_view/examples_list_view.lua index d5f98d2..13bf094 100644 --- a/example/components/examples_list_view/examples_list_view.lua +++ b/example/components/examples_list_view/examples_list_view.lua @@ -4,9 +4,9 @@ local storage = require("saver.storage") local examples_list_view_item = require("example.components.examples_list_view.examples_list_view_item") ----@class examples_list_view: druid.base_component +---@class examples_list_view: druid.component ---@field root druid.container ----@field druid druid_instance +---@field druid druid.instance ---@field scroll druid.scroll ---@field grid druid.grid local M = component.create("examples_list_view") @@ -46,6 +46,10 @@ function M:init(template, nodes) end) end +---@class example_instance: druid.widget +---@field on_example_created fun(self: example_instance, output_list: output_list)? +---@field properties_control fun(self: example_instance, properties_panel: properties_panel)? +---@field get_debug_info fun(self: example_instance):string? ---@param examples druid.examples ---@param druid_example druid.example @The main GUI component @@ -92,9 +96,10 @@ function M:add_example(examples, druid_example) local instance if example_data.widget_class then instance = druid_example.druid:new_widget(example_data.widget_class, example_data.template) - else + elseif example_data.component_class then -- Keep for backward compatibility instance = druid_example.druid:new(example_data.component_class, example_data.template) end + ---@cast instance example_instance self.selected_example = { data = example_data, @@ -105,7 +110,9 @@ function M:add_example(examples, druid_example) item:set_selected(true) druid_example.output_list:clear() - if example_data.on_create then + if instance.on_example_created then + instance:on_example_created(druid_example.output_list) + elseif example_data.on_create then example_data.on_create(instance, druid_example.output_list) end @@ -118,7 +125,11 @@ function M:add_example(examples, druid_example) druid_example.example_scene:set_gui_path(example_data.code_url) druid_example.properties_panel:clear() - if example_data.properties_control then + + -- First we want to chec + if instance.properties_control then + instance:properties_control(druid_example.properties_panel) + elseif example_data.properties_control then example_data.properties_control(instance, druid_example.properties_panel) end @@ -167,6 +178,13 @@ function M:update_debug_info() return end + local instance = self.selected_example.instance + if instance.get_debug_info then + local info = instance:get_debug_info() + self.on_debug_info:trigger(info) + return + end + local data = self.selected_example.data if data.get_debug_info then local info = data.get_debug_info(self.selected_example.instance) diff --git a/example/components/examples_list_view/examples_list_view_item.lua b/example/components/examples_list_view/examples_list_view_item.lua index 1b4edc1..26427b5 100644 --- a/example/components/examples_list_view/examples_list_view_item.lua +++ b/example/components/examples_list_view/examples_list_view_item.lua @@ -1,9 +1,9 @@ local component = require("druid.component") ----@class examples_list_view_item: druid.base_component +---@class examples_list_view_item: druid.component ---@field root druid.container ---@field text druid.lang_text ----@field druid druid_instance +---@field druid druid.instance ---@field on_click event local M = component.create("examples_list_view_item") diff --git a/example/components/output_list/output_list.lua b/example/components/output_list/output_list.lua index c7e0802..13f997c 100644 --- a/example/components/output_list/output_list.lua +++ b/example/components/output_list/output_list.lua @@ -1,10 +1,10 @@ local component = require("druid.component") ----@class output_list: druid.base_component +---@class output_list: druid.component ---@field root druid.container ---@field text_header druid.text ---@field scroll druid.scroll ----@field druid druid_instance +---@field druid druid.instance local M = component.create("output_list") ---@param template string diff --git a/example/components/panel_druid_profiler/panel_druid_profiler.lua b/example/components/panel_druid_profiler/panel_druid_profiler.lua index 233e50b..d2c2e27 100644 --- a/example/components/panel_druid_profiler/panel_druid_profiler.lua +++ b/example/components/panel_druid_profiler/panel_druid_profiler.lua @@ -3,9 +3,9 @@ local helper = require("druid.helper") local component = require("druid.component") ----@class panel_druid_profiler: druid.base_component +---@class panel_druid_profiler: druid.component ---@field root druid.container ----@field druid druid_instance +---@field druid druid.instance local M = component.create("panel_druid_profiler") local FPS_SAMPLES = 60 @@ -110,7 +110,7 @@ end function M:update_components() - ---@diagnostic disable-next-line: undefined-field + ---@diagnostic disable-next-line, invisible local components = #self.druid.components_all self.text_components_amount:set_text(tostring(components)) diff --git a/example/components/panel_information/panel_information.lua b/example/components/panel_information/panel_information.lua index cd799dd..a190151 100644 --- a/example/components/panel_information/panel_information.lua +++ b/example/components/panel_information/panel_information.lua @@ -1,11 +1,11 @@ local lang = require("lang.lang") local component = require("druid.component") ----@class panel_information: druid.base_component +---@class panel_information: druid.component ---@field root druid.container ---@field text_header druid.lang_text ---@field rich_text druid.rich_text ----@field druid druid_instance +---@field druid druid.instance local PanelInformation = component.create("panel_information") ---@param template string diff --git a/example/components/properties_panel/properties/property_button.lua b/example/components/properties_panel/properties/property_button.lua index 6dcc2ab..008c0d4 100644 --- a/example/components/properties_panel/properties/property_button.lua +++ b/example/components/properties_panel/properties/property_button.lua @@ -1,18 +1,12 @@ -local component = require("druid.component") - ----@class property_button: druid.base_component +---@class property_button: druid.widget ---@field root node ---@field text_name druid.lang_text ---@field button druid.button ---@field text_button druid.text ----@field druid druid_instance -local M = component.create("property_button") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.root = self:get_node("root") self.text_name = self.druid:new_lang_text("text_name") --[[@as druid.lang_text]] self.selected = self:get_node("selected") diff --git a/example/components/properties_panel/properties/property_checkbox.lua b/example/components/properties_panel/properties/property_checkbox.lua index d3e9ce8..81b56db 100644 --- a/example/components/properties_panel/properties/property_checkbox.lua +++ b/example/components/properties_panel/properties/property_checkbox.lua @@ -1,18 +1,12 @@ -local component = require("druid.component") - ----@class property_checkbox: druid.base_component ----@field druid druid_instance +---@class property_checkbox: druid.widget ---@field root druid.container ---@field text_name druid.lang_text ---@field button druid.button ---@field selected node -local M = component.create("property_checkbox") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.root = self.druid:new_container("root") --[[@as druid.container]] self.icon = self:get_node("icon") diff --git a/example/components/properties_panel/properties/property_slider.lua b/example/components/properties_panel/properties/property_slider.lua index 9784d24..ecae11d 100644 --- a/example/components/properties_panel/properties/property_slider.lua +++ b/example/components/properties_panel/properties/property_slider.lua @@ -1,19 +1,12 @@ -local component = require("druid.component") - ----@class property_slider: druid.base_component ----@field druid druid_instance +---@class property_slider: druid.widget ---@field root druid.container ---@field text_name druid.lang_text ---@field text_value druid.text ---@field slider druid.slider -local M = component.create("property_slider") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.root = self.druid:new_container("root") --[[@as druid.container]] self.selected = self:get_node("selected") gui.set_alpha(self.selected, 0) diff --git a/example/components/properties_panel/properties_panel.gui b/example/components/properties_panel/properties_panel.gui index 5e59d95..449fdaa 100644 --- a/example/components/properties_panel/properties_panel.gui +++ b/example/components/properties_panel/properties_panel.gui @@ -153,6 +153,60 @@ nodes { inherit_alpha: true template: "/example/components/properties_panel/properties/property_slider.gui" } +nodes { + type: TYPE_BOX + id: "property_slider/root" + parent: "property_slider" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "property_slider/text_name" + parent: "property_slider/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_slider/E_Anchor" + parent: "property_slider/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_slider/button" + parent: "property_slider/E_Anchor" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_slider/selected" + parent: "property_slider/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "property_slider/text_value" + parent: "property_slider/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_slider/slider" + parent: "property_slider/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_slider/slider_back" + parent: "property_slider/slider" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_slider/slider_pin" + parent: "property_slider/slider" + template_node_child: true +} nodes { position { y: -50.0 @@ -163,6 +217,36 @@ nodes { inherit_alpha: true template: "/example/components/properties_panel/properties/property_checkbox.gui" } +nodes { + type: TYPE_BOX + id: "property_checkbox/root" + parent: "property_checkbox" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "property_checkbox/text_name" + parent: "property_checkbox/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_checkbox/button" + parent: "property_checkbox/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_checkbox/icon" + parent: "property_checkbox/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_checkbox/selected" + parent: "property_checkbox/button" + template_node_child: true +} nodes { position { y: -100.0 @@ -173,6 +257,36 @@ nodes { inherit_alpha: true template: "/example/components/properties_panel/properties/property_button.gui" } +nodes { + type: TYPE_BOX + id: "property_button/root" + parent: "property_button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "property_button/text_name" + parent: "property_button/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_button/button" + parent: "property_button/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "property_button/selected" + parent: "property_button/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "property_button/text_button" + parent: "property_button/button" + template_node_child: true +} nodes { position { x: -200.0 diff --git a/example/components/properties_panel/properties_panel.lua b/example/components/properties_panel/properties_panel.lua index 2d370d1..8093db5 100644 --- a/example/components/properties_panel/properties_panel.lua +++ b/example/components/properties_panel/properties_panel.lua @@ -4,11 +4,11 @@ local property_checkbox = require("example.components.properties_panel.propertie local property_slider = require("example.components.properties_panel.properties.property_slider") local property_button = require("example.components.properties_panel.properties.property_button") ----@class properties_panel: druid.base_component +---@class properties_panel: druid.component ---@field root druid.container ---@field text_no_properties druid.lang_text ---@field scroll druid.scroll ----@field druid druid_instance +---@field druid druid.instance local M = component.create("properties_panel") ---@param template string @@ -65,7 +65,7 @@ end ---@return property_checkbox function M:add_checkbox(text_id, initial_value, on_change_callback) local nodes = gui.clone_tree(self.property_checkbox_prefab) - local instance = self.druid:new(property_checkbox, "property_checkbox", nodes) --[[@as property_checkbox]] + local instance = self.druid:new_widget(property_checkbox, "property_checkbox", nodes) --[[@as property_checkbox]] instance.text_name:translate(text_id) instance:set_value(initial_value, true) instance.button.on_click:subscribe(function() @@ -87,7 +87,7 @@ end ---@return property_slider function M:add_slider(text_id, initial_value, on_change_callback) local nodes = gui.clone_tree(self.property_slider_prefab) - local instance = self.druid:new(property_slider, "property_slider", nodes) --[[@as property_slider]] + local instance = self.druid:new_widget(property_slider, "property_slider", nodes) --[[@as property_slider]] instance.text_name:translate(text_id) instance:set_value(initial_value, true) @@ -108,7 +108,7 @@ end ---@param on_click_callback function function M:add_button(text_id, on_click_callback) local nodes = gui.clone_tree(self.property_button_prefab) - local instance = self.druid:new(property_button, "property_button", nodes) --[[@as property_button]] + local instance = self.druid:new_widget(property_button, "property_button", nodes) --[[@as property_button]] instance.text_name:translate(text_id) gui.set_enabled(instance.root, true) diff --git a/example/druid.collection b/example/druid.collection index 5273ec0..009ffaa 100644 --- a/example/druid.collection +++ b/example/druid.collection @@ -5,35 +5,10 @@ embedded_instances { data: "components {\n" " id: \"druid\"\n" " component: \"/example/druid.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" + "}\n" + "components {\n" + " id: \"druid1\"\n" + " component: \"/druid/druid.script\"\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } diff --git a/example/druid.gui b/example/druid.gui index 1538aa4..b5ae34c 100644 --- a/example/druid.gui +++ b/example/druid.gui @@ -4713,9 +4713,6 @@ nodes { template_node_child: true } nodes { - position { - x: -200.0 - } type: TYPE_TEMPLATE id: "property_input" parent: "widgets" @@ -4788,6 +4785,25 @@ nodes { parent: "property_input/E_Anchor" template_node_child: true } +nodes { + type: TYPE_TEMPLATE + id: "example_tiling_node" + parent: "widgets" + inherit_alpha: true + template: "/example/examples/widgets/tiling_node/example_tiling_node.gui" +} +nodes { + type: TYPE_BOX + id: "example_tiling_node/root" + parent: "example_tiling_node" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "example_tiling_node/tiling_node" + parent: "example_tiling_node/root" + template_node_child: true +} nodes { position { x: -20.0 diff --git a/example/druid.gui_script b/example/druid.gui_script index 4b5c865..db779a9 100644 --- a/example/druid.gui_script +++ b/example/druid.gui_script @@ -2,6 +2,7 @@ local lang = require("lang.lang") local saver = require("saver.saver") local storage = require("saver.storage") local druid = require("druid.druid") +local helper = require("druid.helper") local druid_logo = require("example.components.druid_logo.druid_logo") local panel_information = require("example.components.panel_information.panel_information") @@ -14,7 +15,7 @@ local output_list = require("example.components.output_list.output_list") local druid_examples = require("example.examples.druid_examples") ---@class druid.example ----@field druid druid_instance +---@field druid druid.instance ---@field container_root druid.container ---@field container_left druid.container ---@field container_logo druid.container @@ -26,21 +27,27 @@ local druid_examples = require("example.examples.druid_examples") ---@field container_output druid.container ---@field container_center druid.container ---@field container_status druid.container ----@field druid_logo druid_logo +---@field druid_logo examples.druid_logo ---@field panel_information panel_information ----@field example_scene example_scene +---@field example_scene examples.example_scene ---@field panel_druid_profiler panel_druid_profiler ---@field examples_list_view examples_list_view ---@field properties_panel properties_panel ---@field output_list output_list +---@field next_example druid.hotkey +---@field previous_example druid.hotkey + + +---@param self druid.example +local function setup_saver(self) + saver.init() + saver.bind_save_state("lang", lang.state) +end --- Generic setup that should be done once per application ---@param self druid.example local function setup_druid(self) - saver.init() - saver.bind_save_state("lang", lang.state) - lang.init() lang.set_lang("en") -- Force default start language to EN, switch through the UI to check druid.set_text_function(lang.txp) @@ -72,15 +79,63 @@ local function setup_layout(self) end +---@param self druid.example +local function on_next_example(self) + local current_index = 1 + local examples = self.examples_list_view.examples + + -- Find current example index + for i, example in ipairs(examples) do + if example.data.name_id == self.examples_list_view.selected_example.data.name_id then + current_index = i + break + end + end + + -- Get next example index (wrap around to first if at end) + local next_index = current_index + 1 + if next_index > #examples then + next_index = 1 + end + + -- Select the next example + self.examples_list_view:select_example_by_name_id(examples[next_index].data.name_id) +end + + +---@param self druid.example +local function on_previous_example(self) + local current_index = 1 + local examples = self.examples_list_view.examples + + -- Find current example index + for i, example in ipairs(examples) do + if example.data.name_id == self.examples_list_view.selected_example.data.name_id then + current_index = i + break + end + end + + -- Get previous example index (wrap around to last if at start) + local prev_index = current_index - 1 + if prev_index < 1 then + prev_index = #examples + end + + -- Select the previous example + self.examples_list_view:select_example_by_name_id(examples[prev_index].data.name_id) +end + + ---@param self druid.example local function setup_components(self) - self.druid_logo = self.druid:new(druid_logo, "druid_logo") --[[@as druid_logo]] + self.druid_logo = self.druid:new(druid_logo, "druid_logo") --[[@as examples.druid_logo]] self.container_logo:add_container(self.druid_logo.root) self.panel_information = self.druid:new(panel_information, "panel_information") --[[@as panel_information]] self.container_info:add_container(self.panel_information.root) - self.example_scene = self.druid:new(example_scene, "example_scene") --[[@as example_scene]] + self.example_scene = self.druid:new(example_scene, "example_scene") --[[@as examples.example_scene]] self.container_center:add_container(self.example_scene.root) self.panel_druid_profiler = self.druid:new(panel_druid_profiler, "panel_druid_profiler") --[[@as panel_druid_profiler]] @@ -95,6 +150,9 @@ local function setup_components(self) self.output_list = self.druid:new(output_list, "output_list") --[[@as output_list]] self.container_output:add_container(self.output_list.root) + self.next_example = self.druid:new_hotkey("key_down", on_next_example, self) + self.previous_example = self.druid:new_hotkey("key_up", on_previous_example, self) + do -- Component bindings self.examples_list_view.on_debug_info:subscribe(function(info) self.example_scene:set_debug_info(info) @@ -172,8 +230,38 @@ local function setup_examples(self) end +---@param self druid.example +local function setup_defos(self) + local is_desktop = helper.is_desktop() + local is_debug = sys.get_engine_info().is_debug + + if is_desktop and is_debug then + timer.delay(1, true, function() + local x, y, w, h = defos.get_window_size() + saver.set_value("window.last_state", { x, y, w, h }) + saver.save_game_state() + end) + + -- Restore window size and position + local prev_settings = saver.get_value("window.last_state") + if prev_settings then + ---@cast prev_settings number[] + local x, y, w, h = unpack(prev_settings) + -- Limit size to 300x200 + x = vmath.clamp(x, 0, 4000) + y = vmath.clamp(y, 0, 4000) + w = vmath.clamp(w, 300, 4000) + h = vmath.clamp(h, 200, 4000) + defos.set_window_size(x, y, w, h) + end + end +end + + ---@param self druid.example function init(self) + setup_saver(self) + setup_defos(self) setup_druid(self) self.druid = druid.new(self) @@ -210,4 +298,4 @@ end ---@param action action function on_input(self, action_id, action) return self.druid:on_input(action_id, action) -end \ No newline at end of file +end diff --git a/example/examples/basic/back_handler/basic_back_handler.lua b/example/examples/basic/back_handler/basic_back_handler.lua index 4b9ee3a..a16c10a 100644 --- a/example/examples/basic/back_handler/basic_back_handler.lua +++ b/example/examples/basic/back_handler/basic_back_handler.lua @@ -1,14 +1,7 @@ -local component = require("druid.component") +---@class examples.basic_back_handler: druid.widget +local M = {} ----@class basic_back_handler: druid.base_component ----@field druid druid_instance -local M = component.create("basic_back_handler") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.druid:new_back_handler(self.on_back) end diff --git a/example/examples/basic/blocker/basic_blocker.gui b/example/examples/basic/blocker/basic_blocker.gui index 8736e65..67a37a8 100644 --- a/example/examples/basic/blocker/basic_blocker.gui +++ b/example/examples/basic/blocker/basic_blocker.gui @@ -56,6 +56,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button/root" + parent: "button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button/text" + parent: "button/root" + template_node_child: true +} nodes { position { x: -246.0 diff --git a/example/examples/basic/blocker/basic_blocker.lua b/example/examples/basic/blocker/basic_blocker.lua index 57bcfc0..e930bcd 100644 --- a/example/examples/basic/blocker/basic_blocker.lua +++ b/example/examples/basic/blocker/basic_blocker.lua @@ -1,17 +1,10 @@ -local component = require("druid.component") - ----@class basic_blocker: druid.base_component ----@field druid druid_instance +---@class examples.basic_blocker: druid.widget ---@field root node ---@field blocker druid.blocker -local M = component.create("basic_blocker") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.root = self:get_node("root") self.button_root = self.druid:new_button(self.root, self.on_root_click) @@ -31,4 +24,15 @@ function M:on_button_click() end +---@param output_log output_list +function M:on_example_created(output_log) + self.button_root.on_click:subscribe(function() + output_log:add_log_text("Root Clicked") + end) + self.button.on_click:subscribe(function() + output_log:add_log_text("Button Clicked") + end) +end + + return M diff --git a/example/examples/basic/button/basic_button.gui b/example/examples/basic/button/basic_button.gui index b6e5721..beacbe7 100644 --- a/example/examples/basic/button/basic_button.gui +++ b/example/examples/basic/button/basic_button.gui @@ -16,5 +16,17 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button/root" + parent: "button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button/text" + parent: "button/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/button/basic_button.lua b/example/examples/basic/button/basic_button.lua index 79172d6..3f6c162 100644 --- a/example/examples/basic/button/basic_button.lua +++ b/example/examples/basic/button/basic_button.lua @@ -1,19 +1,29 @@ -local component = require("druid.component") - ----@class basic_button: druid.base_component ----@field druid druid_instance +---@class examples.basic_button: druid.widget ---@field button druid.button -local M = component.create("basic_button") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.button = self.druid:new_button("button/root", function() print("Button pressed") end) end +---@param output_log output_list +function M:on_example_created(output_log) + self.button.on_click:subscribe(function() + output_log:add_log_text("Button Clicked") + end) +end + + +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local checkbox = properties_panel:add_checkbox("ui_enabled", false, function(value) + self.button:set_enabled(value) + end) + checkbox:set_value(true) +end + + return M diff --git a/example/examples/basic/button/basic_button_double_click.gui b/example/examples/basic/button/basic_button_double_click.gui index b6e5721..beacbe7 100644 --- a/example/examples/basic/button/basic_button_double_click.gui +++ b/example/examples/basic/button/basic_button_double_click.gui @@ -16,5 +16,17 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button/root" + parent: "button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button/text" + parent: "button/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/button/basic_button_double_click.lua b/example/examples/basic/button/basic_button_double_click.lua index 1889fe5..94444bd 100644 --- a/example/examples/basic/button/basic_button_double_click.lua +++ b/example/examples/basic/button/basic_button_double_click.lua @@ -1,15 +1,8 @@ -local component = require("druid.component") - ----@class basic_button_double_click: druid.base_component ----@field druid druid_instance +---@class examples.basic_button_double_click: druid.widget ---@field button druid.button -local M = component.create("basic_button_double_click") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.button = self.druid:new_button("button/root", function() print("Click") end) @@ -20,4 +13,15 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.button.on_click:subscribe(function() + output_log:add_log_text("Clicked") + end) + self.button.on_double_click:subscribe(function() + output_log:add_log_text("Double Clicked") + end) +end + + return M diff --git a/example/examples/basic/button/basic_button_hold.lua b/example/examples/basic/button/basic_button_hold.lua index 97d1a5b..925292a 100644 --- a/example/examples/basic/button/basic_button_hold.lua +++ b/example/examples/basic/button/basic_button_hold.lua @@ -1,19 +1,13 @@ -local component = require("druid.component") local panthera = require("panthera.panthera") local animation = require("example.examples.basic.button.basic_button_hold_panthera") ----@class basic_button_hold: druid.base_component ----@field druid druid_instance +---@class examples.basic_button_hold: druid.widget ---@field button druid.button -local M = component.create("basic_button_hold") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - - self.animation = panthera.create_gui(animation, self:get_template(), nodes) +function M:init() + self.animation = panthera.create_gui(animation, self:get_template(), self:get_nodes()) self.button = self.druid:new_button("button", function() print("Click") @@ -46,4 +40,15 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.button.on_click:subscribe(function() + output_log:add_log_text("Clicked") + end) + self.button.on_long_click:subscribe(function() + output_log:add_log_text("On long click") + end) +end + + return M diff --git a/example/examples/basic/button/basic_button_hold_panthera.lua b/example/examples/basic/button/basic_button_hold_panthera.lua index b63a4e2..646d4c9 100644 --- a/example/examples/basic/button/basic_button_hold_panthera.lua +++ b/example/examples/basic/button/basic_button_hold_panthera.lua @@ -1,266 +1,268 @@ return { - type = "animation_editor", - format = "json", data = { - nodes = { - }, animations = { { animation_id = "default", - duration = 1, animation_keys = { }, + duration = 1, }, { animation_id = "hold", - duration = 1, animation_keys = { { + easing = "outsine", end_value = -90, - easing = "outsine", - property_id = "rotation_z", + key_type = "tween", node_id = "button_image", - key_type = "tween", - }, - { - end_value = 90, - easing = "outsine", property_id = "rotation_z", + }, + { + easing = "outsine", + end_value = 90, + key_type = "tween", node_id = "mask", - key_type = "tween", + property_id = "rotation_z", }, { - end_value = 1.1, - easing = "outsine", - property_id = "scale_x", duration = 0.15, + easing = "outsine", + end_value = 1.1, key_type = "tween", node_id = "button", + property_id = "scale_x", start_value = 1, }, { - end_value = 1.1, - easing = "outsine", - property_id = "scale_y", duration = 0.15, + easing = "outsine", + end_value = 1.1, key_type = "tween", node_id = "button", - start_value = 1, - }, - { - end_value = 1.3, - easing = "outsine", - property_id = "scale_x", - duration = 0.15, - key_type = "tween", - node_id = "text", - start_value = 1, - }, - { - end_value = 1.3, - easing = "outsine", property_id = "scale_y", - duration = 0.15, - key_type = "tween", - node_id = "text", start_value = 1, }, { - start_value = 360, + duration = 0.15, easing = "outsine", - property_id = "fill_angle", + end_value = 1.3, + key_type = "tween", + node_id = "text", + property_id = "scale_x", + start_value = 1, + }, + { + duration = 0.15, + easing = "outsine", + end_value = 1.3, + key_type = "tween", + node_id = "text", + property_id = "scale_y", + start_value = 1, + }, + { duration = 1, + easing = "outsine", + key_type = "tween", node_id = "mask", - key_type = "tween", + property_id = "fill_angle", + start_value = 360, }, { - end_value = 1, - easing = "incirc", - property_id = "scale_x", duration = 0.85, - start_value = 1.1, + easing = "incirc", + end_value = 1, key_type = "tween", node_id = "button", + property_id = "scale_x", start_time = 0.15, + start_value = 1.1, }, { - end_value = 1, - easing = "incirc", - property_id = "scale_y", duration = 0.85, - start_value = 1.1, + easing = "incirc", + end_value = 1, key_type = "tween", node_id = "button", - start_time = 0.15, - }, - { - end_value = 1, - easing = "outsine", - property_id = "scale_x", - duration = 0.51, - start_value = 1.3, - key_type = "tween", - node_id = "text", - start_time = 0.49, - }, - { - end_value = 1, - easing = "outsine", property_id = "scale_y", + start_time = 0.15, + start_value = 1.1, + }, + { duration = 0.51, - start_value = 1.3, + easing = "outsine", + end_value = 1, key_type = "tween", node_id = "text", + property_id = "scale_x", start_time = 0.49, + start_value = 1.3, + }, + { + duration = 0.51, + easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "text", + property_id = "scale_y", + start_time = 0.49, + start_value = 1.3, }, }, + duration = 1, }, { animation_id = "complete", - duration = 0.4, animation_keys = { { - easing = "linear", - property_id = "inherit_alpha", data = "false", + easing = "linear", key_type = "trigger", node_id = "text", + property_id = "inherit_alpha", start_data = "true", }, { - end_value = 0.624, easing = "outsine", - property_id = "color_b", + end_value = 0.62, key_type = "tween", node_id = "button_image", + property_id = "color_b", start_value = 0.62, }, { - end_value = 0.875, easing = "outsine", - property_id = "color_g", + end_value = 0.88, key_type = "tween", node_id = "button_image", + property_id = "color_g", start_value = 0.835, }, { - end_value = 0.902, easing = "outsine", - property_id = "color_r", + end_value = 0.9, key_type = "tween", node_id = "button_image", + property_id = "color_r", start_value = 0.557, }, { + duration = 0.17, + easing = "outsine", end_value = 1.1, - easing = "outsine", + key_type = "tween", + node_id = "root", property_id = "color_a", - duration = 0.17, - key_type = "tween", - node_id = "root", start_value = 1, }, { - end_value = 1.2, + duration = 0.17, easing = "outsine", + end_value = 1.2, + key_type = "tween", + node_id = "root", property_id = "scale_x", - duration = 0.17, - key_type = "tween", - node_id = "root", start_value = 1, }, { + duration = 0.17, + easing = "outsine", end_value = 1.2, - easing = "outsine", - property_id = "scale_y", - duration = 0.17, key_type = "tween", node_id = "root", + property_id = "scale_y", start_value = 1, }, { - end_value = 0.557, + duration = 0.38, easing = "outsine", + end_value = 0.56, + key_type = "tween", + node_id = "button_image", property_id = "color_r", - duration = 0.38, - start_value = 0.902, - key_type = "tween", - node_id = "button_image", start_time = 0.02, + start_value = 0.9, }, { + duration = 0.38, + easing = "outsine", end_value = 0.62, - easing = "outsine", + key_type = "tween", + node_id = "button_image", property_id = "color_b", - duration = 0.38, - start_value = 0.624, - key_type = "tween", - node_id = "button_image", start_time = 0.02, + start_value = 0.62, }, { - end_value = 0.835, + duration = 0.38, easing = "outsine", + end_value = 0.84, + key_type = "tween", + node_id = "button_image", property_id = "color_g", - duration = 0.38, - start_value = 0.875, - key_type = "tween", - node_id = "button_image", start_time = 0.02, + start_value = 0.88, }, { - end_value = 1, + duration = 0.22, easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "root", property_id = "color_a", - duration = 0.22, + start_time = 0.17, start_value = 1.1, - key_type = "tween", - node_id = "root", - start_time = 0.17, }, { - end_value = 1, + duration = 0.22, easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "root", property_id = "scale_x", - duration = 0.22, - start_value = 1.2, - key_type = "tween", - node_id = "root", start_time = 0.17, + start_value = 1.2, }, { - end_value = 1, + duration = 0.22, easing = "outsine", - property_id = "scale_y", - duration = 0.22, - start_value = 1.2, + end_value = 1, key_type = "tween", node_id = "root", + property_id = "scale_y", start_time = 0.17, + start_value = 1.2, }, { - easing = "linear", - property_id = "inherit_alpha", - start_data = "false", data = "true", + easing = "linear", key_type = "trigger", node_id = "text", + property_id = "inherit_alpha", + start_data = "false", start_time = 0.39, }, }, + duration = 0.4, }, }, metadata = { - layers = { + fps = 60, + gizmo_steps = { }, gui_path = "/example/examples/basic/button/basic_button_hold.gui", - gizmo_steps = { + layers = { }, settings = { font_size = 40, }, - fps = 60, + template_animation_paths = { + }, + }, + nodes = { }, }, + format = "json", + type = "animation_editor", version = 1, } \ No newline at end of file diff --git a/example/examples/basic/checkbox/checkbox.lua b/example/examples/basic/checkbox/checkbox.lua index cd27d26..d8dee22 100644 --- a/example/examples/basic/checkbox/checkbox.lua +++ b/example/examples/basic/checkbox/checkbox.lua @@ -1,17 +1,12 @@ -local component = require("druid.component") local event = require("event.event") ----@class checkbox: druid.base_component ----@field druid druid_instance +---@class examples.checkbox: druid.widget ---@field button druid.button -local M = component.create("checkbox") +---@field is_enabled boolean +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.button = self.druid:new_button("root", self.on_checkbox_click) -- Button to handle checkbox self.icon = self:get_node("icon") -- Checkbox icon to hide/show self.selected = self:get_node("selected") -- Selected effect to show when checkbox is changed @@ -47,4 +42,12 @@ function M:get_state() end +---@param output_log output_list +function M:on_example_created(output_log) + self.button.on_click:subscribe(function() + output_log:add_log_text("Checkbox Clicked: " .. tostring(self.is_enabled)) + end) +end + + return M diff --git a/example/examples/basic/checkbox_group/checkbox_group.gui b/example/examples/basic/checkbox_group/checkbox_group.gui index a51e797..2eeaef4 100644 --- a/example/examples/basic/checkbox_group/checkbox_group.gui +++ b/example/examples/basic/checkbox_group/checkbox_group.gui @@ -27,6 +27,30 @@ nodes { inherit_alpha: true template: "/example/examples/basic/checkbox/checkbox.gui" } +nodes { + type: TYPE_BOX + id: "checkbox_1/root" + parent: "checkbox_1" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_1/button" + parent: "checkbox_1/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_1/icon" + parent: "checkbox_1/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_1/selected" + parent: "checkbox_1/button" + template_node_child: true +} nodes { type: TYPE_TEMPLATE id: "checkbox_2" @@ -34,6 +58,30 @@ nodes { inherit_alpha: true template: "/example/examples/basic/checkbox/checkbox.gui" } +nodes { + type: TYPE_BOX + id: "checkbox_2/root" + parent: "checkbox_2" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_2/button" + parent: "checkbox_2/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_2/icon" + parent: "checkbox_2/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_2/selected" + parent: "checkbox_2/button" + template_node_child: true +} nodes { position { x: 100.0 @@ -44,5 +92,29 @@ nodes { inherit_alpha: true template: "/example/examples/basic/checkbox/checkbox.gui" } +nodes { + type: TYPE_BOX + id: "checkbox_3/root" + parent: "checkbox_3" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_3/button" + parent: "checkbox_3/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_3/icon" + parent: "checkbox_3/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_3/selected" + parent: "checkbox_3/button" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/checkbox_group/checkbox_group.lua b/example/examples/basic/checkbox_group/checkbox_group.lua index 2ef54ce..ec01ffe 100644 --- a/example/examples/basic/checkbox_group/checkbox_group.lua +++ b/example/examples/basic/checkbox_group/checkbox_group.lua @@ -1,23 +1,19 @@ local event = require("event.event") -local component = require("druid.component") -- Require checkbox component from checkbox example local checkbox = require("example.examples.basic.checkbox.checkbox") ----@class checkbox_group: druid.base_component ----@field druid druid_instance ----@field button druid.button -local M = component.create("checkbox_group") +---@class examples.checkbox_group: druid.widget +---@field checkbox_1 examples.checkbox +---@field checkbox_2 examples.checkbox +---@field checkbox_3 examples.checkbox +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - - self.checkbox_1 = self.druid:new(checkbox, "checkbox_1") - self.checkbox_2 = self.druid:new(checkbox, "checkbox_2") - self.checkbox_3 = self.druid:new(checkbox, "checkbox_3") +function M:init() + self.checkbox_1 = self.druid:new_widget(checkbox, "checkbox_1") + self.checkbox_2 = self.druid:new_widget(checkbox, "checkbox_2") + self.checkbox_3 = self.druid:new_widget(checkbox, "checkbox_3") self.checkbox_1.on_state_changed:subscribe(self.on_checkbox_click, self) self.checkbox_2.on_state_changed:subscribe(self.on_checkbox_click, self) @@ -36,4 +32,12 @@ function M:on_checkbox_click() end +---@param output_log output_list +function M:on_example_created(output_log) + self.on_state_changed:subscribe(function(state1, state2, state3) + output_log:add_log_text("State: " .. tostring(state1) .. " " .. tostring(state2) .. " " .. tostring(state3)) + end) +end + + return M diff --git a/example/examples/basic/drag/drag.gui b/example/examples/basic/drag/drag.gui index c4ea468..a0f03f3 100644 --- a/example/examples/basic/drag/drag.gui +++ b/example/examples/basic/drag/drag.gui @@ -19,5 +19,17 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_blue.gui" } +nodes { + type: TYPE_BOX + id: "drag/root" + parent: "drag" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "drag/text" + parent: "drag/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/drag/drag.lua b/example/examples/basic/drag/drag.lua index fa51ad4..175b51f 100644 --- a/example/examples/basic/drag/drag.lua +++ b/example/examples/basic/drag/drag.lua @@ -1,15 +1,7 @@ -local component = require("druid.component") - ----@class drag: druid.base_component ----@field druid druid_instance -local M = component.create("drag") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +---@class examples.drag: druid.widget +local M = {} +function M:init() -- Init drag and move the drag node on drag callback self.drag = self.druid:new_drag("drag/root", function(_, dx, dy) local position_x = gui.get(self.drag.node, "position.x") @@ -25,5 +17,4 @@ function M:init(template, nodes) end) end - return M diff --git a/example/examples/basic/drag/drag_to_node.gui b/example/examples/basic/drag/drag_to_node.gui index 1bc8e22..2bbe09a 100644 --- a/example/examples/basic/drag/drag_to_node.gui +++ b/example/examples/basic/drag/drag_to_node.gui @@ -23,6 +23,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_blue.gui" } +nodes { + type: TYPE_BOX + id: "drag/root" + parent: "drag" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "drag/text" + parent: "drag/root" + template_node_child: true +} nodes { position { y: 300.0 diff --git a/example/examples/basic/drag/drag_to_node.lua b/example/examples/basic/drag/drag_to_node.lua index eb927f9..61d2260 100644 --- a/example/examples/basic/drag/drag_to_node.lua +++ b/example/examples/basic/drag/drag_to_node.lua @@ -1,14 +1,7 @@ -local component = require("druid.component") +---@class examples.drag_to_node: druid.widget +local M = {} ----@class drag_to_node: druid.base_component ----@field druid druid_instance -local M = component.create("drag_to_node") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.zone = self:get_node("zone") self.counter = 0 self.text_counter = self:get_node("text_counter") diff --git a/example/examples/basic/examples_list.lua b/example/examples/basic/examples_list.lua index e130afb..ebf5071 100644 --- a/example/examples/basic/examples_list.lua +++ b/example/examples/basic/examples_list.lua @@ -1,5 +1,3 @@ -local const = require("druid.const") -local helper = require("druid.helper") local M = {} function M.get_examples() @@ -11,21 +9,7 @@ function M.get_examples() template = "basic_button", root = "basic_button/root", code_url = "example/examples/basic/button/basic_button.lua", - component_class = require("example.examples.basic.button.basic_button"), - properties_control = function(instance, properties_panel) - ---@cast instance basic_button - - local checkbox = properties_panel:add_checkbox("ui_enabled", false, function(value) - instance.button:set_enabled(value) - end) - checkbox:set_value(true) - end, - on_create = function(instance, output_log) - ---@cast instance basic_button - instance.button.on_click:subscribe(function() - output_log:add_log_text("Button Clicked") - end) - end, + widget_class = require("example.examples.basic.button.basic_button"), }, { name_id = "ui_example_basic_button_double_click", @@ -33,16 +17,7 @@ function M.get_examples() template = "basic_button_double_click", root = "basic_button_double_click/root", code_url = "example/examples/basic/button/basic_button_double_click.lua", - component_class = require("example.examples.basic.button.basic_button_double_click"), - on_create = function(instance, output_log) - ---@cast instance basic_button_double_click - instance.button.on_click:subscribe(function() - output_log:add_log_text("Clicked") - end) - instance.button.on_double_click:subscribe(function() - output_log:add_log_text("Double Clicked") - end) - end, + widget_class = require("example.examples.basic.button.basic_button_double_click"), }, { name_id = "ui_example_basic_button_hold", @@ -50,16 +25,7 @@ function M.get_examples() template = "basic_button_hold", root = "basic_button_hold/root", code_url = "example/examples/basic/button/basic_button_hold.lua", - component_class = require("example.examples.basic.button.basic_button_hold"), - on_create = function(instance, output_log) - ---@cast instance basic_button_hold - instance.button.on_click:subscribe(function() - output_log:add_log_text("Clicked") - end) - instance.button.on_long_click:subscribe(function() - output_log:add_log_text("On long click") - end) - end, + widget_class = require("example.examples.basic.button.basic_button_hold"), }, { name_id = "ui_example_basic_text", @@ -67,57 +33,7 @@ function M.get_examples() template = "basic_text", root = "basic_text/root", code_url = "example/examples/basic/text/basic_text.lua", - component_class = require("example.examples.basic.text.basic_text"), - properties_control = function(instance, properties_panel) - ---@cast instance basic_text - - local adjust_index = 1 - local adjust_types = { - const.TEXT_ADJUST.DOWNSCALE, - const.TEXT_ADJUST.DOWNSCALE_LIMITED, - --const.TEXT_ADJUST.SCALE_THEN_SCROLL, -- works bad with container for some reason - --const.TEXT_ADJUST.SCROLL, -- works bad with container for some reason - const.TEXT_ADJUST.TRIM, - } - properties_panel:add_button("ui_adjust_next", function() - adjust_index = adjust_index + 1 - if adjust_index > #adjust_types then - adjust_index = 1 - end - instance.text:set_text_adjust(adjust_types[adjust_index], 0.5) - end) - - local pivot_index = 1 - local pivot_list = { - gui.PIVOT_CENTER, - gui.PIVOT_W, - gui.PIVOT_SW, - gui.PIVOT_S, - gui.PIVOT_SE, - gui.PIVOT_E, - gui.PIVOT_NE, - gui.PIVOT_N, - gui.PIVOT_NW, - } - - ---@cast instance rich_text_tags - properties_panel:add_button("ui_pivot_next", function() - pivot_index = pivot_index + 1 - if pivot_index > #pivot_list then - pivot_index = 1 - end - instance:set_pivot(pivot_list[pivot_index]) - end) - end, - get_debug_info = function(instance) - ---@cast instance multiline_text - local info = "" - - info = info .. "Text Adjust: " .. instance.text.adjust_type .. "\n" - info = info .. "Pivot: " .. gui.get_pivot(instance.text.node) .. "\n" - - return info - end + widget_class = require("example.examples.basic.text.basic_text"), }, { name_id = "ui_example_basic_multiline_text", @@ -125,56 +41,7 @@ function M.get_examples() template = "multiline_text", root = "multiline_text/root", code_url = "example/examples/basic/text/multiline_text.lua", - component_class = require("example.examples.basic.text.multiline_text"), - properties_control = function(instance, properties_panel) - ---@cast instance multiline_text - - local adjust_index = 1 - local adjust_types = { - const.TEXT_ADJUST.DOWNSCALE, - const.TEXT_ADJUST.DOWNSCALE_LIMITED, - --const.TEXT_ADJUST.SCALE_THEN_SCROLL, -- works bad with container for some reason - --const.TEXT_ADJUST.SCROLL, -- works bad with container for some reason - const.TEXT_ADJUST.TRIM, - } - properties_panel:add_button("ui_adjust_next", function() - adjust_index = adjust_index + 1 - if adjust_index > #adjust_types then - adjust_index = 1 - end - instance.text:set_text_adjust(adjust_types[adjust_index], 0.8) - end) - - local pivot_index = 1 - local pivot_list = { - gui.PIVOT_CENTER, - gui.PIVOT_W, - gui.PIVOT_SW, - gui.PIVOT_S, - gui.PIVOT_SE, - gui.PIVOT_E, - gui.PIVOT_NE, - gui.PIVOT_N, - gui.PIVOT_NW, - } - - properties_panel:add_button("ui_pivot_next", function() - pivot_index = pivot_index + 1 - if pivot_index > #pivot_list then - pivot_index = 1 - end - instance:set_pivot(pivot_list[pivot_index]) - end) - end, - get_debug_info = function(instance) - ---@cast instance multiline_text - local info = "" - - info = info .. "Text Adjust: " .. instance.text.adjust_type .. "\n" - info = info .. "Pivot: " .. gui.get_pivot(instance.text.node) .. "\n" - - return info - end + widget_class = require("example.examples.basic.text.multiline_text"), }, { name_id = "ui_example_basic_hover", @@ -182,7 +49,7 @@ function M.get_examples() template = "hover", root = "hover/root", code_url = "example/examples/basic/hover/hover.lua", - component_class = require("example.examples.basic.hover.hover"), + widget_class = require("example.examples.basic.hover.hover"), }, { name_id = "ui_example_basic_drag", @@ -190,7 +57,7 @@ function M.get_examples() template = "drag", root = "drag/root", code_url = "example/examples/basic/drag/drag.lua", - component_class = require("example.examples.basic.drag.drag"), + widget_class = require("example.examples.basic.drag.drag"), }, { name_id = "ui_example_basic_drag_to_node", @@ -198,7 +65,7 @@ function M.get_examples() template = "drag_to_node", root = "drag_to_node/root", code_url = "example/examples/basic/drag/drag_to_node.lua", - component_class = require("example.examples.basic.drag.drag_to_node"), + widget_class = require("example.examples.basic.drag.drag_to_node"), }, { name_id = "ui_example_basic_slider", @@ -206,14 +73,7 @@ function M.get_examples() template = "basic_slider", root = "basic_slider/root", code_url = "example/examples/basic/slider/basic_slider.lua", - component_class = require("example.examples.basic.slider.basic_slider"), - on_create = function(instance, output_log) - ---@cast instance basic_slider - instance.slider.on_change_value:subscribe(function(_, value) - local value = helper.round(value, 2) - output_log:add_log_text("Slider Value: " .. value) - end) - end, + widget_class = require("example.examples.basic.slider.basic_slider"), }, { name_id = "ui_example_basic_slider_vertical", @@ -221,14 +81,7 @@ function M.get_examples() template = "basic_slider_vertical", root = "basic_slider_vertical/root", code_url = "example/examples/basic/slider/basic_slider_vertical.lua", - component_class = require("example.examples.basic.slider.basic_slider_vertical"), - on_create = function(instance, output_log) - ---@cast instance basic_slider_vertical - instance.slider.on_change_value:subscribe(function(_, value) - local value = helper.round(value, 2) - output_log:add_log_text("Slider Value: " .. value) - end) - end, + widget_class = require("example.examples.basic.slider.basic_slider_vertical"), }, { name_id = "ui_example_basic_slider_stepped", @@ -236,14 +89,7 @@ function M.get_examples() template = "basic_slider_stepped", root = "basic_slider_stepped/root", code_url = "example/examples/basic/slider/basic_slider_stepped.lua", - component_class = require("example.examples.basic.slider.basic_slider_stepped"), - on_create = function(instance, output_log) - ---@cast instance basic_slider - instance.slider.on_change_value:subscribe(function(_, value) - local value = helper.round(value, 2) - output_log:add_log_text("Slider Value: " .. value) - end) - end, + widget_class = require("example.examples.basic.slider.basic_slider_stepped"), }, { name_id = "ui_example_basic_progress_bar", @@ -251,13 +97,7 @@ function M.get_examples() template = "basic_progress_bar", root = "basic_progress_bar/root", code_url = "example/examples/basic/progress_bar/basic_progress_bar.lua", - component_class = require("example.examples.basic.progress_bar.basic_progress_bar"), - properties_control = function(instance, properties_panel) - ---@cast instance basic_progress_bar - properties_panel:add_slider("ui_value", 1, function(value) - instance:set_value(value) - end) - end, + widget_class = require("example.examples.basic.progress_bar.basic_progress_bar"), }, { name_id = "ui_example_basic_progress_bar_slice9", @@ -265,13 +105,7 @@ function M.get_examples() template = "basic_progress_bar_slice9", root = "basic_progress_bar_slice9/root", code_url = "example/examples/basic/progress_bar/basic_progress_bar_slice9.lua", - component_class = require("example.examples.basic.progress_bar.basic_progress_bar_slice9"), - properties_control = function(instance, properties_panel) - ---@cast instance basic_progress_bar_slice9 - properties_panel:add_slider("ui_value", 1, function(value) - instance:set_value(value) - end) - end, + widget_class = require("example.examples.basic.progress_bar.basic_progress_bar_slice9"), }, { name_id = "ui_example_basic_blocker", @@ -279,16 +113,7 @@ function M.get_examples() template = "basic_blocker", root = "basic_blocker/root", code_url = "example/examples/basic/blocker/basic_blocker.lua", - component_class = require("example.examples.basic.blocker.basic_blocker"), - on_create = function(instance, output_log) - ---@cast instance basic_blocker - instance.button_root.on_click:subscribe(function() - output_log:add_log_text("Root Clicked") - end) - instance.button.on_click:subscribe(function() - output_log:add_log_text("Button Clicked") - end) - end, + widget_class = require("example.examples.basic.blocker.basic_blocker"), }, { name_id = "ui_example_basic_back_handler", @@ -296,7 +121,7 @@ function M.get_examples() template = "basic_back_handler", root = "basic_back_handler/root", code_url = "example/examples/basic/back_handler/basic_back_handler.lua", - component_class = require("example.examples.basic.back_handler.basic_back_handler"), + widget_class = require("example.examples.basic.back_handler.basic_back_handler"), }, { name_id = "ui_example_basic_timer", @@ -304,13 +129,7 @@ function M.get_examples() template = "basic_timer", root = "basic_timer/root", code_url = "example/examples/basic/timer/basic_timer.lua", - component_class = require("example.examples.basic.timer.basic_timer"), - on_create = function(instance, output_log) - ---@cast instance basic_timer - instance.on_cycle_end:subscribe(function() - output_log:add_log_text("Timer Cycle End") - end) - end, + widget_class = require("example.examples.basic.timer.basic_timer"), }, { name_id = "ui_example_basic_hotkey", @@ -318,13 +137,7 @@ function M.get_examples() template = "basic_hotkey", root = "basic_hotkey/root", code_url = "example/examples/basic/hotkey/basic_hotkey.lua", - component_class = require("example.examples.basic.hotkey.basic_hotkey"), - on_create = function(instance, output_log) - ---@cast instance basic_hotkey - instance.hotkey.on_hotkey_released:subscribe(function() - output_log:add_log_text("Hotkey Released") - end) - end, + widget_class = require("example.examples.basic.hotkey.basic_hotkey"), }, { name_id = "ui_example_basic_scroll", @@ -332,71 +145,7 @@ function M.get_examples() template = "scroll", root = "scroll/root", code_url = "example/examples/basic/scroll/scroll.lua", - component_class = require("example.examples.basic.scroll.scroll"), - on_create = function(instance, output_log) - ---@cast instance scroll - instance.button_tutorial.on_click:subscribe(function() - output_log:add_log_text("Button Tutorial Clicked") - end) - instance.button_stencil.on_click:subscribe(function() - output_log:add_log_text("Button Stencil Clicked") - end) - end, - properties_control = function(instance, properties_panel) - ---@cast instance scroll - local scroll = instance.scroll - local is_stretch = instance.scroll.style.EXTRA_STRETCH_SIZE > 0 - properties_panel:add_checkbox("ui_elastic_scroll", is_stretch, function(value) - instance.scroll:set_extra_stretch_size(value and 100 or 0) - end) - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - local slider_frict = properties_panel:add_slider("ui_slider_friction", 0, function(value) - scroll.style.FRICT = 1 - ((1 - value) * 0.1) - end) - slider_frict:set_text_function(function(value) - return string.format("%.2f", 1 - ((1 - value) * 0.1)) - end) - slider_frict:set_value(1 - (1 - scroll.style.FRICT) / 0.1) - - local slider_speed = properties_panel:add_slider("ui_slider_speed", 0, function(value) - scroll.style.INERT_SPEED = value * 50 - end) - slider_speed:set_value(scroll.style.INERT_SPEED / 50) - slider_speed:set_text_function(function(value) - return string.format("%.1f", value * 50) - end) - - local slider_wheel_speed = properties_panel:add_slider("ui_slider_wheel_speed", 0, function(value) - scroll.style.WHEEL_SCROLL_SPEED = value * 30 - end) - slider_wheel_speed:set_value(scroll.style.WHEEL_SCROLL_SPEED / 30) - slider_wheel_speed:set_text_function(function(value) - return string.format("%.1f", value * 30) - end) - - local wheel_by_inertion = properties_panel:add_checkbox("ui_wheel_by_inertion", scroll.style.WHEEL_SCROLL_BY_INERTION, function(value) - scroll.style.WHEEL_SCROLL_BY_INERTION = value - end) - wheel_by_inertion:set_value(scroll.style.WHEEL_SCROLL_BY_INERTION) - end, - get_debug_info = function(instance) - ---@cast instance scroll - local info = "" - - local s = instance.scroll - info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" - info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" - info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" - info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" - - return info - end + widget_class = require("example.examples.basic.scroll.scroll"), }, { name_id = "ui_example_basic_scroll_slider", @@ -404,19 +153,7 @@ function M.get_examples() template = "scroll_slider", root = "scroll_slider/root", code_url = "example/examples/basic/scroll_slider/scroll_slider.lua", - component_class = require("example.examples.basic.scroll_slider.scroll_slider"), - get_debug_info = function(instance) - ---@cast instance scroll_slider - local info = "" - - local s = instance.scroll - info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" - info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" - info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" - info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" - - return info - end + widget_class = require("example.examples.basic.scroll_slider.scroll_slider"), }, { name_id = "ui_example_basic_grid", @@ -424,87 +161,7 @@ function M.get_examples() template = "grid", root = "grid/root", code_url = "example/examples/basic/grid/grid.lua", - component_class = require("example.examples.basic.grid.grid"), - properties_control = function(instance, properties_panel) - ---@cast instance grid - - local grid = instance.grid - - local slider = properties_panel:add_slider("ui_grid_in_row", 0.3, function(value) - local in_row_amount = math.ceil(value * 10) - in_row_amount = math.max(1, in_row_amount) - grid:set_in_row(in_row_amount) - end) - slider:set_text_function(function(value) - return tostring(math.ceil(value * 10)) - end) - - properties_panel:add_button("ui_add_element", function() - if #instance.created_nodes >= 36 then - return - end - instance:add_element() - end) - - properties_panel:add_button("ui_remove_element", function() - instance:remove_element() - end) - - properties_panel:add_button("ui_clear_elements", function() - instance:clear() - end) - - properties_panel:add_checkbox("ui_dynamic_pos", grid.style.IS_DYNAMIC_NODE_POSES, function() - grid.style.IS_DYNAMIC_NODE_POSES = not grid.style.IS_DYNAMIC_NODE_POSES - grid:refresh() - end) - - properties_panel:add_checkbox("ui_align_last_row", grid.style.IS_ALIGN_LAST_ROW, function() - grid.style.IS_ALIGN_LAST_ROW = not grid.style.IS_ALIGN_LAST_ROW - grid:refresh() - end) - - local pivot_index = 1 - local pivot_list = { - gui.PIVOT_CENTER, - gui.PIVOT_W, - gui.PIVOT_SW, - gui.PIVOT_S, - gui.PIVOT_SE, - gui.PIVOT_E, - gui.PIVOT_NE, - gui.PIVOT_N, - gui.PIVOT_NW, - } - - properties_panel:add_button("ui_pivot_next", function() - pivot_index = pivot_index + 1 - if pivot_index > #pivot_list then - pivot_index = 1 - end - grid:set_pivot(pivot_list[pivot_index]) - end) - - local slider_size = properties_panel:add_slider("ui_item_size", 0.5, function(value) - local size = 50 + value * 100 - grid:set_item_size(size, size) - end) - slider_size:set_text_function(function(value) - return tostring(50 + math.ceil(value * 100)) - end) - slider_size:set_value(0.5) - end, - get_debug_info = function(instance) - ---@cast instance grid - local info = "" - - local grid = instance.grid - info = info .. "Grid Items: " .. #grid.nodes .. "\n" - info = info .. "Grid Item Size: " .. grid.node_size.x .. " x " .. grid.node_size.y .. "\n" - info = info .. "Pivot: " .. tostring(grid.pivot) - - return info - end + widget_class = require("example.examples.basic.grid.grid"), }, { name_id = "ui_example_basic_scroll_bind_grid", @@ -512,52 +169,7 @@ function M.get_examples() template = "scroll_bind_grid", root = "scroll_bind_grid/root", code_url = "example/examples/basic/scroll_bind_grid/scroll_bind_grid.lua", - component_class = require("example.examples.basic.scroll_bind_grid.scroll_bind_grid"), - properties_control = function(instance, properties_panel) - ---@cast instance scroll_bind_grid - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - properties_panel:add_button("ui_add_element", function() - if #instance.created_nodes >= 100 then - return - end - instance:add_element() - end) - - properties_panel:add_button("ui_remove_element", function() - instance:remove_element() - end) - - properties_panel:add_button("ui_clear_elements", function() - instance:clear() - end) - end, - get_debug_info = function(instance) - ---@cast instance scroll_bind_grid - local info = "" - - local s = instance.scroll - local view_node_size = gui.get(s.view_node, "size.y") - local scroll_position = -s.position - local scroll_bottom_position = vmath.vector3(scroll_position.x, scroll_position.y - view_node_size, scroll_position.z) - - info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" - info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" - info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" - info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" - info = info .. "Grid Items: " .. #instance.grid.nodes .. "\n" - info = info .. "Grid Item Size: " .. instance.grid.node_size.x .. " x " .. instance.grid.node_size.y .. "\n" - info = info .. "Top Scroll Pos Grid Index: " .. instance.grid:get_index(scroll_position) .. "\n" - info = info .. "Bottm Scroll Pos Grid Index: " .. instance.grid:get_index(scroll_bottom_position) .. "\n" - - - return info - end + widget_class = require("example.examples.basic.scroll_bind_grid.scroll_bind_grid"), }, { name_id = "ui_example_basic_scroll_bind_grid_horizontal", @@ -565,53 +177,7 @@ function M.get_examples() template = "scroll_bind_grid_horizontal", root = "scroll_bind_grid_horizontal/root", code_url = "example/examples/basic/scroll_bind_grid/scroll_bind_grid_horizontal.lua", - component_class = require("example.examples.basic.scroll_bind_grid.scroll_bind_grid_horizontal"), - properties_control = function(instance, properties_panel) - ---@cast instance scroll_bind_grid_horizontal - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - - properties_panel:add_button("ui_add_element", function() - if #instance.created_nodes >= 100 then - return - end - instance:add_element() - end) - - properties_panel:add_button("ui_remove_element", function() - instance:remove_element() - end) - - properties_panel:add_button("ui_clear_elements", function() - instance:clear() - end) - end, - get_debug_info = function(instance) - ---@cast instance scroll_bind_grid_horizontal - local info = "" - - local s = instance.scroll - local view_node_size = gui.get(s.view_node, "size.x") - local scroll_position = -s.position - local scroll_bottom_position = vmath.vector3(scroll_position.x + view_node_size, scroll_position.y, scroll_position.z) - - info = info .. "View Size X: " .. gui.get(s.view_node, "size.x") .. "\n" - info = info .. "Content Size X: " .. gui.get(s.content_node, "size.x") .. "\n" - info = info .. "Content position X: " .. math.ceil(s.position.x) .. "\n" - info = info .. "Content Range X: " .. s.available_pos.x .. " - " .. s.available_pos.z .. "\n" - info = info .. "Grid Items: " .. #instance.grid.nodes .. "\n" - info = info .. "Grid Item Size: " .. instance.grid.node_size.x .. " x " .. instance.grid.node_size.y .. "\n" - info = info .. "Left Scroll Pos Grid Index: " .. instance.grid:get_index(scroll_position) .. "\n" - info = info .. "Right Scroll Pos Grid Index: " .. instance.grid:get_index(scroll_bottom_position) .. "\n" - - return info - end + widget_class = require("example.examples.basic.scroll_bind_grid.scroll_bind_grid_horizontal"), }, { name_id = "ui_example_basic_scroll_bind_grid_points", @@ -619,52 +185,7 @@ function M.get_examples() template = "scroll_bind_grid_points", root = "scroll_bind_grid_points/root", code_url = "example/examples/basic/scroll_bind_grid/scroll_bind_grid_points.lua", - component_class = require("example.examples.basic.scroll_bind_grid.scroll_bind_grid_points"), - properties_control = function(instance, properties_panel) - ---@cast instance scroll_bind_grid_points - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - properties_panel:add_button("ui_add_element", function() - if #instance.created_nodes >= 100 then - return - end - instance:add_element() - end) - - properties_panel:add_button("ui_remove_element", function() - instance:remove_element() - end) - - properties_panel:add_button("ui_clear_elements", function() - instance:clear() - end) - end, - get_debug_info = function(instance) - ---@cast instance scroll_bind_grid_points - local info = "" - - local s = instance.scroll - local view_node_size = gui.get(s.view_node, "size.y") - local scroll_position = -s.position - local scroll_bottom_position = vmath.vector3(scroll_position.x, scroll_position.y - view_node_size, scroll_position.z) - - info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" - info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" - info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" - info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" - info = info .. "Grid Items: " .. #instance.grid.nodes .. "\n" - info = info .. "Grid Item Size: " .. instance.grid.node_size.x .. " x " .. instance.grid.node_size.y .. "\n" - info = info .. "Top Scroll Pos Grid Index: " .. instance.grid:get_index(scroll_position) .. "\n" - info = info .. "Bottm Scroll Pos Grid Index: " .. instance.grid:get_index(scroll_bottom_position) .. "\n" - - - return info - end + widget_class = require("example.examples.basic.scroll_bind_grid.scroll_bind_grid_points"), }, { name_id = "ui_example_basic_input", @@ -672,16 +193,7 @@ function M.get_examples() template = "basic_input", root = "basic_input/root", code_url = "example/examples/basic/input/basic_input.lua", - component_class = require("example.examples.basic.input.basic_input"), - on_create = function(instance, output_log) - ---@cast instance basic_input - instance.input.on_input_unselect:subscribe(function(_, text) - output_log:add_log_text("Input: " .. text) - end) - instance.input_2.on_input_unselect:subscribe(function(_, text) - output_log:add_log_text("Input 2: " .. text) - end) - end, + widget_class = require("example.examples.basic.input.basic_input"), }, { name_id = "ui_example_input_password", @@ -689,13 +201,7 @@ function M.get_examples() template = "input_password", root = "input_password/root", code_url = "example/examples/basic/input/input_password.lua", - component_class = require("example.examples.basic.input.input_password"), - on_create = function(instance, output_log) - ---@cast instance input_password - instance.input.on_input_unselect:subscribe(function(_, text) - output_log:add_log_text("Input: " .. text) - end) - end, + widget_class = require("example.examples.basic.input.input_password"), }, { name_id = "ui_example_basic_rich_input", @@ -703,16 +209,7 @@ function M.get_examples() template = "basic_rich_input", root = "basic_rich_input/root", code_url = "example/examples/basic/input/rich_input.lua", - component_class = require("example.examples.basic.input.rich_input"), - on_create = function(instance, output_log) - ---@cast instance rich_input - instance.rich_input.input.on_input_unselect:subscribe(function(_, text) - output_log:add_log_text("Input: " .. text) - end) - instance.rich_input_2.input.on_input_unselect:subscribe(function(_, text) - output_log:add_log_text("Input 2: " .. text) - end) - end, + widget_class = require("example.examples.basic.input.rich_input"), }, { name_id = "ui_example_basic_rich_text", @@ -720,7 +217,7 @@ function M.get_examples() template = "basic_rich_text", root = "basic_rich_text/root", code_url = "example/examples/basic/rich_text/basic_rich_text.lua", - component_class = require("example.examples.basic.rich_text.basic_rich_text"), + widget_class = require("example.examples.basic.rich_text.basic_rich_text"), }, { name_id = "ui_example_rich_text_tags", @@ -728,30 +225,7 @@ function M.get_examples() template = "rich_text_tags", root = "rich_text_tags/root", code_url = "example/examples/basic/rich_text/rich_text_tags.lua", - component_class = require("example.examples.basic.rich_text.rich_text_tags"), - properties_control = function(instance, properties_panel) - local pivot_index = 1 - local pivot_list = { - gui.PIVOT_CENTER, - gui.PIVOT_W, - gui.PIVOT_SW, - gui.PIVOT_S, - gui.PIVOT_SE, - gui.PIVOT_E, - gui.PIVOT_NE, - gui.PIVOT_N, - gui.PIVOT_NW, - } - - ---@cast instance rich_text_tags - properties_panel:add_button("ui_pivot_next", function() - pivot_index = pivot_index + 1 - if pivot_index > #pivot_list then - pivot_index = 1 - end - instance:set_pivot(pivot_list[pivot_index]) - end) - end + widget_class = require("example.examples.basic.rich_text.rich_text_tags"), }, --{ -- name_id = "ui_example_rich_text_tags_custom", @@ -797,13 +271,7 @@ function M.get_examples() template = "basic_swipe", root = "basic_swipe/root", code_url = "example/examples/basic/swipe/basic_swipe.lua", - component_class = require("example.examples.basic.swipe.basic_swipe"), - on_create = function(instance, output_log) - ---@cast instance basic_swipe - instance.swipe.on_swipe:subscribe(function(_, side, dist, delta_time) - output_log:add_log_text("Swipe Side: " .. side) - end) - end, + widget_class = require("example.examples.basic.swipe.basic_swipe"), }, { name_id = "ui_example_checkbox", @@ -811,13 +279,7 @@ function M.get_examples() template = "checkbox", root = "checkbox/root", code_url = "example/examples/basic/checkbox/checkbox.lua", - component_class = require("example.examples.basic.checkbox.checkbox"), - on_create = function(instance, output_log) - ---@cast instance checkbox - instance.button.on_click:subscribe(function() - output_log:add_log_text("Checkbox Clicked: " .. tostring(instance.is_enabled)) - end) - end, + widget_class = require("example.examples.basic.checkbox.checkbox"), }, { name_id = "ui_example_checkbox_group", @@ -825,13 +287,7 @@ function M.get_examples() template = "checkbox_group", root = "checkbox_group/root", code_url = "example/examples/basic/checkbox_group/checkbox_group.lua", - component_class = require("example.examples.basic.checkbox_group.checkbox_group"), - on_create = function(instance, output_log) - ---@cast instance checkbox_group - instance.on_state_changed:subscribe(function(state1, state2, state3) - output_log:add_log_text("State: " .. tostring(state1) .. " " .. tostring(state2) .. " " .. tostring(state3)) - end) - end, + widget_class = require("example.examples.basic.checkbox_group.checkbox_group"), }, { name_id = "ui_example_radio_group", @@ -839,15 +295,9 @@ function M.get_examples() template = "radio_group", root = "radio_group/root", code_url = "example/examples/basic/radio_group/radio_group.lua", - component_class = require("example.examples.basic.radio_group.radio_group"), - on_create = function(instance, output_log) - ---@cast instance radio_group - instance.on_state_changed:subscribe(function(selected) - output_log:add_log_text("Selected: " .. selected) - end) - end, + widget_class = require("example.examples.basic.radio_group.radio_group"), }, } end -return M \ No newline at end of file +return M diff --git a/example/examples/basic/grid/grid.lua b/example/examples/basic/grid/grid.lua index db0bd16..874896d 100644 --- a/example/examples/basic/grid/grid.lua +++ b/example/examples/basic/grid/grid.lua @@ -1,17 +1,9 @@ -local component = require("druid.component") - ----@class grid: druid.base_component +---@class examples.grid: druid.widget ---@field grid druid.grid ---@field text druid.text ----@field druid druid_instance -local M = component.create("grid") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.created_nodes = {} self.prefab = self:get_node("prefab") @@ -63,4 +55,86 @@ function M:clear() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local grid = self.grid + + local slider = properties_panel:add_slider("ui_grid_in_row", 0.3, function(value) + local in_row_amount = math.ceil(value * 10) + in_row_amount = math.max(1, in_row_amount) + grid:set_in_row(in_row_amount) + end) + slider:set_text_function(function(value) + return tostring(math.ceil(value * 10)) + end) + + properties_panel:add_button("ui_add_element", function() + if #self.created_nodes >= 36 then + return + end + self:add_element() + end) + + properties_panel:add_button("ui_remove_element", function() + self:remove_element() + end) + + properties_panel:add_button("ui_clear_elements", function() + self:clear() + end) + + properties_panel:add_checkbox("ui_dynamic_pos", grid.style.IS_DYNAMIC_NODE_POSES, function() + grid.style.IS_DYNAMIC_NODE_POSES = not grid.style.IS_DYNAMIC_NODE_POSES + grid:refresh() + end) + + properties_panel:add_checkbox("ui_align_last_row", grid.style.IS_ALIGN_LAST_ROW, function() + grid.style.IS_ALIGN_LAST_ROW = not grid.style.IS_ALIGN_LAST_ROW + grid:refresh() + end) + + local pivot_index = 1 + local pivot_list = { + gui.PIVOT_CENTER, + gui.PIVOT_W, + gui.PIVOT_SW, + gui.PIVOT_S, + gui.PIVOT_SE, + gui.PIVOT_E, + gui.PIVOT_NE, + gui.PIVOT_N, + gui.PIVOT_NW, + } + + properties_panel:add_button("ui_pivot_next", function() + pivot_index = pivot_index + 1 + if pivot_index > #pivot_list then + pivot_index = 1 + end + grid:set_pivot(pivot_list[pivot_index]) + end) + + local slider_size = properties_panel:add_slider("ui_item_size", 0.5, function(value) + local size = 50 + value * 100 + grid:set_item_size(size, size) + end) + slider_size:set_text_function(function(value) + return tostring(50 + math.ceil(value * 100)) + end) + slider_size:set_value(0.5) +end + + +---@return string +function M:get_debug_info() + local info = "" + + info = info .. "Grid Items: " .. #self.grid.nodes .. "\n" + info = info .. "Grid Item Size: " .. self.grid.node_size.x .. " x " .. self.grid.node_size.y .. "\n" + info = info .. "Pivot: " .. tostring(self.grid.pivot) + + return info +end + + return M diff --git a/example/examples/basic/hotkey/basic_hotkey.lua b/example/examples/basic/hotkey/basic_hotkey.lua index fec96aa..829d456 100644 --- a/example/examples/basic/hotkey/basic_hotkey.lua +++ b/example/examples/basic/hotkey/basic_hotkey.lua @@ -1,17 +1,9 @@ -local component = require("druid.component") - ----@class basic_hotkey: druid.base_component ----@field druid druid_instance +---@class examples.basic_hotkey: druid.widget ---@field root node ---@field text druid.text -local M = component.create("basic_hotkey") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.root = self:get_node("root") self.hotkey = self.druid:new_hotkey({ "key_lshift", "key_x" }, self.on_hotkey) end @@ -24,4 +16,12 @@ function M:on_hotkey() end +---@param output_log output_list +function M:on_example_created(output_log) + self.hotkey.on_hotkey_released:subscribe(function() + output_log:add_log_text("Hotkey Released") + end) +end + + return M diff --git a/example/examples/basic/hover/hover.gui b/example/examples/basic/hover/hover.gui index 30312c1..76e8413 100644 --- a/example/examples/basic/hover/hover.gui +++ b/example/examples/basic/hover/hover.gui @@ -22,6 +22,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button_mouse_hover/root" + parent: "button_mouse_hover" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_mouse_hover/text" + parent: "button_mouse_hover/root" + template_node_child: true +} nodes { position { y: -100.0 @@ -32,5 +44,17 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button_mobile_hover/root" + parent: "button_mobile_hover" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_mobile_hover/text" + parent: "button_mobile_hover/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/hover/hover.lua b/example/examples/basic/hover/hover.lua index 3044b85..dfb5eee 100644 --- a/example/examples/basic/hover/hover.lua +++ b/example/examples/basic/hover/hover.lua @@ -1,19 +1,12 @@ -local component = require("druid.component") - ----@class hover: druid.base_component ----@field druid druid_instance +---@class examples.hover: druid.widget ---@field hover druid.hover ---@field hover_pressed druid.hover -local M = component.create("hover") +local M = {} ---Color: #E6DF9F local HOVERED_COLOR = vmath.vector4(230/255, 223/255, 159/255, 1.0) ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() -- Default hover callback is `on_hover`, designed for mobile devices -- It's only hover if touch action is above the node self.hover_default = self.druid:new_hover("button_mobile_hover/root", self.on_hover) diff --git a/example/examples/basic/input/basic_input.gui b/example/examples/basic/input/basic_input.gui index c13ede9..df53e44 100644 --- a/example/examples/basic/input/basic_input.gui +++ b/example/examples/basic/input/basic_input.gui @@ -15,6 +15,18 @@ nodes { inherit_alpha: true template: "/example/templates/input.gui" } +nodes { + type: TYPE_BOX + id: "input/root" + parent: "input" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "input/text" + parent: "input/root" + template_node_child: true +} nodes { position { y: -150.0 @@ -25,5 +37,17 @@ nodes { inherit_alpha: true template: "/example/templates/input.gui" } +nodes { + type: TYPE_BOX + id: "input_2/root" + parent: "input_2" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "input_2/text" + parent: "input_2/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/input/basic_input.lua b/example/examples/basic/input/basic_input.lua index 7be4813..c169756 100644 --- a/example/examples/basic/input/basic_input.lua +++ b/example/examples/basic/input/basic_input.lua @@ -1,16 +1,8 @@ -local component = require("druid.component") - ----@class basic_input: druid.base_component ----@field druid druid_instance +---@class examples.basic_input: druid.widget ---@field input druid.input -local M = component.create("basic_input") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.input = self.druid:new_input("input/root", "input/text") self.input_2 = self.druid:new_input("input_2/root", "input_2/text") --[[@as druid.input]] @@ -22,4 +14,21 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.input.on_input_select:subscribe(function() + output_log:add_log_text("Input Selected") + end) + self.input_2.on_input_select:subscribe(function() + output_log:add_log_text("Input 2 Selected") + end) + self.input.on_input_unselect:subscribe(function(_, text) + output_log:add_log_text("Input Deselected. Text: " .. text) + end) + self.input_2.on_input_unselect:subscribe(function(_, text) + output_log:add_log_text("Input Deselected. Text: " .. text) + end) +end + + return M diff --git a/example/examples/basic/input/input_password.gui b/example/examples/basic/input/input_password.gui index 03bdeef..ade46cd 100644 --- a/example/examples/basic/input/input_password.gui +++ b/example/examples/basic/input/input_password.gui @@ -15,5 +15,17 @@ nodes { inherit_alpha: true template: "/example/templates/input.gui" } +nodes { + type: TYPE_BOX + id: "input/root" + parent: "input" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "input/text" + parent: "input/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/input/input_password.lua b/example/examples/basic/input/input_password.lua index 014f1d7..d9af327 100644 --- a/example/examples/basic/input/input_password.lua +++ b/example/examples/basic/input/input_password.lua @@ -1,16 +1,10 @@ -local component = require("druid.component") - ----@class input_password: druid.base_component ----@field druid druid_instance +---@class examples.input_password: druid.widget ---@field root node -local M = component.create("input_password") +---@field input druid.input +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.root = self:get_node("root") self.input = self.druid:new_input("input/root", "input/text", gui.KEYBOARD_TYPE_PASSWORD) self.input:set_text("") @@ -21,4 +15,12 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.input.on_input_unselect:subscribe(function(_, text) + output_log:add_log_text("Input: " .. text) + end) +end + + return M diff --git a/example/examples/basic/input/rich_input.gui b/example/examples/basic/input/rich_input.gui index 89e445d..ffdf8df 100644 --- a/example/examples/basic/input/rich_input.gui +++ b/example/examples/basic/input/rich_input.gui @@ -19,6 +19,42 @@ nodes { inherit_alpha: true template: "/example/templates/rich_input.gui" } +nodes { + type: TYPE_BOX + id: "rich_input/root" + parent: "rich_input" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "rich_input/button" + parent: "rich_input/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "rich_input/placeholder_text" + parent: "rich_input/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "rich_input/input_text" + parent: "rich_input/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "rich_input/cursor_node" + parent: "rich_input/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "rich_input/cursor_text" + parent: "rich_input/cursor_node" + template_node_child: true +} nodes { position { y: -150.0 @@ -29,5 +65,41 @@ nodes { inherit_alpha: true template: "/example/templates/rich_input.gui" } +nodes { + type: TYPE_BOX + id: "rich_input_2/root" + parent: "rich_input_2" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "rich_input_2/button" + parent: "rich_input_2/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "rich_input_2/placeholder_text" + parent: "rich_input_2/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "rich_input_2/input_text" + parent: "rich_input_2/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "rich_input_2/cursor_node" + parent: "rich_input_2/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "rich_input_2/cursor_text" + parent: "rich_input_2/cursor_node" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/input/rich_input.lua b/example/examples/basic/input/rich_input.lua index a7e04ab..606ffbc 100644 --- a/example/examples/basic/input/rich_input.lua +++ b/example/examples/basic/input/rich_input.lua @@ -1,15 +1,10 @@ -local component = require("druid.component") - ----@class rich_input: druid.base_component ----@field druid druid_instance +---@class examples.rich_input: druid.widget ---@field rich_input druid.rich_input -local M = component.create("rich_input") +---@field rich_input_2 druid.rich_input +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.rich_input = self.druid:new_rich_input("rich_input") --[[@as druid.rich_input]] self.rich_input:set_placeholder("Enter text") @@ -18,4 +13,15 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.rich_input.input.on_input_unselect:subscribe(function(_, text) + output_log:add_log_text("Input: " .. text) + end) + self.rich_input_2.input.on_input_unselect:subscribe(function(_, text) + output_log:add_log_text("Input 2: " .. text) + end) +end + + return M diff --git a/example/examples/basic/progress_bar/basic_progress_bar.lua b/example/examples/basic/progress_bar/basic_progress_bar.lua index fe85f93..c742668 100644 --- a/example/examples/basic/progress_bar/basic_progress_bar.lua +++ b/example/examples/basic/progress_bar/basic_progress_bar.lua @@ -1,16 +1,8 @@ -local component = require("druid.component") - ----@class basic_progress_bar: druid.base_component ----@field druid druid_instance +---@class examples.basic_progress_bar: druid.widget ---@field progress druid.progress -local M = component.create("basic_progress_bar") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.progress = self.druid:new_progress("progress_bar_fill", "x") self.text_value = self:get_node("progress_value") @@ -24,4 +16,12 @@ function M:set_value(value) end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + properties_panel:add_slider("ui_value", 1, function(value) + self:set_value(value) + end) +end + + return M diff --git a/example/examples/basic/progress_bar/basic_progress_bar_slice9.lua b/example/examples/basic/progress_bar/basic_progress_bar_slice9.lua index 2640001..1708779 100644 --- a/example/examples/basic/progress_bar/basic_progress_bar_slice9.lua +++ b/example/examples/basic/progress_bar/basic_progress_bar_slice9.lua @@ -1,16 +1,8 @@ -local component = require("druid.component") - ----@class basic_progress_bar_slice9: druid.base_component ----@field druid druid_instance +---@class examples.basic_progress_bar_slice9: druid.widget ---@field progress druid.progress -local M = component.create("basic_progress_bar_slice9") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.progress = self.druid:new_progress("progress_bar_fill", "x") self.text_value = self:get_node("progress_value") @@ -24,4 +16,12 @@ function M:set_value(value) end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + properties_panel:add_slider("ui_value", 1, function(value) + self:set_value(value) + end) +end + + return M diff --git a/example/examples/basic/radio_group/radio_group.gui b/example/examples/basic/radio_group/radio_group.gui index a51e797..2eeaef4 100644 --- a/example/examples/basic/radio_group/radio_group.gui +++ b/example/examples/basic/radio_group/radio_group.gui @@ -27,6 +27,30 @@ nodes { inherit_alpha: true template: "/example/examples/basic/checkbox/checkbox.gui" } +nodes { + type: TYPE_BOX + id: "checkbox_1/root" + parent: "checkbox_1" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_1/button" + parent: "checkbox_1/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_1/icon" + parent: "checkbox_1/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_1/selected" + parent: "checkbox_1/button" + template_node_child: true +} nodes { type: TYPE_TEMPLATE id: "checkbox_2" @@ -34,6 +58,30 @@ nodes { inherit_alpha: true template: "/example/examples/basic/checkbox/checkbox.gui" } +nodes { + type: TYPE_BOX + id: "checkbox_2/root" + parent: "checkbox_2" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_2/button" + parent: "checkbox_2/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_2/icon" + parent: "checkbox_2/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_2/selected" + parent: "checkbox_2/button" + template_node_child: true +} nodes { position { x: 100.0 @@ -44,5 +92,29 @@ nodes { inherit_alpha: true template: "/example/examples/basic/checkbox/checkbox.gui" } +nodes { + type: TYPE_BOX + id: "checkbox_3/root" + parent: "checkbox_3" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_3/button" + parent: "checkbox_3/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_3/icon" + parent: "checkbox_3/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "checkbox_3/selected" + parent: "checkbox_3/button" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/basic/radio_group/radio_group.lua b/example/examples/basic/radio_group/radio_group.lua index b1ac9bb..f81f9f7 100644 --- a/example/examples/basic/radio_group/radio_group.lua +++ b/example/examples/basic/radio_group/radio_group.lua @@ -1,25 +1,20 @@ -local component = require("druid.component") local event = require("event.event") -- Require checkbox component from checkbox example local checkbox = require("example.examples.basic.checkbox.checkbox") ----@class radio_group: druid.base_component ----@field druid druid_instance ----@field button druid.button -local M = component.create("radio_group") +---@class examples.radio_group: druid.widget +---@field checkboxes examples.checkbox[] +---@field state boolean[] +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.state = {} self.checkboxes = { - self.druid:new(checkbox, "checkbox_1"), - self.druid:new(checkbox, "checkbox_2"), - self.druid:new(checkbox, "checkbox_3") + self.druid:new_widget(checkbox, "checkbox_1"), + self.druid:new_widget(checkbox, "checkbox_2"), + self.druid:new_widget(checkbox, "checkbox_3") } for i = 1, #self.checkboxes do @@ -52,4 +47,12 @@ function M:on_checkbox_click() end +---@param output_log output_list +function M:on_example_created(output_log) + self.on_state_changed:subscribe(function(selected) + output_log:add_log_text("Selected: " .. selected) + end) +end + + return M diff --git a/example/examples/basic/rich_text/basic_rich_text.lua b/example/examples/basic/rich_text/basic_rich_text.lua index e61226b..2662ae6 100644 --- a/example/examples/basic/rich_text/basic_rich_text.lua +++ b/example/examples/basic/rich_text/basic_rich_text.lua @@ -1,15 +1,9 @@ -local component = require("druid.component") - ----@class basic_rich_text: druid.base_component ----@field druid druid_instance +---@class examples.basic_rich_text: druid.widget ---@field rich_text druid.rich_text -local M = component.create("basic_rich_text") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.druid:new_rich_text("text", "Hello, I'm a Rich Text!") end diff --git a/example/examples/basic/rich_text/rich_text_tags.lua b/example/examples/basic/rich_text/rich_text_tags.lua index 3e92a8f..a1c803d 100644 --- a/example/examples/basic/rich_text/rich_text_tags.lua +++ b/example/examples/basic/rich_text/rich_text_tags.lua @@ -1,17 +1,16 @@ -local component = require("druid.component") local helper = require("druid.helper") ----@class rich_text_tags: druid.base_component ----@field druid druid_instance ----@field rich_text druid.rich_text -local M = component.create("rich_text_tags") +---@class examples.rich_text_tags: druid.widget +---@field rich_text_color druid.rich_text +---@field rich_text_font druid.rich_text +---@field rich_text_size druid.rich_text +---@field rich_text_breaks druid.rich_text +---@field rich_text_image druid.rich_text +---@field position table +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.rich_text_color = self.druid:new_rich_text("rich_text_color") --[[@as druid.rich_text]] self.rich_text_color:set_text("Hello, I'm a Rich Text and it's nested color tag") @@ -72,4 +71,29 @@ function M:set_pivot(pivot) end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local pivot_index = 1 + local pivot_list = { + gui.PIVOT_CENTER, + gui.PIVOT_W, + gui.PIVOT_SW, + gui.PIVOT_S, + gui.PIVOT_SE, + gui.PIVOT_E, + gui.PIVOT_NE, + gui.PIVOT_N, + gui.PIVOT_NW, + } + + properties_panel:add_button("ui_pivot_next", function() + pivot_index = pivot_index + 1 + if pivot_index > #pivot_list then + pivot_index = 1 + end + self:set_pivot(pivot_list[pivot_index]) + end) +end + + return M diff --git a/example/examples/basic/rich_text/rich_text_tags_custom.lua b/example/examples/basic/rich_text/rich_text_tags_custom.lua index 38adf14..734366c 100644 --- a/example/examples/basic/rich_text/rich_text_tags_custom.lua +++ b/example/examples/basic/rich_text/rich_text_tags_custom.lua @@ -1,18 +1,16 @@ -local component = require("druid.component") local helper = require("druid.helper") local event = require("event.event") ----@class rich_text_tags_custom: druid.base_component ----@field druid druid_instance ----@field rich_text druid.rich_text -local M = component.create("rich_text_tags_custom") +---@class examples.rich_text_tags_custom: druid.widget +---@field rich_text_link druid.rich_text +---@field rich_text_characters druid.rich_text +---@field rich_text_custom druid.rich_text +---@field position table +---@field on_link_click event +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() do -- Init rich text with links example self.rich_text_link = self.druid:new_rich_text("rich_text_link") --[[@as druid.rich_text]] self.rich_text_link:set_text("Hello, I'm a Custom Link") diff --git a/example/examples/basic/scroll/scroll.gui b/example/examples/basic/scroll/scroll.gui index fe6722b..eabb283 100644 --- a/example/examples/basic/scroll/scroll.gui +++ b/example/examples/basic/scroll/scroll.gui @@ -76,6 +76,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button_tutorial/root" + parent: "button_tutorial" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_tutorial/text" + parent: "button_tutorial/root" + template_node_child: true +} nodes { position { x: -185.0 @@ -288,6 +300,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button_stencil/root" + parent: "button_stencil" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_stencil/text" + parent: "button_stencil/root" + template_node_child: true +} nodes { position { x: -185.0 diff --git a/example/examples/basic/scroll/scroll.lua b/example/examples/basic/scroll/scroll.lua index 65efe8c..6e695d3 100644 --- a/example/examples/basic/scroll/scroll.lua +++ b/example/examples/basic/scroll/scroll.lua @@ -1,16 +1,11 @@ local component = require("druid.component") ----@class scroll: druid.base_component +---@class examples.scroll: druid.widget ---@field root node ---@field scroll druid.scroll ----@field druid druid_instance -local M = component.create("scroll") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.scroll = self.druid:new_scroll("scroll_view", "scroll_content") self.button_tutorial = self.druid:new_button("button_tutorial/root") @@ -18,4 +13,74 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.button_tutorial.on_click:subscribe(function() + output_log:add_log_text("Button Tutorial Clicked") + end) + self.button_stencil.on_click:subscribe(function() + output_log:add_log_text("Button Stencil Clicked") + end) +end + + +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local scroll = self.scroll + local is_stretch = self.scroll.style.EXTRA_STRETCH_SIZE > 0 + properties_panel:add_checkbox("ui_elastic_scroll", is_stretch, function(value) + self.scroll:set_extra_stretch_size(value and 100 or 0) + end) + + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + local slider_frict = properties_panel:add_slider("ui_slider_friction", 0, function(value) + scroll.style.FRICT = 1 - ((1 - value) * 0.1) + end) + slider_frict:set_text_function(function(value) + return string.format("%.2f", 1 - ((1 - value) * 0.1)) + end) + slider_frict:set_value(1 - (1 - scroll.style.FRICT) / 0.1) + + local slider_speed = properties_panel:add_slider("ui_slider_speed", 0, function(value) + scroll.style.INERT_SPEED = value * 50 + end) + slider_speed:set_value(scroll.style.INERT_SPEED / 50) + slider_speed:set_text_function(function(value) + return string.format("%.1f", value * 50) + end) + + local slider_wheel_speed = properties_panel:add_slider("ui_slider_wheel_speed", 0, function(value) + scroll.style.WHEEL_SCROLL_SPEED = value * 30 + end) + slider_wheel_speed:set_value(scroll.style.WHEEL_SCROLL_SPEED / 30) + slider_wheel_speed:set_text_function(function(value) + return string.format("%.1f", value * 30) + end) + + local wheel_by_inertion = properties_panel:add_checkbox("ui_wheel_by_inertion", scroll.style.WHEEL_SCROLL_BY_INERTION, function(value) + scroll.style.WHEEL_SCROLL_BY_INERTION = value + end) + wheel_by_inertion:set_value(scroll.style.WHEEL_SCROLL_BY_INERTION) +end + + +---@return string +function M:get_debug_info() + local info = "" + + local s = self.scroll + info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" + info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" + info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" + info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/scroll_bind_grid/scroll_bind_grid.lua b/example/examples/basic/scroll_bind_grid/scroll_bind_grid.lua index f026f74..af15637 100644 --- a/example/examples/basic/scroll_bind_grid/scroll_bind_grid.lua +++ b/example/examples/basic/scroll_bind_grid/scroll_bind_grid.lua @@ -1,18 +1,10 @@ -local component = require("druid.component") - ----@class scroll_bind_grid: druid.base_component +---@class examples.scroll_bind_grid: druid.widget ---@field scroll druid.scroll ---@field grid druid.grid ---@field text druid.text ----@field druid druid_instance -local M = component.create("scroll_bind_grid") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.created_nodes = {} self.prefab = self:get_node("prefab") @@ -66,4 +58,51 @@ function M:clear() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + properties_panel:add_button("ui_add_element", function() + if #self.created_nodes >= 100 then + return + end + self:add_element() + end) + + properties_panel:add_button("ui_remove_element", function() + self:remove_element() + end) + + properties_panel:add_button("ui_clear_elements", function() + self:clear() + end) +end + + +---@return string +function M:get_debug_info() + local info = "" + + local s = self.scroll + local view_node_size = gui.get(s.view_node, "size.y") + local scroll_position = -s.position + local scroll_bottom_position = vmath.vector3(scroll_position.x, scroll_position.y - view_node_size, scroll_position.z) + + info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" + info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" + info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" + info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" + info = info .. "Grid Items: " .. #self.grid.nodes .. "\n" + info = info .. "Grid Item Size: " .. self.grid.node_size.x .. " x " .. self.grid.node_size.y .. "\n" + info = info .. "Top Scroll Pos Grid Index: " .. self.grid:get_index(scroll_position) .. "\n" + info = info .. "Bottm Scroll Pos Grid Index: " .. self.grid:get_index(scroll_bottom_position) .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/scroll_bind_grid/scroll_bind_grid_horizontal.lua b/example/examples/basic/scroll_bind_grid/scroll_bind_grid_horizontal.lua index 7e26681..69f65e7 100644 --- a/example/examples/basic/scroll_bind_grid/scroll_bind_grid_horizontal.lua +++ b/example/examples/basic/scroll_bind_grid/scroll_bind_grid_horizontal.lua @@ -1,18 +1,10 @@ -local component = require("druid.component") - ----@class scroll_bind_grid_horizontal: druid.base_component +---@class examples.scroll_bind_grid_horizontal: druid.widget ---@field scroll druid.scroll ---@field grid druid.grid ---@field text druid.text ----@field druid druid_instance -local M = component.create("scroll_bind_grid_horizontal") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.created_nodes = {} self.prefab = self:get_node("prefab") @@ -66,4 +58,53 @@ function M:clear() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + + properties_panel:add_button("ui_add_element", function() + if #self.created_nodes >= 100 then + return + end + self:add_element() + end) + + properties_panel:add_button("ui_remove_element", function() + self:remove_element() + end) + + properties_panel:add_button("ui_clear_elements", function() + self:clear() + end) +end + + +---@return string +function M:get_debug_info() + local info = "" + + local s = self.scroll + local view_node_size = gui.get(s.view_node, "size.x") + local scroll_position = -s.position + local scroll_bottom_position = vmath.vector3(scroll_position.x + view_node_size, scroll_position.y, scroll_position.z) + + info = info .. "View Size X: " .. gui.get(s.view_node, "size.x") .. "\n" + info = info .. "Content Size X: " .. gui.get(s.content_node, "size.x") .. "\n" + info = info .. "Content position X: " .. math.ceil(s.position.x) .. "\n" + info = info .. "Content Range X: " .. s.available_pos.x .. " - " .. s.available_pos.z .. "\n" + info = info .. "Grid Items: " .. #self.grid.nodes .. "\n" + info = info .. "Grid Item Size: " .. self.grid.node_size.x .. " x " .. self.grid.node_size.y .. "\n" + info = info .. "Left Scroll Pos Grid Index: " .. self.grid:get_index(scroll_position) .. "\n" + info = info .. "Right Scroll Pos Grid Index: " .. self.grid:get_index(scroll_bottom_position) .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/scroll_bind_grid/scroll_bind_grid_points.lua b/example/examples/basic/scroll_bind_grid/scroll_bind_grid_points.lua index 91f185a..7618dde 100644 --- a/example/examples/basic/scroll_bind_grid/scroll_bind_grid_points.lua +++ b/example/examples/basic/scroll_bind_grid/scroll_bind_grid_points.lua @@ -1,18 +1,10 @@ -local component = require("druid.component") - ----@class scroll_bind_grid_points: druid.base_component +---@class examples.scroll_bind_grid_points: druid.widget ---@field scroll druid.scroll ---@field grid druid.grid ---@field text druid.text ----@field druid druid_instance -local M = component.create("scroll_bind_grid_points") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.created_nodes = {} self.prefab = self:get_node("prefab") @@ -72,4 +64,51 @@ function M:clear() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + properties_panel:add_button("ui_add_element", function() + if #self.created_nodes >= 100 then + return + end + self:add_element() + end) + + properties_panel:add_button("ui_remove_element", function() + self:remove_element() + end) + + properties_panel:add_button("ui_clear_elements", function() + self:clear() + end) +end + + +---@return string +function M:get_debug_info() + local info = "" + + local s = self.scroll + local view_node_size = gui.get(s.view_node, "size.y") + local scroll_position = -s.position + local scroll_bottom_position = vmath.vector3(scroll_position.x, scroll_position.y - view_node_size, scroll_position.z) + + info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" + info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" + info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" + info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" + info = info .. "Grid Items: " .. #self.grid.nodes .. "\n" + info = info .. "Grid Item Size: " .. self.grid.node_size.x .. " x " .. self.grid.node_size.y .. "\n" + info = info .. "Top Scroll Pos Grid Index: " .. self.grid:get_index(scroll_position) .. "\n" + info = info .. "Bottm Scroll Pos Grid Index: " .. self.grid:get_index(scroll_bottom_position) .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/scroll_slider/scroll_slider.gui b/example/examples/basic/scroll_slider/scroll_slider.gui index 0766e91..717829b 100644 --- a/example/examples/basic/scroll_slider/scroll_slider.gui +++ b/example/examples/basic/scroll_slider/scroll_slider.gui @@ -76,6 +76,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button1/root" + parent: "button1" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button1/text" + parent: "button1/root" + template_node_child: true +} nodes { position { y: -300.0 @@ -86,6 +98,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button2/root" + parent: "button2" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button2/text" + parent: "button2/root" + template_node_child: true +} nodes { position { y: -500.0 @@ -96,6 +120,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button3/root" + parent: "button3" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button3/text" + parent: "button3/root" + template_node_child: true +} nodes { position { y: -700.0 @@ -106,6 +142,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button4/root" + parent: "button4" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button4/text" + parent: "button4/root" + template_node_child: true +} nodes { position { y: -900.0 @@ -116,6 +164,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button5/root" + parent: "button5" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button5/text" + parent: "button5/root" + template_node_child: true +} nodes { position { y: -1100.0 @@ -126,6 +186,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button6/root" + parent: "button6" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button6/text" + parent: "button6/root" + template_node_child: true +} nodes { position { y: -1300.0 @@ -136,6 +208,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button7/root" + parent: "button7" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button7/text" + parent: "button7/root" + template_node_child: true +} nodes { position { y: -1500.0 @@ -146,6 +230,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button8/root" + parent: "button8" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button8/text" + parent: "button8/root" + template_node_child: true +} nodes { position { y: -1700.0 @@ -156,6 +252,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button9/root" + parent: "button9" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button9/text" + parent: "button9/root" + template_node_child: true +} nodes { position { y: -1900.0 @@ -166,6 +274,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button10/root" + parent: "button10" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button10/text" + parent: "button10/root" + template_node_child: true +} nodes { position { y: -2100.0 @@ -176,6 +296,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button11/root" + parent: "button11" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button11/text" + parent: "button11/root" + template_node_child: true +} nodes { position { y: -2300.0 @@ -186,6 +318,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button12/root" + parent: "button12" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button12/text" + parent: "button12/root" + template_node_child: true +} nodes { position { y: -2500.0 @@ -196,6 +340,18 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_green.gui" } +nodes { + type: TYPE_BOX + id: "button13/root" + parent: "button13" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button13/text" + parent: "button13/root" + template_node_child: true +} nodes { position { x: 200.0 diff --git a/example/examples/basic/scroll_slider/scroll_slider.lua b/example/examples/basic/scroll_slider/scroll_slider.lua index 0627f82..6304089 100644 --- a/example/examples/basic/scroll_slider/scroll_slider.lua +++ b/example/examples/basic/scroll_slider/scroll_slider.lua @@ -1,17 +1,10 @@ -local component = require("druid.component") - ----@class scroll_slider: druid.base_component +---@class examples.scroll_slider: druid.widget ---@field root node ---@field scroll druid.scroll ---@field slider druid.slider ----@field druid druid_instance -local M = component.create("scroll_slider") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.scroll = self.druid:new_scroll("scroll_view", "scroll_content") self.scroll.on_scroll:subscribe(self.on_scroll) @@ -50,4 +43,18 @@ function M:on_slider_back_hover(is_hover) end +---@return string +function M:get_debug_info() + local info = "" + + local s = self.scroll + info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" + info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" + info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" + info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/slider/basic_slider.gui b/example/examples/basic/slider/basic_slider.gui index 7c15e3e..b8551e6 100644 --- a/example/examples/basic/slider/basic_slider.gui +++ b/example/examples/basic/slider/basic_slider.gui @@ -34,6 +34,24 @@ nodes { inherit_alpha: true template: "/example/templates/slider.gui" } +nodes { + type: TYPE_BOX + id: "slider/root" + parent: "slider" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "slider/slider_back" + parent: "slider/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "slider/slider_pin" + parent: "slider/root" + template_node_child: true +} nodes { position { y: 50.0 diff --git a/example/examples/basic/slider/basic_slider.lua b/example/examples/basic/slider/basic_slider.lua index 73fe031..85d74f4 100644 --- a/example/examples/basic/slider/basic_slider.lua +++ b/example/examples/basic/slider/basic_slider.lua @@ -1,17 +1,11 @@ -local component = require("druid.component") +local helper = require("druid.helper") ----@class basic_slider: druid.base_component ----@field druid druid_instance +---@class examples.basic_slider: druid.widget ---@field root node ---@field slider druid.slider -local M = component.create("basic_slider") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.slider = self.druid:new_slider("slider/slider_pin", vmath.vector3(118, 0, 0), self.on_slider_change) --[[@as druid.slider]] -- To add input across all slider widget add a root node to acquire additional input @@ -26,4 +20,13 @@ function M:on_slider_change(value) end +---@param output_log output_list +function M:on_example_created(output_log) + self.slider.on_change_value:subscribe(function(_, value) + value = helper.round(value, 2) + output_log:add_log_text("Slider Value: " .. value) + end) +end + + return M diff --git a/example/examples/basic/slider/basic_slider_stepped.gui b/example/examples/basic/slider/basic_slider_stepped.gui index 7c15e3e..b8551e6 100644 --- a/example/examples/basic/slider/basic_slider_stepped.gui +++ b/example/examples/basic/slider/basic_slider_stepped.gui @@ -34,6 +34,24 @@ nodes { inherit_alpha: true template: "/example/templates/slider.gui" } +nodes { + type: TYPE_BOX + id: "slider/root" + parent: "slider" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "slider/slider_back" + parent: "slider/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "slider/slider_pin" + parent: "slider/root" + template_node_child: true +} nodes { position { y: 50.0 diff --git a/example/examples/basic/slider/basic_slider_stepped.lua b/example/examples/basic/slider/basic_slider_stepped.lua index 8a22642..06a14bd 100644 --- a/example/examples/basic/slider/basic_slider_stepped.lua +++ b/example/examples/basic/slider/basic_slider_stepped.lua @@ -1,17 +1,11 @@ -local component = require("druid.component") +local helper = require("druid.helper") ----@class basic_slider_stepped: druid.base_component ----@field druid druid_instance +---@class examples.basic_slider_stepped: druid.widget ---@field root node ---@field slider druid.slider -local M = component.create("basic_slider_stepped") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.slider = self.druid:new_slider("slider/slider_pin", vmath.vector3(118, 0, 0), self.on_slider_change) --[[@as druid.slider]] -- To add input across all slider widget add a root node to acquire additional input @@ -28,4 +22,13 @@ function M:on_slider_change(value) end +---@param output_log output_list +function M:on_example_created(output_log) + self.slider.on_change_value:subscribe(function(_, value) + value = helper.round(value, 2) + output_log:add_log_text("Slider Value: " .. value) + end) +end + + return M diff --git a/example/examples/basic/slider/basic_slider_vertical.gui b/example/examples/basic/slider/basic_slider_vertical.gui index b59f960..7e615dd 100644 --- a/example/examples/basic/slider/basic_slider_vertical.gui +++ b/example/examples/basic/slider/basic_slider_vertical.gui @@ -34,6 +34,37 @@ nodes { inherit_alpha: true template: "/example/templates/slider.gui" } +nodes { + size { + x: 40.0 + y: 260.0 + } + type: TYPE_BOX + id: "slider/root" + parent: "slider" + overridden_fields: 4 + template_node_child: true +} +nodes { + rotation { + z: 90.0 + } + type: TYPE_BOX + id: "slider/slider_back" + parent: "slider/root" + overridden_fields: 2 + template_node_child: true +} +nodes { + position { + y: 118.0 + } + type: TYPE_BOX + id: "slider/slider_pin" + parent: "slider/root" + overridden_fields: 1 + template_node_child: true +} nodes { position { y: 170.0 diff --git a/example/examples/basic/slider/basic_slider_vertical.lua b/example/examples/basic/slider/basic_slider_vertical.lua index bbeb019..c340bd8 100644 --- a/example/examples/basic/slider/basic_slider_vertical.lua +++ b/example/examples/basic/slider/basic_slider_vertical.lua @@ -1,17 +1,11 @@ -local component = require("druid.component") +local helper = require("druid.helper") ----@class basic_slider_vertical: druid.base_component ----@field druid druid_instance +---@class examples.basic_slider_vertical: druid.widget ---@field root node ---@field slider druid.slider -local M = component.create("basic_slider_vertical") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.slider = self.druid:new_slider("slider/slider_pin", vmath.vector3(0, -118, 0), self.on_slider_change) --[[@as druid.slider]] -- To add input across all slider widget add a root node to acquire additional input @@ -26,4 +20,14 @@ function M:on_slider_change(value) end +---@param output_log output_list +function M:on_example_created(output_log) + self.slider.on_change_value:subscribe(function(_, value) + value = helper.round(value, 2) + output_log:add_log_text("Slider Value: " .. value) + end) +end + + + return M diff --git a/example/examples/basic/swipe/basic_swipe.lua b/example/examples/basic/swipe/basic_swipe.lua index ca56596..5ef7d6a 100644 --- a/example/examples/basic/swipe/basic_swipe.lua +++ b/example/examples/basic/swipe/basic_swipe.lua @@ -1,14 +1,9 @@ -local component = require("druid.component") +---@class examples.basic_swipe: druid.widget +---@field swipe druid.swipe +local M = {} ----@class basic_swipe: druid.base_component ----@field druid druid_instance -local M = component.create("basic_swipe") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.swipe = self.druid:new_swipe("root", self.on_swipe) --[[@as druid.swipe]] self.text_hint = self:get_node("swipe_hint") @@ -30,4 +25,12 @@ function M:on_swipe(swipe_side, dist, delta_time) end +---@param output_log output_list +function M:on_example_created(output_log) + self.swipe.on_swipe:subscribe(function(_, side, dist, delta_time) + output_log:add_log_text("Swipe Side: " .. side) + end) +end + + return M diff --git a/example/examples/basic/text/basic_text.lua b/example/examples/basic/text/basic_text.lua index dca1682..1d61dd3 100644 --- a/example/examples/basic/text/basic_text.lua +++ b/example/examples/basic/text/basic_text.lua @@ -1,16 +1,10 @@ local helper = require("druid.helper") -local component = require("druid.component") ----@class basic_text: druid.base_component ----@field druid druid_instance +---@class examples.basic_text: druid.widget ---@field text druid.text -local M = component.create("basic_text") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.text = self.druid:new_text("text") -- This code is for adjustable text area with mouse @@ -37,4 +31,56 @@ function M:refresh_text_position() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local adjust_index = 1 + local adjust_types = { + "downscale", + "downscale_limited", + --"scale_then_scroll", -- works bad with container for some reason + --"scroll", -- works bad with container for some reason + "trim", + } + properties_panel:add_button("ui_adjust_next", function() + adjust_index = adjust_index + 1 + if adjust_index > #adjust_types then + adjust_index = 1 + end + self.text:set_text_adjust(adjust_types[adjust_index], 0.5) + end) + + local pivot_index = 1 + local pivot_list = { + gui.PIVOT_CENTER, + gui.PIVOT_W, + gui.PIVOT_SW, + gui.PIVOT_S, + gui.PIVOT_SE, + gui.PIVOT_E, + gui.PIVOT_NE, + gui.PIVOT_N, + gui.PIVOT_NW, + } + + properties_panel:add_button("ui_pivot_next", function() + pivot_index = pivot_index + 1 + if pivot_index > #pivot_list then + pivot_index = 1 + end + self:set_pivot(pivot_list[pivot_index]) + end) +end + + +---@return string +function M:get_debug_info() + local info = "" + + info = info .. "Text Adjust: " .. self.text.adjust_type .. "\n" + info = info .. "Pivot: " .. gui.get_pivot(self.text.node) .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/text/multiline_text.lua b/example/examples/basic/text/multiline_text.lua index d50de10..a28be61 100644 --- a/example/examples/basic/text/multiline_text.lua +++ b/example/examples/basic/text/multiline_text.lua @@ -1,16 +1,10 @@ local helper = require("druid.helper") -local component = require("druid.component") ----@class multiline_text: druid.base_component +---@class examples.multiline_text: druid.widget ---@field root node ----@field druid druid_instance -local M = component.create("multiline_text") - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.root = self:get_node("root") self.text = self.druid:new_text("text") @@ -38,4 +32,56 @@ function M:refresh_text_position() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local adjust_index = 1 + local adjust_types = { + "downscale", + "downscale_limited", + --"scale_then_scroll", -- works bad with container for some reason + --"scroll", -- works bad with container for some reason + "trim", + } + properties_panel:add_button("ui_adjust_next", function() + adjust_index = adjust_index + 1 + if adjust_index > #adjust_types then + adjust_index = 1 + end + self.text:set_text_adjust(adjust_types[adjust_index], 0.8) + end) + + local pivot_index = 1 + local pivot_list = { + gui.PIVOT_CENTER, + gui.PIVOT_W, + gui.PIVOT_SW, + gui.PIVOT_S, + gui.PIVOT_SE, + gui.PIVOT_E, + gui.PIVOT_NE, + gui.PIVOT_N, + gui.PIVOT_NW, + } + + properties_panel:add_button("ui_pivot_next", function() + pivot_index = pivot_index + 1 + if pivot_index > #pivot_list then + pivot_index = 1 + end + self:set_pivot(pivot_list[pivot_index]) + end) +end + + +---@return string +function M:get_debug_info() + local info = "" + + info = info .. "Text Adjust: " .. self.text.adjust_type .. "\n" + info = info .. "Pivot: " .. gui.get_pivot(self.text.node) .. "\n" + + return info +end + + return M diff --git a/example/examples/basic/timer/basic_timer.lua b/example/examples/basic/timer/basic_timer.lua index 1687628..19e9efa 100644 --- a/example/examples/basic/timer/basic_timer.lua +++ b/example/examples/basic/timer/basic_timer.lua @@ -1,19 +1,11 @@ local event = require("event.event") -local component = require("druid.component") - ----@class basic_timer: druid.base_component ----@field druid druid_instance +---@class examples.basic_timer: druid.widget ---@field root node ---@field text druid.text -local M = component.create("basic_timer") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +local M = {} +function M:init() self.root = self:get_node("root") self.timer = self.druid:new_timer("text") @@ -29,4 +21,12 @@ function M:init(template, nodes) end +---@param output_log output_list +function M:on_example_created(output_log) + self.on_cycle_end:subscribe(function() + output_log:add_log_text("Timer Cycle End") + end) +end + + return M diff --git a/example/examples/data_list/add_remove_clear/data_list_add_remove_clear.lua b/example/examples/data_list/add_remove_clear/data_list_add_remove_clear.lua index b4ab3f6..423884e 100644 --- a/example/examples/data_list/add_remove_clear/data_list_add_remove_clear.lua +++ b/example/examples/data_list/add_remove_clear/data_list_add_remove_clear.lua @@ -1,17 +1,15 @@ local event = require("event.event") -local component = require("druid.component") ----@class data_list_add_remove_clear: druid.base_component ----@field druid druid_instance +---@class examples.data_list_add_remove_clear: druid.widget +---@field prefab node +---@field scroll druid.scroll +---@field grid druid.grid ---@field data_list druid.data_list -local M = component.create("data_list_add_remove_clear") +---@field on_item_click event +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.prefab = self:get_node("prefab") gui.set_enabled(self.prefab, false) @@ -31,7 +29,7 @@ end ---@param item_data table ---@param index number ----@return node, druid.base_component +---@return node, druid.component function M:create_item_callback(item_data, index) local nodes = gui.clone_tree(self.prefab) @@ -66,4 +64,61 @@ function M:clear() end +---@param output_list output_list +function M:on_example_created(output_list) + self.on_item_click:subscribe(function(index) + self:remove_item(index) + output_list:add_log_text("Item removed: " .. index) + end) +end + + +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + properties_panel:add_slider("ui_scroll", 0, function(value) + self.scroll:scroll_to_percent(vmath.vector3(0, 1 - value, 0), true) + end) + + properties_panel:add_button("ui_add_element", function() + self:add_item() + end) + + properties_panel:add_button("ui_remove_element", function() + self:remove_item() + end) + + properties_panel:add_button("ui_clear_elements", function() + self.data_list:clear() + end) +end + + +---@return string +function M:get_debug_info() + local data_list = self.data_list + + local data = data_list:get_data() + local info = "" + info = info .. "Data length: " .. #data .. "\n" + info = info .. "First Visual Index: " .. data_list.top_index .. "\n" + info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" + + local s = self.scroll + info = info .. "\n" + info = info .. "View Size X: " .. gui.get(s.view_node, "size.x") .. "\n" + info = info .. "Content Size X: " .. gui.get(s.content_node, "size.x") .. "\n" + info = info .. "Content position X: " .. math.ceil(s.position.x) .. "\n" + info = info .. "Content Range X: " .. s.available_pos.x .. " - " .. s.available_pos.z .. "\n" + + return info +end + + return M diff --git a/example/examples/data_list/basic/data_list_basic.lua b/example/examples/data_list/basic/data_list_basic.lua index f950b73..c2adaa2 100644 --- a/example/examples/data_list/basic/data_list_basic.lua +++ b/example/examples/data_list/basic/data_list_basic.lua @@ -1,16 +1,15 @@ local event = require("event.event") -local component = require("druid.component") ----@class data_list_basic: druid.base_component ----@field druid druid_instance -local M = component.create("data_list_basic") +---@class examples.data_list_basic: druid.widget +---@field prefab node +---@field scroll druid.scroll +---@field grid druid.grid +---@field data_list druid.data_list +---@field on_item_click event +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.prefab = self:get_node("prefab") gui.set_enabled(self.prefab, false) @@ -30,7 +29,7 @@ end ---@param item_data table ---@param index number ----@return node, druid.base_component +---@return node, druid.component function M:create_item_callback(item_data, index) local nodes = gui.clone_tree(self.prefab) @@ -49,4 +48,48 @@ function M:on_button_click(index) end +---@param output_list output_list +function M:on_example_created(output_list) + self.on_item_click:subscribe(function(index) + output_list:add_log_text("Item clicked: " .. index) + end) +end + + +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + properties_panel:add_slider("ui_scroll", 0, function(value) + self.scroll:scroll_to_percent(vmath.vector3(0, 1 - value, 0), true) + end) +end + + +---@return string +function M:get_debug_info() + local data_list = self.data_list + + local data = data_list:get_data() + local info = "" + info = info .. "Data length: " .. #data .. "\n" + info = info .. "First Visual Index: " .. data_list.top_index .. "\n" + info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" + + local s = self.scroll + info = info .. "\n" + info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" + info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" + info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" + info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" + + return info +end + + return M diff --git a/example/examples/data_list/basic/data_list_horizontal_basic.lua b/example/examples/data_list/basic/data_list_horizontal_basic.lua index 262bea1..2614bc2 100644 --- a/example/examples/data_list/basic/data_list_horizontal_basic.lua +++ b/example/examples/data_list/basic/data_list_horizontal_basic.lua @@ -1,15 +1,12 @@ -local component = require("druid.component") - ----@class data_list_horizontal_basic: druid.base_component ----@field druid druid_instance -local M = component.create("data_list_horizontal_basic") +---@class examples.data_list_horizontal_basic: druid.widget +---@field prefab node +---@field scroll druid.scroll +---@field grid druid.grid +---@field data_list druid.data_list +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.prefab = self:get_node("prefab") gui.set_enabled(self.prefab, false) @@ -42,4 +39,36 @@ function M:on_button_click(index) end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) +end + + +---@return string +function M:get_debug_info() + local data_list = self.data_list + + local data = data_list:get_data() + local info = "" + info = info .. "Data length: " .. #data .. "\n" + info = info .. "First Visual Index: " .. data_list.top_index .. "\n" + info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" + + local s = self.scroll + info = info .. "\n" + info = info .. "View Size X: " .. gui.get(s.view_node, "size.x") .. "\n" + info = info .. "Content Size X: " .. gui.get(s.content_node, "size.x") .. "\n" + info = info .. "Content position X: " .. math.ceil(s.position.x) .. "\n" + info = info .. "Content Range X: " .. s.available_pos.x .. " - " .. s.available_pos.z .. "\n" + + return info +end + + return M diff --git a/example/examples/data_list/cache_with_component/button_component.lua b/example/examples/data_list/cache_with_component/button_component.lua index 4719caf..042f7a1 100644 --- a/example/examples/data_list/cache_with_component/button_component.lua +++ b/example/examples/data_list/cache_with_component/button_component.lua @@ -1,17 +1,12 @@ -local component = require("druid.component") - ----@class button_component: druid.base_component +---@class examples.button_component: druid.widget ---@field root node ----@field druid druid_instance ---@field text druid.text +---@field button druid.button ---@field data any -local M = component.create("button_component") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.root = self:get_node("root") self.button = self.druid:new_button(self.root) diff --git a/example/examples/data_list/cache_with_component/cache_with_component.gui b/example/examples/data_list/cache_with_component/cache_with_component.gui index 1be4909..a6051e0 100644 --- a/example/examples/data_list/cache_with_component/cache_with_component.gui +++ b/example/examples/data_list/cache_with_component/cache_with_component.gui @@ -58,5 +58,23 @@ nodes { inherit_alpha: true template: "/example/examples/data_list/cache_with_component/button_component.gui" } +nodes { + type: TYPE_BOX + id: "button_component/root" + parent: "button_component" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_component/panel" + parent: "button_component/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_component/text" + parent: "button_component/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/data_list/cache_with_component/cache_with_component.lua b/example/examples/data_list/cache_with_component/cache_with_component.lua index 1c2a0ac..304e21b 100644 --- a/example/examples/data_list/cache_with_component/cache_with_component.lua +++ b/example/examples/data_list/cache_with_component/cache_with_component.lua @@ -1,18 +1,17 @@ local event = require("event.event") -local component = require("druid.component") local button_component = require("example.examples.data_list.cache_with_component.button_component") ----@class data_list_cache_with_component: druid.base_component ----@field druid druid_instance -local M = component.create("data_list_cache_with_component") +---@class examples.data_list_cache_with_component: druid.widget +---@field prefab node +---@field scroll druid.scroll +---@field grid druid.grid +---@field data_list druid.data_list +---@field on_item_click event +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.prefab = self:get_node("button_component/root") gui.set_enabled(self.prefab, false) @@ -35,11 +34,11 @@ end ---@param item_data table ---@param index number ----@return node, druid.base_component +---@return node, druid.component function M:create_item_callback(item_data, index) local nodes = gui.clone_tree(self.prefab) - local instance = self.druid:new(button_component, "button_component", nodes) + local instance = self.druid:new_widget(button_component, "button_component", nodes) gui.set_enabled(instance.root, true) return instance.root, instance @@ -48,7 +47,7 @@ end ---@param index number ---@param node node ----@param instance button_component +---@param instance examples.button_component ---@param data table function M:on_element_add(index, node, instance, data) instance.text:set_text("Data Item " .. index) @@ -62,11 +61,55 @@ function M:on_element_remove(index, node, instance, data) end ----@param instance button_component +---@param instance examples.button_component function M:on_button_click(instance) local data = instance:get_data() self.on_item_click:trigger(data) end +---@param output_list output_list +function M:on_example_created(output_list) + self.on_item_click:subscribe(function(index) + output_list:add_log_text("Item clicked: " .. index) + end) +end + + +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local view_node = self.scroll.view_node + local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL + + properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) + gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) + end) + + properties_panel:add_slider("ui_scroll", 0, function(value) + self.scroll:scroll_to_percent(vmath.vector3(0, 1 - value, 0), true) + end) +end + + +---@return string +function M:get_debug_info() + local data_list = self.data_list + + local data = data_list:get_data() + local info = "" + info = info .. "Data length: " .. #data .. "\n" + info = info .. "First Visual Index: " .. data_list.top_index .. "\n" + info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" + + local s = self.scroll + info = info .. "\n" + info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" + info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" + info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" + info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" + + return info +end + + return M diff --git a/example/examples/data_list/examples_list.lua b/example/examples/data_list/examples_list.lua index 1f496fa..b761165 100644 --- a/example/examples/data_list/examples_list.lua +++ b/example/examples/data_list/examples_list.lua @@ -9,46 +9,7 @@ function M.get_examples() template = "data_list_basic", root = "data_list_basic/root", code_url = "example/examples/data_list/basic/data_list_basic.lua", - component_class = require("example.examples.data_list.basic.data_list_basic"), - on_create = function(instance, output_list) - ---@cast instance data_list_basic - instance.on_item_click:subscribe(function(index) - output_list:add_log_text("Item clicked: " .. index) - end) - end, - properties_control = function(instance, properties_panel) - ---@cast instance data_list_basic - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - properties_panel:add_slider("ui_scroll", 0, function(value) - instance.scroll:scroll_to_percent(vmath.vector3(0, 1 - value, 0), true) - end) - end, - get_debug_info = function(instance) - ---@cast instance data_list_basic - local data_list = instance.data_list - - local data = data_list:get_data() - local info = "" - info = info .. "Data length: " .. #data .. "\n" - info = info .. "First Visual Index: " .. data_list.top_index .. "\n" - info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" - - local s = instance.scroll - info = info .. "\n" - info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" - info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" - info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" - info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" - - return info - end + widget_class = require("example.examples.data_list.basic.data_list_basic"), }, { @@ -57,36 +18,7 @@ function M.get_examples() template = "data_list_horizontal_basic", root = "data_list_horizontal_basic/root", code_url = "example/examples/data_list/basic/data_list_horizontal_basic.lua", - component_class = require("example.examples.data_list.basic.data_list_horizontal_basic"), - properties_control = function(instance, properties_panel) - ---@cast instance data_list_horizontal_basic - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - end, - get_debug_info = function(instance) - ---@cast instance data_list_horizontal_basic - local data_list = instance.data_list - - local data = data_list:get_data() - local info = "" - info = info .. "Data length: " .. #data .. "\n" - info = info .. "First Visual Index: " .. data_list.top_index .. "\n" - info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" - - local s = instance.scroll - info = info .. "\n" - info = info .. "View Size X: " .. gui.get(s.view_node, "size.x") .. "\n" - info = info .. "Content Size X: " .. gui.get(s.content_node, "size.x") .. "\n" - info = info .. "Content position X: " .. math.ceil(s.position.x) .. "\n" - info = info .. "Content Range X: " .. s.available_pos.x .. " - " .. s.available_pos.z .. "\n" - - return info - end + widget_class = require("example.examples.data_list.basic.data_list_horizontal_basic"), }, { @@ -95,59 +27,7 @@ function M.get_examples() template = "data_list_add_remove_clear", root = "data_list_add_remove_clear/root", code_url = "example/examples/data_list/add_remove_clear/data_list_add_remove_clear.lua", - component_class = require("example.examples.data_list.add_remove_clear.data_list_add_remove_clear"), - on_create = function(instance, output_list) - ---@cast instance data_list_add_remove_clear - instance.on_item_click:subscribe(function(index) - instance:remove_item(index) - output_list:add_log_text("Item removed: " .. index) - end) - end, - properties_control = function(instance, properties_panel) - ---@cast instance data_list_add_remove_clear - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - properties_panel:add_slider("ui_scroll", 0, function(value) - instance.scroll:scroll_to_percent(vmath.vector3(0, 1 - value, 0), true) - end) - - properties_panel:add_button("ui_add_element", function() - instance:add_item() - end) - - properties_panel:add_button("ui_remove_element", function() - instance:remove_item() - end) - - properties_panel:add_button("ui_clear_elements", function() - instance.data_list:clear() - end) - end, - get_debug_info = function(instance) - ---@cast instance data_list_add_remove_clear - local data_list = instance.data_list - - local data = data_list:get_data() - local info = "" - info = info .. "Data length: " .. #data .. "\n" - info = info .. "First Visual Index: " .. data_list.top_index .. "\n" - info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" - - local s = instance.scroll - info = info .. "\n" - info = info .. "View Size X: " .. gui.get(s.view_node, "size.x") .. "\n" - info = info .. "Content Size X: " .. gui.get(s.content_node, "size.x") .. "\n" - info = info .. "Content position X: " .. math.ceil(s.position.x) .. "\n" - info = info .. "Content Range X: " .. s.available_pos.x .. " - " .. s.available_pos.z .. "\n" - - return info - end + widget_class = require("example.examples.data_list.add_remove_clear.data_list_add_remove_clear"), }, { @@ -156,48 +36,9 @@ function M.get_examples() template = "data_list_cache_with_component", root = "data_list_cache_with_component/root", code_url = "example/examples/data_list/cache_with_component/cache_with_component.lua", - component_class = require("example.examples.data_list.cache_with_component.cache_with_component"), - on_create = function(instance, output_list) - ---@cast instance data_list_cache_with_component - instance.on_item_click:subscribe(function(index) - output_list:add_log_text("Item clicked: " .. index) - end) - end, - properties_control = function(instance, properties_panel) - ---@cast instance data_list_cache_with_component - - local view_node = instance.scroll.view_node - local is_stencil = gui.get_clipping_mode(view_node) == gui.CLIPPING_MODE_STENCIL - - properties_panel:add_checkbox("ui_clipping", is_stencil, function(value) - gui.set_clipping_mode(view_node, value and gui.CLIPPING_MODE_STENCIL or gui.CLIPPING_MODE_NONE) - end) - - properties_panel:add_slider("ui_scroll", 0, function(value) - instance.scroll:scroll_to_percent(vmath.vector3(0, 1 - value, 0), true) - end) - end, - get_debug_info = function(instance) - ---@cast instance data_list_cache_with_component - local data_list = instance.data_list - - local data = data_list:get_data() - local info = "" - info = info .. "Data length: " .. #data .. "\n" - info = info .. "First Visual Index: " .. data_list.top_index .. "\n" - info = info .. "Last Visual Index: " .. data_list.last_index .. "\n" - - local s = instance.scroll - info = info .. "\n" - info = info .. "View Size Y: " .. gui.get(s.view_node, "size.y") .. "\n" - info = info .. "Content Size Y: " .. gui.get(s.content_node, "size.y") .. "\n" - info = info .. "Content position Y: " .. math.ceil(s.position.y) .. "\n" - info = info .. "Content Range Y: " .. s.available_pos.y .. " - " .. s.available_pos.w .. "\n" - - return info - end + widget_class = require("example.examples.data_list.cache_with_component.cache_with_component"), }, } end -return M \ No newline at end of file +return M diff --git a/example/examples/druid_examples.lua b/example/examples/druid_examples.lua index 62ec6d2..2a15e75 100644 --- a/example/examples/druid_examples.lua +++ b/example/examples/druid_examples.lua @@ -18,11 +18,11 @@ local M = {} ---@field root string ---@field template string|nil ---@field code_url string|nil @URL to the source code ----@field component_class druid.base_component|nil +---@field component_class druid.component|nil ---@field widget_class druid.widget|nil New way to create components ----@field on_create fun(instance: druid.base_component|druid.widget, output_list: output_list)|nil ----@field get_debug_info (fun(instance: druid.base_component):string)|nil ----@field properties_control (fun(instance: druid.base_component, properties_panel: properties_panel))|nil +---@field on_create fun(instance: druid.component|druid.widget, output_list: output_list)|nil +---@field get_debug_info (fun(instance: druid.component):string)|nil +---@field properties_control (fun(instance: druid.component, properties_panel: properties_panel))|nil ---@field information_text_id string|nil @@ -49,4 +49,4 @@ function M.get_examples() return examples end -return M \ No newline at end of file +return M diff --git a/example/examples/gamepad/examples_list.lua b/example/examples/gamepad/examples_list.lua index aba51c0..2289fc1 100644 --- a/example/examples/gamepad/examples_list.lua +++ b/example/examples/gamepad/examples_list.lua @@ -10,63 +10,17 @@ function M.get_examples() template = "gamepad_tester", root = "gamepad_tester/root", code_url = "example/examples/gamepad/gamepad_tester/gamepad_tester.lua", - component_class = require("example.examples.gamepad.gamepad_tester.gamepad_tester"), - on_create = function(instance, output_list) - ---@cast instance gamepad_tester - instance.button_left.on_click:subscribe(function() - output_list:add_log_text("Button Left Clicked") - end) - instance.button_right.on_click:subscribe(function() - output_list:add_log_text("Button Right Clicked") - end) - instance.button_up.on_click:subscribe(function() - output_list:add_log_text("Button Up Clicked") - end) - instance.button_down.on_click:subscribe(function() - output_list:add_log_text("Button Down Clicked") - end) - instance.button_a.on_click:subscribe(function() - output_list:add_log_text("Button A Clicked") - end) - instance.button_b.on_click:subscribe(function() - output_list:add_log_text("Button B Clicked") - end) - instance.button_x.on_click:subscribe(function() - output_list:add_log_text("Button X Clicked") - end) - instance.button_y.on_click:subscribe(function() - output_list:add_log_text("Button Y Clicked") - end) - instance.button_back.on_click:subscribe(function() - output_list:add_log_text("Button Back Clicked") - end) - instance.button_start.on_click:subscribe(function() - output_list:add_log_text("Button Start Clicked") - end) - instance.button_l1.on_click:subscribe(function() - output_list:add_log_text("Button L1 Clicked") - end) - instance.button_r1.on_click:subscribe(function() - output_list:add_log_text("Button R1 Clicked") - end) - instance.button_stick_left.on_click:subscribe(function() - output_list:add_log_text("Button Stick Left Clicked") - end) - instance.button_stick_right.on_click:subscribe(function() - output_list:add_log_text("Button Stick Right Clicked") - end) - end, + widget_class = require("example.examples.gamepad.gamepad_tester.gamepad_tester"), }, - { name_id = "ui_example_on_screen_control", information_text_id = "ui_example_on_screen_control_description", template = "on_screen_control", root = "on_screen_control/root", code_url = "example/examples/gamepad/on_screen_control/on_screen_control.lua", - component_class = require("example.examples.gamepad.on_screen_control.on_screen_control"), + widget_class = require("example.examples.gamepad.on_screen_control.on_screen_control"), } } end -return M \ No newline at end of file +return M diff --git a/example/examples/gamepad/gamepad_tester/gamepad_tester.gui b/example/examples/gamepad/gamepad_tester/gamepad_tester.gui index 4dbc25b..03dfb38 100644 --- a/example/examples/gamepad/gamepad_tester/gamepad_tester.gui +++ b/example/examples/gamepad/gamepad_tester/gamepad_tester.gui @@ -36,6 +36,66 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui" } +nodes { + type: TYPE_BOX + id: "stick_left/root" + parent: "stick_left" + template_node_child: true +} +nodes { + type: TYPE_PIE + id: "stick_left/background_mask" + parent: "stick_left/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/background" + parent: "stick_left/background_mask" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/stick_root" + parent: "stick_left/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/stick_shadow" + parent: "stick_left/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/stick" + parent: "stick_left/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/dot_1" + parent: "stick_left/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/dot_2" + parent: "stick_left/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/dot_3" + parent: "stick_left/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_left/dot_4" + parent: "stick_left/stick" + template_node_child: true +} nodes { position { x: 200.0 @@ -47,6 +107,66 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui" } +nodes { + type: TYPE_BOX + id: "stick_right/root" + parent: "stick_right" + template_node_child: true +} +nodes { + type: TYPE_PIE + id: "stick_right/background_mask" + parent: "stick_right/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/background" + parent: "stick_right/background_mask" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/stick_root" + parent: "stick_right/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/stick_shadow" + parent: "stick_right/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/stick" + parent: "stick_right/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/dot_1" + parent: "stick_right/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/dot_2" + parent: "stick_right/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/dot_3" + parent: "stick_right/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "stick_right/dot_4" + parent: "stick_right/stick" + template_node_child: true +} nodes { position { x: -330.0 @@ -73,6 +193,30 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_left/button" + parent: "button_left" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_left/text" + parent: "button_left/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} +nodes { + rotation { + z: 180.0 + } + type: TYPE_BOX + id: "button_left/icon" + parent: "button_left/button" + overridden_fields: 2 + template_node_child: true +} nodes { position { y: 100.0 @@ -83,6 +227,30 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_up/button" + parent: "button_up" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_up/text" + parent: "button_up/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} +nodes { + rotation { + z: 90.0 + } + type: TYPE_BOX + id: "button_up/icon" + parent: "button_up/button" + overridden_fields: 2 + template_node_child: true +} nodes { position { x: 100.0 @@ -93,6 +261,26 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_right/button" + parent: "button_right" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_right/text" + parent: "button_right/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} +nodes { + type: TYPE_BOX + id: "button_right/icon" + parent: "button_right/button" + template_node_child: true +} nodes { position { y: -100.0 @@ -103,6 +291,30 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_down/button" + parent: "button_down" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_down/text" + parent: "button_down/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} +nodes { + rotation { + z: -90.0 + } + type: TYPE_BOX + id: "button_down/icon" + parent: "button_down/button" + overridden_fields: 2 + template_node_child: true +} nodes { position { x: 330.0 @@ -129,6 +341,26 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_x/button" + parent: "button_x" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_x/text" + parent: "button_x/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_x/icon" + parent: "button_x/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { y: 100.0 @@ -139,6 +371,28 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_y/button" + parent: "button_y" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "Y" + id: "button_y/text" + parent: "button_y/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_y/icon" + parent: "button_y/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { x: 100.0 @@ -149,6 +403,28 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_b/button" + parent: "button_b" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "B" + id: "button_b/text" + parent: "button_b/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_b/icon" + parent: "button_b/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { y: -100.0 @@ -159,6 +435,28 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_a/button" + parent: "button_a" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "A" + id: "button_a/text" + parent: "button_a/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_a/icon" + parent: "button_a/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { y: 160.0 @@ -184,6 +482,33 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + size { + x: 170.0 + y: 90.0 + } + type: TYPE_BOX + id: "button_back/button" + parent: "button_back" + overridden_fields: 4 + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "Back" + id: "button_back/text" + parent: "button_back/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_back/icon" + parent: "button_back/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { x: 110.0 @@ -194,6 +519,33 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + size { + x: 170.0 + y: 90.0 + } + type: TYPE_BOX + id: "button_start/button" + parent: "button_start" + overridden_fields: 4 + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "Start" + id: "button_start/text" + parent: "button_start/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_start/icon" + parent: "button_start/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { x: -330.0 @@ -221,6 +573,28 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_l1/button" + parent: "button_l1" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "L1" + id: "button_l1/text" + parent: "button_l1/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_l1/icon" + parent: "button_l1/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { y: 60.0 @@ -231,6 +605,26 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_trigger.gui" } +nodes { + type: TYPE_BOX + id: "button_l2/button" + parent: "button_l2" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_l2/fill" + parent: "button_l2/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "L2" + id: "button_l2/text" + parent: "button_l2/button" + overridden_fields: 8 + template_node_child: true +} nodes { position { x: 330.0 @@ -257,6 +651,28 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_r1/button" + parent: "button_r1" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "R1" + id: "button_r1/text" + parent: "button_r1/button" + overridden_fields: 8 + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_r1/icon" + parent: "button_r1/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} nodes { position { y: 60.0 @@ -267,5 +683,25 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_trigger.gui" } +nodes { + type: TYPE_BOX + id: "button_r2/button" + parent: "button_r2" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_r2/fill" + parent: "button_r2/button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + text: "R2" + id: "button_r2/text" + parent: "button_r2/button" + overridden_fields: 8 + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/gamepad/gamepad_tester/gamepad_tester.lua b/example/examples/gamepad/gamepad_tester/gamepad_tester.lua index 4b807d4..da01b2c 100644 --- a/example/examples/gamepad/gamepad_tester/gamepad_tester.lua +++ b/example/examples/gamepad/gamepad_tester/gamepad_tester.lua @@ -1,21 +1,29 @@ -local component = require("druid.component") - ----@class gamepad_tester: druid.base_component +---@class examples.gamepad_tester: druid.widget ---@field root node ----@field buttons druid.button ----@field buttons_system druid.button ----@field button_left_bump druid.button ----@field button_right_bump druid.button ----@field druid druid_instance -local M = component.create("gamepad_tester") +---@field button_left druid.button +---@field button_right druid.button +---@field button_up druid.button +---@field button_down druid.button +---@field button_x druid.button +---@field button_b druid.button +---@field button_y druid.button +---@field button_a druid.button +---@field button_l1 druid.button +---@field button_r1 druid.button +---@field button_stick_left druid.button +---@field button_stick_right druid.button +---@field button_start druid.button +---@field button_back druid.button +---@field trigger_l2 druid.progress +---@field trigger_r2 druid.progress +---@field stick_left node +---@field stick_right node +local M = {} local STICK_DISTANCE = 50 ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.root = self:get_node("root") self.button_left = self.druid:new_button("button_left/button"):set_key_trigger("gamepad_lpad_left") @@ -83,4 +91,51 @@ function M:on_input(action_id, action) end +---@param output_list output_list +function M:on_example_created(output_list) + self.button_left.on_click:subscribe(function() + output_list:add_log_text("Button Left Clicked") + end) + self.button_right.on_click:subscribe(function() + output_list:add_log_text("Button Right Clicked") + end) + self.button_up.on_click:subscribe(function() + output_list:add_log_text("Button Up Clicked") + end) + self.button_down.on_click:subscribe(function() + output_list:add_log_text("Button Down Clicked") + end) + self.button_a.on_click:subscribe(function() + output_list:add_log_text("Button A Clicked") + end) + self.button_b.on_click:subscribe(function() + output_list:add_log_text("Button B Clicked") + end) + self.button_x.on_click:subscribe(function() + output_list:add_log_text("Button X Clicked") + end) + self.button_y.on_click:subscribe(function() + output_list:add_log_text("Button Y Clicked") + end) + self.button_back.on_click:subscribe(function() + output_list:add_log_text("Button Back Clicked") + end) + self.button_start.on_click:subscribe(function() + output_list:add_log_text("Button Start Clicked") + end) + self.button_l1.on_click:subscribe(function() + output_list:add_log_text("Button L1 Clicked") + end) + self.button_r1.on_click:subscribe(function() + output_list:add_log_text("Button R1 Clicked") + end) + self.button_stick_left.on_click:subscribe(function() + output_list:add_log_text("Button Stick Left Clicked") + end) + self.button_stick_right.on_click:subscribe(function() + output_list:add_log_text("Button Stick Right Clicked") + end) +end + + return M diff --git a/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui b/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui index 215dc15..017b97f 100644 --- a/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui +++ b/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui @@ -8,8 +8,8 @@ textures { } nodes { size { - x: 12.0 - y: 12.0 + x: 250.0 + y: 250.0 } color { x: 0.31 diff --git a/example/examples/gamepad/on_screen_control/on_screen_control.gui b/example/examples/gamepad/on_screen_control/on_screen_control.gui index 8fab1e3..b037306 100644 --- a/example/examples/gamepad/on_screen_control/on_screen_control.gui +++ b/example/examples/gamepad/on_screen_control/on_screen_control.gui @@ -133,6 +133,66 @@ nodes { parent: "on_screen_input/root" template_node_child: true } +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/root" + parent: "on_screen_input/on_screen_stick" + template_node_child: true +} +nodes { + type: TYPE_PIE + id: "on_screen_input/on_screen_stick/background_mask" + parent: "on_screen_input/on_screen_stick/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/background" + parent: "on_screen_input/on_screen_stick/background_mask" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/stick_root" + parent: "on_screen_input/on_screen_stick/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/stick_shadow" + parent: "on_screen_input/on_screen_stick/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/stick" + parent: "on_screen_input/on_screen_stick/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/dot_1" + parent: "on_screen_input/on_screen_stick/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/dot_2" + parent: "on_screen_input/on_screen_stick/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/dot_3" + parent: "on_screen_input/on_screen_stick/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/on_screen_stick/dot_4" + parent: "on_screen_input/on_screen_stick/stick" + template_node_child: true +} nodes { type: TYPE_BOX id: "on_screen_input/on_screen_button" @@ -145,5 +205,23 @@ nodes { parent: "on_screen_input/on_screen_button" template_node_child: true } +nodes { + type: TYPE_BOX + id: "on_screen_input/button_action/button" + parent: "on_screen_input/button_action" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "on_screen_input/button_action/text" + parent: "on_screen_input/button_action/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_input/button_action/icon" + parent: "on_screen_input/button_action/button" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/gamepad/on_screen_control/on_screen_control.lua b/example/examples/gamepad/on_screen_control/on_screen_control.lua index 321c78f..f551926 100644 --- a/example/examples/gamepad/on_screen_control/on_screen_control.lua +++ b/example/examples/gamepad/on_screen_control/on_screen_control.lua @@ -1,25 +1,24 @@ -local component = require("druid.component") local on_screen_input = require("example.examples.gamepad.on_screen_control.on_screen_input") ----@class on_screen_control: druid.base_component ----@field druid druid_instance ----@field on_screen_input on_screen_input -local M = component.create("on_screen_control") +---@class examples.on_screen_control: druid.widget +---@field on_screen_input examples.on_screen_input +---@field character node +---@field character_position vector3 +---@field character_eye_left node +---@field character_eye_right node +local M = {} local CHARACTER_SPEED = 700 ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.character = self:get_node("character") self.character_position = gui.get_position(self.character) self.character_eye_left = self:get_node("eye_left") self.character_eye_right = self:get_node("eye_right") - self.on_screen_input = self.druid:new(on_screen_input, "on_screen_input") --[[@as on_screen_input]] + self.on_screen_input = self.druid:new_widget(on_screen_input, "on_screen_input") self.on_screen_input.on_action:subscribe(self.on_action_button, self) self.on_screen_input.on_movement:subscribe(self.on_movement, self) diff --git a/example/examples/gamepad/on_screen_control/on_screen_input.gui b/example/examples/gamepad/on_screen_control/on_screen_input.gui index 5a6dc92..ed48a3e 100644 --- a/example/examples/gamepad/on_screen_control/on_screen_input.gui +++ b/example/examples/gamepad/on_screen_control/on_screen_input.gui @@ -22,6 +22,66 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_stick.gui" } +nodes { + type: TYPE_BOX + id: "on_screen_stick/root" + parent: "on_screen_stick" + template_node_child: true +} +nodes { + type: TYPE_PIE + id: "on_screen_stick/background_mask" + parent: "on_screen_stick/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/background" + parent: "on_screen_stick/background_mask" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/stick_root" + parent: "on_screen_stick/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/stick_shadow" + parent: "on_screen_stick/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/stick" + parent: "on_screen_stick/stick_root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/dot_1" + parent: "on_screen_stick/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/dot_2" + parent: "on_screen_stick/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/dot_3" + parent: "on_screen_stick/stick" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "on_screen_stick/dot_4" + parent: "on_screen_stick/stick" + template_node_child: true +} nodes { position { x: 300.0 @@ -43,5 +103,25 @@ nodes { inherit_alpha: true template: "/example/examples/gamepad/gamepad_tester/templates/gamepad_button.gui" } +nodes { + type: TYPE_BOX + id: "button_action/button" + parent: "button_action" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button_action/text" + parent: "button_action/button" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "button_action/icon" + parent: "button_action/button" + overridden_fields: 45 + template_node_child: true + enabled: false +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/gamepad/on_screen_control/on_screen_input.lua b/example/examples/gamepad/on_screen_control/on_screen_input.lua index bb927a0..bb1af9a 100644 --- a/example/examples/gamepad/on_screen_control/on_screen_input.lua +++ b/example/examples/gamepad/on_screen_control/on_screen_input.lua @@ -1,22 +1,25 @@ local const = require("druid.const") local event = require("event.event") local helper = require("druid.helper") -local component = require("druid.component") ----@class on_screen_input: druid.base_component ----@field druid druid_instance +---@class examples.on_screen_input: druid.widget +---@field button_action node +---@field on_screen_control node +---@field stick_root node +---@field stick_position vector3 ---@field on_action event @() ---@field on_movement event @(x: number, y: number, dt: number) X/Y values are in range -1..1 ---@field on_movement_stop event @() -local M = component.create("on_screen_input") +---@field is_multitouch boolean +---@field _is_stick_drag boolean|number +---@field _prev_x number +---@field _prev_y number +local M = {} local STICK_DISTANCE = 80 ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.button_action = self:get_node("on_screen_button") self.on_screen_control = self:get_node("on_screen_stick/root") diff --git a/example/examples/intro/examples_list.lua b/example/examples/intro/examples_list.lua index 0618863..a3d8809 100644 --- a/example/examples/intro/examples_list.lua +++ b/example/examples/intro/examples_list.lua @@ -10,7 +10,7 @@ function M.get_examples() template = "intro", root = "intro/root", code_url = "example/examples/intro/intro/intro.lua", - component_class = require("example.examples.intro.intro.intro"), + widget_class = require("example.examples.intro.intro.intro"), }, --{ -- name_id = "ui_example_how_to_use_example", @@ -18,9 +18,9 @@ function M.get_examples() -- template = "how_to_use_example", -- root = "how_to_use_example/root", -- code_url = "example/examples/intro/how_to_use_example/how_to_use_example.lua", - -- component_class = require("example.examples.intro.how_to_use_example.how_to_use_example"), + -- widget_class = require("example.examples.intro.how_to_use_example.how_to_use_example"), --} } end -return M \ No newline at end of file +return M diff --git a/example/examples/intro/how_to_use_example/how_to_use_example.lua b/example/examples/intro/how_to_use_example/how_to_use_example.lua index b797f98..6f7c922 100644 --- a/example/examples/intro/how_to_use_example/how_to_use_example.lua +++ b/example/examples/intro/how_to_use_example/how_to_use_example.lua @@ -1,14 +1,9 @@ -local component = require("druid.component") -local panthera = require("panthera.panthera") - ----@class how_to_use_example: druid.base_component +---@class examples.how_to_use_example: druid.widget ---@field root node -local M = component.create("how_to_use_example") +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) + +function M:init() self.root = self:get_node("root") self.druid:new_rich_text("text_hello", "Hello!") diff --git a/example/examples/intro/intro/intro.lua b/example/examples/intro/intro/intro.lua index 10ea849..798429e 100644 --- a/example/examples/intro/intro/intro.lua +++ b/example/examples/intro/intro/intro.lua @@ -1,15 +1,13 @@ -local component = require("druid.component") local panthera = require("panthera.panthera") local intro_panthera = require("example.examples.intro.intro.intro_panthera") ----@class intro: druid.base_component +---@class examples.intro: druid.widget ---@field root node -local M = component.create("intro") +---@field animation panthera.animation +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) + +function M:init() self.root = self:get_node("root") self.druid:new_rich_text("text_hello", "Hello!") @@ -24,7 +22,7 @@ function M:init(template, nodes) :add("sponsor_kofi") :set_margin(8, 0) - self.animation = panthera.create_gui(intro_panthera, self:get_template(), nodes) + self.animation = panthera.create_gui(intro_panthera, self:get_template(), self:get_nodes()) panthera.play(self.animation, "idle", { is_loop = true }) end diff --git a/example/examples/layout/basic/basic_layout.lua b/example/examples/layout/basic/basic_layout.lua index f6805e1..710af3c 100644 --- a/example/examples/layout/basic/basic_layout.lua +++ b/example/examples/layout/basic/basic_layout.lua @@ -1,11 +1,12 @@ local helper = require("druid.helper") -local component = require("druid.component") local layout = require("druid.extended.layout") ----@class basic_layout: druid.base_component ----@field druid druid_instance +---@class examples.basic_layout: druid.widget ---@field root node -local M = component.create("basic_layout") +---@field layout druid.layout +---@field prefab node +---@field nodes table +local M = {} local PIVOTS = { gui.PIVOT_CENTER, @@ -20,11 +21,7 @@ local PIVOTS = { } ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.root = self:get_node("root") self.layout = self.druid:new(layout, "layout", "horizontal_wrap") @@ -73,4 +70,79 @@ function M:on_remove() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + + properties_panel:add_slider("ui_padding", 0, function(value) + local padding = math.floor((value * 64) * 100) / 100 + self.layout:set_padding(padding, padding, padding, padding) + end) + + properties_panel:add_slider("ui_margin_x", 0, function(value) + local margin = math.floor((value * 64) * 100) / 100 + self.layout:set_margin(margin, nil) + end) + + properties_panel:add_slider("ui_margin_y", 0, function(value) + local margin = math.floor((value * 64) * 100) / 100 + self.layout:set_margin(nil, margin) + end) + + properties_panel:add_checkbox("ui_justify", false, function(value) + self.layout:set_justify(value) + end) + + local pivot_index = 1 + local pivot_list = { + gui.PIVOT_CENTER, + gui.PIVOT_W, + gui.PIVOT_SW, + gui.PIVOT_S, + gui.PIVOT_SE, + gui.PIVOT_E, + gui.PIVOT_NE, + gui.PIVOT_N, + gui.PIVOT_NW, + } + + properties_panel:add_button("ui_pivot_next", function() + pivot_index = pivot_index + 1 + if pivot_index > #pivot_list then + pivot_index = 1 + end + self:set_pivot(pivot_list[pivot_index]) + end) + + local type_index = 1 + local type_list = { + "horizontal_wrap", + "horizontal", + "vertical", + } + + properties_panel:add_button("ui_type_next", function() + type_index = type_index + 1 + if type_index > #type_list then + type_index = 1 + end + self.layout:set_type(type_list[type_index]) + end) +end + + +---@return string +function M:get_debug_info() + local layout = self.layout + local p = layout.padding + local info = "" + info = info .. "Layout: " .. layout.type .. "\n" + info = info .. "Padding: " .. math.floor(p.x) .. " " .. math.floor(p.y) .. " " .. math.floor(p.z) .. " " .. math.floor(p.w) .. "\n" + info = info .. "Margin: " .. layout.margin.x .. " " .. layout.margin.y .. "\n" + info = info .. "Justify: " .. tostring(layout.is_justify) .. "\n" + info = info .. "Pivot: " .. tostring(gui.get_pivot(layout.node)) .. "\n" + + return info +end + + return M diff --git a/example/examples/layout/examples_list.lua b/example/examples/layout/examples_list.lua index 3dc15ba..3c03a28 100644 --- a/example/examples/layout/examples_list.lua +++ b/example/examples/layout/examples_list.lua @@ -10,82 +10,10 @@ function M.get_examples() template = "basic_layout", root = "basic_layout/root", code_url = "example/examples/layout/basic/basic_layout.lua", - component_class = require("example.examples.layout.basic.basic_layout"), - properties_control = function(instance, properties_panel) - ---@cast instance basic_layout - - properties_panel:add_slider("ui_padding", 0, function(value) - local padding = math.floor((value * 64) * 100) / 100 - instance.layout:set_padding(vmath.vector4(padding)) - end) - - properties_panel:add_slider("ui_margin_x", 0, function(value) - local margin = math.floor((value * 64) * 100) / 100 - instance.layout:set_margin(margin, nil) - end) - - properties_panel:add_slider("ui_margin_y", 0, function(value) - local margin = math.floor((value * 64) * 100) / 100 - instance.layout:set_margin(nil, margin) - end) - - properties_panel:add_checkbox("ui_justify", false, function(value) - instance.layout:set_justify(value) - end) - - local pivot_index = 1 - local pivot_list = { - gui.PIVOT_CENTER, - gui.PIVOT_W, - gui.PIVOT_SW, - gui.PIVOT_S, - gui.PIVOT_SE, - gui.PIVOT_E, - gui.PIVOT_NE, - gui.PIVOT_N, - gui.PIVOT_NW, - } - - properties_panel:add_button("ui_pivot_next", function() - pivot_index = pivot_index + 1 - if pivot_index > #pivot_list then - pivot_index = 1 - end - instance:set_pivot(pivot_list[pivot_index]) - end) - - - local type_index = 1 - local type_list = { - "horizontal_wrap", - "horizontal", - "vertical", - } - - properties_panel:add_button("ui_type_next", function() - type_index = type_index + 1 - if type_index > #type_list then - type_index = 1 - end - instance.layout:set_type(type_list[type_index]) - end) - end, - get_debug_info = function(instance) - ---@cast instance basic_layout - local layout = instance.layout - local p = layout.padding - local info = "" - info = info .. "Layout: " .. layout.type .. "\n" - info = info .. "Padding: " .. math.floor(p.x) .. " " .. math.floor(p.y) .. " " .. math.floor(p.z) .. " " .. math.floor(p.w) .. "\n" - info = info .. "Margin: " .. layout.margin.x .. " " .. layout.margin.y .. "\n" - info = info .. "Justify: " .. tostring(layout.is_justify) .. "\n" - info = info .. "Pivot: " .. tostring(gui.get_pivot(layout.node)) .. "\n" - - return info - end + widget_class = require("example.examples.layout.basic.basic_layout"), } } end -return M \ No newline at end of file +return M diff --git a/example/examples/panthera/animation_blend/animation_blend.lua b/example/examples/panthera/animation_blend/animation_blend.lua index 2192db2..e3ed42b 100644 --- a/example/examples/panthera/animation_blend/animation_blend.lua +++ b/example/examples/panthera/animation_blend/animation_blend.lua @@ -1,28 +1,28 @@ local panthera = require("panthera.panthera") -local component = require("druid.component") local helper = require("druid.helper") local event = require("event.event") local character_animation_blend = require("example.examples.panthera.animation_blend.character_animation_blend") ----@class animation_blend: druid.base_component +---@class examples.animation_blend: druid.widget ---@field root node ----@field druid druid_instance -local M = component.create("animation_blend") +---@field root_size vector3 +---@field animation_idle panthera.animation +---@field animation_vertical panthera.animation +---@field animation_horizontal panthera.animation +---@field rich_text druid.rich_text +---@field on_update event +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.root = self:get_node("root") self.root_size = gui.get_size(self.root) self.druid:new_lang_text("text_hint", "ui_example_panthera_animation_blend_hint") - self.animation_idle = panthera.create_gui(character_animation_blend, self:get_template(), nodes) - self.animation_vertical = panthera.create_gui(character_animation_blend, self:get_template(), nodes) - self.animation_horizontal = panthera.create_gui(character_animation_blend, self:get_template(), nodes) + self.animation_idle = panthera.create_gui(character_animation_blend, self:get_template(), self:get_nodes()) + self.animation_vertical = panthera.create_gui(character_animation_blend, self:get_template(), self:get_nodes()) + self.animation_horizontal = panthera.create_gui(character_animation_blend, self:get_template(), self:get_nodes()) panthera.play(self.animation_idle, "idle", { is_loop = true, @@ -70,4 +70,25 @@ function M:setup_rich_text() end +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + local vertical_time = panthera.get_time(self.animation_vertical) + + local vertical_slider = properties_panel:add_slider("ui_animation_vertical", vertical_time, function(value) + panthera.set_time(self.animation_vertical, "vertical", value) + end) + + local horizontal_time = panthera.get_time(self.animation_horizontal) + + local horizontal_slider = properties_panel:add_slider("ui_animation_horizontal", horizontal_time, function(value) + panthera.set_time(self.animation_horizontal, "horizontal", value) + end) + + self.on_update:subscribe(function() + vertical_slider:set_value(panthera.get_time(self.animation_vertical)) + horizontal_slider:set_value(panthera.get_time(self.animation_horizontal)) + end) +end + + return M diff --git a/example/examples/panthera/animation_blend/assets/animation_blend.atlas b/example/examples/panthera/animation_blend/assets/animation_blend.atlas index 5ce1d2b..d81ed7c 100644 --- a/example/examples/panthera/animation_blend/assets/animation_blend.atlas +++ b/example/examples/panthera/animation_blend/assets/animation_blend.atlas @@ -1,46 +1,31 @@ images { image: "/example/examples/panthera/animation_blend/assets/facial_part_eye_open.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/facial_part_eyebrow_b.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/facial_part_mouth_happy.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/facial_part_mouth_smirk.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/pink_body_squircle.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/pink_hand_closed.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/pink_hand_open.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/pink_hand_point.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/shadow.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } images { image: "/example/examples/panthera/animation_blend/assets/facial_part_eye_half_top.png" - sprite_trim_mode: SPRITE_TRIM_MODE_OFF } -margin: 0 extrude_borders: 2 -inner_padding: 0 -max_page_width: 0 -max_page_height: 0 -rename_patterns: "" diff --git a/example/examples/panthera/basic_animation/basic_animation.gui b/example/examples/panthera/basic_animation/basic_animation.gui index 4eb714a..c51399b 100644 --- a/example/examples/panthera/basic_animation/basic_animation.gui +++ b/example/examples/panthera/basic_animation/basic_animation.gui @@ -20,5 +20,17 @@ nodes { inherit_alpha: true template: "/example/templates/button_text_blue.gui" } +nodes { + type: TYPE_BOX + id: "button/root" + parent: "button" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "button/text" + parent: "button/root" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/panthera/basic_animation/basic_animation.lua b/example/examples/panthera/basic_animation/basic_animation.lua index b179207..791b57b 100644 --- a/example/examples/panthera/basic_animation/basic_animation.lua +++ b/example/examples/panthera/basic_animation/basic_animation.lua @@ -1,19 +1,15 @@ local panthera = require("panthera.panthera") -local component = require("druid.component") local basic_animation_panthera = require("example.examples.panthera.basic_animation.basic_animation_panthera") ----@class basic_animation: druid.base_component ----@field druid druid_instance -local M = component.create("basic_animation") +---@class examples.basic_animation: druid.widget +---@field animation panthera.animation +---@field button druid.button +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - - self.animation = panthera.create_gui(basic_animation_panthera, self:get_template(), nodes) +function M:init() + self.animation = panthera.create_gui(basic_animation_panthera, self:get_template(), self:get_nodes()) self.button = self.druid:new_button("button/root", function() panthera.play(self.animation, "on_click", { diff --git a/example/examples/panthera/examples_list.lua b/example/examples/panthera/examples_list.lua index 7f401ee..f086489 100644 --- a/example/examples/panthera/examples_list.lua +++ b/example/examples/panthera/examples_list.lua @@ -10,7 +10,7 @@ function M.get_examples() template = "basic_animation", root = "basic_animation/root", code_url = "example/examples/panthera/basic_animation/basic_animation.lua", - component_class = require("example.examples.panthera.basic_animation.basic_animation"), + widget_class = require("example.examples.panthera.basic_animation.basic_animation"), }, { name_id = "ui_example_panthera_animation_blend", @@ -18,28 +18,9 @@ function M.get_examples() template = "animation_blend", root = "animation_blend/root", code_url = "example/examples/panthera/animation_blend/animation_blend.lua", - component_class = require("example.examples.panthera.animation_blend.animation_blend"), - properties_control = function(instance, properties_panel) - ---@cast instance animation_blend - local vertical_time = panthera.get_time(instance.animation_vertical) - - local vertical_slider = properties_panel:add_slider("ui_animation_vertical", vertical_time, function(value) - panthera.set_time(instance.animation_vertical, "vertical", value) - end) - - local horizontal_time = panthera.get_time(instance.animation_horizontal) - - local horizontal_slider = properties_panel:add_slider("ui_animation_horizontal", horizontal_time, function(value) - panthera.set_time(instance.animation_horizontal, "horizontal", value) - end) - - instance.on_update:subscribe(function() - vertical_slider:set_value(panthera.get_time(instance.animation_vertical)) - horizontal_slider:set_value(panthera.get_time(instance.animation_horizontal)) - end) - end, + widget_class = require("example.examples.panthera.animation_blend.animation_blend"), } } end -return M \ No newline at end of file +return M diff --git a/example/examples/widgets/examples_list.lua b/example/examples/widgets/examples_list.lua index d127fb0..77a8867 100644 --- a/example/examples/widgets/examples_list.lua +++ b/example/examples/widgets/examples_list.lua @@ -9,7 +9,7 @@ function M.get_examples() template = "hover_hint_example", root = "hover_hint_example/root", code_url = "example/examples/widgets/hover_hint/hover_hint_example.lua", - component_class = require("example.examples.widgets.hover_hint.hover_hint_example"), + widget_class = require("example.examples.widgets.hover_hint.hover_hint_example"), }, { name_id = "ui_example_widget_properties_panel", @@ -19,7 +19,7 @@ function M.get_examples() code_url = "example/examples/widgets/properties_panel/properties_panel.lua", widget_class = require("druid.widget.properties_panel.properties_panel"), on_create = function(instance, output_list) - ---@cast instance widget.properties_panel + ---@cast instance druid.widget.properties_panel instance:add_button(function(button) button:set_text_button("Button") @@ -83,7 +83,7 @@ function M.get_examples() template = "property_button", root = "property_button/root", code_url = "example/components/properties_panel/properties/property_button.lua", - component_class = require("example.components.properties_panel.properties.property_button"), + widget_class = require("example.components.properties_panel.properties.property_button"), on_create = function(instance, output_list) ---@cast instance property_button instance.button.on_click:subscribe(function() @@ -105,7 +105,7 @@ function M.get_examples() template = "property_slider", root = "property_slider/root", code_url = "example/components/properties_panel/properties/property_slider.lua", - component_class = require("example.components.properties_panel.properties.property_slider"), + widget_class = require("example.components.properties_panel.properties.property_slider"), on_create = function(instance, output_list) ---@cast instance property_slider instance.slider.on_change_value:subscribe(function(_, value) @@ -119,7 +119,7 @@ function M.get_examples() template = "property_checkbox", root = "property_checkbox/root", code_url = "example/components/properties_panel/properties/property_checkbox.lua", - component_class = require("example.components.properties_panel.properties.property_checkbox"), + widget_class = require("example.components.properties_panel.properties.property_checkbox"), on_create = function(instance, output_list) ---@cast instance property_checkbox instance.button.on_click:subscribe(function() @@ -132,10 +132,10 @@ function M.get_examples() information_text_id = "ui_example_widget_memory_panel_description", template = "memory_panel", root = "memory_panel/root", - code_url = "druid.widget.memory_panel.memory_panel.lua", + code_url = "druid/widget/memory_panel/memory_panel.lua", widget_class = require("druid.widget.memory_panel.memory_panel"), on_create = function(instance, output_list) - ---@cast instance widget.memory_panel + ---@cast instance druid.widget.memory_panel print("Memory panel created") end, }, @@ -144,10 +144,10 @@ function M.get_examples() information_text_id = "ui_example_widget_fps_panel_description", template = "fps_panel", root = "fps_panel/root", - code_url = "druid.widget.fps_panel.fps_panel.lua", + code_url = "druid/widget/fps_panel/fps_panel.lua", widget_class = require("druid.widget.fps_panel.fps_panel"), on_create = function(instance, output_list) - ---@cast instance widget.fps_panel + ---@cast instance druid.widget.fps_panel print("FPS panel created") end, }, @@ -156,14 +156,14 @@ function M.get_examples() information_text_id = "ui_example_widget_mini_graph_description", template = "mini_graph", root = "mini_graph/root", - code_url = "druid.widget.mini_graph.mini_graph.lua", + code_url = "druid/widget/mini_graph/mini_graph.lua", widget_class = require("druid.widget.mini_graph.mini_graph"), on_create = function(instance, output_list) - ---@cast instance widget.mini_graph + ---@cast instance druid.widget.mini_graph instance:set_samples(50) end, properties_control = function(instance, properties_panel) - ---@cast instance widget.mini_graph + ---@cast instance druid.widget.mini_graph properties_panel:add_slider("value", 0.5, function(value) -- Remap to -1, 2 value = value * 3 - 1 @@ -177,8 +177,16 @@ function M.get_examples() end end) end, + }, + { + name_id = "ui_example_widget_tiling_node", + information_text_id = "ui_example_widget_tiling_node_description", + template = "example_tiling_node", + root = "example_tiling_node/root", + code_url = "example/examples/widgets/tiling_node/example_tiling_node.lua", + widget_class = require("example.examples.widgets.tiling_node.example_tiling_node"), } } end -return M \ No newline at end of file +return M diff --git a/example/examples/widgets/fps_panel/example_fps_panel.lua b/example/examples/widgets/fps_panel/example_fps_panel.lua index 50de100..a26b10c 100644 --- a/example/examples/widgets/fps_panel/example_fps_panel.lua +++ b/example/examples/widgets/fps_panel/example_fps_panel.lua @@ -1,6 +1,6 @@ local fps_panel = require("druid.widget.fps_panel.fps_panel") ----@class widget.example_fps_panel: druid.widget +---@class examples.example_fps_panel: druid.widget local M = {} @@ -9,4 +9,4 @@ function M:init() end -return M \ No newline at end of file +return M diff --git a/example/examples/widgets/hover_hint/hover_hint.lua b/example/examples/widgets/hover_hint/hover_hint.lua index 2cf4537..f0710a4 100644 --- a/example/examples/widgets/hover_hint/hover_hint.lua +++ b/example/examples/widgets/hover_hint/hover_hint.lua @@ -1,9 +1,7 @@ local helper = require("druid.helper") local druid_const = require("druid.const") -local component = require("druid.component") ----@class hover_hint: druid.base_component ----@field druid druid_instance +---@class examples.hover_hint: druid.widget ---@field root node ---@field panel_hint node ---@field text_hint druid.text @@ -11,7 +9,7 @@ local component = require("druid.component") ---@field is_shown boolean ---@field private _hint_text string ---@field private _hover_timer_id hash -local M = component.create("hover_hint") +local M = {} local TIMER_DELAY = 0.5 local MIN_PANEL_WIDTH = 100 @@ -19,10 +17,7 @@ local MIN_PANEL_HEIGHT = 50 local PANEL_MARGIN = 40 local HINT_OFFSET = 20 ----@param template string -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.root = self:get_node("root") self.panel_hint = self:get_node("panel_hint") self.text_hint = self.druid:new_text("text_hint") diff --git a/example/examples/widgets/hover_hint/hover_hint_example.gui b/example/examples/widgets/hover_hint/hover_hint_example.gui index 9c19b51..da55c14 100644 --- a/example/examples/widgets/hover_hint/hover_hint_example.gui +++ b/example/examples/widgets/hover_hint/hover_hint_example.gui @@ -33,6 +33,24 @@ nodes { inherit_alpha: true template: "/example/examples/widgets/hover_hint/hover_hint.gui" } +nodes { + type: TYPE_BOX + id: "hover_hint/root" + parent: "hover_hint" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "hover_hint/panel_hint" + parent: "hover_hint/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "hover_hint/text_hint" + parent: "hover_hint/panel_hint" + template_node_child: true +} nodes { position { y: 100.0 diff --git a/example/examples/widgets/hover_hint/hover_hint_example.lua b/example/examples/widgets/hover_hint/hover_hint_example.lua index 28cf278..18ad5f8 100644 --- a/example/examples/widgets/hover_hint/hover_hint_example.lua +++ b/example/examples/widgets/hover_hint/hover_hint_example.lua @@ -1,17 +1,10 @@ local hover_hint = require("example.examples.widgets.hover_hint.hover_hint") -local component = require("druid.component") +---@class examples.hover_hint_example: druid.widget +local M = {} ----@class hover_hint_example: druid.base_component ----@field druid druid_instance -local M = component.create("hover_hint_example") - - ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - self.hover_hint = self.druid:new(hover_hint, "hover_hint") +function M:init() + self.hover_hint = self.druid:new_widget(hover_hint, "hover_hint") self.hover_hint:add_hover_hint(self:get_node("node_yellow"), "Yellow box", gui.PIVOT_N, gui.PIVOT_S) self.hover_hint:add_hover_hint(self:get_node("node_green"), "Green box", gui.PIVOT_S, gui.PIVOT_N) diff --git a/example/examples/widgets/memory_panel/example_memory_panel.lua b/example/examples/widgets/memory_panel/example_memory_panel.lua index f42f0f6..29d6c45 100644 --- a/example/examples/widgets/memory_panel/example_memory_panel.lua +++ b/example/examples/widgets/memory_panel/example_memory_panel.lua @@ -1,6 +1,6 @@ local memory_panel = require("druid.widget.memory_panel.memory_panel") ----@class widget.example_memory_panel: druid.widget +---@class examples.example_memory_panel: druid.widget local M = {} @@ -9,4 +9,4 @@ function M:init() end -return M \ No newline at end of file +return M diff --git a/example/examples/widgets/properties_panel/example_properties_panel.gui b/example/examples/widgets/properties_panel/example_properties_panel.gui index b1889c7..c88910a 100644 --- a/example/examples/widgets/properties_panel/example_properties_panel.gui +++ b/example/examples/widgets/properties_panel/example_properties_panel.gui @@ -364,5 +364,209 @@ nodes { parent: "properties_panel/property_left_right_selector/E_Anchor" template_node_child: true } +nodes { + type: TYPE_TEMPLATE + id: "properties_panel/property_vector3" + parent: "properties_panel/propeties" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/root" + parent: "properties_panel/property_vector3" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/text_name" + parent: "properties_panel/property_vector3/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/E_Anchor" + parent: "properties_panel/property_vector3/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/field_x" + parent: "properties_panel/property_vector3/E_Anchor" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/text_x" + parent: "properties_panel/property_vector3/field_x" + template_node_child: true +} +nodes { + type: TYPE_TEMPLATE + id: "properties_panel/property_vector3/rich_input_x" + parent: "properties_panel/property_vector3/field_x" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_x/root" + parent: "properties_panel/property_vector3/rich_input_x" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_x/button" + parent: "properties_panel/property_vector3/rich_input_x/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_x/placeholder_text" + parent: "properties_panel/property_vector3/rich_input_x/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_x/input_text" + parent: "properties_panel/property_vector3/rich_input_x/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_x/cursor_node" + parent: "properties_panel/property_vector3/rich_input_x/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_x/cursor_text" + parent: "properties_panel/property_vector3/rich_input_x/cursor_node" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/selected_x" + parent: "properties_panel/property_vector3/field_x" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/field_y" + parent: "properties_panel/property_vector3/E_Anchor" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/text_y" + parent: "properties_panel/property_vector3/field_y" + template_node_child: true +} +nodes { + type: TYPE_TEMPLATE + id: "properties_panel/property_vector3/rich_input_y" + parent: "properties_panel/property_vector3/field_y" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_y/root" + parent: "properties_panel/property_vector3/rich_input_y" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_y/button" + parent: "properties_panel/property_vector3/rich_input_y/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_y/placeholder_text" + parent: "properties_panel/property_vector3/rich_input_y/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_y/input_text" + parent: "properties_panel/property_vector3/rich_input_y/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_y/cursor_node" + parent: "properties_panel/property_vector3/rich_input_y/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_y/cursor_text" + parent: "properties_panel/property_vector3/rich_input_y/cursor_node" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/selected_y" + parent: "properties_panel/property_vector3/field_y" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/field_z" + parent: "properties_panel/property_vector3/E_Anchor" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/text_z" + parent: "properties_panel/property_vector3/field_z" + template_node_child: true +} +nodes { + type: TYPE_TEMPLATE + id: "properties_panel/property_vector3/rich_input_z" + parent: "properties_panel/property_vector3/field_z" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_z/root" + parent: "properties_panel/property_vector3/rich_input_z" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_z/button" + parent: "properties_panel/property_vector3/rich_input_z/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_z/placeholder_text" + parent: "properties_panel/property_vector3/rich_input_z/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_z/input_text" + parent: "properties_panel/property_vector3/rich_input_z/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/rich_input_z/cursor_node" + parent: "properties_panel/property_vector3/rich_input_z/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "properties_panel/property_vector3/rich_input_z/cursor_text" + parent: "properties_panel/property_vector3/rich_input_z/cursor_node" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "properties_panel/property_vector3/selected_z" + parent: "properties_panel/property_vector3/field_z" + template_node_child: true +} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT diff --git a/example/examples/widgets/properties_panel/example_properties_panel.lua b/example/examples/widgets/properties_panel/example_properties_panel.lua index 887950d..9106f9b 100644 --- a/example/examples/widgets/properties_panel/example_properties_panel.lua +++ b/example/examples/widgets/properties_panel/example_properties_panel.lua @@ -1,6 +1,6 @@ local properties_panel = require("druid.widget.properties_panel.properties_panel") ----@class widget.example_properties_panel: druid.widget +---@class druid.widget.example_properties_panel: druid.widget local M = {} diff --git a/example/examples/widgets/tiling_node/example_tiling_node.gui b/example/examples/widgets/tiling_node/example_tiling_node.gui new file mode 100644 index 0000000..f98269f --- /dev/null +++ b/example/examples/widgets/tiling_node/example_tiling_node.gui @@ -0,0 +1,34 @@ +textures { + name: "tiling_texture" + texture: "/example/examples/widgets/tiling_node/tiling_texture.atlas" +} +nodes { + size { + x: 200.0 + y: 100.0 + } + type: TYPE_BOX + id: "root" + inherit_alpha: true + size_mode: SIZE_MODE_AUTO + visible: false +} +nodes { + size { + x: 900.0 + y: 900.0 + } + type: TYPE_BOX + texture: "tiling_texture/pattern_0004" + id: "tiling_node" + parent: "root" + inherit_alpha: true + alpha: 0.42 + material: "gui_tiling_node" +} +material: "/builtins/materials/gui.material" +adjust_reference: ADJUST_REFERENCE_PARENT +materials { + name: "gui_tiling_node" + material: "/druid/custom/tiling_node/gui_tiling_node.material" +} diff --git a/example/examples/widgets/tiling_node/example_tiling_node.lua b/example/examples/widgets/tiling_node/example_tiling_node.lua new file mode 100644 index 0000000..53a8522 --- /dev/null +++ b/example/examples/widgets/tiling_node/example_tiling_node.lua @@ -0,0 +1,37 @@ +local tiling_node = require("druid.custom.tiling_node.tiling_node") + +---@class examples.example_tiling_node: druid.widget +local M = {} + + +function M:init() + self.tiling_node = self.druid:new(tiling_node, self:get_node("tiling_node")) +end + + +---@param properties_panel properties_panel +function M:properties_control(properties_panel) + properties_panel:add_slider("Repeat X", 0, function(value) + local repeat_x = math.floor(value * 10) + self.tiling_node:set_repeat(repeat_x, nil) + end) + properties_panel:add_slider("Repeat Y", 0, function(value) + local repeat_y = math.floor(value * 10) + self.tiling_node:set_repeat(nil, repeat_y) + end) + properties_panel:add_slider("Offset X", 0, function(value) + self.tiling_node:set_offset(value, nil) + end) + properties_panel:add_slider("Offset Y", 0, function(value) + self.tiling_node:set_offset(nil, value) + end) + properties_panel:add_slider("Margin X", 0, function(value) + self.tiling_node:set_margin(value, nil) + end) + properties_panel:add_slider("Margin Y", 0, function(value) + self.tiling_node:set_margin(nil, value) + end) +end + + +return M diff --git a/example/examples/widgets/tiling_node/pattern_0004.png b/example/examples/widgets/tiling_node/pattern_0004.png new file mode 100644 index 0000000..c3adc2e Binary files /dev/null and b/example/examples/widgets/tiling_node/pattern_0004.png differ diff --git a/example/examples/widgets/tiling_node/tiling_texture.atlas b/example/examples/widgets/tiling_node/tiling_texture.atlas new file mode 100644 index 0000000..6135667 --- /dev/null +++ b/example/examples/widgets/tiling_node/tiling_texture.atlas @@ -0,0 +1,3 @@ +images { + image: "/example/examples/widgets/tiling_node/pattern_0004.png" +} diff --git a/example/examples/windows/examples_list.lua b/example/examples/windows/examples_list.lua index da826a3..b799aff 100644 --- a/example/examples/windows/examples_list.lua +++ b/example/examples/windows/examples_list.lua @@ -10,13 +10,7 @@ function M.get_examples() template = "window_language", root = "window_language/root", code_url = "example/examples/windows/window_language/window_language.lua", - component_class = require("example.examples.windows.window_language.window_language"), - on_create = function(instance, output_list) - ---@cast instance window_language - instance.on_language_change:subscribe(function(language) - output_list:add_log_text("Language changed to " .. language) - end) - end + widget_class = require("example.examples.windows.window_language.window_language"), }, { name_id = "ui_example_window_confirmation", @@ -24,21 +18,7 @@ function M.get_examples() root = "window_confirmation/root", information_text_id = "ui_example_window_language_description", code_url = "example/examples/windows/window_confirmation/window_confirmation.lua", - component_class = require("example.examples.windows.window_confirmation.window_confirmation"), - on_create = function(instance, output_list) - ---@cast instance window_confirmation - instance.text_header:translate("ui_confirmation") - instance.text_button_accept:translate("ui_confirm") - instance.text_button_decline:translate("ui_cancel") - instance.text_description:translate("ui_confirmation_description") - - instance.button_accept.on_click:subscribe(function() - output_list:add_log_text("Confirmation Accepted") - end) - instance.button_decline.on_click:subscribe(function() - output_list:add_log_text("Confirmation Declined") - end) - end, + widget_class = require("example.examples.windows.window_confirmation.window_confirmation"), }, { name_id = "ui_example_window_information", @@ -46,19 +26,9 @@ function M.get_examples() root = "window_info/root", information_text_id = "ui_example_window_information_description", code_url = "example/examples/windows/window_info/window_info.lua", - component_class = require("example.examples.windows.window_info.window_info"), - on_create = function(instance, output_list) - ---@cast instance window_info - instance.text_header:translate("ui_information") - instance.text_button_accept:translate("ui_confirm") - instance.text_description:translate("ui_example_window_information_text") - - instance.button_accept.on_click:subscribe(function() - output_list:add_log_text("Information Accepted") - end) - end + widget_class = require("example.examples.windows.window_info.window_info"), } } end -return M \ No newline at end of file +return M diff --git a/example/examples/windows/window_confirmation/window_confirmation.collection b/example/examples/windows/window_confirmation/window_confirmation.collection index 6017d36..2303afa 100644 --- a/example/examples/windows/window_confirmation/window_confirmation.collection +++ b/example/examples/windows/window_confirmation/window_confirmation.collection @@ -5,35 +5,6 @@ embedded_instances { data: "components {\n" " id: \"window_confirmation\"\n" " component: \"/example/examples/windows/window_confirmation/window_confirmation.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } diff --git a/example/examples/windows/window_confirmation/window_confirmation.lua b/example/examples/windows/window_confirmation/window_confirmation.lua index f91b7a5..f5f9b0a 100644 --- a/example/examples/windows/window_confirmation/window_confirmation.lua +++ b/example/examples/windows/window_confirmation/window_confirmation.lua @@ -1,23 +1,20 @@ -local component = require("druid.component") local panthera = require("panthera.panthera") local window_animation_panthera = require("example.examples.windows.window_animation_panthera") ----@class window_confirmation: druid.base_component ----@field druid druid_instance +---@class examples.window_confirmation: druid.widget ---@field text_header druid.lang_text ---@field text_button_accept druid.lang_text ---@field text_button_decline druid.lang_text ---@field text_description druid.lang_text ---@field button_close druid.button -local M = component.create("window_confirmation") +---@field button_accept druid.button +---@field button_decline druid.button +---@field animation panthera.animation +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.text_header = self.druid:new_lang_text("text_header", "ui_confirmation") --[[@as druid.lang_text]] self.text_button_accept = self.druid:new_lang_text("button_accept/text", "ui_accept") --[[@as druid.lang_text]] self.text_button_decline = self.druid:new_lang_text("button_decline/text", "ui_decline") --[[@as druid.lang_text]] @@ -27,7 +24,7 @@ function M:init(template, nodes) self.button_accept = self.druid:new_button("button_accept/root") self.button_decline = self.druid:new_button("button_decline/root") - self.animation = panthera.create_gui(window_animation_panthera, self:get_template(), nodes) + self.animation = panthera.create_gui(window_animation_panthera, self:get_template(), self:get_nodes()) panthera.play(self.animation, "open") end @@ -37,4 +34,20 @@ function M:on_button_close() end +---@param output_list output_list +function M:on_example_created(output_list) + self.text_header:translate("ui_confirmation") + self.text_button_accept:translate("ui_confirm") + self.text_button_decline:translate("ui_cancel") + self.text_description:translate("ui_confirmation_description") + + self.button_accept.on_click:subscribe(function() + output_list:add_log_text("Confirmation Accepted") + end) + self.button_decline.on_click:subscribe(function() + output_list:add_log_text("Confirmation Declined") + end) +end + + return M diff --git a/example/examples/windows/window_info/window_info.collection b/example/examples/windows/window_info/window_info.collection index 6790821..23423c9 100644 --- a/example/examples/windows/window_info/window_info.collection +++ b/example/examples/windows/window_info/window_info.collection @@ -5,35 +5,6 @@ embedded_instances { data: "components {\n" " id: \"window_info\"\n" " component: \"/example/examples/windows/window_info/window_info.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } diff --git a/example/examples/windows/window_info/window_info.lua b/example/examples/windows/window_info/window_info.lua index 3385176..5cae2be 100644 --- a/example/examples/windows/window_info/window_info.lua +++ b/example/examples/windows/window_info/window_info.lua @@ -1,22 +1,18 @@ -local component = require("druid.component") local panthera = require("panthera.panthera") local window_animation_panthera = require("example.examples.windows.window_animation_panthera") ----@class window_info: druid.base_component +---@class examples.window_info: druid.widget ---@field text_header druid.lang_text ---@field text_button_accept druid.lang_text ---@field text_description druid.lang_text ---@field button_close druid.button ----@field druid druid_instance -local M = component.create("window_info") +---@field button_accept druid.button +---@field animation panthera.animation +local M = {} ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) - +function M:init() self.text_header = self.druid:new_lang_text("text_header", "ui_information") --[[@as druid.lang_text]] self.text_button_accept = self.druid:new_lang_text("button_accept/text", "ui_accept") --[[@as druid.lang_text]] self.text_description = self.druid:new_lang_text("text") --[[@as druid.lang_text]] @@ -24,7 +20,7 @@ function M:init(template, nodes) self.button_close = self.druid:new_button("button_close", self.on_button_close) self.button_accept = self.druid:new_button("button_accept/root") - self.animation = panthera.create_gui(window_animation_panthera, self:get_template(), nodes) + self.animation = panthera.create_gui(window_animation_panthera, self:get_template(), self:get_nodes()) panthera.play(self.animation, "open") end @@ -34,4 +30,16 @@ function M:on_button_close() end +---@param output_list output_list +function M:on_example_created(output_list) + self.text_header:translate("ui_information") + self.text_button_accept:translate("ui_confirm") + self.text_description:translate("ui_example_window_information_text") + + self.button_accept.on_click:subscribe(function() + output_list:add_log_text("Information Accepted") + end) +end + + return M diff --git a/example/examples/windows/window_language/window_language.collection b/example/examples/windows/window_language/window_language.collection index b479753..2912c9e 100644 --- a/example/examples/windows/window_language/window_language.collection +++ b/example/examples/windows/window_language/window_language.collection @@ -5,35 +5,6 @@ embedded_instances { data: "components {\n" " id: \"window_language\"\n" " component: \"/example/examples/windows/window_language/window_language.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } diff --git a/example/examples/windows/window_language/window_language.lua b/example/examples/windows/window_language/window_language.lua index 25c9bf4..b891213 100644 --- a/example/examples/windows/window_language/window_language.lua +++ b/example/examples/windows/window_language/window_language.lua @@ -1,30 +1,27 @@ local lang = require("lang.lang") local druid = require("druid.druid") local event = require("event.event") -local component = require("druid.component") local panthera = require("panthera.panthera") local window_animation_panthera = require("example.examples.windows.window_animation_panthera") ----@class window_language: druid.base_component +---@class examples.window_language: druid.widget ---@field text_header druid.text ---@field button_close druid.button ----@field druid druid_instance ---@field lang_buttons table ---@field grid druid.grid ---@field on_language_change event -local M = component.create("window_language") +---@field animation panthera.animation +local M = {} + ---Color: #F0FBFF local DEFAULT_LANGUAGE_COLOR = vmath.vector4(240/255, 251/255, 255/255, 1.0) ---Color: #E6DF9F local SELECTED_LANGUAGE_COLOR = vmath.vector4(230/255, 223/255, 159/255, 1.0) ----@param template string ----@param nodes table -function M:init(template, nodes) - self.druid = self:get_druid(template, nodes) +function M:init() self.lang_buttons = {} self.created_nodes = {} self.prefab = self:get_node("button_prefab") @@ -113,4 +110,12 @@ function M:on_language_button(lang_id) end +---@param output_list output_list +function M:on_example_created(output_list) + self.on_language_change:subscribe(function(language) + output_list:add_log_text("Language changed to " .. language) + end) +end + + return M diff --git a/example/locales/en.json b/example/locales/en.json index dcf64ea..78f1e17 100644 --- a/example/locales/en.json +++ b/example/locales/en.json @@ -23,6 +23,7 @@ "ui_type_next": "Next Type", "ui_adjust_next": "Next Adjust", "ui_enabled": "Enabled", + "ui_item_size": "Item Size", "ui_examples_basic": "Basic", "ui_examples_data_list": "Data List", @@ -183,12 +184,21 @@ "ui_example_widget_fps_panel": "FPS Panel", "ui_example_widget_fps_panel_description": "Here is a example of FPS panel usage", + "ui_example_widget_mini_graph": "Mini Graph", + "ui_example_widget_mini_graph_description": "Here is a example of mini graph usage", + "ui_example_widget_properties_panel": "Properties Panel", "ui_example_widget_properties_panel_description": "Here is a example of properties panel usage", + "ui_example_widget_property_input": "Property Input", + "ui_example_widget_property_input_description": "Here is a example of property input usage", + "ui_example_gamepad_tester": "Gamepad Tester", "ui_example_gamepad_tester_description": "Test your gamepad here to bind buttons and axes", + "ui_example_widget_tiling_node": "Tiling Node", + "ui_example_widget_tiling_node_description": "Here is a example of tiling node usage", + "ui_example_on_screen_control": "On Screen Control", "ui_example_on_screen_control_description": "Here is a example of on screen control. The on_screen_input here is a joystick with a callback as Druid component", @@ -215,4 +225,4 @@ "ui_language_it": "Italiano", "ui_language_kr": "한국어", "ui_language_zh": "中文" -} \ No newline at end of file +} diff --git a/example/other/go_bindings/go_bindings.collection b/example/other/go_bindings/go_bindings.collection new file mode 100644 index 0000000..ade704a --- /dev/null +++ b/example/other/go_bindings/go_bindings.collection @@ -0,0 +1,33 @@ +name: "go_bindings" +scale_along_z: 0 +embedded_instances { + id: "go" + data: "components {\n" + " id: \"go_widget\"\n" + " component: \"/example/other/go_bindings/go_widget.gui\"\n" + "}\n" + "components {\n" + " id: \"go_bindings\"\n" + " component: \"/example/other/go_bindings/go_bindings.script\"\n" + "}\n" + "embedded_components {\n" + " id: \"sprite\"\n" + " type: \"sprite\"\n" + " data: \"default_animation: \\\"ui_circle_8\\\"\\n" + "material: \\\"/builtins/materials/sprite.material\\\"\\n" + "textures {\\n" + " sampler: \\\"texture_sampler\\\"\\n" + " texture: \\\"/druid/druid.atlas\\\"\\n" + "}\\n" + "\"\n" + " rotation {\n" + " z: 0.70710677\n" + " w: 0.70710677\n" + " }\n" + "}\n" + "" + position { + x: 776.0 + y: 366.0 + } +} diff --git a/example/other/go_bindings/go_bindings.script b/example/other/go_bindings/go_bindings.script new file mode 100644 index 0000000..aa7c12c --- /dev/null +++ b/example/other/go_bindings/go_bindings.script @@ -0,0 +1,26 @@ +local panthera = require("panthera.panthera") + +local animation = require("example.other.go_bindings.go_bindings_panthera") + +local druid = require("druid.druid") +local widget = require("example.other.go_bindings.go_widget") + +function init(self) + local gui_url = msg.url(nil, nil, "go_widget") + self.go_widget = druid.get_widget(widget, gui_url) + self.go_widget:play_animation() + self.go_widget:set_position(go.get_position()) + + self.animation = panthera.create_go(animation) + panthera.play(self.animation, "default", { + is_loop = true, + }) + + msg.post(".", "acquire_input_focus") +end + + +function update(self, dt) + self.go_widget:set_position(go.get_position()) +end + diff --git a/example/other/go_bindings/go_bindings_panthera.lua b/example/other/go_bindings/go_bindings_panthera.lua new file mode 100644 index 0000000..3d1ab31 --- /dev/null +++ b/example/other/go_bindings/go_bindings_panthera.lua @@ -0,0 +1,79 @@ +return { + data = { + animations = { + { + animation_id = "default", + animation_keys = { + { + duration = 1.13, + easing = "outback", + end_value = 706, + key_type = "tween", + node_id = "go", + property_id = "position_x", + start_value = 776, + }, + { + duration = 1.46, + easing = "outback", + end_value = 271, + key_type = "tween", + node_id = "go", + property_id = "position_y", + start_time = 1.13, + start_value = 366, + }, + { + duration = 1.44, + easing = "outback", + end_value = 826, + key_type = "tween", + node_id = "go", + property_id = "position_x", + start_time = 2.59, + start_value = 706, + }, + { + duration = 1.17, + easing = "outback", + end_value = 366, + key_type = "tween", + node_id = "go", + property_id = "position_y", + start_time = 4.02, + start_value = 271, + }, + { + duration = 0.81, + easing = "outback", + end_value = 776, + key_type = "tween", + node_id = "go", + property_id = "position_x", + start_time = 5.19, + start_value = 826, + }, + }, + duration = 6, + }, + }, + metadata = { + fps = 60, + gizmo_steps = { + }, + gui_path = "/example/other/go_bindings/go_bindings.collection", + layers = { + }, + settings = { + font_size = 30, + }, + template_animation_paths = { + }, + }, + nodes = { + }, + }, + format = "json", + type = "animation_editor", + version = 1, +} \ No newline at end of file diff --git a/example/other/go_bindings/go_widget.gui b/example/other/go_bindings/go_widget.gui new file mode 100644 index 0000000..7a88d2b --- /dev/null +++ b/example/other/go_bindings/go_widget.gui @@ -0,0 +1,156 @@ +script: "/druid/druid_widget.gui_script" +fonts { + name: "druid_text_bold" + font: "/druid/fonts/druid_text_bold.font" +} +textures { + name: "druid" + texture: "/druid/druid.atlas" +} +nodes { + type: TYPE_BOX + texture: "druid/empty" + id: "root" + inherit_alpha: true + size_mode: SIZE_MODE_AUTO +} +nodes { + position { + y: 20.0 + } + size { + x: 32.0 + y: 120.0 + } + type: TYPE_BOX + texture: "druid/ui_circle_32" + id: "circle" + pivot: PIVOT_S + parent: "root" + inherit_alpha: true + slice9 { + x: 16.0 + y: 16.0 + z: 16.0 + w: 16.0 + } +} +nodes { + position { + y: 190.0 + } + size { + x: 200.0 + y: 100.0 + } + type: TYPE_TEXT + text: "20" + font: "druid_text_bold" + id: "text" + parent: "root" + inherit_alpha: true + outline_alpha: 0.0 + shadow_alpha: 0.0 +} +nodes { + position { + x: 233.0 + y: 127.0 + } + type: TYPE_TEMPLATE + id: "memory_panel" + inherit_alpha: true + template: "/druid/widget/memory_panel/memory_panel.gui" +} +nodes { + type: TYPE_BOX + id: "memory_panel/root" + parent: "memory_panel" + template_node_child: true +} +nodes { + type: TYPE_TEMPLATE + id: "memory_panel/mini_graph" + parent: "memory_panel/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/mini_graph/root" + parent: "memory_panel/mini_graph" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/mini_graph/header" + parent: "memory_panel/mini_graph/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "memory_panel/mini_graph/text_header" + parent: "memory_panel/mini_graph/header" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/mini_graph/icon_drag" + parent: "memory_panel/mini_graph/header" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/mini_graph/content" + parent: "memory_panel/mini_graph/root" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/mini_graph/prefab_line" + parent: "memory_panel/mini_graph/content" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/mini_graph/color_low" + parent: "memory_panel/mini_graph/content" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/content" + parent: "memory_panel/root" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "memory_panel/text_max_value" + parent: "memory_panel/content" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "memory_panel/text_per_second" + parent: "memory_panel/content" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/line_second_1" + parent: "memory_panel/content" + template_node_child: true +} +nodes { + type: TYPE_BOX + id: "memory_panel/line_second_2" + parent: "memory_panel/content" + template_node_child: true +} +nodes { + type: TYPE_TEXT + id: "memory_panel/text_memory" + parent: "memory_panel/content" + template_node_child: true +} +material: "/druid/materials/gui_world/gui_world.material" +adjust_reference: ADJUST_REFERENCE_DISABLED diff --git a/example/other/go_bindings/go_widget.lua b/example/other/go_bindings/go_widget.lua new file mode 100644 index 0000000..7d481f3 --- /dev/null +++ b/example/other/go_bindings/go_widget.lua @@ -0,0 +1,39 @@ +local panthera = require("panthera.panthera") + +local animation = require("example.other.go_bindings.go_widget_panthera") +local memory_panel = require("druid.widget.memory_panel.memory_panel") + +---@class druid.widget.go_widget: druid.widget +local M = {} + + +function M:init() + print("init widget", msg.url()) + self.root = self:get_node("root") + self.circle = self:get_node("circle") + self.animation = panthera.create_gui(animation) + self.counter = 0 + self.text_counter = self:get_node("text") + gui.set_text(self.text_counter, 0) + + self.memory_panel = self.druid:new_widget(memory_panel, "memory_panel") +end + + +function M:play_animation() + panthera.play(self.animation, "default", { + is_loop = true, + callback = function() + self.counter = self.counter + 1 + gui.set_text(self.text_counter, self.counter) + end + }) +end + + +---@param position vector3 The position to set +function M:set_position(position) + gui.set_position(self.root, position) +end + +return M diff --git a/example/other/go_bindings/go_widget_panthera.lua b/example/other/go_bindings/go_widget_panthera.lua new file mode 100644 index 0000000..ad69818 --- /dev/null +++ b/example/other/go_bindings/go_widget_panthera.lua @@ -0,0 +1,186 @@ +return { + data = { + animations = { + { + animation_id = "default", + animation_keys = { + { + easing = "outsine", + end_value = 1.6, + key_type = "tween", + node_id = "text", + property_id = "scale_x", + start_value = 1, + }, + { + easing = "outsine", + end_value = 1.6, + key_type = "tween", + node_id = "text", + property_id = "scale_y", + start_value = 1, + }, + { + duration = 0.15, + easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "text", + property_id = "scale_x", + start_value = 1.6, + }, + { + duration = 0.15, + easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "text", + property_id = "scale_y", + start_value = 1.6, + }, + { + duration = 0.39, + easing = "outsine", + end_value = 400, + key_type = "tween", + node_id = "text", + property_id = "position_y", + start_value = 190, + }, + { + duration = 0.43, + easing = "outsine", + end_value = 300, + key_type = "tween", + node_id = "circle", + property_id = "size_y", + start_value = 120, + }, + { + duration = 1, + easing = "inoutexpo", + end_value = 720, + key_type = "tween", + node_id = "root", + property_id = "rotation_z", + }, + { + duration = 0.24, + easing = "outsine", + end_value = 2, + key_type = "tween", + node_id = "text", + property_id = "scale_x", + start_time = 0.15, + start_value = 1, + }, + { + duration = 0.24, + easing = "outsine", + end_value = 2, + key_type = "tween", + node_id = "text", + property_id = "scale_y", + start_time = 0.15, + start_value = 1, + }, + { + duration = 0.3, + easing = "outsine", + key_type = "tween", + node_id = "circle", + property_id = "color_b", + start_time = 0.31, + start_value = 1, + }, + { + duration = 0.3, + easing = "outsine", + key_type = "tween", + node_id = "circle", + property_id = "color_g", + start_time = 0.31, + start_value = 1, + }, + { + duration = 0.61, + easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "text", + property_id = "scale_x", + start_time = 0.39, + start_value = 2, + }, + { + duration = 0.61, + easing = "outsine", + end_value = 1, + key_type = "tween", + node_id = "text", + property_id = "scale_y", + start_time = 0.39, + start_value = 2, + }, + { + duration = 0.26, + easing = "insine", + end_value = 1, + key_type = "tween", + node_id = "circle", + property_id = "color_b", + start_time = 0.61, + }, + { + duration = 0.26, + easing = "insine", + end_value = 1, + key_type = "tween", + node_id = "circle", + property_id = "color_g", + start_time = 0.61, + }, + { + duration = 0.36, + easing = "outsine", + end_value = 190, + key_type = "tween", + node_id = "text", + property_id = "position_y", + start_time = 0.62, + start_value = 400, + }, + { + duration = 0.35, + easing = "outsine", + end_value = 120, + key_type = "tween", + node_id = "circle", + property_id = "size_y", + start_time = 0.65, + start_value = 300, + }, + }, + duration = 1, + }, + }, + metadata = { + fps = 60, + gizmo_steps = { + }, + gui_path = "/example/other/go_bindings/go_widget.gui", + layers = { + }, + settings = { + font_size = 30, + }, + template_animation_paths = { + }, + }, + nodes = { + }, + }, + format = "json", + type = "animation_editor", + version = 1, +} \ No newline at end of file diff --git a/game.project b/game.project index e233e1c..66da382 100644 --- a/game.project +++ b/game.project @@ -19,11 +19,11 @@ publisher = Insality developer = Maksim Tuprikov custom_resources = /example/locales dependencies#0 = https://github.com/britzl/deftest/archive/refs/tags/2.8.0.zip -dependencies#1 = https://github.com/Insality/defold-saver/archive/refs/tags/1.zip +dependencies#1 = https://github.com/Insality/defold-saver/archive/refs/heads/develop.zip dependencies#2 = https://github.com/Insality/defold-tweener/archive/refs/tags/3.zip -dependencies#3 = https://github.com/Insality/panthera/archive/refs/tags/runtime.4.zip +dependencies#3 = https://github.com/Insality/panthera/archive/refs/heads/develop.zip dependencies#4 = https://github.com/Insality/defold-lang/archive/refs/tags/3.zip -dependencies#5 = https://github.com/Insality/defold-event/archive/refs/tags/10.zip +dependencies#5 = https://github.com/Insality/defold-event/archive/refs/heads/develop.zip dependencies#6 = https://github.com/subsoap/defos/archive/refs/tags/v2.8.0.zip [library] @@ -36,8 +36,6 @@ game_binding = /builtins/input/all.input_bindingc [druid] no_auto_input = 0 -no_stencil_check = 0 -no_auto_template = 0 input_text = text input_touch = touch input_marked_text = marked_text @@ -60,7 +58,7 @@ cssfile = /builtins/manifests/web/dark_theme.css show_console_banner = 0 [native_extension] -app_manifest = +app_manifest = [graphics] texture_profiles = /builtins/graphics/default.texture_profiles @@ -109,3 +107,5 @@ path = /example/locales langs = en,ru,es,de,fr,ja,pt,it,kr,zh default = es +[event] +use_xpcall = 1 diff --git a/liveupdate.settings b/liveupdate.settings deleted file mode 100644 index 6d746e9..0000000 --- a/liveupdate.settings +++ /dev/null @@ -1,4 +0,0 @@ -[liveupdate] -mode = Zip -supported-versions = - diff --git a/manifest.private.der b/manifest.private.der deleted file mode 100644 index 73a06b0..0000000 Binary files a/manifest.private.der and /dev/null differ diff --git a/manifest.public.der b/manifest.public.der deleted file mode 100644 index ebf423a..0000000 Binary files a/manifest.public.der and /dev/null differ diff --git a/settings_deployer b/settings_deployer index 155dcc9..36ed926 100644 --- a/settings_deployer +++ b/settings_deployer @@ -2,7 +2,7 @@ bob_folder=./ # You can point bob version for project in format "filename:sha" -bob_sha="196:11d2cd3a9be17b2fc5a2cb5cea59bbfb4af1ca96" +bob_sha=":868769ba7a3458db12d149188bf3be80a339a85c" # Select Defold channel. Values: stable, beta, alpha bob_channel="stable" @@ -14,4 +14,4 @@ use_latest_bob=false build_server="https://build.defold.com" # Is need to build html report -is_build_html_report=true \ No newline at end of file +is_build_html_report=true diff --git a/test/helper/test_helper.lua b/test/helper/test_helper.lua index a451959..11b027e 100644 --- a/test/helper/test_helper.lua +++ b/test/helper/test_helper.lua @@ -3,7 +3,7 @@ local mock = require("deftest.mock.mock") local M = {} -- Userdata type instead of script self ----@return vector3|vector4 +---@return vector function M.get_context() return vmath.vector({}) end diff --git a/test/test.collection b/test/test.collection index fe2bf3f..503ceda 100644 --- a/test/test.collection +++ b/test/test.collection @@ -5,35 +5,6 @@ embedded_instances { data: "components {\n" " id: \"test\"\n" " component: \"/test/test.gui\"\n" - " position {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " }\n" - " rotation {\n" - " x: 0.0\n" - " y: 0.0\n" - " z: 0.0\n" - " w: 1.0\n" - " }\n" - " property_decls {\n" - " }\n" "}\n" "" - position { - x: 0.0 - y: 0.0 - z: 0.0 - } - rotation { - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - } - scale3 { - x: 1.0 - y: 1.0 - z: 1.0 - } } diff --git a/test/test.gui b/test/test.gui index d0f87d1..97579f5 100644 --- a/test/test.gui +++ b/test/test.gui @@ -1,10 +1,3 @@ script: "/test/test.gui_script" -background_color { - x: 0.0 - y: 0.0 - z: 0.0 - w: 0.0 -} material: "/builtins/materials/gui.material" adjust_reference: ADJUST_REFERENCE_PARENT -max_nodes: 512 diff --git a/test/test.gui_script b/test/test.gui_script index 59f6c21..608f448 100644 --- a/test/test.gui_script +++ b/test/test.gui_script @@ -1,21 +1,11 @@ local deftest = require("deftest.deftest") -local tests = { - -- Test list - require("test.tests.test_button"), - require("test.tests.test_hover"), - require("test.tests.test_drag"), - require("test.tests.test_back_handler"), - require("test.tests.test_blocker"), - --require("test.tests.test_static_grid"), -} - - function init(self) - print('[DefTest]: Init of DefTest') - for i = 1, #tests do - deftest.add(tests[i]) - end + deftest.add(require("test.tests.test_button")) + deftest.add(require("test.tests.test_hover")) + deftest.add(require("test.tests.test_drag")) + deftest.add(require("test.tests.test_back_handler")) + deftest.add(require("test.tests.test_blocker")) local is_report = (sys.get_config_int("test.report", 0) == 1) deftest.run({ coverage = { enabled = is_report } }) diff --git a/test/tests/test_blocker.lua b/test/tests/test_blocker.lua index 3c32481..04cb220 100644 --- a/test/tests/test_blocker.lua +++ b/test/tests/test_blocker.lua @@ -1,34 +1,32 @@ return function() - local mock_gui = nil - local mock_time = nil - local mock_input = nil - local test_helper = nil - local druid_system = nil - - local druid = nil - local context = nil - describe("Blocker component", function() + local mock_gui = nil + local mock_time = nil + local mock_input = nil + local test_helper = nil + local druid_system = nil + + local druid = nil ---@type druid.instance + before(function() mock_gui = require("deftest.mock.gui") + mock_gui.mock() + mock_time = require("deftest.mock.time") mock_input = require("test.helper.mock_input") test_helper = require("test.helper.test_helper") druid_system = require("druid.druid") - mock_gui.mock() mock_time.mock() mock_time.set(60) - context = test_helper.get_context() - druid = druid_system.new(context) + druid = druid_system.new(vmath.vector3()) end) after(function() mock_gui.unmock() mock_time.unmock() - druid:final(context) - druid = nil + druid:final() end) it("Should consume input", function() diff --git a/test/tests/test_button.lua b/test/tests/test_button.lua index 057135b..131522a 100644 --- a/test/tests/test_button.lua +++ b/test/tests/test_button.lua @@ -1,22 +1,23 @@ return function() - local mock_gui = nil - local mock_time = nil - local mock_input = nil - local test_helper = nil - local druid_system = nil - - local druid = nil - local context = nil - describe("Button Component", function() + local mock_gui = nil + local mock_time = nil + local mock_input = nil + local test_helper = nil + local druid_system = nil + + local druid = nil + local context = nil + before(function() mock_gui = require("deftest.mock.gui") + mock_gui.mock() + mock_time = require("deftest.mock.time") mock_input = require("test.helper.mock_input") test_helper = require("test.helper.test_helper") druid_system = require("druid.druid") - mock_gui.mock() mock_time.mock() mock_time.set(60) diff --git a/docs_md/02-creating_custom_components.md b/wiki/02-creating_custom_components.md similarity index 95% rename from docs_md/02-creating_custom_components.md rename to wiki/02-creating_custom_components.md index bdb1ea9..bd5177d 100644 --- a/docs_md/02-creating_custom_components.md +++ b/wiki/02-creating_custom_components.md @@ -1,5 +1,12 @@ # Creating Custom Components +# Deprecated +Custom compomnents from 1.1 release are deprecated. Now we have a new way to create custom components - widgets. + +Custom components are will exists for more system things like basic components. You don't have to migrate to widgets. + +Read more about widgets in [widgets.md](widgets.md) + ## Overview Druid offers the flexibility to create custom components that contain your own logic, as well as other Druid basic components or custom components. While Druid provides a set of predefined components like buttons and scrolls, it goes beyond that and provides a way to handle all your GUI elements in a more abstract manner. Custom components are a powerful way to separate logic and create higher levels of abstraction in your code. @@ -9,6 +16,7 @@ Every component is a child of the Basic Druid component. You can call methods of ## Custom Components ### Basic Component Template + A basic custom component template looks like this (you can copy it from `/druid/templates/component.template.lua`): ```lua @@ -32,6 +40,7 @@ return M ``` Then you can create your custom component with Druid: + ```lua local druid = require("druid.druid") @@ -43,8 +52,6 @@ function init(self) -- We pass a GUI template "template_name" and skip nodes due it already on the scene self.my_component = self.druid:new(my_component, "template_name") self.my_component:hello() -- Hello from custom component - - end ``` diff --git a/docs_md/03-styles.md b/wiki/03-styles.md similarity index 93% rename from docs_md/03-styles.md rename to wiki/03-styles.md index 278bd92..23ab005 100644 --- a/docs_md/03-styles.md +++ b/wiki/03-styles.md @@ -1,6 +1,7 @@ # Styles ## Overview + Styles - set of functions and parameters for components to customize their behavior. Styles is a table, where key is name of component, and value is style table for this component. @@ -8,29 +9,33 @@ Styles is a table, where key is name of component, and value is style table for In component API documentation, you can find the style API for this component. Or just lookup for existing styles and modify them. ## Usage + Setup default druid style for all druid instances via `druid.set_default_style` You can pass _nil_ or _empty_table_ to use default values for all components (no styles) + ```lua local druid = require("druid.druid") local my_style = require("my.amazing.style") function init(self) - druid.set_default_style(my_style) + druid.set_default_style(my_style) end ``` Setup custom style to specific druid instance: + ```lua local druid = require("druid.druid") local my_style = require("my.amazing.style") function init(self) - -- This druid instance will be use my_style as default - self.druid = druid.new(self, my_style) + -- This druid instance will be use my_style as default + self.druid = druid.new(self, my_style) end ``` Change component style with _set_style_ function + ```lua local druid = require("druid.druid") local my_style = require("my.amazing.style") diff --git a/docs_md/advanced-setup.md b/wiki/advanced-setup.md similarity index 80% rename from docs_md/advanced-setup.md rename to wiki/advanced-setup.md index cf369d1..3744225 100644 --- a/docs_md/advanced-setup.md +++ b/wiki/advanced-setup.md @@ -1,6 +1,5 @@ # Advanced Druid Setup - ## Input Bindings By default, **Druid** uses all key names from Defold's default `/builtins/input/all.input_binding` for input bindings. @@ -96,23 +95,3 @@ local function on_window_callback(self, event, data) end window.set_listener(on_window_callback) ``` - - -## Lua Annotations - -[EmmyLua](https://emmylua.github.io/annotation.html) is a Lua annotation library. It is a useful tool for enabling Lua code autocompletion in editors such as [VSCode](https://github.com/EmmyLua/VSCode-EmmyLua) and [IntelliJ IDEA](https://github.com/EmmyLua/IntelliJ-EmmyLua). - -Since dependencies cannot be processed by external editors, to use the EmmyLua annotations, you should copy the _druid/annotations.lua_ file to your project. - -Remember that you can restart the EmmyLua server to refresh the changes if something goes wrong. - -After the annotations are processed, you should specify the type of "Druid" in the "require" statement: - -```lua ----@type druid -local druid = require("druid.druid") - --- Now the autocomplete is working -``` - - diff --git a/wiki/basic_usage.md b/wiki/basic_usage.md new file mode 100644 index 0000000..187dd52 --- /dev/null +++ b/wiki/basic_usage.md @@ -0,0 +1,176 @@ +# Basic Usage + +This guide will help you get started with **Druid** UI framework. We'll cover the basic setup and usage patterns. + +## Initial Setup + +To use **Druid**, you need to create a **Druid** instance in your GUI script. This instance will handle all component management and core functionality. + +Create a new `*.gui_script` file with the following template: + +```lua +local druid = require("druid.druid") + +function init(self) + self.druid = druid.new(self) +end + +function final(self) + self.druid:final() +end + +function update(self, dt) + self.druid:update(dt) +end + +function on_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 +``` + +Add this script to your GUI scene. Now you can start creating **Druid** components. + +> **Note:** When passing nodes to components, you can use node name strings instead of `gui.get_node()` function. + +## Basic Components Example + +Here's a simple example showing how to create and use basic **Druid** components: + +```lua +local druid = require("druid.druid") + +-- All component callbacks pass "self" as first argument +-- This "self" is a context data passed in `druid.new(context)` +local function on_button_callback(self) + self.text:set_text("The button clicked!") +end + +function init(self) + self.druid = druid.new(self) + -- We can use the node_id instead of gui.get_node(): + self.button = self.druid:new_button("button_node_id", on_button_callback) + self.text = self.druid:new_text("text_node_id", "Hello, Druid!") +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 +``` + +## Widgets + +Widgets are reusable UI components that encapsulate multiple **Druid** components. Read more in the [Widgets](wiki/widgets.md) documentation. + +### Creating a Widget + +Create a new Lua file for your widget class. This file should be placed near the corresponding GUI file with the same name. + +Define `init` function to initialize the widget. + +Here's a basic widget example: + +```lua +---@class your_widget_class: druid.widget +local M = {} + +function M:init() + self.root = self:get_node("root") + self.button = self.druid:new_button("button_node_id", self.on_click) + self.text = self.druid:new_text("text_node_id", "Hello, Druid!") +end + +function M:on_click() + self.text:set_text("The button clicked!") +end + +return M +``` + +### Using Widgets + +You can create widgets in your GUI script like this: + +```lua +local druid = require("druid.druid") + +function init(self) + self.druid = druid.new(self) + self.my_widget = self.druid:new_widget(your_widget_class) +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 +``` + +## Widget Templates + +Widgets can use templates defined in your GUI scene. Templates are collections of nodes that define the widget's structure. + +### Using Templates + +If you have a GUI template with ID `my_widget_example` containing `button_node_id` and `text_node_id` nodes, you can use it like this: + +```lua +function init(self) + self.druid = druid.new(self) + self.my_widget = self.druid:new_widget(your_widget_class, "my_widget_example") + + self.my_widget.button.on_click:subscribe(function() + print("my custom callback") + end) + self.my_widget.text:set_text("Hello, Widgets!") +end +``` + +### Dynamic Templates + +For dynamically created GUI templates (from prefabs), you can pass nodes directly to the widget: + +```lua +function init(self) + self.druid = druid.new(self) + self.prefab = gui.get_node("my_widget_prefab/root") + local nodes = gui.clone_tree(self.prefab) + self.my_widget = self.druid:new_widget(your_widget_class, "my_widget_example", nodes) +end +``` + +You can also use the root node ID or node directly: + +```lua +self.my_widget = self.druid:new_widget(your_widget_class, "my_widget_example", "my_widget_prefab/root") +-- or +self.my_widget = self.druid:new_widget(your_widget_class, "my_widget_example", self.prefab) +``` + + + diff --git a/docs_md/changelog.md b/wiki/changelog.md similarity index 95% rename from docs_md/changelog.md rename to wiki/changelog.md index a74190b..39ff472 100644 --- a/docs_md/changelog.md +++ b/wiki/changelog.md @@ -574,3 +574,43 @@ And all my other supporters! Very appreciated! Please support me if you like this project! It will help me keep engaged to update **Druid** and make it even better! [![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality) + + +### Druid 1.1 + +Hello! Druid 1.1 is here! It's brings a lot of new features and improvements. Let's dive in! + +--- + +**Milestone**: + +**Changelog 1.1** +- Remove external annotations, remove old HTML API page +- Fully annotated code and new API README page (hope more comfortable to use) +- Widgets here! + - A replacement for `custom_components`. Basically it's the same, but `widgets` contains no boilerplate code and more convinient to use. + - Now I can include a kind of `widgets` with Druid and you can use it almost instantly in your project. +- Removed `druid.register()`. Now all components are available by default and available with `self.druid:new_*` functions + - This means the Druid will be bigger in size, but it's much comfortable to use + - In case you want to delete components you not using, you can do it in fork in `druid.lua` file + - Any additional widgets, color library will be not included until you use it +- Remove `druid.event`, replaced with `defold-event` library. Now it required to double dependency to use Druid. +- Add Druid UI kit, contains atlas so now you can use Druid GUI files in your projects. + - Contains mostly basic shapes for the UI and can contains several icons. Atlas is a small, only `128x128` size and will be included in build only if you use it. +- [Text]: Add `trim_left` and `scale_then_trim_left` text adjust modes +- [Text]: Add `set_text` function instead `set_to` (now it deprecated) +- Add `druid.color` module to work with colors and palettes +- Add `container` component to handle more complex adaptive layouts +- [Shaders] Add repeat, hard image stencil and world gui materials +- [Widget] Add widget `mini_graph` +- [Widget] Add widget `memory_panel` +- [Widget] Add widget `fps_panel` +- [Widget] Add widget `properties_panel` + - Include `property_button` widget + - Include `property_checkbox` widget + - Include `property_input` widget + - Include `property_left_right_selector` widget + - Include `property_slider` widget + - Include `property_text` widget + - Include `property_vector3` widget +- Removed old `druid.no_stencil_check` and `druid.no_auto_template` flags. Now it's always disabled diff --git a/wiki/optimize_druid_size.md b/wiki/optimize_druid_size.md new file mode 100644 index 0000000..675e962 --- /dev/null +++ b/wiki/optimize_druid_size.md @@ -0,0 +1,54 @@ +# Optimize Druid Size + +From the Druid 1.1 release now all components are included by default. This was done to simplify the usage of Druid and remove the `druid.register` function which raised a lot of questions about using the non-included components. + +This also means that the size of the Druid library for the build now is slightly larger than before. While this will be a not issue for most users, for those who want to redure the build size for a kind of ~50kb in case not using a lot of `extended` components, you can strip these components from the build. + +## Stripping Components + +You need to download and modify the Druid library inside your project. To strip the not used components you need to edit the `druid/system/druid_instance.lua` file. + +For example, if you want to strip the `hotkey` component, you need to remove the `new_hotkey` function from the `M` table. + +You need to delete these lines: + +```lua +local hotkey = require("druid.extended.hotkey") +---Create Hotkey component +---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys +---@param callback function|nil The callback function +---@param callback_argument any|nil The argument to pass into the callback function +---@return druid.hotkey component Hotkey component +function M:new_hotkey(keys_array, callback, callback_argument) + return self:new(hotkey, keys_array, callback, callback_argument) +end +``` + +Thats all. Now the Druid library will have no any links to the `hotkey` component and the size of the build will be reduced by size of this component. + +## Component Sizes + +Here is a table with the size of the components in the Druid library at the state of the Druid 1.1 release. Just for information. + +| Component | Size (Desktop) | Size (Mobile) | +|-----------------|----------------|---------------| +| `button` | 4.36 kb | 2.42 kb | +| `text` | 5.31 kb | 2.90 kb | +| `scroll` | 8.27 kb | 4.73 kb | +| `grid` | 5.97 kb | 2.87 kb | +| `blocker` | 0.66 kb | 0.45 kb | +| `back_handler` | 0.57 kb | 0.42 kb | +| `hover` | 2.31 kb | 1.34 kb | +| `drag` | 3.73 kb | 2.17 kb | +| `progress` | 2.76 kb | 1.64 kb | +| `slider` | 2.67 kb | 1.66 kb | +| `swipe` | 2.02 kb | 1.23 kb | +| `input` | 5.59 kb | 3.38 kb | +| `timer` | 1.47 kb | 0.94 kb | +| `layout` | 4.96 kb | 2.83 kb | +| `lang_text` | 1.10 kb | 0.63 kb | +| `hotkey` | 2.29 kb | 1.46 kb | +| `data_list` | 3.24 kb | 1.81 kb | +| `container` | 6.86 kb | 3.75 kb | +| `rich_text` | 13.24 kb | 8.27 kb | +| `rich_input` | 4.16 kb | 2.38 kb | diff --git a/wiki/widgets.md b/wiki/widgets.md new file mode 100644 index 0000000..f19a6e3 --- /dev/null +++ b/wiki/widgets.md @@ -0,0 +1,113 @@ +# Widgets + +Widgets are reusable UI components that simplify the creation and management of user interfaces in your game. + +## What is widget + +Before widgets, there were "custom components". Widgets replace custom components. Basically, they're the same thing, with the only difference being how they're initialized. + +Let's see a basic custom component template: + +```lua +local component = require("druid.component") + +---@class my_component: druid.component +local M = component.create("my_component") + +function M:init(template, nodes, output_string) + self:set_template(template) + self:set_nodes(nodes) + self.druid = self:get_druid() + + self.druid:new_button("button_node_name", print, output_string) +end +``` + +Basic components are created with the `druid:new()` function: + +```lua +local template = "my_component" -- The template name on GUI scene, if nil will take nodes directly by gui.get_node() +local nodes = gui.clone_tree(gui.get_node("my_component/root")) -- We can clone component nodes and init over cloned nodes + +local my_component = druid:new("my_component", template, nodes, "Hello world!") +``` + +Now, let's see how to do it with widgets: + +```lua +---@type my_widget: druid.widget +local M = {} + +function M:init(output_string) + self.druid:new_button("button_node_name", print, output_string) +end + +return M +``` + +That's all! The same functionality but without any boilerplate code, just a Lua table. The Druid instance, templates and nodes are already created and available. + +And you can create your own widgets like this: + +```lua +local druid = require("druid.druid") +local my_widget = require("widgets.my_widget.my_widget") + +function init(self) + self.druid = druid.new(self) + self.my_widget = self.druid:new_widget(my_widget, template, nodes, "Hello world!") +end +``` + +So now creating UI components with widgets is much easier and cleaner than using custom components. + +## Create a new widget + +Let's start from the beginning. Widgets usually consist of 2 parts: + +1. GUI scene +2. Widget Lua module + +Make a GUI scene of your widget (user portrait avatar panel, shop window, game panel menu, etc). Design it as you wish, but it's recommended to add one `root` node with the id `root` and make all your other nodes children of this node. This makes working with the widget much easier. Also ofter this root will represent the widget size, so it's recommended to set it's size to the desired size of the widget. + +Let's create a new widget by creating a new file next to our GUI scene file: + +```lua +-- my_widget.lua +local M = {} + +function M:init() + self.root = self:get_node("root") + self.button = self.druid:new_button("button_open", self.open_widget, self) +end + +function M:open_widget() + print("Open widget pressed") +end + +return M +``` + +That's the basic creation process. Now we have a widget where we access the root node and use the "button_open" node as a button. + +Now, let's create a widget inside your game scene. + +Place a widget (GUI template) on your main scene. Then import Druid and create a new widget instance using this GUI template placed on the scene: + +```lua +local druid = require("druid.druid") +local my_widget = require("widgets.my_widget.my_widget") + +function init(self) + self.druid = druid.new(self) + self.my_widget = self.druid:new_widget(my_widget, "my_widget") + + -- In case we want to clone it and use several times we can pass the nodes table + local array_of_widgets = {} + for index = 1, 10 do + -- For widgets now we can use a root node directly instead of manually cloning the nodes + local widget = self.druid:new_widget(my_widget, "my_widget", "my_widget/root") + table.insert(array_of_widgets, widget) + end +end +```