This commit is contained in:
Insality 2025-03-25 22:56:47 +02:00
parent fb9c80b284
commit e83e5a6c84
9 changed files with 116 additions and 75 deletions

37
CONTRIBUTING.md Normal file
View File

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

View File

@ -7,7 +7,7 @@
[![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** - a powerful, flexible and easy to use **Defold** component UI framework. Contains a wide range of components and features to create stunning and customizable GUIs. Provides a powerful way to create, compose and manage your custom components and scenes.
**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
@ -15,6 +15,13 @@ Check the [**HTML5 version**](https://insality.github.io/druid/) of the **Druid*
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
@ -42,7 +49,7 @@ 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.
> **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 | Full Size |
| ---------------- | ------------- |
@ -59,11 +66,41 @@ 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*.
To use **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.
Create a new `*.gui_script` file and add the following code:
All **Druid** and component methods are invoked using the `:` operator, such as `self.druid:new_button()`.
```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
```
Now add this `*.gui_script` as a script to your GUI scene and now you can start creating Druid components.
Always, when you need to pass a node to a component, you can pass a node name string instead of `gui.get_node()` function.
All functions of **Druid** are invoked using the `:` operator, such as `self.druid:new_button()`.
Here is a basic example with a com
```lua
local druid = require("druid.druid")
@ -71,48 +108,13 @@ 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!")
self.text:set_text("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 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)
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)

View File

@ -310,7 +310,6 @@ function M:set_web_user_interaction(is_web_mode)
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)

View File

@ -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)

View File

@ -135,8 +135,9 @@ end
---@param nodes table<hash, node>|nil
---@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)

View File

@ -112,12 +112,14 @@ 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_string string? GUI url, if nil current gui will be used
---@param gui_url url GUI url
---@return T
function M.get_widget(widget_class, gui_url_string)
local gui_url = msg.url(gui_url_string)
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

View File

@ -34,6 +34,7 @@
---@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.

View File

@ -8,31 +8,29 @@ local druid_component = require("druid.component")
---The Druid Factory used to create components
---@class druid.instance
---@field components_all druid.component[] All created components
---@field components_interest table<string, druid.component[]> All components sorted by interest
---@field private _context table Druid context, usually a self of gui script
---@field private _style table Druid style table
---@field private _is_late_remove_enabled boolean
---@field private _late_remove druid.component[]
---@field private _input_blacklist druid.component[]|nil
---@field private _input_whitelist druid.component[]|nil
---@field private input_inited boolean
---@field private _late_init_timer_id number
---@field private _input_components druid.component[]
---@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<string, druid.component[]> 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
return
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
@ -98,7 +96,7 @@ local function register_interests(self, instance)
end
-- Create the Druid component instance
---Create the Druid component instance
---@param self druid.instance
---@param instance_class druid.component
---@return druid.component
@ -148,8 +146,8 @@ end
---Check whitelists and blacklists for input components
---@param component druid.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
@ -181,7 +179,7 @@ end
---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
---@return druid.instance
---@return druid.instance instance The new Druid instance
function M.create_druid_instance(context, style)
local self = setmetatable({}, { __index = M })
@ -244,8 +242,8 @@ end
---Remove created component from Druid instance.
--
-- Component `on_remove` function will be invoked, if exist.
---
---Component `on_remove` function will be invoked, if exist.
---@generic T: druid.component
---@param component T Component instance
---@return boolean is_removed True if component was removed
@ -422,8 +420,8 @@ end
---Calls the on_language_change function in all related components
-- This one called by global druid.on_language_change, but can be
-- call manualy to update all translations
---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]
@ -540,7 +538,7 @@ 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 back_handler The new back handler component
function M:new_back_handler(callback, params)
@ -722,7 +720,7 @@ 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 rich_input The new rich input component

View File

@ -6,7 +6,8 @@ local druid = require("druid.druid")
local widget = require("example.other.go_bindings.go_widget")
function init(self)
self.go_widget = druid.get_widget(widget, "#go_widget")
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())