diff --git a/README.md b/README.md
index 6944e06a..681033df 100644
--- a/README.md
+++ b/README.md
@@ -78,11 +78,11 @@ no_auto_template = 1
### Stencil check [optional]
-When creating input components inside stencil nodes, you probably will use `component:set_click_zone()` to restrict clicks outside this stencil zone.
-Druid can do it automatically on _late_init_ component step. To enable this feature add next field in your _game.project_ file
+When creating input components inside stencil nodes, **Druid** automatically setup `component:set_click_zone()` on _late_init_ component step to restrict input clicks outside this stencil zone.
+To disable this feature add next field in your _game.project_ file
```
[druid]
-stencil_check = 1
+no_stencil_check = 1
```
diff --git a/deployer_build_stats.csv b/deployer_build_stats.csv
index de95ac51..09bbddc9 100644
--- a/deployer_build_stats.csv
+++ b/deployer_build_stats.csv
@@ -7,3 +7,5 @@ date,sha,version,build_size,build_time,platform,mode,is_cache_using,commits_coun
2022-03-12T10:01:30Z,d0f3d6641a08b0d6b719b13017aa85907d1667e5,0.8.564,2200,44,js-web,release,true,564
2022-08-29T18:27:58Z,b2643ebd268b15884363efd17724e689279946f1,0.9.589,2316,45,js-web,release,true,589
2022-08-29T18:46:47Z,13003e472169cbd261e703eca7b133adf64a24f7,0.9.592,2316,40,js-web,release,true,592
+2022-09-09T17:55:42Z,072507cc9e715541bdee7636d2e5eeeb3c22a57d,0.10.603,2340,43,js-web,release,true,603
+2022-09-09T18:00:07Z,072507cc9e715541bdee7636d2e5eeeb3c22a57d,0.10.603,2340,5,js-web,release,true,603
diff --git a/docs/druid/archive/archive_files.json b/docs/druid/archive/archive_files.json
index 51382343..28c4c68a 100644
--- a/docs/druid/archive/archive_files.json
+++ b/docs/druid/archive/archive_files.json
@@ -1 +1 @@
-{"content":[{"name":"game.projectc","size":3808,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":17728,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":421233,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":18513,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]}
\ No newline at end of file
+{"content":[{"name":"game.projectc","size":3797,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":19808,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":449757,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":20704,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]}
\ No newline at end of file
diff --git a/docs/druid/archive/game.arcd0 b/docs/druid/archive/game.arcd0
index 39b87ed2..3e66d763 100644
Binary files a/docs/druid/archive/game.arcd0 and b/docs/druid/archive/game.arcd0 differ
diff --git a/docs/druid/archive/game.arci0 b/docs/druid/archive/game.arci0
index 4865b5c8..6bfe0dff 100644
Binary files a/docs/druid/archive/game.arci0 and b/docs/druid/archive/game.arci0 differ
diff --git a/docs/druid/archive/game.dmanifest0 b/docs/druid/archive/game.dmanifest0
index 04fba65f..05763cba 100644
Binary files a/docs/druid/archive/game.dmanifest0 and b/docs/druid/archive/game.dmanifest0 differ
diff --git a/docs/druid/archive/game.projectc0 b/docs/druid/archive/game.projectc0
index 8f2cc9f1..4c25f8ee 100644
--- a/docs/druid/archive/game.projectc0
+++ b/docs/druid/archive/game.projectc0
@@ -1,12 +1,12 @@
[project]
title = druid
-version = 0.9.592
+version = 0.10.603
write_log = 0
compress_archive = 1
publisher = Insality
developer = Insality
-commit_sha = 13003e472169cbd261e703eca7b133adf64a24f7
-build_date = 2022-08-29T18:46:47Z
+commit_sha = 072507cc9e715541bdee7636d2e5eeeb3c22a57d
+build_date = 2022-09-09T18:00:07Z
title_as_file_name = druid
[display]
@@ -120,7 +120,7 @@ default_language = en
localizations = en
[android]
-version_code = 592
+version_code = 603
minimum_sdk_version = 16
target_sdk_version = 30
package = com.insality.druid
@@ -144,7 +144,7 @@ localizations = en
custom_heap_size = 0
heap_size = 64
htmlfile = /builtins/manifests/web/engine_template.html
-cssfile = /builtins/manifests/web/light_theme.css
+cssfile = /example/light_theme.css
archive_location_prefix = archive
show_fullscreen_button = 0
show_made_with_defold = 0
@@ -192,7 +192,7 @@ run_while_iconified = 0
[druid]
no_auto_input = 0
-stencil_check = 0
+no_stencil_check = 0
no_auto_template = 0
input_text = text
input_touch = touch
diff --git a/docs/druid/index.html b/docs/druid/index.html
index 7531689a..b2ac38d0 100644
--- a/docs/druid/index.html
+++ b/docs/druid/index.html
@@ -7,7 +7,7 @@
-
druid 0.9.592
+ druid 0.10.603
diff --git a/docs/index.html b/docs/index.html
index 772268eb..1b184f44 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -49,8 +49,10 @@ Modules
CheckboxGroup
DataList
DynamicGrid
+ Hotkey
Input
LangText
+ Layout
Progress
RadioGroup
Slider
@@ -140,6 +142,10 @@ Modules
DynamicGrid |
Component to handle placing components in row |
+
+ Hotkey |
+ Druid hotkey component |
+
Input |
Druid input text component. |
@@ -149,6 +155,10 @@ Modules
Component to handle all GUI texts
Good working with localization system |
+
+ Layout |
+ Layout management on node |
+
Progress |
Basic progress bar component. |
diff --git a/docs/modules/BackHandler.html b/docs/modules/BackHandler.html
index a6c768d2..6d23e396 100644
--- a/docs/modules/BackHandler.html
+++ b/docs/modules/BackHandler.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/BaseComponent.html b/docs/modules/BaseComponent.html
index d920a1ca..77841a8f 100644
--- a/docs/modules/BaseComponent.html
+++ b/docs/modules/BaseComponent.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
@@ -136,7 +138,7 @@
Set component input state. |
- set_input_priority(self, value) |
+ set_input_priority(self, value, is_temporary) |
Set component input priority |
@@ -563,7 +565,7 @@ Returns:
- set_input_priority(self, value)
+ set_input_priority(self, value, is_temporary)
Set component input priority
@@ -579,6 +581,10 @@ Parameters:
number
The new input priority value
+ is_temporary
+ boolean
+ If true, the reset input priority will return to previous value
+
Returns:
diff --git a/docs/modules/Blocker.html b/docs/modules/Blocker.html
index 0297f82e..6e8651da 100644
--- a/docs/modules/Blocker.html
+++ b/docs/modules/Blocker.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Button.html b/docs/modules/Button.html
index 4d3b310a..f22eac12 100644
--- a/docs/modules/Button.html
+++ b/docs/modules/Button.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Checkbox.html b/docs/modules/Checkbox.html
index 3cb13d5d..3c9542f7 100644
--- a/docs/modules/Checkbox.html
+++ b/docs/modules/Checkbox.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/CheckboxGroup.html b/docs/modules/CheckboxGroup.html
index 912993ec..1f108e23 100644
--- a/docs/modules/CheckboxGroup.html
+++ b/docs/modules/CheckboxGroup.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/DataList.html b/docs/modules/DataList.html
index baadf334..69704fd0 100644
--- a/docs/modules/DataList.html
+++ b/docs/modules/DataList.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Drag.html b/docs/modules/Drag.html
index 09aee5c9..42925c2b 100644
--- a/docs/modules/Drag.html
+++ b/docs/modules/Drag.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
@@ -87,9 +89,17 @@
Drag component 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 |
+
@@ -118,11 +128,11 @@
on_drag |
- on drag progress callback(self, dx, dy) |
+ on drag progress callback(self, dx, dy, total_x, total_y) |
on_drag_end |
- Event on drag end callback(self) |
+ Event on drag end callback(self, total_x, total_y) |
on_drag_start |
@@ -185,6 +195,33 @@ Parameters:
+
+
+
+ is_enabled(self)
+
+
+ Check if Drag component is enabled
+
+
+ Parameters:
+
+
+ Returns:
+
+
+ bool
+
+
+
+
+
+
@@ -211,6 +248,31 @@ Parameters:
+
+
+
+ set_enabled(self, is_enabled)
+
+
+ Set Drag input enabled or disabled
+
+
+ Parameters:
+
+ - self
+ Drag
+ Drag
+
+ - is_enabled
+ bool
+
+
+
+
+
+
+
+
@@ -329,7 +391,7 @@
on_drag
- on drag progress callback(self, dx, dy)
+ on drag progress callback(self, dx, dy, total_x, total_y)
+ late_init(self) |
+ Druid late update function call after init and before udpate step |
+
+
log_message(self, message[, context]) |
Log message, if is_debug mode is enabled |
@@ -153,6 +161,10 @@
new_grid(self, parent, element[, in_row=1]) |
Create grid basic component
Deprecated |
+
+
+ new_hotkey(self, keys_array, callback[, params]) |
+ Create hotkey component |
new_hover(self, node, on_hover_callback) |
@@ -167,6 +179,10 @@
Create lang_text component |
+ new_layout(self, node, mode) |
+ Create layout component |
+
+
new_progress(self, node, key[, init_value=1]) |
Create progress component |
@@ -256,6 +272,27 @@ Parameters:
+
+
+
+ late_init(self)
+
+
+ Druid late update function call after init and before udpate step
+
+
+ Parameters:
+
+ - self
+ DruidInstance
+
+
+
+
+
+
+
+
@@ -658,6 +695,46 @@ Returns:
+
+
+
+ new_hotkey(self, keys_array, callback[, params])
+
+
+ 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
+ Button callback
+
+ - params
+ value
+ Button callback params
+ (optional)
+
+
+
+ Returns:
+
+
+ Hotkey
+ hotkey component
+
+
+
+
+
@@ -772,6 +849,41 @@ Returns:
+
+
+
+ new_layout(self, node, mode)
+
+
+ Create layout component
+
+
+ Parameters:
+
+ - self
+ DruidInstance
+
+
+ - node
+ string or node
+ Layout node
+
+ - mode
+ string
+ The layout mode
+
+
+
+ Returns:
+
+
+ Layout
+ layout component
+
+
+
+
+
diff --git a/docs/modules/DynamicGrid.html b/docs/modules/DynamicGrid.html
index 2879b8f8..d4f1b923 100644
--- a/docs/modules/DynamicGrid.html
+++ b/docs/modules/DynamicGrid.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Helper.html b/docs/modules/Helper.html
index 75500963..cdcb0212 100644
--- a/docs/modules/Helper.html
+++ b/docs/modules/Helper.html
@@ -50,9 +50,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Hotkey.html b/docs/modules/Hotkey.html
new file mode 100644
index 00000000..8ea2ccd6
--- /dev/null
+++ b/docs/modules/Hotkey.html
@@ -0,0 +1,314 @@
+
+
+
+
+ Defold Druid UI Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Druid
+
+
+
+
Contents
+
+
+
+
Modules
+
+
+
+
+
+
+
Module Hotkey
+
Druid hotkey component
+
+
+
+
+
+
+
+
+ style |
+ Component style params. |
+
+
+
+
+
+ button |
+ Button component from click_node |
+
+
+ click_node |
+ Button trigger node |
+
+
+ node |
+ Visual node |
+
+
+ on_change_state |
+ On change state callback(self, state) |
+
+
+
+
+
+
+
+
+
+
+ -
+
+ 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
+ value
+ The argument to pass into the callback function
+ (optional)
+
+
+
+
+
+
+
+
+ -
+
+ init(self, keys, callback[, callback_argument])
+
+ -
+ Component init function
+
+
+
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
+ value
+ The argument to pass into the callback function
+ (optional)
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ 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
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ button
+
+ -
+ Button component from click_node
+
+
+
+ - button
+ Button
+ Button
+
+
+
+
+
+
+
+
+ -
+
+ click_node
+
+ -
+ Button trigger node
+
+
+
+ - click_node
+ node
+
+ (default node)
+
+
+
+
+
+
+
+
+ -
+
+ node
+
+ -
+ Visual 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/Hover.html b/docs/modules/Hover.html
index e3b6d478..9172f9c5 100644
--- a/docs/modules/Hover.html
+++ b/docs/modules/Hover.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Input.html b/docs/modules/Input.html
index d247b11b..ed576a02 100644
--- a/docs/modules/Input.html
+++ b/docs/modules/Input.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/LangText.html b/docs/modules/LangText.html
index ab9f8b87..7f524bab 100644
--- a/docs/modules/LangText.html
+++ b/docs/modules/LangText.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Layout.html b/docs/modules/Layout.html
new file mode 100644
index 00000000..cb333087
--- /dev/null
+++ b/docs/modules/Layout.html
@@ -0,0 +1,462 @@
+
+
+
+
+ Defold Druid UI Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Druid
+
+
+
+
Contents
+
+
+
+
Modules
+
+
+
+
+
+
+
Module Layout
+
Layout management on node
+
+
+
+
+
+
+
+
+ mode |
+ Current layout mode |
+
+
+ node |
+ Layout node |
+
+
+ on_size_changed |
+ On window resize callback(self, new_size) |
+
+
+
+
+
+
+
+
+
+
+ -
+
+ fit_into_node(self[, node])
+
+ -
+ Set node for layout node to fit inside it. Pass nil to reset
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - node
+ Node
+
+ (optional)
+
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+ -
+
+ fit_into_size(self, target_size)
+
+ -
+ Set size for layout node to fit inside it
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - target_size
+ vector3
+
+
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+ -
+
+ fit_into_window(self)
+
+ -
+ Set current size for layout node to fit inside it
+
+
+
Parameters:
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+ -
+
+ init(self, node, mode[, on_size_changed_callback])
+
+ -
+ Component init function
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - node
+ node
+ Gui node
+
+ - mode
+ string
+ The layout mode (from const.LAYOUT_MODE)
+
+ - on_size_changed_callback
+ function
+ The callback on window resize
+ (optional)
+
+
+
+
+
+
+
+
+ -
+
+ set_max_size(self, max_size)
+
+ -
+ Set maximum size of layout node
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - max_size
+ vector3
+
+
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+ -
+
+ set_min_size(self, min_size)
+
+ -
+ Set minimal size of layout node
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - min_size
+ vector3
+
+
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+ -
+
+ set_origin_position(self, new_origin_position)
+
+ -
+ Set new origin position of layout node. You should apply this on node movement
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - new_origin_position
+ vector3
+
+
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+ -
+
+ set_origin_size(self, new_origin_size)
+
+ -
+ Set new origin size of layout node. You should apply this on node manual size change
+
+
+
Parameters:
+
+ - self
+ Layout
+ Layout
+
+ - new_origin_size
+ vector3
+
+
+
+
+ Returns:
+
+
+ Layout
+ Layout
+
+
+
+
+
+
+
+
+
+
+ -
+
+ mode
+
+ -
+ Current layout mode
+
+
+
+
+
+
+
+
+
+ -
+
+ node
+
+ -
+ Layout node
+
+
+
+
+
+
+
+
+
+ -
+
+ on_size_changed
+
+ -
+ On window resize callback(self, new_size)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
generated by LDoc TESTING
+
Last updated 2015-01-01 12:00:00
+
+
+
+
diff --git a/docs/modules/PinKnob.html b/docs/modules/PinKnob.html
index 1fe3571c..8a53914d 100644
--- a/docs/modules/PinKnob.html
+++ b/docs/modules/PinKnob.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Progress.html b/docs/modules/Progress.html
index 4494d3f6..4ac940c8 100644
--- a/docs/modules/Progress.html
+++ b/docs/modules/Progress.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
@@ -97,6 +99,10 @@
Component init function |
+ 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 |
@@ -251,6 +257,37 @@ Parameters:
+
+
+
+ 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
+
+
+
+
+
diff --git a/docs/modules/RadioGroup.html b/docs/modules/RadioGroup.html
index a451edd6..8522b329 100644
--- a/docs/modules/RadioGroup.html
+++ b/docs/modules/RadioGroup.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/RichInput.html b/docs/modules/RichInput.html
index df5f87bc..4d192af0 100644
--- a/docs/modules/RichInput.html
+++ b/docs/modules/RichInput.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Scroll.html b/docs/modules/Scroll.html
index 2781ee8e..80989382 100644
--- a/docs/modules/Scroll.html
+++ b/docs/modules/Scroll.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Slider.html b/docs/modules/Slider.html
index 6b7b70d1..ccf9abd1 100644
--- a/docs/modules/Slider.html
+++ b/docs/modules/Slider.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/StaticGrid.html b/docs/modules/StaticGrid.html
index a9a9c6cc..57755040 100644
--- a/docs/modules/StaticGrid.html
+++ b/docs/modules/StaticGrid.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
@@ -148,7 +150,7 @@
anchor |
- Item anchor |
+ Item anchor [0..1] |
border |
@@ -194,6 +196,10 @@
parent |
Parent gui node |
+
+ pivot |
+ Item pivot [-0.5..0.5] |
+
@@ -677,7 +683,7 @@
anchor
- Item anchor
+ Item anchor [0..1]
+
+
+ pivot
+
+
+ Item pivot [-0.5..0.5]
+
+
+
+
+
+
+
+
diff --git a/docs/modules/Swipe.html b/docs/modules/Swipe.html
index 87fc4352..de50f8c9 100644
--- a/docs/modules/Swipe.html
+++ b/docs/modules/Swipe.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Text.html b/docs/modules/Text.html
index 8fd4d8a1..271b2d8a 100644
--- a/docs/modules/Text.html
+++ b/docs/modules/Text.html
@@ -52,9 +52,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/Timer.html b/docs/modules/Timer.html
index 61a3214e..de1e3350 100644
--- a/docs/modules/Timer.html
+++ b/docs/modules/Timer.html
@@ -51,9 +51,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs/modules/druid.html b/docs/modules/druid.html
index 20b016cf..3a2f78b9 100644
--- a/docs/modules/druid.html
+++ b/docs/modules/druid.html
@@ -50,9 +50,11 @@ Modules
DruidInstance
DynamicGrid
Helper
+ Hotkey
Hover
Input
LangText
+ Layout
PinKnob
Progress
RadioGroup
diff --git a/docs_md/01-components.md b/docs_md/01-components.md
index 5b9eb987..892b8d12 100644
--- a/docs_md/01-components.md
+++ b/docs_md/01-components.md
@@ -147,7 +147,7 @@ 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.
+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
@@ -165,7 +165,7 @@ 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.
+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)
@@ -277,7 +277,7 @@ Create component with druid: `grid = druid:new_static_grid(parent_node, prefab_
### Overview
Component for manage node positions with different node sizes.
Unlike Static Grid, Dynamic Grid can place nodes only in one row or in one column.
-Dynamic Grid can't have gaps between elements
+Dynamic Grid can't have gaps between elements
- you will get error, if try spawn element far away from others.
Dynamic Grid should have __West__, __East__, __South__ or __North__ pivot (vertical or horizontal element placement)
@@ -301,7 +301,7 @@ Check the _parent_node_ have correct pivot point. You will get the error otherwi
[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.
+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
@@ -368,10 +368,12 @@ System Druid component, handle drag actions on node
Create drag component with druid: `hover = druid:new_drag(node, drag_callback)`
### Notes
-- Drag callback have next params: (self, swipe_side, distance, time)
+- 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
@@ -387,3 +389,56 @@ Create drag component with druid: `hover = druid:new_drag(node, drag_callback)`
- _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 handle node size depends on layout mode. Unlike from Defold Adjust modes, you able to select node stretch by one size or zoom by minimum or maximum side
+
+### 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, on_size_change_callback)`
+
+
+### Notes
+- Layout mode can be next:
+ - `const.LAYOUT_MODE.STRETCH_X` - Stretch node only by X
+ - `const.LAYOUT_MODE.STRETCH_Y` - Stretch node only by Y
+ - `const.LAYOUT_MODE.ZOOM_MIN` - Zoom node by minimal stretch multiplier
+ - `const.LAYOUT_MODE.ZOOM_MAX` - Zoom node by maximum stretch multiplier
+ - `const.LAYOUT_MODE.FIT` - Usual Defold Fit mode
+ - `const.LAYOUT_MODE.STRETCH` - Usual Defold Stretch Mode
+- The Layout component will change the node size property. So it's able to increase size of 9patch nodes without scaling issue
+- The Layout works even inside parent node with Fit adjust mode
+
diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md
index 64303d3b..ad96efc8 100644
--- a/docs_md/02-creating_custom_components.md
+++ b/docs_md/02-creating_custom_components.md
@@ -85,6 +85,9 @@ function Component:on_language_change() end
-- [OPTIONAL] Call if game layout has changed and need to restore values in component
function Component:on_layout_change() end
+-- [OPTIONAL] Call if game window size is changed
+function Component:on_window_resized() end
+
-- [OPTIONAL] Call, if input was capturing before this component
-- Example: scroll is start scrolling, so you need unhover button
function Component:on_input_interrupt() end
diff --git a/docs_md/changelog.md b/docs_md/changelog.md
index ae7ec628..a442d6b4 100644
--- a/docs_md/changelog.md
+++ b/docs_md/changelog.md
@@ -382,7 +382,7 @@ Take care of yourself
- The docs in (https://insality.github.io/druid/) now have cross links for every custom type
- **#175** Remove Druid Assets repository, move to Druid library
- Added folder `druid/custom`. It will have the complex custom components. Usually you should to use default GUI template or create your own with similar GUI scheme. Currently add `RichInput` and `PinKnob` components from druid-assets repository.
- - Usually to use custom component you have to require lua file first and create it's via `druid:new(Component, template_name, [nodes]). See component docs to see constructor params.
+ - Usually to use custom component you have to require lua file first and create it's via `druid:new(Component, template_name, [nodes])`. See component docs to see constructor params.
- This components will be included in build only if used
- **#176** Keep last scene and scroll position in Druid example
- Probably, it's useful for faster debug, but anyway. The example now keep the last scene and scroll position.
@@ -391,3 +391,58 @@ Take care of yourself
- Move emmylua annotations inside Druid dependency folder. You can copy it from Defold Editor outline
- Optimize different stuff(Scroll, Druid Event, Druid instance and Base component)
- Force Data List component to `IS_DYNAMIC_NODE_POSES = false` style
+
+
+### Druid 0.10.0
+
+Hello! Here is new Druid update. It's brings to you two new components: Layout and Hotkey. Both components are "extended", so to use it, you should register it first (when you try to use it, in console will be prompt with code you should use)
+
+In general:
+```
+local layout = require("druid.extended.layout")
+druid.register("layout", layout)
+```
+
+The Drag component now knows about window scaling, so now it have more accuracy dx/dy values depends on the screen size. The scroll and other components should work better :)
+
+Now you can change the input priority of components temporary. For example while you interact with them (input fields, drag on select etc).
+
+Also the update brings several bug fixes and now **Druid** have stencil_check mode enabled by default. It should be more easy to use input components with stencil nodes without manual `set_click_zone` functions.
+
+And yeah, the new **Druid** logo is here!
+
+**Changelog 0.10.0**
+
+---
+
+- **#133** [Hotkey] Add new extended component: Hotkey
+ - It's allow you set hotkeys to call callbacks
+ - You should pass one action key and several modificator keys (left shift, right ctrl etc)
+ - List of modificator keys ids setup via component style (you can change it)
+ - You can add several hotkeys on one callback via `hotkey:add_hotkey` with additional params
+- **#98** [Layout] Add new extended component: Layout
+ - It's allow you to extend standart Defold node adjust modes
+ - Layout mode can be next:
+ - `const.LAYOUT_MODE.STRETCH_X` - Stretch node only by X
+ - `const.LAYOUT_MODE.STRETCH_Y` - Stretch node only by Y
+ - `const.LAYOUT_MODE.ZOOM_MIN` - Zoom node by minimal stretch multiplier
+ - `const.LAYOUT_MODE.ZOOM_MAX` - Zoom node by maximum stretch multiplier
+ - `const.LAYOUT_MODE.FIT` - Usual Defold Fit mode
+ - `const.LAYOUT_MODE.STRETCH` - Usual Defold Stretch Mode
+ - The Layout changes the node size property. So it's look much better if you use 9slice nodes
+ - Works even the node parent is have Fit adjust mode
+- **#200** [Scroll] Glitch if content size equals to scroll view size in runtime
+- **#201** [DataList] Update DataList:
+ - Add two events: `on_element_add` and `on_element_remove`
+ - Add `data_list:get_data()` to access all current data in DataList
+ - Add `data_list:get_created_nodes()` to access currently visual nodes in DataList
+ - Add `data_list:get_created_components()` to access currenly visual component in DataList (if created)
+- **#190** [Progress] Add `progress:set_max_size` function to change max size of progress bar
+- **#188** [Drag] Add two values passed to on_drag callback. Now it is `on_drag(self, dx, dy, total_x, total_y)` to check the overral drag distance
+- **#195** [Drag] Add `drag:is_enabled` and `drag:set_enabled` to enable/disable drag input component
+- **#186** [Grid] Fix: Method `set_in_row` works incorrectly with IS_DYNAMIC_NODE_POSES style option
+- **#185** [System] Add `on_window_resized` component interest. It will called on game window size changes
+- **#189** [System] Add optional flag to `component:set_input_priority` to mark it as temporary. It will reset to default input priority after the `component:reset_input_priority`
+- **#204** [System] Fix: wrong code example link, if open example from direct URL
+- **#202** [System] Enabled stencil check to true by default. To disable this, use `druid.no_stencil_check` in game.project settings
+- [Examples] Add layout, layout fit, progres bar, data list + component examples
diff --git a/druid/annotations.lua b/druid/annotations.lua
index 497a34d3..7d331174 100644
--- a/druid/annotations.lua
+++ b/druid/annotations.lua
@@ -149,8 +149,9 @@ function druid__base_component.set_input_enabled(self, state) end
--- Set component input priority
---@param self druid.base_component @{BaseComponent}
---@param value number The new input priority value
+---@param is_temporary boolean If true, the reset input priority will return to previous value
---@return number The component input priority
-function druid__base_component.set_input_priority(self, value) end
+function druid__base_component.set_input_priority(self, value, is_temporary) end
--- Set current component nodes (protected)
---@protected
@@ -404,8 +405,8 @@ function druid__data_list.set_data(self, data) end
---@field can_y bool Is drag component process horizontal.
---@field is_drag bool Is component now dragging
---@field is_touch bool Is component now touching
----@field on_drag druid.event on drag progress callback(self, dx, dy)
----@field on_drag_end druid.event Event on drag end callback(self)
+---@field on_drag druid.event on drag progress callback(self, dx, dy, total_x, total_y)
+---@field on_drag_end druid.event Event on drag end callback(self, total_x, total_y)
---@field on_drag_start druid.event Event on drag start callback(self)
---@field on_touch_end druid.event Event on touch end callback(self)
---@field on_touch_start druid.event Event on touch start callback(self)
@@ -421,12 +422,22 @@ local druid__drag = {}
---@param on_drag_callback function Callback for on_drag_event(self, dx, dy)
function druid__drag.init(self, node, on_drag_callback) end
+--- Check if Drag component is enabled
+---@param self druid.drag @{Drag}
+---@return bool
+function druid__drag.is_enabled(self) end
+
--- Strict drag click area.
--- Useful for restrict events outside stencil node
---@param self druid.drag @{Drag}
---@param node node Gui node
function druid__drag.set_click_zone(self, node) end
+--- Set Drag input enabled or disabled
+---@param self druid.drag @{Drag}
+---@param is_enabled bool
+function druid__drag.set_enabled(self, is_enabled) end
+
---@class druid.drag.style
---@field DRAG_DEADZONE field Distance in pixels to start dragging
@@ -568,6 +579,33 @@ local druid__helper = {}
function druid__helper.table_to_string(t) end
+---@class druid.hotkey : druid.base_component
+---@field button druid.button Button component from click_node
+---@field click_node node Button trigger node
+---@field node node Visual node
+---@field on_change_state druid.event On change state callback(self, state)
+---@field style druid.hotkey.style Component style params.
+local druid__hotkey = {}
+
+--- Add hotkey for component callback
+---@param self druid.hotkey @{Hotkey}
+---@param keys string[]|hash[]|string|hash that have to be pressed before key pressed to activate
+---@param callback_argument value The argument to pass into the callback function
+function druid__hotkey.add_hotkey(self, keys, callback_argument) end
+
+--- Component init function
+---@param self druid.hotkey @{Hotkey}
+---@param keys string[]|string The keys to be pressed for trigger callback. Should contains one key and any modificator keys
+---@param callback function The callback function
+---@param callback_argument value The argument to pass into the callback function
+function druid__hotkey.init(self, keys, callback, callback_argument) end
+
+
+---@class druid.hotkey.style
+---@field MODIFICATORS field The list of action_id as hotkey modificators
+local druid__hotkey__style = {}
+
+
---@class druid.hover : druid.base_component
---@field on_hover druid.event On hover callback(self, state)
---@field on_mouse_hover druid.event On mouse hover callback(self, state)
@@ -725,6 +763,64 @@ function druid__lang_text.set_to(self, text) end
function druid__lang_text.translate(self, locale_id, a, b, c, d, e, f, g) end
+---@class druid.layout : druid.base_component
+---@field mode string Current layout mode
+---@field node node Layout node
+---@field on_size_changed druid.event On window resize callback(self, new_size)
+local druid__layout = {}
+
+--- Set node for layout node to fit inside it.
+--- Pass nil to reset
+---@param self druid.layout @{Layout}
+---@param node Node
+---@return druid.layout @{Layout}
+function druid__layout.fit_into_node(self, node) end
+
+--- Set size for layout node to fit inside it
+---@param self druid.layout @{Layout}
+---@param target_size vector3
+---@return druid.layout @{Layout}
+function druid__layout.fit_into_size(self, target_size) end
+
+--- Set current size for layout node to fit inside it
+---@param self druid.layout @{Layout}
+---@return druid.layout @{Layout}
+function druid__layout.fit_into_window(self) end
+
+--- Component init function
+---@param self druid.layout @{Layout}
+---@param node node Gui node
+---@param mode string The layout mode (from const.LAYOUT_MODE)
+---@param on_size_changed_callback function The callback on window resize
+function druid__layout.init(self, node, mode, on_size_changed_callback) end
+
+--- Set maximum size of layout node
+---@param self druid.layout @{Layout}
+---@param max_size vector3
+---@return druid.layout @{Layout}
+function druid__layout.set_max_size(self, max_size) end
+
+--- Set minimal size of layout node
+---@param self druid.layout @{Layout}
+---@param min_size vector3
+---@return druid.layout @{Layout}
+function druid__layout.set_min_size(self, min_size) end
+
+--- Set new origin position of layout node.
+--- You should apply this on node movement
+---@param self druid.layout @{Layout}
+---@param new_origin_position vector3
+---@return druid.layout @{Layout}
+function druid__layout.set_origin_position(self, new_origin_position) end
+
+--- Set new origin size of layout node.
+--- You should apply this on node manual size change
+---@param self druid.layout @{Layout}
+---@param new_origin_size vector3
+---@return druid.layout @{Layout}
+function druid__layout.set_origin_size(self, new_origin_size) end
+
+
---@class druid.pin_knob : druid.base_component
---@field druid druid_instance The component druid instance
---@field is_drag bool Is currently under user control
@@ -783,6 +879,12 @@ function druid__progress.get(self) end
---@param init_value number Initial value of progress bar
function druid__progress.init(self, node, key, init_value) end
+--- Set progress bar max node size
+---@param self druid.progress @{Progress}
+---@param max_size vector3 The new node maximum (full) size
+---@return druid.progress @{Progress}
+function druid__progress.set_max_size(self, max_size) end
+
--- Set points on progress bar to fire the callback
---@param self druid.progress @{Progress}
---@param steps number[] Array of progress bar values
@@ -1026,7 +1128,7 @@ function druid__slider.set_steps(self, steps) end
---@class druid.static_grid : druid.base_component
----@field anchor vector3 Item anchor
+---@field anchor vector3 Item anchor [0..1]
---@field border vector4 The size of item content
---@field first_index number The first index of node in grid
---@field last_index number The last index of node in grid
@@ -1038,6 +1140,7 @@ function druid__slider.set_steps(self, steps) end
---@field on_remove_item druid.event On item remove callback(self, index)
---@field on_update_positions druid.event On update item positions callback(self)
---@field parent node Parent gui node
+---@field pivot vector3 Item pivot [-0.5..0.5]
---@field style druid.static_grid.style Component style params.
local druid__static_grid = {}
@@ -1302,6 +1405,10 @@ local druid_instance = {}
---@param self druid_instance
function druid_instance.final(self) end
+--- Druid late update function call after init and before udpate step
+---@param self druid_instance
+function druid_instance.late_init(self) end
+
--- Log message, if is_debug mode is enabled
---@param self druid_instance @{DruidInstance}
---@param message string
@@ -1382,6 +1489,14 @@ function druid_instance.new_dynamic_grid(self, parent) end
---@return druid.static_grid grid component
function druid_instance.new_grid(self, parent, element, in_row) end
+--- Create hotkey component
+---@param self druid_instance
+---@param keys_array string|string[] Keys for trigger action. Should contains one action key and any amount of modificator keys
+---@param callback function Button callback
+---@param params value Button callback params
+---@return druid.hotkey hotkey component
+function druid_instance.new_hotkey(self, keys_array, callback, params) end
+
--- Create hover basic component
---@param self druid_instance
---@param node node Gui node
@@ -1405,6 +1520,13 @@ function druid_instance.new_input(self, click_node, text_node, keyboard_type) en
---@return druid.lang_text lang_text component
function druid_instance.new_lang_text(self, node, locale_id, no_adjust) end
+--- Create layout component
+---@param self druid_instance
+---@param node string|node Layout node
+---@param mode string The layout mode
+---@return druid.layout layout component
+function druid_instance.new_layout(self, node, mode) end
+
--- Create progress component
---@param self druid_instance
---@param node string|node Progress bar fill node or node name
diff --git a/druid/base/drag.lua b/druid/base/drag.lua
index b51c1af4..cd0a50fb 100644
--- a/druid/base/drag.lua
+++ b/druid/base/drag.lua
@@ -17,10 +17,10 @@
--- Event on drag start callback(self)
-- @tfield DruidEvent on_drag_start @{DruidEvent}
---- on drag progress callback(self, dx, dy)
+--- on drag progress callback(self, dx, dy, total_x, total_y)
-- @tfield DruidEvent on_drag Event @{DruidEvent}
---- Event on drag end callback(self)
+--- Event on drag end callback(self, total_x, total_y)
-- @tfield DruidEvent on_drag_end @{DruidEvent}
--- Is component now touching
@@ -70,7 +70,7 @@ end
local function end_touch(self)
if self.is_drag then
- self.on_drag_end:trigger(self:get_context())
+ self.on_drag_end:trigger(self:get_context(), self.x - self.touch_start_pos.x, self.y - self.touch_start_pos.y)
end
self.is_drag = false
@@ -96,7 +96,7 @@ local function process_touch(self, touch)
if not self.is_drag and distance >= self.style.DRAG_DEADZONE then
self.is_drag = true
self.on_drag_start:trigger(self:get_context())
- self:set_input_priority(const.PRIORITY_INPUT_MAX)
+ self:set_input_priority(const.PRIORITY_INPUT_MAX, true)
end
end
@@ -176,6 +176,7 @@ function Drag.init(self, node, on_drag_callback)
self.is_touch = false
self.is_drag = false
self.touch_start_pos = vmath.vector3(0)
+ self._is_disabled = false
self.can_x = true
self.can_y = true
@@ -186,6 +187,8 @@ function Drag.init(self, node, on_drag_callback)
self.on_drag_start = Event()
self.on_drag = Event(on_drag_callback)
self.on_drag_end = Event()
+
+ self:on_window_resized()
end
@@ -199,6 +202,13 @@ function Drag.on_late_init(self)
end
+function Drag.on_window_resized(self)
+ local x_koef, y_koef = helper.get_screen_aspect_koef()
+ self._x_koef = x_koef
+ self._y_koef = y_koef
+end
+
+
function Drag.on_input_interrupt(self)
if self.is_drag or self.is_touch then
end_touch(self)
@@ -211,7 +221,7 @@ function Drag.on_input(self, action_id, action)
return false
end
- if not helper.is_enabled(self.node) then
+ if not helper.is_enabled(self.node) or self._is_disabled then
return false
end
@@ -268,7 +278,11 @@ function Drag.on_input(self, action_id, action)
end
if self.is_drag then
- self.on_drag:trigger(self:get_context(), self.dx, self.dy)
+ self.on_drag:trigger(self:get_context(),
+ self.dx * self._x_koef,
+ self.dy * self._y_koef,
+ (self.x - self.touch_start_pos.x) * self._x_koef,
+ (self.y - self.touch_start_pos.y) * self._y_koef)
end
return self.is_drag
@@ -284,4 +298,20 @@ function Drag.set_click_zone(self, node)
end
+--- Set Drag input enabled or disabled
+-- @tparam Drag self @{Drag}
+-- @tparam bool is_enabled
+function Drag.set_enabled(self, is_enabled)
+ self._is_disabled = not is_enabled
+end
+
+
+--- Check if Drag component is enabled
+-- @tparam Drag self @{Drag}
+-- @treturn bool
+function Drag.is_enabled(self)
+ return not self._is_disabled
+end
+
+
return Drag
diff --git a/druid/base/scroll.lua b/druid/base/scroll.lua
index 0d5c7e3f..358970bb 100755
--- a/druid/base/scroll.lua
+++ b/druid/base/scroll.lua
@@ -739,7 +739,6 @@ function Scroll._process_scroll_wheel(self, action_id, action)
return false
end
-
local koef = (action_id == const.ACTION_SCROLL_UP) and 1 or -1
if self.style.WHEEL_SCROLL_INVERTED then
koef = -koef
diff --git a/druid/base/static_grid.lua b/druid/base/static_grid.lua
index c32d4c0b..a08788de 100644
--- a/druid/base/static_grid.lua
+++ b/druid/base/static_grid.lua
@@ -33,9 +33,12 @@
--- The last index of node in grid
-- @tfield number last_index
---- Item anchor
+--- Item anchor [0..1]
-- @tfield vector3 anchor
+--- Item pivot [-0.5..0.5]
+-- @tfield vector3 pivot
+
--- Item size
-- @tfield vector3 node_size
@@ -104,7 +107,6 @@ function StaticGrid.init(self, parent, element, in_row)
self.border = vmath.vector4(0) -- Current grid content size
-
self.on_add_item = Event()
self.on_remove_item = Event()
self.on_change_items = Event()
@@ -359,6 +361,11 @@ end
function StaticGrid.set_in_row(self, in_row)
self.in_row = in_row
self._grid_horizonal_offset = self.node_size.x * (self.in_row - 1) * self.anchor.x
+ self._zero_offset = vmath.vector3(
+ self.node_size.x * self.node_pivot.x - self.node_size.x * self.pivot.x - self._grid_horizonal_offset,
+ self.node_size.y * self.node_pivot.y - self.node_size.y * self.pivot.y,
+ 0)
+
self:_update(true)
self.on_change_items:trigger(self:get_context())
diff --git a/druid/base/text.lua b/druid/base/text.lua
index 566aba97..8981ccc2 100755
--- a/druid/base/text.lua
+++ b/druid/base/text.lua
@@ -240,10 +240,16 @@ end
-- @treturn number Height
function Text.get_text_size(self, text)
text = text or self.last_value
- local font = gui.get_font(self.node)
+ local font_name = gui.get_font(self.node)
+ local font = gui.get_font_resource(font_name)
local scale = gui.get_scale(self.node)
local linebreak = gui.get_line_break(self.node)
- local metrics = gui.get_text_metrics(font, text, 0, linebreak, 0, 0)
+ local metrics = resource.get_text_metrics(font, text, {
+ line_break = linebreak,
+ leading = 1,
+ tracking = 0,
+ width = self.start_size.x
+ })
local width = metrics.width
for i = #text, 1, -1 do
local c = string.sub(text, i, i)
diff --git a/druid/component.lua b/druid/component.lua
index e63fecf2..e71add09 100644
--- a/druid/component.lua
+++ b/druid/component.lua
@@ -25,6 +25,7 @@ BaseComponent.ON_FOCUS_LOST = const.ON_FOCUS_LOST
BaseComponent.ON_FOCUS_GAINED = const.ON_FOCUS_GAINED
BaseComponent.ON_LAYOUT_CHANGE = const.ON_LAYOUT_CHANGE
BaseComponent.ON_MESSAGE_INPUT = const.ON_MESSAGE_INPUT
+BaseComponent.ON_WINDOW_RESIZED = const.ON_WINDOW_RESIZED
BaseComponent.ON_LANGUAGE_CHANGE = const.ON_LANGUAGE_CHANGE
@@ -37,6 +38,7 @@ BaseComponent.ALL_INTERESTS = {
BaseComponent.ON_FOCUS_GAINED,
BaseComponent.ON_LAYOUT_CHANGE,
BaseComponent.ON_MESSAGE_INPUT,
+ BaseComponent.ON_WINDOW_RESIZED,
BaseComponent.ON_LANGUAGE_CHANGE,
}
@@ -46,6 +48,7 @@ BaseComponent.SPECIFIC_UI_MESSAGES = {
[hash("layout_changed")] = BaseComponent.ON_LAYOUT_CHANGE, -- The message_id from Defold
[hash(BaseComponent.ON_FOCUS_LOST)] = BaseComponent.ON_FOCUS_LOST,
[hash(BaseComponent.ON_FOCUS_GAINED)] = BaseComponent.ON_FOCUS_GAINED,
+ [hash(BaseComponent.ON_WINDOW_RESIZED)] = BaseComponent.ON_WINDOW_RESIZED,
[hash(BaseComponent.ON_MESSAGE_INPUT)] = BaseComponent.ON_MESSAGE_INPUT,
[hash(BaseComponent.ON_LANGUAGE_CHANGE)] = BaseComponent.ON_LANGUAGE_CHANGE,
}
@@ -170,7 +173,7 @@ function BaseComponent.get_node(self, node_or_name)
end
if not node then
- assert(node, "No component with name: " .. template_name .. node_or_name)
+ assert(node, "No component with name: " .. (template_name or "") .. (node_or_name or ""))
end
return node
@@ -215,17 +218,22 @@ end
--- Set component input priority
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam number value The new input priority value
+-- @tparam boolean is_temporary If true, the reset input priority will return to previous value
-- @treturn number The component input priority
-function BaseComponent.set_input_priority(self, value)
+function BaseComponent.set_input_priority(self, value, is_temporary)
assert(value)
if self._component.input_priority ~= value then
self._component.input_priority = value
self._component._is_input_priority_changed = true
+ if not is_temporary then
+ self._component.default_input_priority = value
+ end
+
local children = self:get_childrens()
for i = 1, #children do
- children[i]:set_input_priority(value)
+ children[i]:set_input_priority(value, is_temporary)
end
end
diff --git a/druid/const.lua b/druid/const.lua
index c40fc582..52762996 100755
--- a/druid/const.lua
+++ b/druid/const.lua
@@ -21,7 +21,7 @@ M.ACTION_SCROLL_UP = hash(sys.get_config("druid.input_scroll_up", "scroll_up"))
M.ACTION_SCROLL_DOWN = hash(sys.get_config("druid.input_scroll_down", "scroll_down"))
-M.IS_STENCIL_CHECK = sys.get_config("druid.stencil_check") == "1"
+M.IS_STENCIL_CHECK = not (sys.get_config("druid.no_stencil_check") == "1")
M.RELEASED = "released"
@@ -40,6 +40,7 @@ M.ON_FOCUS_LOST = "on_focus_lost"
M.ON_FOCUS_GAINED = "on_focus_gained"
M.ON_LAYOUT_CHANGE = "on_layout_change"
M.ON_MESSAGE_INPUT = "on_message_input"
+M.ON_WINDOW_RESIZED = "on_window_resized"
M.ON_LANGUAGE_CHANGE = "on_language_change"
@@ -83,6 +84,15 @@ M.REVERSE_PIVOTS = {
}
+M.LAYOUT_MODE = {
+ STRETCH_X = "stretch_x",
+ STRETCH_Y = "stretch_y",
+ ZOOM_MIN = "zoom_min",
+ ZOOM_MAX = "zoom_max",
+ FIT = gui.ADJUST_FIT,
+ STRETCH = gui.ADJUST_STRETCH,
+}
+
M.VECTOR_ZERO = vmath.vector3(0)
M.VECTOR_ONE = vmath.vector3(1)
M.SYS_INFO = sys.get_sys_info()
diff --git a/druid/druid.lua b/druid/druid.lua
index ed5303fc..44f13c69 100644
--- a/druid/druid.lua
+++ b/druid/druid.lua
@@ -117,6 +117,12 @@ function M.on_window_callback(event)
msg.post(instances[i].url, base_component.ON_FOCUS_GAINED)
end
end
+
+ if event == window.WINDOW_EVENT_RESIZED then
+ for i = 1, #instances do
+ msg.post(instances[i].url, base_component.ON_WINDOW_RESIZED)
+ end
+ end
end
diff --git a/druid/extended/hotkey.lua b/druid/extended/hotkey.lua
new file mode 100644
index 00000000..23ecd49a
--- /dev/null
+++ b/druid/extended/hotkey.lua
@@ -0,0 +1,154 @@
+-- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license
+
+--- Druid hotkey component
+-- @module Hotkey
+-- @within BaseComponent
+-- @alias druid.hotkey
+
+--- On change state callback(self, state)
+-- @tfield DruidEvent on_change_state @{DruidEvent}
+
+--- Visual node
+-- @tfield node node
+
+--- Button trigger node
+-- @tfield[opt=node] node click_node
+
+--- Button component from click_node
+-- @tfield Button button @{Button}
+
+---
+
+local helper = require("druid.helper")
+local component = require("druid.component")
+
+local Hotkey = component.create("hotkey")
+
+
+--- Component init function
+-- @tparam Hotkey self @{Hotkey}
+-- @tparam string[]|string keys The keys to be pressed for trigger callback. Should contains one key and any modificator keys
+-- @tparam function callback The callback function
+-- @tparam[opt] value callback_argument The argument to pass into the callback function
+function Hotkey.init(self, keys, callback, callback_argument)
+ self.druid = self:get_druid()
+
+ self._hotkeys = {}
+ self._modificators = {}
+ self._callback = callback
+
+ if keys then
+ self:add_hotkey(keys, callback_argument)
+ 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[] MODIFICATORS The list of action_id as hotkey modificators
+function Hotkey.on_style_change(self, style)
+ self.style = {}
+ self.style.MODIFICATORS = style.MODIFICATORS or {}
+
+ for index = 1, #style.MODIFICATORS do
+ self.style.MODIFICATORS[index] = hash(self.style.MODIFICATORS[index])
+ end
+end
+
+
+--- Add hotkey for component callback
+-- @tparam Hotkey self @{Hotkey}
+-- @tparam string[]|hash[]|string|hash keys that have to be pressed before key pressed to activate
+-- @tparam[opt] value callback_argument The argument to pass into the callback function
+function Hotkey.add_hotkey(self, keys, callback_argument)
+ keys = keys or {}
+ if type(keys) == "string" then
+ keys = { keys }
+ end
+
+ local modificators = {}
+ local key = nil
+
+ for index = 1, #keys do
+ local key_hash = hash(keys[index])
+ if helper.contains(self.style.MODIFICATORS, key_hash) then
+ table.insert(modificators, key_hash)
+ else
+ if not key then
+ key = key_hash
+ else
+ error("The hotkey keys should contains only one key (except modificator keys)")
+ end
+ end
+ end
+
+ table.insert(self._hotkeys, {
+ modificators = modificators,
+ key = key,
+ is_processing = false,
+ callback_argument = callback_argument,
+ })
+
+ -- Current hotkey status
+ for index = 1, #self.style.MODIFICATORS do
+ local modificator = hash(self.style.MODIFICATORS[index])
+ self._modificators[modificator] = self._modificators[modificator] or false
+ end
+
+ return self
+end
+
+
+function Hotkey.on_input(self, action_id, action)
+ if not action_id then
+ return false
+ end
+
+ if self._modificators[action_id] ~= nil then
+ if action.pressed then
+ self._modificators[action_id] = true
+ end
+ if action.released then
+ self._modificators[action_id] = false
+ end
+ end
+
+ for index = 1, #self._hotkeys do
+ local hotkey = self._hotkeys[index]
+ if action_id == hotkey.key then
+ local is_modificator_ok = true
+
+ -- Check only required modificators pressed
+ for i = 1, #self.style.MODIFICATORS do
+ local mod = self.style.MODIFICATORS[i]
+ if helper.contains(hotkey.modificators, mod) and self._modificators[mod] == false then
+ is_modificator_ok = false
+ end
+ if not helper.contains(hotkey.modificators, mod) and self._modificators[mod] == true then
+ is_modificator_ok = false
+ end
+ end
+
+ if action.pressed and is_modificator_ok then
+ hotkey.is_processing = true
+ end
+ if action.released and is_modificator_ok and hotkey.is_processing then
+ hotkey.is_processing = false
+ if hotkey.callback_argument then
+ self._callback(self:get_context(), hotkey.callback_argument)
+ return true
+ else
+ self._callback(self:get_context())
+ return true
+ end
+ end
+ end
+ end
+
+ return false
+end
+
+
+return Hotkey
diff --git a/druid/extended/input.lua b/druid/extended/input.lua
index d463871b..36da224a 100755
--- a/druid/extended/input.lua
+++ b/druid/extended/input.lua
@@ -281,8 +281,8 @@ function Input.select(self)
gui.reset_keyboard()
self.marked_value = ""
if not self.is_selected then
- self:set_input_priority(const.PRIORITY_INPUT_MAX)
- self.button:set_input_priority(const.PRIORITY_INPUT_MAX)
+ self:set_input_priority(const.PRIORITY_INPUT_MAX, true)
+ self.button:set_input_priority(const.PRIORITY_INPUT_MAX, true)
self.previous_value = self.value
self.is_selected = true
diff --git a/druid/extended/lang_text.lua b/druid/extended/lang_text.lua
index f30b48a7..f78b70b7 100755
--- a/druid/extended/lang_text.lua
+++ b/druid/extended/lang_text.lua
@@ -14,6 +14,7 @@
---
+local const = require("druid.const")
local Event = require("druid.event")
local settings = require("druid.system.settings")
local component = require("druid.component")
diff --git a/druid/extended/layout.lua b/druid/extended/layout.lua
new file mode 100644
index 00000000..0c544f56
--- /dev/null
+++ b/druid/extended/layout.lua
@@ -0,0 +1,188 @@
+-- Copyright (c) 2021 Maksim Tuprikov . This code is licensed under MIT license
+
+--- Layout management on node
+-- @module Layout
+-- @within BaseComponent
+-- @alias druid.layout
+
+--- Layout node
+-- @tfield node node
+
+--- Current layout mode
+-- @tfield string mode
+
+---On window resize callback(self, new_size)
+-- @tfield DruidEvent on_size_changed @{DruidEvent}
+
+---
+
+
+local const = require("druid.const")
+local helper = require("druid.helper")
+local component = require("druid.component")
+local Event = require("druid.event")
+
+
+local Layout = component.create("layout")
+
+
+--- Component init function
+-- @tparam Layout self @{Layout}
+-- @tparam node node Gui node
+-- @tparam string mode The layout mode (from const.LAYOUT_MODE)
+-- @tparam[opt] function on_size_changed_callback The callback on window resize
+function Layout.init(self, node, mode, on_size_changed_callback)
+ self.node = self:get_node(node)
+
+ self._min_size = nil
+ self._max_size = nil
+ self._inited = false
+
+ self._fit_node = nil
+
+ self.mode = mode or const.LAYOUT_MODE.FIT
+
+ self.on_size_changed = Event(on_size_changed_callback)
+end
+
+
+function Layout.on_late_init(self)
+ self._inited = true
+ self.origin_size = self.origin_size or gui.get_size(self.node)
+ self.fit_size = self.fit_size or vmath.vector3(self.origin_size)
+ self.pivot = helper.get_pivot_offset(gui.get_pivot(self.node))
+ self.origin_position = gui.get_position(self.node)
+ self.position = vmath.vector3(self.origin_position)
+ gui.set_size_mode(self.node, gui.SIZE_MODE_MANUAL)
+ gui.set_adjust_mode(self.node, gui.ADJUST_FIT)
+ self:on_window_resized()
+end
+
+
+function Layout.on_window_resized(self)
+ if not self._inited then
+ return
+ end
+
+ local x_koef, y_koef = helper.get_screen_aspect_koef()
+
+ if self._fit_node then
+ self.fit_size = gui.get_size(self._fit_node)
+ self.fit_size.x = self.fit_size.x / x_koef
+ self.fit_size.y = self.fit_size.y / y_koef
+ end
+
+ x_koef = self.fit_size.x / self.origin_size.x * x_koef
+ y_koef = self.fit_size.y / self.origin_size.y * y_koef
+
+ local new_size = vmath.vector3(self.origin_size)
+
+ if self.mode == const.LAYOUT_MODE.STRETCH_X or self.mode == const.LAYOUT_MODE.STRETCH then
+ new_size.x = new_size.x * x_koef
+ end
+ if self.mode == const.LAYOUT_MODE.STRETCH_Y or self.mode == const.LAYOUT_MODE.STRETCH then
+ new_size.y = new_size.y * y_koef
+ end
+
+ -- Fit to the stretched container (node size or other defined)
+ if self.mode == const.LAYOUT_MODE.ZOOM_MIN then
+ new_size = new_size * math.min(x_koef, y_koef)
+ end
+ if self.mode == const.LAYOUT_MODE.ZOOM_MAX then
+ new_size = new_size * math.max(x_koef, y_koef)
+ end
+
+ if self._min_size then
+ new_size.x = math.max(new_size.x, self._min_size.x)
+ new_size.y = math.max(new_size.y, self._min_size.y)
+ end
+ if self._max_size then
+ new_size.x = math.min(new_size.x, self._max_size.x)
+ new_size.y = math.min(new_size.y, self._max_size.y)
+ end
+ gui.set_size(self.node, new_size)
+
+ self.position.x = self.origin_position.x + self.origin_position.x * (x_koef - 1)
+ self.position.y = self.origin_position.y + self.origin_position.y * (y_koef - 1)
+ gui.set_position(self.node, self.position)
+
+ self.on_size_changed:trigger(self:get_context(), new_size)
+end
+
+
+--- Set minimal size of layout node
+-- @tparam Layout self @{Layout}
+-- @tparam vector3 min_size
+-- @treturn Layout @{Layout}
+function Layout.set_min_size(self, min_size)
+ self._min_size = min_size
+ return self
+end
+
+
+--- Set maximum size of layout node
+-- @tparam Layout self @{Layout}
+-- @tparam vector3 max_size
+-- @treturn Layout @{Layout}
+function Layout.set_max_size(self, max_size)
+ self._max_size = max_size
+ return self
+end
+
+
+--- Set new origin position of layout node. You should apply this on node movement
+-- @tparam Layout self @{Layout}
+-- @tparam vector3 new_origin_position
+-- @treturn Layout @{Layout}
+function Layout.set_origin_position(self, new_origin_position)
+ self.origin_position = new_origin_position or self.origin_position
+ self:on_window_resized()
+ return self
+end
+
+
+--- Set new origin size of layout node. You should apply this on node manual size change
+-- @tparam Layout self @{Layout}
+-- @tparam vector3 new_origin_size
+-- @treturn Layout @{Layout}
+function Layout.set_origin_size(self, new_origin_size)
+ self.origin_size = new_origin_size or self.origin_size
+ self:on_window_resized()
+ return self
+end
+
+
+--- Set size for layout node to fit inside it
+-- @tparam Layout self @{Layout}
+-- @tparam vector3 target_size
+-- @treturn Layout @{Layout}
+function Layout.fit_into_size(self, target_size)
+ self.fit_size = target_size
+ self:on_window_resized()
+ return self
+end
+
+
+--- Set node for layout node to fit inside it. Pass nil to reset
+-- @tparam Layout self @{Layout}
+-- @tparam[opt] Node node
+-- @treturn Layout @{Layout}
+function Layout.fit_into_node(self, node)
+ self._fit_node = node
+ self:on_window_resized()
+ return self
+end
+
+
+--- Set current size for layout node to fit inside it
+-- @tparam Layout self @{Layout}
+-- @treturn Layout @{Layout}
+function Layout.fit_into_window(self)
+ return self:fit_into_size(vmath.vector3(
+ gui.get_width(),
+ gui.get_height(),
+ 0))
+end
+
+
+return Layout
diff --git a/druid/extended/progress.lua b/druid/extended/progress.lua
index 1ebe6e78..1e6fd4d9 100644
--- a/druid/extended/progress.lua
+++ b/druid/extended/progress.lua
@@ -75,6 +75,9 @@ local function set_bar_to(self, set_to, is_silent)
if not is_silent then
check_steps(self, prev_value, set_to)
+ if prev_value ~= self.last_value then
+ self.on_change:trigger(self:get_context(), self.last_value)
+ end
end
end
@@ -103,11 +106,14 @@ function Progress.init(self, node, key, init_value)
self.prop = hash("scale."..key)
self.key = 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 = self.size[self.key]
self.slice = gui.get_slice9(self.node)
+ self.last_value = self._init_value
+
if key == const.SIDE.X then
self.slice_size = self.slice.x + self.slice.z
else
@@ -115,8 +121,12 @@ function Progress.init(self, node, key, init_value)
end
self.on_change = Event()
+end
- self:set_to(init_value or 1)
+
+-- @tparam Progress self @{Progress}
+function Progress.on_late_init(self)
+ self:set_to(self._init_value)
end
@@ -163,6 +173,7 @@ end
-- @tparam Progress self @{Progress}
-- @tparam number to Progress bar value, from 0 to 1
function Progress.set_to(self, to)
+ to = helper.clamp(to, 0, 1)
set_bar_to(self, to)
end
@@ -204,4 +215,15 @@ function Progress.to(self, to, callback)
end
+--- Set progress bar max node size
+-- @tparam Progress self @{Progress}
+-- @tparam vector3 max_size The new node maximum (full) size
+-- @treturn Progress @{Progress}
+function Progress.set_max_size(self, max_size)
+ self.max_size = max_size[self.key]
+ self:set_to(self.last_value)
+ return self
+end
+
+
return Progress
diff --git a/druid/helper.lua b/druid/helper.lua
index d5ebee20..c7849d11 100644
--- a/druid/helper.lua
+++ b/druid/helper.lua
@@ -8,6 +8,7 @@ local const = require("druid.const")
local M = {}
+
--- Text node or icon node can be nil
local function get_text_width(text_node)
if text_node then
@@ -97,6 +98,15 @@ function M.centrate_nodes(margin, ...)
end
+function M.get_screen_aspect_koef()
+ local window_x, window_y = window.get_size()
+ local stretch_x = window_x / gui.get_width()
+ local stretch_y = window_y / gui.get_height()
+ return stretch_x / math.min(stretch_x, stretch_y),
+ stretch_y / math.min(stretch_x, stretch_y)
+end
+
+
function M.step(current, target, step)
if current < target then
return math.min(current + step, target)
diff --git a/druid/styles/default/style.lua b/druid/styles/default/style.lua
index bd18a784..897b5993 100644
--- a/druid/styles/default/style.lua
+++ b/druid/styles/default/style.lua
@@ -147,4 +147,9 @@ M["text"] = {
}
+M["hotkey"] = {
+ MODIFICATORS = { "key_lshift", "key_rshift", "key_lctrl", "key_rctrl", "key_lalt", "key_ralt", "key_lsuper", "key_rsuper" }, -- Add key ids to mark it as modificator keys
+}
+
+
return M
diff --git a/druid/system/druid_instance.lua b/druid/system/druid_instance.lua
index dea1439c..ea002cab 100755
--- a/druid/system/druid_instance.lua
+++ b/druid/system/druid_instance.lua
@@ -30,6 +30,8 @@
-- @see Drag
-- @see DataList
-- @see Hover
+-- @see Layout
+-- @see Hotkey
local helper = require("druid.helper")
local class = require("druid.system.middleclass")
@@ -55,7 +57,7 @@ local lang_text = require("druid.extended.lang_text")
local progress = require("druid.extended.progress")
local radio_group = require("druid.extended.radio_group")
local slider = require("druid.extended.slider")
-local timer = require("druid.extended.timer")
+local timer_component = require("druid.extended.timer")
local data_list = require("druid.extended.data_list")
@@ -213,6 +215,10 @@ function DruidInstance.initialize(self, context, style)
for i = 1, #base_component.ALL_INTERESTS do
self.components_interest[base_component.ALL_INTERESTS[i]] = {}
end
+
+ timer.delay(0, false, function()
+ self:late_init()
+ end)
end
@@ -309,10 +315,9 @@ function DruidInstance.remove(self, component)
end
---- Druid update function
+--- Druid late update function call after init and before udpate step
-- @tparam DruidInstance self
--- @tparam number dt Delta time
-function DruidInstance.update(self, dt)
+function DruidInstance.late_init(self)
local late_init_components = self.components_interest[base_component.ON_LATE_INIT]
while late_init_components[1] do
late_init_components[1]:on_late_init()
@@ -323,7 +328,13 @@ function DruidInstance.update(self, dt)
-- Input init on late init step, to be sure it goes after user go acquire input
input_init(self)
end
+end
+
+--- Druid update function
+-- @tparam DruidInstance self
+-- @tparam number dt Delta time
+function DruidInstance.update(self, dt)
self._is_late_remove_enabled = true
local components = self.components_interest[base_component.ON_UPDATE]
for i = 1, #components do
@@ -722,7 +733,7 @@ end
-- @treturn Timer timer component
function DruidInstance.new_timer(self, node, seconds_from, seconds_to, callback)
-- return helper.extended_component("timer")
- return DruidInstance.new(self, timer, node, seconds_from, seconds_to, callback)
+ return DruidInstance.new(self, timer_component, node, seconds_from, seconds_to, callback)
end
@@ -738,4 +749,25 @@ function DruidInstance.new_progress(self, node, key, init_value)
end
+--- Create layout component
+-- @tparam DruidInstance self
+-- @tparam string|node node Layout node
+-- @tparam string mode The layout mode
+-- @treturn Layout layout component
+function DruidInstance.new_layout(self, node, mode)
+ return helper.extended_component("layout")
+end
+
+
+--- Create hotkey component
+-- @tparam DruidInstance self
+-- @tparam string|string[] keys_array Keys for trigger action. Should contains one action key and any amount of modificator keys
+-- @tparam function callback Button callback
+-- @tparam[opt] value params Button callback params
+-- @treturn Hotkey hotkey component
+function DruidInstance.new_hotkey(self, keys_array, callback, params)
+ return helper.extended_component("hotkey")
+end
+
+
return DruidInstance
diff --git a/example/assets/images/kenney.atlas b/example/assets/images/kenney.atlas
index 31a9f7ba..ead7b5af 100644
--- a/example/assets/images/kenney.atlas
+++ b/example/assets/images/kenney.atlas
@@ -62,6 +62,10 @@ images {
image: "/example/assets/images/buttons/button_blue.png"
sprite_trim_mode: SPRITE_TRIM_MODE_OFF
}
+images {
+ image: "/example/assets/images/logo.png"
+ sprite_trim_mode: SPRITE_TRIM_MODE_OFF
+}
margin: 0
extrude_borders: 2
inner_padding: 0
diff --git a/example/assets/images/logo.png b/example/assets/images/logo.png
new file mode 100644
index 00000000..7a56d26e
Binary files /dev/null and b/example/assets/images/logo.png differ
diff --git a/example/example.collection b/example/example.collection
index 4bb97e34..097a84ff 100644
--- a/example/example.collection
+++ b/example/example.collection
@@ -1688,6 +1688,132 @@ embedded_instances {
z: 1.0
}
}
+embedded_instances {
+ id: "general_layout"
+ data: "components {\n"
+ " id: \"screen_factory\"\n"
+ " component: \"/monarch/screen_factory.script\"\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"
+ " properties {\n"
+ " id: \"screen_id\"\n"
+ " value: \"general_layout\"\n"
+ " type: PROPERTY_TYPE_HASH\n"
+ " }\n"
+ " properties {\n"
+ " id: \"popup\"\n"
+ " value: \"true\"\n"
+ " type: PROPERTY_TYPE_BOOLEAN\n"
+ " }\n"
+ "}\n"
+ "embedded_components {\n"
+ " id: \"collectionfactory\"\n"
+ " type: \"collectionfactory\"\n"
+ " data: \"prototype: \\\"/example/examples/general/layout/layout.collection\\\"\\n"
+ "load_dynamically: false\\n"
+ "\"\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"
+ "}\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
+ }
+}
+embedded_instances {
+ id: "general_hotkey"
+ data: "components {\n"
+ " id: \"screen_factory\"\n"
+ " component: \"/monarch/screen_factory.script\"\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"
+ " properties {\n"
+ " id: \"screen_id\"\n"
+ " value: \"general_hotkey\"\n"
+ " type: PROPERTY_TYPE_HASH\n"
+ " }\n"
+ " properties {\n"
+ " id: \"popup\"\n"
+ " value: \"true\"\n"
+ " type: PROPERTY_TYPE_BOOLEAN\n"
+ " }\n"
+ "}\n"
+ "embedded_components {\n"
+ " id: \"collectionfactory\"\n"
+ " type: \"collectionfactory\"\n"
+ " data: \"prototype: \\\"/example/examples/general/hotkey/hotkey.collection\\\"\\n"
+ "load_dynamically: false\\n"
+ "\"\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"
+ "}\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
+ }
+}
embedded_instances {
id: "data_list_with_component"
data: "components {\n"
@@ -1751,3 +1877,129 @@ embedded_instances {
z: 1.0
}
}
+embedded_instances {
+ id: "layout_fit"
+ data: "components {\n"
+ " id: \"screen_factory\"\n"
+ " component: \"/monarch/screen_factory.script\"\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"
+ " properties {\n"
+ " id: \"screen_id\"\n"
+ " value: \"layout_fit\"\n"
+ " type: PROPERTY_TYPE_HASH\n"
+ " }\n"
+ " properties {\n"
+ " id: \"popup\"\n"
+ " value: \"true\"\n"
+ " type: PROPERTY_TYPE_BOOLEAN\n"
+ " }\n"
+ "}\n"
+ "embedded_components {\n"
+ " id: \"collectionfactory\"\n"
+ " type: \"collectionfactory\"\n"
+ " data: \"prototype: \\\"/example/examples/layout/layout_fit/layout_fit.collection\\\"\\n"
+ "load_dynamically: false\\n"
+ "\"\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"
+ "}\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
+ }
+}
+embedded_instances {
+ id: "general_progress_bar"
+ data: "components {\n"
+ " id: \"screen_factory\"\n"
+ " component: \"/monarch/screen_factory.script\"\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"
+ " properties {\n"
+ " id: \"screen_id\"\n"
+ " value: \"general_progress_bar\"\n"
+ " type: PROPERTY_TYPE_HASH\n"
+ " }\n"
+ " properties {\n"
+ " id: \"popup\"\n"
+ " value: \"true\"\n"
+ " type: PROPERTY_TYPE_BOOLEAN\n"
+ " }\n"
+ "}\n"
+ "embedded_components {\n"
+ " id: \"collectionfactory\"\n"
+ " type: \"collectionfactory\"\n"
+ " data: \"prototype: \\\"/example/examples/general/progress_bar/progress_bar.collection\\\"\\n"
+ "load_dynamically: false\\n"
+ "\"\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"
+ "}\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/example.gui b/example/example.gui
index f613534e..64f0e71a 100644
--- a/example/example.gui
+++ b/example/example.gui
@@ -274,7 +274,7 @@ nodes {
xanchor: XANCHOR_NONE
yanchor: YANCHOR_NONE
pivot: PIVOT_N
- adjust_mode: ADJUST_MODE_STRETCH
+ adjust_mode: ADJUST_MODE_FIT
parent: "lobby_view"
layer: ""
inherit_alpha: true
diff --git a/example/example.gui_script b/example/example.gui_script
index abf8d640..e8f0709b 100644
--- a/example/example.gui_script
+++ b/example/example.gui_script
@@ -128,12 +128,14 @@ local function init_lobby(self)
self.lobby_grid:add(get_button(self, "Sliders", "general_sliders", "/general/sliders/sliders.gui_script"))
self.lobby_grid:add(get_button(self, "Scrolls", "general_scroll", "/general/scroll/scroll.gui_script"))
self.lobby_grid:add(get_button(self, "Grids", "general_grid", "/general/grid/grid.gui_script"))
- self.lobby_grid:add(get_button_disabled(self, "Progress Bar", "scene_name"))
+ self.lobby_grid:add(get_button(self, "Progress Bar", "general_progress_bar", "/general/progress_bar/progress_bar.gui_script"))
self.lobby_grid:add(get_button(self, "Data List", "general_data_list", "/general/data_list/data_list.gui_script"))
self.lobby_grid:add(get_button(self, "Checkboxes", "general_checkboxes", "/general/checkboxes/checkboxes.gui_script"))
self.lobby_grid:add(get_button(self, "Input text", "general_input", "/general/input/input.gui_script"))
+ self.lobby_grid:add(get_button(self, "Layout", "general_layout", "/general/layout/layout.gui_script"))
self.lobby_grid:add(get_button(self, "Swipe", "general_swipe", "/general/swipe/swipe.gui_script"))
self.lobby_grid:add(get_button(self, "Drag", "general_drag", "/general/drag/drag.gui_script"))
+ self.lobby_grid:add(get_button(self, "Hotkey", "general_hotkey", "/general/hotkey/hotkey.gui_script"))
self.lobby_grid:add(get_title(self, "Texts"))
self.lobby_grid:add(get_button(self, "Texts", "texts_general", "/texts/texts_general/texts_general.gui_script"))
@@ -160,6 +162,9 @@ local function init_lobby(self)
self.lobby_grid:add(get_button(self, "Reinit data", "data_list_reinit_data", "/data_list/reinit_data/reinit_data.gui_script"))
self.lobby_grid:add(get_button(self, "With component", "data_list_with_component", "/data_list/with_component/with_component.gui_script"))
+ self.lobby_grid:add(get_title(self, "Layouts"))
+ self.lobby_grid:add(get_button(self, "Layout fit", "layout_fit", "/custom/layout_fit/layout_fit.gui_script"))
+
self.lobby_grid:add(get_title(self, "Custom components"))
self.lobby_grid:add(get_button(self, "Rich Input", "custom_rich_input", "/custom/rich_input/rich_input.gui_script"))
self.lobby_grid:add(get_button(self, "Pin Knob", "custom_pin_knob", "/custom/pin_knob/pin_knob.gui_script"))
diff --git a/example/examples/general/drag/drag.gui b/example/examples/general/drag/drag.gui
index 4aed380a..a0c145ad 100644
--- a/example/examples/general/drag/drag.gui
+++ b/example/examples/general/drag/drag.gui
@@ -308,6 +308,169 @@ nodes {
text_tracking: 0.0
custom_type: 0
}
+nodes {
+ position {
+ x: 0.0
+ y: -344.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEMPLATE
+ id: "button_drag"
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ template: "/example/templates/button.gui"
+ template_node_child: false
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 60.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/button_blue"
+ id: "button_drag/button"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "button_drag"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 15.0
+ y: 15.0
+ z: 15.0
+ w: 15.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ overridden_fields: 4
+ template_node_child: true
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 7.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.7
+ y: 0.7
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Toggle Drag Enabled"
+ font: "game"
+ id: "button_drag/text"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ shadow {
+ x: 0.101960786
+ y: 0.2
+ z: 0.6
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "button_drag/button"
+ layer: "text"
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.0
+ shadow_alpha: 0.78
+ overridden_fields: 8
+ template_node_child: true
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
layers {
name: "image"
}
diff --git a/example/examples/general/drag/drag.gui_script b/example/examples/general/drag/drag.gui_script
index 46c4dcf8..06e35848 100644
--- a/example/examples/general/drag/drag.gui_script
+++ b/example/examples/general/drag/drag.gui_script
@@ -1,9 +1,10 @@
local druid = require("druid.druid")
-local function on_drag_callback(self, dx, dy)
+local function on_drag_callback(self, dx, dy, total_x, total_y)
self.position.x = self.position.x + dx
self.position.y = self.position.y + dy
+ print("Total drag:", total_x, total_y)
gui.set_position(self.box, self.position)
end
@@ -15,6 +16,11 @@ local function on_drag_end(self)
end
+local function on_drag_toggle(self)
+ self.drag:set_enabled(not self.drag:is_enabled())
+end
+
+
function init(self)
self.druid = druid.new(self)
@@ -23,6 +29,8 @@ function init(self)
self.drag = self.druid:new_drag("drag_node", on_drag_callback)
self.drag.on_drag_end:subscribe(on_drag_end, self)
+
+ self.druid:new_button("button_drag/button", on_drag_toggle)
end
diff --git a/example/examples/general/hotkey/hotkey.collection b/example/examples/general/hotkey/hotkey.collection
new file mode 100644
index 00000000..0b416851
--- /dev/null
+++ b/example/examples/general/hotkey/hotkey.collection
@@ -0,0 +1,37 @@
+name: "hotkey"
+scale_along_z: 0
+embedded_instances {
+ id: "go"
+ data: "components {\n"
+ " id: \"template\"\n"
+ " component: \"/example/examples/general/hotkey/hotkey.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"
+ "}\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/general/hotkey/hotkey.gui b/example/examples/general/hotkey/hotkey.gui
new file mode 100644
index 00000000..34d0b7ca
--- /dev/null
+++ b/example/examples/general/hotkey/hotkey.gui
@@ -0,0 +1,207 @@
+script: "/example/examples/general/hotkey/hotkey.gui_script"
+fonts {
+ name: "game"
+ font: "/example/assets/fonts/game.font"
+}
+textures {
+ name: "kenney"
+ texture: "/example/assets/images/kenney.atlas"
+}
+background_color {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+}
+nodes {
+ position {
+ x: 300.0
+ y: 415.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 600.0
+ y: 830.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/empty"
+ id: "root"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 400.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Use Ctrl + G or Cmd + G to tirgger the hotkey"
+ font: "game"
+ id: "text_hint"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: true
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -140.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 400.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Counter: 0"
+ font: "game"
+ id: "text_counter"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: true
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+layers {
+ name: "image"
+}
+layers {
+ name: "text"
+}
+material: "/builtins/materials/gui.material"
+adjust_reference: ADJUST_REFERENCE_PARENT
+max_nodes: 512
diff --git a/example/examples/general/hotkey/hotkey.gui_script b/example/examples/general/hotkey/hotkey.gui_script
new file mode 100644
index 00000000..2b920d61
--- /dev/null
+++ b/example/examples/general/hotkey/hotkey.gui_script
@@ -0,0 +1,38 @@
+local hotkey = require("druid.extended.hotkey")
+local druid = require("druid.druid")
+
+
+local function on_hotkey(self)
+ self.counter = self.counter + 1
+ gui.set_text(gui.get_node("text_counter"), "Counter: " .. self.counter)
+end
+
+
+function init(self)
+ druid.register("hotkey", hotkey)
+ self.druid = druid.new(self)
+ self.counter = 0
+
+ self.hotkey = self.druid:new_hotkey({ "key_lsuper", "key_g" }, on_hotkey)
+ self.hotkey:add_hotkey({ "key_lctrl", "key_g"})
+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
diff --git a/example/examples/general/layout/layout.collection b/example/examples/general/layout/layout.collection
new file mode 100644
index 00000000..3269796e
--- /dev/null
+++ b/example/examples/general/layout/layout.collection
@@ -0,0 +1,37 @@
+name: "layout"
+scale_along_z: 0
+embedded_instances {
+ id: "go"
+ data: "components {\n"
+ " id: \"layout\"\n"
+ " component: \"/example/examples/general/layout/layout.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"
+ "}\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/general/layout/layout.gui b/example/examples/general/layout/layout.gui
new file mode 100644
index 00000000..385aaff0
--- /dev/null
+++ b/example/examples/general/layout/layout.gui
@@ -0,0 +1,679 @@
+script: "/example/examples/general/layout/layout.gui_script"
+fonts {
+ name: "game"
+ font: "/example/assets/fonts/game.font"
+}
+textures {
+ name: "kenney"
+ texture: "/example/assets/images/kenney.atlas"
+}
+background_color {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+}
+nodes {
+ position {
+ x: 300.0
+ y: 415.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 600.0
+ y: 830.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/empty"
+ id: "root"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_STRETCH
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 250.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/slider_move"
+ id: "node_stretch"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_STRETCH
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 17.0
+ y: 17.0
+ z: 17.0
+ w: 17.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.65
+ y: 0.65
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 450.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Regular Stretch Mode"
+ font: "game"
+ id: "text_regular"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "node_stretch"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/slider_move"
+ id: "node_layout_stretch"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_STRETCH
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 17.0
+ y: 17.0
+ z: 17.0
+ w: 17.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.65
+ y: 0.65
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 450.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Layout Stretch"
+ font: "game"
+ id: "text_layout_stretch"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "node_layout_stretch"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -50.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/slider_move"
+ id: "node_layout_stretch_x"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_STRETCH
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 17.0
+ y: 17.0
+ z: 17.0
+ w: 17.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.65
+ y: 0.65
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 450.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Layout Stretch by X"
+ font: "game"
+ id: "text_layout_stretch1"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "node_layout_stretch_x"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -200.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/slider_move"
+ id: "node_layout_stretch_y"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_STRETCH
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 17.0
+ y: 17.0
+ z: 17.0
+ w: 17.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.65
+ y: 0.65
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 450.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Layout Stretch by Y"
+ font: "game"
+ id: "text_layout_stretch2"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "node_layout_stretch_y"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: -250.0
+ y: -350.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/slider_move"
+ id: "node_layout_stretch_y_anchor_w"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_W
+ adjust_mode: ADJUST_MODE_STRETCH
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 17.0
+ y: 17.0
+ z: 17.0
+ w: 17.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 150.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.65
+ y: 0.65
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 450.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Layout Stretch by X Anchor W"
+ font: "game"
+ id: "text_layout_stretch3"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: true
+ parent: "node_layout_stretch_y_anchor_w"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+layers {
+ name: "image"
+}
+layers {
+ name: "text"
+}
+material: "/builtins/materials/gui.material"
+adjust_reference: ADJUST_REFERENCE_PARENT
+max_nodes: 512
diff --git a/example/examples/general/layout/layout.gui_script b/example/examples/general/layout/layout.gui_script
new file mode 100644
index 00000000..a5adf93b
--- /dev/null
+++ b/example/examples/general/layout/layout.gui_script
@@ -0,0 +1,33 @@
+local druid = require("druid.druid")
+local const_druid = require("druid.const")
+local layout = require("druid.extended.layout")
+
+function init(self)
+ druid.register("layout", layout)
+ self.druid = druid.new(self)
+
+ self.druid:new_layout("node_layout_stretch", const_druid.LAYOUT_MODE.STRETCH)
+ self.druid:new_layout("node_layout_stretch_x", const_druid.LAYOUT_MODE.STRETCH_X)
+ self.druid:new_layout("node_layout_stretch_y", const_druid.LAYOUT_MODE.STRETCH_Y)
+ self.druid:new_layout("node_layout_stretch_y_anchor_w", const_druid.LAYOUT_MODE.STRETCH_X)
+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
diff --git a/example/examples/general/progress_bar/progress_bar.collection b/example/examples/general/progress_bar/progress_bar.collection
new file mode 100644
index 00000000..022f8075
--- /dev/null
+++ b/example/examples/general/progress_bar/progress_bar.collection
@@ -0,0 +1,37 @@
+name: "progress_bar"
+scale_along_z: 0
+embedded_instances {
+ id: "go"
+ data: "components {\n"
+ " id: \"progress_bar\"\n"
+ " component: \"/example/examples/general/progress_bar/progress_bar.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"
+ "}\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/general/progress_bar/progress_bar.gui b/example/examples/general/progress_bar/progress_bar.gui
new file mode 100644
index 00000000..24c3154b
--- /dev/null
+++ b/example/examples/general/progress_bar/progress_bar.gui
@@ -0,0 +1,981 @@
+script: "/example/examples/general/progress_bar/progress_bar.gui_script"
+fonts {
+ name: "game"
+ font: "/example/assets/fonts/game.font"
+}
+textures {
+ name: "kenney"
+ texture: "/example/assets/images/kenney.atlas"
+}
+background_color {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+}
+nodes {
+ position {
+ x: 300.0
+ y: 415.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 600.0
+ y: 830.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/empty"
+ id: "root"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: -150.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 45.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/progress_back"
+ id: "progress_back_x"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_W
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 300.0
+ y: 45.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/progress_fill_yellow"
+ id: "progress_fill_x"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_W
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "progress_back_x"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 10.0
+ y: 0.0
+ z: 10.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 150.0
+ y: 2.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.7
+ y: 0.7
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 100.0
+ y: 60.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "15%"
+ font: "game"
+ id: "text_progress_amount_x"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "progress_back_x"
+ layer: "text"
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: -195.0
+ y: 123.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 45.0
+ y: 300.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/progress_back"
+ id: "progress_back_y"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_N
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 10.0
+ z: 0.0
+ w: 10.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 45.0
+ y: 300.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/progress_fill_yellow"
+ id: "progress_fill_y"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_N
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "progress_back_y"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 10.0
+ y: 10.0
+ z: 10.0
+ w: 10.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -150.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 90.0
+ w: 1.0
+ }
+ scale {
+ x: 0.7
+ y: 0.7
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 100.0
+ y: 60.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "15%"
+ font: "game"
+ id: "text_progress_amount_y"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "progress_back_y"
+ layer: "text"
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 1.0
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: -150.0
+ y: 200.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEMPLATE
+ id: "button_set_0"
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ template: "/example/templates/button.gui"
+ template_node_child: false
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 130.0
+ y: 60.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/button_blue"
+ id: "button_set_0/button"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "button_set_0"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 15.0
+ y: 15.0
+ z: 15.0
+ w: 15.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: true
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 7.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.7
+ y: 0.7
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Set 0"
+ font: "game"
+ id: "button_set_0/text"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ shadow {
+ x: 0.101960786
+ y: 0.2
+ z: 0.6
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "button_set_0/button"
+ layer: "text"
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.0
+ shadow_alpha: 0.78
+ overridden_fields: 8
+ template_node_child: true
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 200.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEMPLATE
+ id: "button_add_25"
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ template: "/example/templates/button.gui"
+ template_node_child: false
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 130.0
+ y: 60.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/button_blue"
+ id: "button_add_25/button"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "button_add_25"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 15.0
+ y: 15.0
+ z: 15.0
+ w: 15.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: true
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 7.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.7
+ y: 0.7
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Add 25"
+ font: "game"
+ id: "button_add_25/text"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ shadow {
+ x: 0.101960786
+ y: 0.2
+ z: 0.6
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "button_add_25/button"
+ layer: "text"
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.0
+ shadow_alpha: 0.78
+ overridden_fields: 8
+ template_node_child: true
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 150.0
+ y: 200.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEMPLATE
+ id: "button_set_100"
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ template: "/example/templates/button.gui"
+ template_node_child: false
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 130.0
+ y: 60.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/button_blue"
+ id: "button_set_100/button"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "button_set_100"
+ layer: "image"
+ inherit_alpha: true
+ slice9 {
+ x: 15.0
+ y: 15.0
+ z: 15.0
+ w: 15.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: true
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 7.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.7
+ y: 0.7
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Set 100"
+ font: "game"
+ id: "button_set_100/text"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ shadow {
+ x: 0.101960786
+ y: 0.2
+ z: 0.6
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "button_set_100/button"
+ layer: "text"
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.0
+ shadow_alpha: 0.78
+ overridden_fields: 8
+ template_node_child: true
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 40.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.5
+ y: 0.5
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 500.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "Last step triggered: none"
+ font: "game"
+ id: "text_x_hint"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: true
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+layers {
+ name: "image"
+}
+layers {
+ name: "text"
+}
+material: "/builtins/materials/gui.material"
+adjust_reference: ADJUST_REFERENCE_PARENT
+max_nodes: 512
diff --git a/example/examples/general/progress_bar/progress_bar.gui_script b/example/examples/general/progress_bar/progress_bar.gui_script
new file mode 100644
index 00000000..1026d588
--- /dev/null
+++ b/example/examples/general/progress_bar/progress_bar.gui_script
@@ -0,0 +1,66 @@
+local druid = require("druid.druid")
+
+
+local function on_button_set_0(self)
+ self.progress_x:to(0)
+ self.progress_y:set_to(0)
+end
+
+
+local function on_button_add_25(self)
+ self.progress_x:to(self.progress_x:get() + 0.25)
+ self.progress_y:set_to(self.progress_y:get() + 0.25)
+end
+
+
+local function on_button_set_100(self)
+ self.progress_x:to(1)
+ self.progress_y:set_to(1)
+end
+
+
+local function on_progress_step(self, value)
+ gui.set_text(gui.get_node("text_x_hint"), "Last step triggered: " .. value)
+end
+
+
+function init(self)
+ self.druid = druid.new(self)
+
+ self.progress_x = self.druid:new_progress("progress_fill_x", "x", 0.4)
+ self.progress_x:set_steps({0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1}, on_progress_step)
+ self.progress_x.on_change:subscribe(function(_, value)
+ value = math.floor(value * 100)
+ gui.set_text(gui.get_node("text_progress_amount_x"), value .. "%")
+ end)
+
+ self.progress_y = self.druid:new_progress("progress_fill_y", "y", 0.6)
+ self.progress_y.on_change:subscribe(function(_, value)
+ value = math.floor(value * 100)
+ gui.set_text(gui.get_node("text_progress_amount_y"), value .. "%")
+ end)
+
+ self.druid:new_button("button_set_0/button", on_button_set_0)
+ self.druid:new_button("button_add_25/button", on_button_add_25)
+ self.druid:new_button("button_set_100/button", on_button_set_100)
+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
diff --git a/example/examples/layout/layout_fit/layout_fit.collection b/example/examples/layout/layout_fit/layout_fit.collection
new file mode 100644
index 00000000..d8e2914f
--- /dev/null
+++ b/example/examples/layout/layout_fit/layout_fit.collection
@@ -0,0 +1,37 @@
+name: "layout_fit"
+scale_along_z: 0
+embedded_instances {
+ id: "go"
+ data: "components {\n"
+ " id: \"layout_fit\"\n"
+ " component: \"/example/examples/layout/layout_fit/layout_fit.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"
+ "}\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/layout/layout_fit/layout_fit.gui b/example/examples/layout/layout_fit/layout_fit.gui
new file mode 100644
index 00000000..fddab633
--- /dev/null
+++ b/example/examples/layout/layout_fit/layout_fit.gui
@@ -0,0 +1,1247 @@
+script: "/example/examples/layout/layout_fit/layout_fit.gui_script"
+fonts {
+ name: "game"
+ font: "/example/assets/fonts/game.font"
+}
+textures {
+ name: "kenney"
+ texture: "/example/assets/images/kenney.atlas"
+}
+background_color {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+}
+nodes {
+ position {
+ x: 300.0
+ y: 415.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 600.0
+ y: 830.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/empty"
+ id: "root"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 0.7019608
+ y: 0.8
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "node_zoom_test"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 274.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: -185.0
+ y: 69.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 96.0
+ y: 96.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 0.3019608
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "back_1"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image_1"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "back_1"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.75
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -106.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.75
+ y: 0.75
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "STRECH"
+ font: "game"
+ id: "text_hint_1"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "back_1"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 69.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 96.0
+ y: 96.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 0.3019608
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "back_2"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image_2"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "back_2"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.75
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -106.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.75
+ y: 0.75
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "ZOOM MAX"
+ font: "game"
+ id: "text_hint_2"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "back_2"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 185.0
+ y: 69.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 96.0
+ y: 96.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 0.3019608
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "back_3"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image_3"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "back_3"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.75
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -106.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.75
+ y: 0.75
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "ZOOM MIN"
+ font: "game"
+ id: "text_hint_3"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "back_3"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: -185.0
+ y: -192.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 96.0
+ y: 96.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 0.3019608
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "back_4"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image_4"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "back_4"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.75
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -106.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.75
+ y: 0.75
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "STRECH X"
+ font: "game"
+ id: "text_hint_4"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "back_4"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -192.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 96.0
+ y: 96.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 0.3019608
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "back_5"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image_5"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "back_5"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.75
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -106.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.75
+ y: 0.75
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "STRECH Y"
+ font: "game"
+ id: "text_hint_5"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "back_5"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 185.0
+ y: -192.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 96.0
+ y: 96.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 0.3019608
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: ""
+ id: "back_6"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "root"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 1.0
+ template_node_child: false
+ size_mode: SIZE_MODE_MANUAL
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 140.0
+ y: 172.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_BOX
+ blend_mode: BLEND_MODE_ALPHA
+ texture: "kenney/logo"
+ id: "image_6"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ adjust_mode: ADJUST_MODE_FIT
+ parent: "back_6"
+ layer: ""
+ inherit_alpha: true
+ slice9 {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 0.0
+ }
+ clipping_mode: CLIPPING_MODE_NONE
+ clipping_visible: true
+ clipping_inverted: false
+ alpha: 0.75
+ template_node_child: false
+ size_mode: SIZE_MODE_AUTO
+ custom_type: 0
+}
+nodes {
+ position {
+ x: 0.0
+ y: -106.0
+ z: 0.0
+ w: 1.0
+ }
+ rotation {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ scale {
+ x: 0.75
+ y: 0.75
+ z: 1.0
+ w: 1.0
+ }
+ size {
+ x: 200.0
+ y: 100.0
+ z: 0.0
+ w: 1.0
+ }
+ color {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ type: TYPE_TEXT
+ blend_mode: BLEND_MODE_ALPHA
+ text: "FIT"
+ font: "game"
+ id: "text_hint_6"
+ xanchor: XANCHOR_NONE
+ yanchor: YANCHOR_NONE
+ pivot: PIVOT_CENTER
+ outline {
+ x: 0.0
+ y: 0.0
+ z: 0.0
+ w: 1.0
+ }
+ shadow {
+ x: 1.0
+ y: 1.0
+ z: 1.0
+ w: 1.0
+ }
+ adjust_mode: ADJUST_MODE_FIT
+ line_break: false
+ parent: "back_6"
+ layer: ""
+ inherit_alpha: true
+ alpha: 1.0
+ outline_alpha: 0.75
+ shadow_alpha: 0.0
+ template_node_child: false
+ text_leading: 1.0
+ text_tracking: 0.0
+ custom_type: 0
+}
+layers {
+ name: "image"
+}
+layers {
+ name: "text"
+}
+material: "/builtins/materials/gui.material"
+adjust_reference: ADJUST_REFERENCE_PARENT
+max_nodes: 512
diff --git a/example/examples/layout/layout_fit/layout_fit.gui_script b/example/examples/layout/layout_fit/layout_fit.gui_script
new file mode 100644
index 00000000..9a1c5383
--- /dev/null
+++ b/example/examples/layout/layout_fit/layout_fit.gui_script
@@ -0,0 +1,44 @@
+local druid = require("druid.druid")
+local const_druid = require("druid.const")
+local layout = require("druid.extended.layout")
+
+function init(self)
+ druid.register("layout", layout)
+ self.druid = druid.new(self)
+
+ self.druid:new_layout("node_zoom_test", const_druid.LAYOUT_MODE.STRETCH)
+ :fit_into_window()
+
+ self.druid:new_layout("image_1", const_druid.LAYOUT_MODE.STRETCH)
+ :fit_into_node(gui.get_node("back_1"))
+ self.druid:new_layout("image_2", const_druid.LAYOUT_MODE.ZOOM_MAX)
+ :fit_into_node(gui.get_node("back_2"))
+ self.druid:new_layout("image_3", const_druid.LAYOUT_MODE.ZOOM_MIN)
+ :fit_into_node(gui.get_node("back_3"))
+ self.druid:new_layout("image_4", const_druid.LAYOUT_MODE.STRETCH_X)
+ :fit_into_node(gui.get_node("back_4"))
+ self.druid:new_layout("image_5", const_druid.LAYOUT_MODE.STRETCH_Y)
+ :fit_into_node(gui.get_node("back_5"))
+ self.druid:new_layout("image_6", const_druid.LAYOUT_MODE.FIT)
+ :fit_into_node(gui.get_node("back_6"))
+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
diff --git a/example/light_theme.css b/example/light_theme.css
new file mode 100644
index 00000000..3b658db4
--- /dev/null
+++ b/example/light_theme.css
@@ -0,0 +1,85 @@
+ .canvas-app-progress {
+ position: absolute;
+ background-color: #d1dbeb;
+ height: 6px;
+ margin-top: -6px;
+ width: 100%;
+ }
+
+ .canvas-app-progress-bar {
+ font-size: 12px;
+ height: 6px;
+ color: rgb(255, 255, 255);
+ background-color: #1a72eb;
+ text-align: center;
+ line-height: 20px;
+ }
+{{#html5.show_fullscreen_button}}
+ .button {
+ background-image: url("data:image/svg+xml,%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg xmlns='http://www.w3.org/2000/svg' baseProfile='full' width='16' height='16' viewBox='0 0 16 16' version='1.1' xml:space='preserve'%3E%3Ctitle%3Eic-16-fullscreen%3C/title%3E%3Cg id='ic-16-fullscreen' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd'%3E%3Cpath d='M3,11.5 C3,11.776 3.224,12 3.5,12 L12.5,12 C12.776,12 13,11.776 13,11.5 L13,4.5 C13,4.224 12.776,4 12.5,4 L3.5,4 C3.224,4 3,4.224 3,4.5 L3,11.5 Z M14,11 L14,13 L12,13 C11.724,13 11.5,13.224 11.5,13.5 C11.5,13.776 11.724,14 12,14 L14.5,14 C14.776,14 15,13.776 15,13.5 L15,11 C15,10.724 14.776,10.5 14.5,10.5 C14.224,10.5 14,10.724 14,11 Z M12,2 C11.724,2 11.5,2.224 11.5,2.5 C11.5,2.776 11.724,3 12,3 L14,3 L14,5 C14,5.276 14.224,5.5 14.5,5.5 C14.776,5.5 15,5.276 15,5 L15,2.5 C15,2.224 14.776,2 14.5,2 L12,2 Z M2,13 L2,11 C2,10.724 1.776,10.5 1.5,10.5 C1.224,10.5 1,10.724 1,11 L1,13.5 C1,13.776 1.224,14 1.5,14 L4,14 C4.276,14 4.5,13.776 4.5,13.5 C4.5,13.224 4.276,13 4,13 L2,13 Z M1,2.5 C1,2.224 1.224,2 1.5,2 L4,2 C4.276,2 4.5,2.224 4.5,2.5 C4.5,2.776 4.276,3 4,3 L2,3 L2,5 C2,5.276 1.776,5.5 1.5,5.5 C1.224,5.5 1,5.276 1,5 L1,2.5 Z ' id='fill_1' fill='%23006fff'%3E%3C/path%3E%3C/g%3E%3C/svg%3E");
+ background-repeat: no-repeat;
+ border-color: transparent;
+ float: left;
+ color: #006fff;
+ padding-left: 50%;
+ padding: 0px 0px 0px 20px;
+ cursor:pointer;
+ background-position: left bottom;
+ margin-left: 2px;
+ }
+{{/html5.show_fullscreen_button}}
+{{#html5.show_made_with_defold}}
+ .link {
+ text-align: right;
+ color: #4e5258;
+ margin-right: 2px;
+ }
+ a {
+ font-weight: 600;
+ color: #006fff;
+ text-decoration: none;
+ }
+{{/html5.show_made_with_defold}}
+ .link, .button {
+ font-family: sans-serif;
+ font-size: 14px;
+ font-weight: normal;
+ font-style: normal;
+ font-stretch: normal;
+ line-height: normal;
+ letter-spacing: 0px;
+ padding-top: 12px;
+ }
+
+ .buttons-background {
+ background-color: #ffffff;
+ width: 100%;
+ height: 42px;
+ }
+
+ body {
+ background-color: #ffffff;
+ }
+
+ .canvas-app-container {
+ background: rgba(250,252,255,1);
+ background: -moz-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%);
+ background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(250,252,255,1)), color-stop(50%, rgba(250,252,255,1)), color-stop(50%, rgba(245,249,255,1)), color-stop(100%, rgba(245,249,255,1)));
+ background: -webkit-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%);
+ background: -o-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%);
+ background: -ms-linear-gradient(-45deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%);
+ background: linear-gradient(135deg, rgba(250,252,255,1) 0%, rgba(250,252,255,1) 50%, rgba(245,249,255,1) 50%, rgba(245,249,255,1) 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fafcff', endColorstr='#f5f9ff', GradientType=1 );
+ }
+
+ .canvas-app-canvas {
+ background-repeat:no-repeat;
+ background-position: center center;
+ background-size: contain;
+{{#DEFOLD_SPLASH_IMAGE}}
+ background-image: url("{{DEFOLD_SPLASH_IMAGE}}");
+{{/DEFOLD_SPLASH_IMAGE}}
+{{^DEFOLD_SPLASH_IMAGE}}
+ background-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='300px' height='64px' viewBox='-2467.5 2469 300 64' style='enable-background:new -2467.5 2469 300 64;' xml:space='preserve'%3E%3Cstyle type='text/css'%3E .st0%7Bfill:%2315244A;%7D .st1%7Bfill:url(%23SVGID_1_);%7D .st2%7Bfill:url(%23SVGID_2_);%7D%0A%3C/style%3E%3Ctitle%3Edefold-logo-html5-splash%3C/title%3E%3Cpolygon class='st0' points='-2177,2482.9 -2175.5,2482.9 -2175.5,2486.7 -2174.4,2486.7 -2174.4,2482.9 -2173.2,2482.9 -2173.2,2481.9 -2177,2481.9 '/%3E%3Cpolygon class='st0' points='-2169.8,2484.1 -2171,2482.1 -2172.1,2482.1 -2172.1,2486.7 -2171,2486.7 -2171,2483.5 -2169.7,2485.6 -2169.7,2485.6 -2168.5,2483.5 -2168.5,2486.7 -2167.5,2486.7 -2167.5,2482.1 -2168.6,2482.1 '/%3E%3Cpath class='st0' d='M-2376,2482h-13.8v38h13.6c6.6,0,12.2-1.9,16.1-5.5c3.8-3.5,5.8-8.5,5.7-13.7v-0.1 C-2354.5,2489.3-2362.9,2482-2376,2482z M-2364,2501.2c0,6.7-4.5,10.9-11.8,10.9h-4.7v-22h4.7c7.3,0,11.8,4.2,11.8,10.9 L-2364,2501.2z'/%3E%3Cpolygon class='st0' points='-2340.9,2505 -2325.1,2505 -2325.1,2497.4 -2340.9,2497.4 -2340.9,2489.6 -2322.4,2489.6 -2322.4,2481.9 -2350.1,2481.9 -2350.1,2520 -2322.2,2520 -2322.2,2512.4 -2340.9,2512.4 '/%3E%3Cpolygon class='st0' points='-2317.1,2481.9 -2317.1,2520 -2307.9,2520 -2307.9,2505.9 -2293,2505.9 -2293,2498.4 -2307.9,2498.4 -2307.9,2489.9 -2289.6,2489.9 -2289.6,2481.9 '/%3E%3Cpolygon class='st0' points='-2233,2482.1 -2242.2,2482.1 -2242.2,2520 -2216.3,2520 -2216.3,2512.2 -2233,2512.2 '/%3E%3Cpath class='st0' d='M-2197.1,2482h-13.7v38h13.5c6.7,0,12.2-1.9,16.1-5.5c3.8-3.5,5.8-8.5,5.7-13.7v-0.1 C-2175.5,2489.3-2184,2482-2197.1,2482z M-2185.1,2501.2c0,6.7-4.5,10.9-11.8,10.9h-4.7v-22h4.7c7.3,0,11.8,4.2,11.8,10.9V2501.2z' /%3E%3Cpath class='st0' d='M-2267.5,2481.7c-10.8,0-19.6,8.8-19.6,19.7c0,10.8,8.8,19.6,19.7,19.6c10.8,0,19.6-8.8,19.6-19.6l0,0 C-2247.8,2490.5-2256.6,2481.7-2267.5,2481.7C-2267.5,2481.7-2267.5,2481.7-2267.5,2481.7z M-2258,2507.9l-8.8,5.1 c-0.5,0.3-1.2,0.3-1.8,0l-8.8-5.1c-0.5-0.3-0.9-0.9-0.9-1.5v-10.2c0-0.6,0.3-1.2,0.9-1.5l8.8-5.1c0.5-0.3,1.2-0.3,1.8,0l8.8,5.1 c0.5,0.3,0.9,0.9,0.9,1.5v10.2C-2257.1,2507-2257.4,2507.6-2258,2507.9z'/%3E%3Cpath class='st0' d='M-2423.2,2494.6l-11.1,6.4l-11.1-6.4l11.1-6.4L-2423.2,2494.6z M-2412.1,2501v12.8l11.1-6.4L-2412.1,2501z M-2467.5,2507.4l11.1,6.4V2501L-2467.5,2507.4z M-2434.3,2526.6l11.1,6.4l11.1-6.4l-11.1-6.4l11.1-6.4l-11.1-6.4l-11.1,6.4 l-11.1-6.4l-11.1,6.4l11.1,6.4l-11.1,6.4l11.1,6.4L-2434.3,2526.6z'/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='-2451.2178' y1='2525.4604' x2='-2406.2178' y2='2499.6304' gradientTransform='matrix(1 0 0 -1 0 5004)'%3E%3Cstop offset='0' style='stop-color:%231C68EC'/%3E%3Cstop offset='1' style='stop-color:%2300E9DF'/%3E%3C/linearGradient%3E%3Cpath class='st1' d='M-2412.1,2513.8v12.8l-11.1-6.4L-2412.1,2513.8z M-2434.3,2513.8V2501l-11.1-6.4v12.8L-2434.3,2513.8z M-2445.4,2469v12.8l11.1-6.4L-2445.4,2469z M-2412.1,2488.2L-2412.1,2488.2 M-2423.2,2507.4l11.1,6.4V2501l11.1,6.4v-12.8 l-11.1-6.4v-12.8l0,0l-11.1-6.4v12.8l-11.1-6.4v12.8l11.1,6.4V2507.4z'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='-2465.9385' y1='2521.2493' x2='-2423.5085' y2='2496.7893' gradientTransform='matrix(1 0 0 -1 0 5004)'%3E%3Cstop offset='0' style='stop-color:%23FF3C2A'/%3E%3Cstop offset='1' style='stop-color:%23FFD215'/%3E%3C/linearGradient%3E%3Cpath class='st2' d='M-2434.3,2513.8V2501l11.1-6.4v12.8L-2434.3,2513.8z M-2434.3,2475.4l11.1,6.4V2469L-2434.3,2475.4z M-2456.5,2488.2L-2456.5,2488.2 M-2445.4,2494.6l11.1-6.4v-12.8l-11.1,6.4V2469l-11.1,6.4l0,0v12.8l-11.1,6.4v12.8l11.1-6.4v12.8 l11.1-6.4V2494.6z M-2456.5,2513.8v12.8l11.1-6.4L-2456.5,2513.8z'/%3E%3C/svg%3E%0A");
+{{/DEFOLD_SPLASH_IMAGE}}
+ }
diff --git a/game.project b/game.project
index 66a1aaa6..d5aaf3aa 100644
--- a/game.project
+++ b/game.project
@@ -12,7 +12,7 @@ dynamic_orientation = 1
[project]
title = druid
-version = 0.9.0
+version = 0.10.0
publisher = Insality
developer = Insality
dependencies#0 = https://github.com/insalitygames/deftest/archive/master.zip
@@ -27,7 +27,7 @@ use_accelerometer = 0
[druid]
no_auto_input = 0
-stencil_check = 0
+no_stencil_check = 0
no_auto_template = 0
input_text = text
input_touch = touch
@@ -47,6 +47,7 @@ splash_image = /media/druid_logo.png
scale_mode = fit
show_fullscreen_button = 0
show_made_with_defold = 0
+cssfile = /example/light_theme.css
[native_extension]
app_manifest = /example/game.appmanifest
diff --git a/input/game.input_binding b/input/game.input_binding
index 0b6d8ca3..a6d0b3a3 100644
--- a/input/game.input_binding
+++ b/input/game.input_binding
@@ -18,6 +18,18 @@ key_trigger {
input: KEY_ESC
action: "key_esc"
}
+key_trigger {
+ input: KEY_LSUPER
+ action: "key_lsuper"
+}
+key_trigger {
+ input: KEY_LCTRL
+ action: "key_lctrl"
+}
+key_trigger {
+ input: KEY_G
+ action: "key_g"
+}
mouse_trigger {
input: MOUSE_WHEEL_UP
action: "scroll_up"
diff --git a/media/druid_logo.png b/media/druid_logo.png
index 84d44b9e..6b5174b5 100644
Binary files a/media/druid_logo.png and b/media/druid_logo.png differ
diff --git a/media/druid_thumb_logo.png b/media/druid_thumb_logo.png
index a9382315..21e7cd3a 100644
Binary files a/media/druid_thumb_logo.png and b/media/druid_thumb_logo.png differ
diff --git a/druid/styles/default/templates/druid_button_blue.gui b/templates/druid_button_blue.gui
similarity index 100%
rename from druid/styles/default/templates/druid_button_blue.gui
rename to templates/druid_button_blue.gui
diff --git a/druid/styles/default/templates/druid_button_green.gui b/templates/druid_button_green.gui
similarity index 100%
rename from druid/styles/default/templates/druid_button_green.gui
rename to templates/druid_button_green.gui
diff --git a/druid/styles/default/templates/druid_button_red.gui b/templates/druid_button_red.gui
similarity index 100%
rename from druid/styles/default/templates/druid_button_red.gui
rename to templates/druid_button_red.gui
diff --git a/druid/styles/default/templates/druid_button_yellow.gui b/templates/druid_button_yellow.gui
similarity index 100%
rename from druid/styles/default/templates/druid_button_yellow.gui
rename to templates/druid_button_yellow.gui
diff --git a/druid/styles/default/templates/druid_checkbox.gui b/templates/druid_checkbox.gui
similarity index 100%
rename from druid/styles/default/templates/druid_checkbox.gui
rename to templates/druid_checkbox.gui
diff --git a/druid/styles/default/templates/druid_input.gui b/templates/druid_input.gui
similarity index 100%
rename from druid/styles/default/templates/druid_input.gui
rename to templates/druid_input.gui
diff --git a/druid/styles/default/templates/druid_slider.gui b/templates/druid_slider.gui
similarity index 100%
rename from druid/styles/default/templates/druid_slider.gui
rename to templates/druid_slider.gui