This commit is contained in:
Insality 2025-04-18 01:24:39 +03:00
parent 0d0581b108
commit f42211782a
10 changed files with 667 additions and 684 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Maxim Tuprikov
Copyright (c) 2025 Maxim Tuprikov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -23,6 +23,12 @@ In this example you can inspect a variety of **Druid** components and see how th
- **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
## Quick Links
- [Basic Usage](wiki/basic_usage.md)
- [Quick API Reference](api/quick_api_reference.md)
- [List of Components](#druid-components)
- [Contributors](#contributors)
## Setup
### [Dependency](https://defold.com/manuals/libraries/#setting-up-library-dependencies)
@ -121,7 +127,7 @@ Here is full **Druid** components list.
| **[Back Handler](/api/components/base/back_handler_api.md)** | 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) | <img src="media/preview/back_handler.gif" width="200" height="100"> |
| **[Static Grid](/api/components/base/static_grid_api.md)** | 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) | <img src="media/preview/static_grid.gif" width="200" height="100"> |
| **[Hover](/api/components/base/hover_api.md)** | 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) | <img src="media/preview/hover.gif" width="200" height="100"> |
| **[Swipe](/api/components/base/swipe_api.md)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/?example=ui_example_basic_swipe) | <img src="media/preview/swipe.gif" width="200" height="100"> |
| **[Swipe](/api/components/extended/swipe_api.md)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/?example=ui_example_basic_swipe) | <img src="media/preview/swipe.gif" width="200" height="100"> |
| **[Drag](/api/components/base/drag_api.md)** | 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) | <img src="media/preview/drag.gif" width="200" height="100"> |
| **[Data List](/api/components/extended/data_list_api.md)** | 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) | <img src="media/preview/data_list.gif" width="200" height="100"> |
| **[Input](/api/components/extended/input_api.md)** | 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) | <img src="media/preview/input.gif" width="200" height="100"> |
@ -137,7 +143,7 @@ Here is full **Druid** components list.
## Druid Events
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:
All **Druid** components using [Defold Event](https://github.com/Insality/defold-event) for components callbacks. In component API ([button example](/api/components/base/button_api.md#fields)) pointed list of component events. You can manually subscribe to these events with the following API:
- **event:subscribe**(callback)
@ -187,8 +193,10 @@ 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](wiki/creating_custom_components.md)
- [Druid styles](wiki/styles.md)
- [Advanced Setup](wiki/advanced-setup.md)
- [Optimize Druid Size](wiki/optimize_druid_size.md)
- [Changelog](wiki/changelog.md)
## Licenses
@ -198,16 +206,16 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
## Issues and suggestions
If you have any issues, questions or suggestions please [create an issue](https://github.com/Insality/druid/issues) or contact me: [insality@gmail.com](mailto:insality@gmail.com)
If you have any issues, questions or suggestions please [create an issue](https://github.com/Insality/druid/issues)
## History
For a complete history of the development of **Druid**, please check the [changelog](docs_md/changelog.md).
## 👏 Contributors
## Contributors
Original idea by [AGulev](https://github.com/AGulev)
Original Druid idea by [AGulev](https://github.com/AGulev)
Special thanks to all the contributors who have helped make **Druid** better!

View File

@ -58,5 +58,11 @@ function M.input_empty_action_nil(x, y)
end
function M.input_text(text)
return hash("text"), {
text = text,
}
end
return M

View File

@ -1,20 +0,0 @@
local mock = require("deftest.mock.mock")
local M = {}
-- Userdata type instead of script self
---@return vector
function M.get_context()
return vmath.vector({})
end
-- Callback for return value from function
function M.get_function(callback)
local listener = {}
listener.callback = function(...) if callback then return callback(...) end end
mock.mock(listener)
return function(...) return listener.callback(...) end, listener.callback
end
return M

View File

@ -1,13 +1,11 @@
return function()
describe("Helper Module", function()
local test_helper = nil
local helper = nil
local const = nil
local node1 = nil
local node2 = nil
before(function()
test_helper = require("test.helper.test_helper")
helper = require("druid.helper")
const = require("druid.const")

View File

@ -95,25 +95,20 @@ return function()
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing "Hello"
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
-- Type "H"
trigger_text_input("H")
druid:on_input(mock_input.input_text("H"))
assert(input:get_text() == "H")
assert(on_input_text_calls == 1)
-- Type "e"
trigger_text_input("e")
druid:on_input(mock_input.input_text("e"))
assert(input:get_text() == "He")
assert(on_input_text_calls == 2)
-- Type "llo"
trigger_text_input("l")
trigger_text_input("l")
trigger_text_input("o")
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("o"))
assert(input:get_text() == "Hello")
assert(on_input_text_calls == 5)
@ -134,17 +129,12 @@ return function()
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate backspace key
local function trigger_backspace()
return druid:on_input(hash("key_backspace"), {pressed = true})
end
-- Delete one letter
assert(trigger_backspace() == true)
druid:on_input(hash("key_backspace"), {pressed = true})
assert(input:get_text() == "Hell")
-- Delete another letter
assert(trigger_backspace() == true)
druid:on_input(hash("key_backspace"), {pressed = true})
assert(input:get_text() == "Hel")
druid:remove(input)
@ -171,18 +161,23 @@ return function()
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing text
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
-- Type "Hello"
assert(trigger_text_input("Hello") == true)
druid:on_input(mock_input.input_text("H"))
druid:on_input(mock_input.input_text("e"))
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("o"))
assert(input:get_text() == "Hello")
assert(on_input_full_calls == 1)
-- Try to type "World" - should truncate
assert(trigger_text_input("World") == true)
druid:on_input(mock_input.input_text("W"))
druid:on_input(mock_input.input_text("o"))
druid:on_input(mock_input.input_text("r"))
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("d"))
assert(input:get_text() == "Hello")
druid:remove(input)
@ -209,20 +204,21 @@ return function()
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing text
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
-- Type valid input "123"
assert(trigger_text_input("123") == true)
druid:on_input(mock_input.input_text("1"))
druid:on_input(mock_input.input_text("2"))
druid:on_input(mock_input.input_text("3"))
assert(input:get_text() == "123")
assert(on_input_wrong_calls == 0)
-- Type invalid input "abc" - should be rejected
assert(trigger_text_input("abc") == true)
druid:on_input(mock_input.input_text("a"))
druid:on_input(mock_input.input_text("b"))
druid:on_input(mock_input.input_text("c"))
assert(input:get_text() == "123")
assert(on_input_wrong_calls == 1)
assert(on_input_wrong_calls == 3)
druid:remove(input)
gui.delete_node(button_node)
@ -241,12 +237,11 @@ return function()
druid:on_input(mock_input.click_pressed(50, 25))
druid:on_input(mock_input.click_released(50, 25))
-- Simulate typing "Hello"
local function trigger_text_input(text)
return druid:on_input(hash("text"), {text = text})
end
assert(trigger_text_input("Hello") == true)
druid:on_input(mock_input.input_text("H"))
druid:on_input(mock_input.input_text("e"))
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("l"))
druid:on_input(mock_input.input_text("o"))
-- Raw text should be "Hello"
assert(input:get_text() == "Hello")

View File

@ -2,7 +2,6 @@ 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
@ -18,14 +17,13 @@ return function()
mock_gui = require("deftest.mock.gui")
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()
context = vmath.vector3()
druid = druid_system.new(context)
parent = mock_gui.add_box("parent", 0, 0, 50, 50)

View File

@ -2,7 +2,6 @@ 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
@ -13,14 +12,13 @@ return function()
mock_gui = require("deftest.mock.gui")
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()
context = vmath.vector3()
druid = druid_system.new(context)
end)