239 Commits
0.9.0 ... 1.0

Author SHA1 Message Date
Maksim Tuprikov
d2b617a14f Merge pull request #283 from Insality/develop
Release 1.0
2024-10-19 11:56:13 +03:00
Insality
2e6168d518 Update characters in default font 2024-10-19 11:29:42 +03:00
Insality
be1f470dbe Update annotations 2024-10-19 11:25:30 +03:00
Insality
86189d6e3e Update docs, annotations 2024-10-19 11:22:24 +03:00
Insality
13fb109ef0 Use gifs instead of mp4 2024-10-19 11:11:21 +03:00
Insality
45c81aa9a0 Add new preview videos 2024-10-19 11:01:07 +03:00
Insality
ebd7f94354 Add new examples 2024-10-19 10:59:13 +03:00
Insality
8d409b8062 Update docs 2024-10-19 10:58:51 +03:00
Insality
0a5bb248d7 Remove checkbox, checkbox group, radio group and old default templates 2024-10-19 10:58:46 +03:00
Insality
d73835a2d5 Update Druid components 2024-10-19 10:58:24 +03:00
Insality
ad339508cf Update example app 2024-10-19 10:57:55 +03:00
Insality
c787ed860e Update example build 2024-10-17 02:13:32 +03:00
Insality
2ea635fc56 Update example build 2024-10-17 02:09:19 +03:00
Maksim Tuprikov
4d29363678 Merge pull request #282 from Insality/example_rework
Example rework
2024-10-17 02:03:35 +03:00
Insality
dd41aab962 Update docs and example page 2024-10-17 02:02:07 +03:00
Insality
3579370287 Update 2024-10-17 01:48:30 +03:00
Insality
91879509a0 Update example with new brand one 2024-10-17 01:24:15 +03:00
Insality
2c762716bb Remove current Druid example 2024-10-17 01:10:21 +03:00
Maksim Tuprikov
032eb4aac5 Merge pull request #275 from Insality/update
Prepare for release 12
2024-10-17 01:07:21 +03:00
Insality
40bda1b0eb Fix deleted knob 2024-10-16 21:30:32 +03:00
Insality
3ccfe2c306 Remove pin knob component 2024-10-16 21:15:16 +03:00
Insality
c0c1870ac5 Solve #239 Remove button style 2024-10-16 20:58:55 +03:00
Insality
aa6310db91 Update 2024-10-16 20:30:55 +03:00
Insality
6e4490a3a7 Fix test.ini 2024-10-15 21:38:40 +03:00
Insality
e8dbc097d0 Update 2024-10-15 21:35:51 +03:00
Insality
ea80c874f6 Update annotations 2024-10-15 19:43:36 +03:00
Insality
5848921cba Update docs, config generations, fix linter 2024-10-15 19:34:07 +03:00
Insality
2f5336fa4f Remove annotations 2024-10-15 02:49:56 +03:00
Insality
a5e579ddaa Update button hold callback 2024-10-15 02:48:41 +03:00
Insality
067b650838 Get rid of middleclass 2024-10-15 01:59:25 +03:00
Insality
54345b924b Update timer & text 2024-10-15 01:30:28 +03:00
Insality
a0113d3356 Update druid component template 2024-10-15 00:56:19 +03:00
Insality
87f52551e2 Update rich text 2024-10-15 00:56:06 +03:00
Insality
66f4a1c8d5 WIP 2024-10-14 23:03:45 +03:00
Insality
a4fa0f0348 WIP 2024-10-14 22:24:57 +03:00
Insality
5d5fe7f374 Rich text based only on text node 2024-10-14 22:13:57 +03:00
Insality
59d3b116ac Add figma layout for druid 1.6.3 2024-10-14 11:33:05 +03:00
Insality
d11aeb6b18 Update 2024-10-14 11:32:53 +03:00
Insality
3c9f539376 Update annotations 2024-10-05 02:27:30 +03:00
Insality
4a8bb214d2 Update 2024-10-05 02:07:53 +03:00
Insality
d39f4715f3 Update annotations, fix rare errors 2024-10-05 01:40:46 +03:00
Insality
b9b74736a7 Merge remote-tracking branch 'origin/update' into update 2024-09-12 21:03:42 +03:00
Insality
ab90927d32 Update Druid logos 2024-09-12 21:03:31 +03:00
Insality
b2a88146e5 Update input and rich input 2024-09-12 20:59:50 +03:00
Insality
d533e5ee2d Fix scroll events while animating
Fix slider issue with negative distance
Add bunch of new functions to grid
More accurate progress bar scaling with 9-slice images
2024-09-10 21:46:29 +03:00
Insality
986a4695f6 Update Rich Input with selection/arrows control. Add template and nodes to self:get_druid 2024-09-07 17:15:40 +03:00
Insality
f93d0c7d40 Add hover on_mouse_hover callback in constructor
Add ON_HOVER_CURSOR and ON_MOUSE_HOVER_CURSOR in hover component in styles
2024-09-04 01:58:20 +03:00
Insality
4a095a2a24 Update README
Button key trigger will not consume input
Update scroll position while animate
Add scroll:set_view_size
Better static grid get_index function
Rework Data List (only static grid)
Update Default style
Remove a component from parent if exists on druid:remove
2024-09-03 21:48:43 +03:00
Insality
0aeb0b3fea Update event to remove middleclass, using defold-event as a base 2024-08-29 09:51:09 +03:00
Insality
ba1ab07e0d Update new component template, replace component name with M as module name 2024-08-29 09:28:54 +03:00
Insality
7e16dacbc2 Update helper to use gui.get to reduce memory footprint 2024-08-29 09:27:34 +03:00
Insality
cece44f2d1 Fix #264 Use pip or pip3 instead only pip3 2024-08-27 18:13:15 +03:00
Insality
678f542bdb Fix #273 Update appmanifest 2024-08-27 17:55:36 +03:00
Maksim Tuprikov
341d1721d1 Merge pull request #274 from mozok/develop
Fixes for annotations
2024-08-27 17:52:48 +03:00
Maksim Tuprikov
5e2a3bdb4b Merge branch 'update' into develop 2024-08-27 17:52:36 +03:00
Insality
45718325a1 Update luacheck 2024-08-27 17:48:46 +03:00
Insality
11ae63a9f6 Update annotations 2024-08-27 17:45:09 +03:00
Insality
5f2ae1eb0d Add Defold annotations 2024-08-27 17:18:55 +03:00
Insality
7f90ae99e6 Update docs 2024-08-27 17:16:33 +03:00
Maksim Tuprikov
731e5f6627 Merge pull request #271 from JustAPotota/patch-1
Fix password input events returning masked text
2024-08-27 17:12:58 +03:00
Insality
217b90163a Merge branch 'master' into develop 2024-08-27 17:08:25 +03:00
Mozok Evgen
15a2450437 Fix LangText annotations 2024-08-24 21:35:48 +03:00
Mozok Evgen
f54347ef6c Fix Slider annotations 2024-08-24 21:27:59 +03:00
Mozok Evgen
2cef65ed40 Fix scroll annotations 2024-08-24 21:22:34 +03:00
Mozok Evgen
32aa760386 Fix "any" type annotation to lowercase 2024-08-24 21:15:55 +03:00
Mozok Evgen
c4a4221841 Fix Grid methods annotations 2024-08-24 21:12:26 +03:00
Mozok Evgen
8a3cff17ab Fix "node" type annotation to lowercase 2024-08-24 20:59:55 +03:00
Mozok Evgen
63c2e8ea93 Fix new_ annotations 2024-08-24 20:53:28 +03:00
Maksim Tuprikov
d7e1174162 Merge pull request #272 from boruok/fix-style-links
fix style docs
2024-07-16 10:28:46 +03:00
boruok
93cbb99cdf fix style docs 2024-07-16 12:10:57 +09:00
JustAPotota
80f60c6e74 Fix password input events returning masked text 2024-07-06 21:42:03 -05:00
Maksim Tuprikov
152ff189ff Merge pull request #269 from boruok/fix-codelinks
Fix wrong code links
2024-07-01 10:01:52 +03:00
boruok
04b7323be2 fixed wrong codelinks 2024-07-01 10:57:36 +09:00
Maksim Tuprikov
1b42824912 Merge pull request #267 from astrochili/annotations-fix-3
Fix sender type for `druid_instance.on_message()`
2024-06-13 10:16:05 +01:00
Roman Silin
3bf50660b3 Fixed sender type for druid_instance.on_message() 2024-06-13 12:15:05 +03:00
Maksim Tuprikov
e2108a5f1e Merge pull request #263 from ivolff/master
fix for DynamicGrid.get_all_pos
2024-04-23 17:49:03 +03:00
ivolff
8741e6cb74 get_all_pos fix 2024-04-23 18:25:03 +04:00
Maksim Tuprikov
0e9445b1a8 Merge pull request #260 from Fossean1/patch-2 2024-03-25 09:32:31 +02:00
Fossean1
9c37582f2b Fix init function in 03-styles.md 2024-03-25 10:59:15 +05:00
Insality
07101355c8 Merge remote-tracking branch 'origin/develop' into develop 2024-03-21 17:47:46 +02:00
Insality
13919fdb04 Update README 2024-03-21 17:47:33 +02:00
Maksim Tuprikov
2dcbb6ad92 Merge pull request #259 from marnason/master
Fixed lang_text URL in example.gui_script
2024-02-28 20:54:28 +02:00
marnason
f47631cae9 Fixed lang_text URL in example.gui_script 2024-02-27 12:13:05 +00:00
Maksim Tuprikov
9b69b65add Merge pull request #252 from astrochili/drag_screen_x_y
Added the screen position to the Drag component
2023-12-12 19:40:17 +02:00
Roman Silin
aa7e62e3f1 Added screen_x and screen_y to the Drag component 2023-12-12 18:43:18 +02:00
Insality
bdd9efb892 Update annotations 2023-12-05 14:55:58 +02:00
Insality
01d1445511 Update annotations, add set_repeat to hotkey component 2023-12-05 14:49:56 +02:00
Insality
97ff6154eb Update wrong links in documentation 2023-12-05 14:28:04 +02:00
Insality
2c083f6a71 Update wrong links in documentation 2023-12-05 14:27:53 +02:00
Maksim Tuprikov
5d4039da4f Merge pull request #247 from Insality/update_annotations
Update Druid annotations
2023-10-20 11:26:19 +03:00
Insality
85e6d41f56 Update HTML5 example 2023-10-20 11:25:06 +03:00
Insality
9132dc477b Update java version for CI 2023-10-20 11:21:30 +03:00
Insality
00a7852225 Update example to 1.6.0 Defold version 2023-10-20 11:19:15 +03:00
Insality
d1d20d73ff Fix wrong link to lang_text example 2023-10-20 11:14:58 +03:00
Insality
88154b2269 Fix scrolls.gui stencil nodes 2023-10-20 11:03:30 +03:00
Insality
4a16a8bc07 Annotations update [5] 2023-10-18 10:40:08 +03:00
Insality
24bb39481d Annotations update [4] 2023-10-17 23:18:25 +03:00
Insality
c99b97f392 Annotations update [3] 2023-10-17 22:32:22 +03:00
Insality
50c9b6bad5 Annotations update [2] 2023-10-17 22:00:43 +03:00
Insality
86b92f90a7 Annotations update 2023-10-17 21:09:45 +03:00
Insality
7fc76ed8c0 Fix #245 Lang Text on_change trigger on language change 2023-09-06 14:48:46 +02:00
Insality
5ed9bdd814 Return width from helper.centrate_nodes 2023-09-02 21:25:58 +03:00
Insality
ca8c4e2425 Rich Text add on layout change 2023-08-27 13:40:49 +03:00
Insality
73ed0c8cd0 Fix #242 Text component metrics zero width issue 2023-08-25 11:07:33 +03:00
Insality
2d8d3cffbb Late scripts require in tests 2023-08-06 14:17:12 +03:00
Insality
3219b280e7 Test with late require 2023-08-06 14:12:57 +03:00
Insality
65fe2521f4 Another way to require druid in test scripts 2023-08-06 14:07:45 +03:00
Insality
b7e16e4321 Test init luacover earlier 2023-08-06 14:02:31 +03:00
Insality
d1195a47a2 Add require test file directly in deftest.add 2023-08-06 10:59:50 +03:00
Insality
300fbf1309 Update docs 2023-08-05 20:10:32 +03:00
Insality
69b3383dc4 Remove all docs 2023-08-05 20:10:11 +03:00
Maksim Tuprikov
03ffd943df Merge pull request #233 from Insality/develop
Merge Druid 0.11 to Master
2023-08-05 19:44:01 +03:00
Insality
646cf5a4b4 Update example 2023-08-05 19:43:09 +03:00
Insality
d7dd4a86b8 Update docs 2023-08-05 19:32:47 +03:00
Insality
37fff52aa5 Fix HTML5 button 2023-08-05 19:27:51 +03:00
Insality
628723386e Update Rich text style params 2023-08-05 19:01:06 +03:00
Insality
5a0cf42e3d Update README, move emmylua section to Advanced Setup manual 2023-07-16 12:28:46 +03:00
Insality
556e1a9bae Small optimization && refactoring 2023-07-15 15:56:06 +03:00
Insality
337090e74c Update docs, little optimizations, inline style anims 2023-07-15 12:35:05 +03:00
Insality
38c117b9d8 Inline helper.is_enabled, remove unused code, documentation fixes, remove formats and druid_input files, add more tests 2023-07-15 11:53:07 +03:00
Insality
c01ee189b4 Prepare for release 0.11 2023-07-13 22:42:23 +03:00
Insality
ea18562270 Update docs 2023-07-13 22:00:52 +03:00
Insality
f910db985c Update README 2023-07-13 21:52:41 +03:00
Maksim Tuprikov
706b5d094a Merge pull request #232 from Insality/rich_text
Rich text
2023-07-13 21:40:51 +03:00
Insality
32d184ca81 Update Docs & Example 2023-07-13 21:39:02 +03:00
Maksim Tuprikov
1cbe573763 Merge pull request #231 from Insality/docs
Update documentation
2023-07-13 21:35:20 +03:00
Insality
5ecd67d8ef Update docs 2023-07-13 21:32:04 +03:00
Insality
23ac068f51 Update docs 2023-07-11 22:23:48 +03:00
Insality
6ed48772a3 Update docs 2023-07-11 21:46:56 +03:00
Insality
bdacd4a440 Update docs 2023-07-11 21:29:12 +03:00
Insality
894b62b888 Update docs 2023-07-09 22:56:44 +03:00
Insality
eca76b12d1 Update docs 2023-07-09 21:47:14 +03:00
Insality
15cf72df27 Update docs 2023-07-09 11:11:30 +03:00
Insality
4896f38e09 Update readme and docs 2023-07-08 09:59:35 +03:00
Maksim Tuprikov
862b61281d Merge pull request #230 from Insality/docs
Docs update
2023-07-05 23:20:58 +03:00
Insality
487851302b Update Bob version to 1.4.7 2023-07-05 23:20:17 +03:00
Insality
d0062c2a78 Update changelog 2023-07-05 23:14:27 +03:00
Insality
fb5508b083 Update docs 2023-06-10 19:18:12 +03:00
Insality
7bf479e6c0 Update Helper docs 2023-06-08 00:06:05 +03:00
Insality
65974e0b30 Update docs 2023-06-07 23:30:37 +03:00
Insality
b22808f585 Remove debug log messages, update docs 2023-06-07 01:41:47 +03:00
Insality
e14f68bc90 Move swipe to extended, update docs 2023-06-07 00:41:05 +03:00
Insality
99fc4ccc31 Start update docs 2023-06-06 23:01:46 +03:00
Insality
76ab3811fa Update rich text texts example 2023-05-31 23:51:57 +03:00
Insality
b628212c58 Update examples 2023-05-31 21:54:55 +03:00
Insality
a01eae3d89 Solve #156 Input field now show keyboard in html5 mobile 2023-05-03 01:13:16 +03:00
Insality
7b40af9a33 Solve #219 Add utf8 native library support 2023-05-03 01:05:31 +03:00
Insality
7aa2da11f6 Update docs, wrong links 2023-05-03 00:51:56 +03:00
Insality
807168d850 Solve #227 Update current URL to match with current example 2023-05-02 21:30:11 +03:00
Insality
c815b6b240 Update rich text examples 2023-05-02 21:08:37 +03:00
Insality
a1d138522e Update rich text example 2023-02-08 21:54:32 +02:00
Insality
5e92cf5ffc Rich Text example progress 2023-02-08 21:01:37 +02:00
Insality
547b10d097 Update rich text for last version 2023-02-07 19:37:05 +02:00
Insality
6ea5ed0b97 Merge branch 'develop' into rich_text 2023-02-07 19:09:38 +02:00
Maksim Tuprikov
2733c88655 Merge pull request #222 from Insality/tests
Initial tests for Druid GUI
2023-02-07 19:05:48 +02:00
Insality
96d1b8c068 Typo fix 2023-02-07 19:04:39 +02:00
Insality
cfaeff1516 Fix tests 2023-02-07 18:58:24 +02:00
Insality
bd9b4ad58f Merge branch 'develop' into tests 2023-02-07 18:45:35 +02:00
Insality
2196cc3e17 Add text_metrics args on change text scale text event 2022-12-03 17:53:57 +02:00
Insality
0368260d16 Schedule late_init if component have on_input 2022-12-03 17:43:08 +02:00
Insality
6d75d61fd5 Add lang text example 2022-12-03 16:59:04 +02:00
Insality
5accec45c3 Solve #216 Button also can be pressed via multitouch action_id (not still simultaneously but can capture the event) 2022-12-03 16:41:28 +02:00
Insality
a983d5e72a Solve #126 Update input bindings according to Defold defaults 2022-12-03 16:40:15 +02:00
Insality
8fb41ea8e9 Solve #214 Fix hover on_input return value. Add hover example. Add hover_instance to hover callback 2022-12-03 16:26:28 +02:00
Insality
d93823ae6a Solve #215 Better late init interest support 2022-12-03 16:16:55 +02:00
Insality
4f7dbf49d3 Progress #210 Add set_max_gui_upscale for layout component 2022-12-03 16:15:48 +02:00
Insality
dad54d8de3 Update #199 rename IS_CONSUME_INPUT_WHILE_SELECTED to NO_CONSUME_INPUT_WHILE_SELECTED. Change default value 2022-12-01 21:05:14 +02:00
Insality
7f5be3ffb0 Solve #217 Fix error font argument, remove deprecated gui.get_text_metrics 2022-12-01 21:02:31 +02:00
Insality
5d3625e2a8 Solve #199 Add input consume flag while input is selected. With false value it's allow to interact with other input components while input is selected (current input will be unselected if this case) 2022-11-12 12:50:19 +02:00
Insality
ec15ac053a Merge remote-tracking branch 'origin/develop' into develop 2022-11-09 20:21:42 +02:00
Insality
337a43ae08 Solve #213 remove late init for progress bar 2022-11-09 20:21:06 +02:00
Insality
fadd0c4c4b Fix progress late init 2022-11-09 17:40:45 +02:00
Insality
66abd3bd31 Update rich text with Druid component and content adjust into root size 2022-11-04 20:09:46 +02:00
Insality
fae7e4afa4 Initial commit with rich text 2022-11-04 20:09:13 +02:00
Maksim Tuprikov
5480f175bf Merge pull request #211 from dmi7ry/patch-1
Fixed wrong link to Text API
2022-11-03 08:53:27 +01:00
Maksim Tuprikov
c766dc7ba4 Merge pull request #212 from dmi7ry/patch-2
misprint in new_text() documentation (Tet → Text)
2022-11-03 08:53:13 +01:00
Dmitry
13f0922ccc misprint (Tet → Text) 2022-11-02 00:43:19 +07:00
Dmitry
dac1218809 Fixed wrong link to Text API 2022-11-02 00:18:59 +07:00
Insality
9b53314fa7 Fix drag node scene koefs 2022-10-20 21:44:04 +03:00
Insality
999789c1c8 Move FUNDING.yml file 2022-10-16 12:59:27 +03:00
Insality
253ea36817 Add FUNDING.yml 2022-10-16 12:58:38 +03:00
Insality
b5b07cb8d9 Update README 2022-10-16 12:51:13 +03:00
Insality
4de50591f8 Update drag/slider scene node koefs, add layout max gui upscale 2022-10-15 16:11:12 +03:00
Insality
9cd1769c37 Fix extended components in example 2022-10-09 17:20:40 +03:00
Insality
92d9e2e5e4 Remove unexists preview 2022-10-09 17:10:04 +03:00
Insality
4c130a68bb Move all extended component out of default bundle 2022-10-09 17:02:54 +03:00
Insality
561fdc7b38 Update README 2022-10-09 16:58:35 +03:00
Insality
674eefd70b Update README 2022-10-09 16:57:57 +03:00
Insality
441c6e3dc4 Update README 2022-10-09 16:55:32 +03:00
Insality
edde50ccb6 Update preview gifs 2022-10-09 16:53:55 +03:00
Insality
9d75af2eb9 Replace gui.get_text_metrics with resource.get_text_metrics 2022-10-09 16:40:23 +03:00
Insality
09ecc45921 Add preview for Druid components, change the README component section 2022-10-09 14:38:29 +03:00
Insality
9e92cf295b Add tests for drag component 2022-10-08 19:11:57 +03:00
Insality
51dc34613b Add tests for hover component 2022-10-08 16:11:45 +03:00
Insality
a87f775ac7 Merge branch 'master' into tests 2022-10-08 15:43:11 +03:00
Maksim Tuprikov
bbd41659f9 Merge pull request #208 from Insality/develop
Solve #207 fix scroll + data_list issue
2022-10-02 14:15:44 +03:00
Insality
2e9353afeb Solve #207 fix scroll + data_list issue 2022-10-02 14:15:17 +03:00
Insality
d92be1cfa7 Update button tests 2022-09-11 14:19:07 +03:00
Insality
79a711fa01 Add button basic tests 2022-09-11 13:10:05 +03:00
Insality
a6de0128bd Add initial Druid tests 2022-09-11 12:16:20 +03:00
Maksim Tuprikov
ad9ed801aa Merge pull request #205 from Insality/develop
Merge release 0.10.0 to develop
2022-09-09 21:02:13 +03:00
Insality
cb5df2b5bc Update docs, html example 2022-09-09 21:01:33 +03:00
Insality
072507cc9e Fix progress bar example 2022-09-09 20:46:26 +03:00
Insality
32e5fdb669 Update progress bar component, add progress bar example 2022-09-09 20:45:27 +03:00
Insality
ba383261b0 Update layout component, add layout fit example 2022-09-09 20:45:08 +03:00
Insality
25a17773e7 Solve #198 move input init and late init to Druid instance init function 2022-09-06 22:09:32 +03:00
Insality
e683eed90f Solve #202 set check stencil node enabled by default 2022-09-06 21:35:43 +03:00
Insality
2c92a792f7 Fix the HTML logo stretch 2022-08-29 22:18:20 +03:00
Insality
a3f109123e Update the changelog for 0.10.0 2022-08-29 21:58:29 +03:00
Insality
2f844a31c4 Update the Druid logo 2022-08-29 21:50:58 +03:00
Insality
9e2648e998 Merge branch 'master' into develop 2022-08-29 21:50:46 +03:00
Insality
8cd954e2dc Update HTML example 2022-08-29 21:47:59 +03:00
Insality
65f5d2db01 Solve #204 fix code url from direct example url open 2022-08-29 21:47:11 +03:00
Insality
13003e4721 Merge branch 'data_list_control' 2022-08-29 21:31:25 +03:00
Maksim Tuprikov
f471013e90 Merge pull request #203 from Insality/data_list_control
Solve #200 #201 Add DataList access functions, example with custom co…
2022-08-29 21:30:49 +03:00
Insality
55cc1c713e Update docs and HTML example project 2022-08-29 21:29:57 +03:00
Insality
b2643ebd26 Solve #200 #201 Add DataList access functions, example with custom component + DataList 2022-08-29 21:27:37 +03:00
Insality
0c47828d96 Add changelog for 0.10.0 2022-07-17 19:38:19 +03:00
Insality
2f964c6ed3 Update docs 2022-07-17 19:22:36 +03:00
Insality
847bee2e6b Update docs 2022-07-17 19:19:25 +03:00
Insality
77e56e8747 Add hotkey example 2022-07-17 19:07:35 +03:00
Insality
3e5a90920e Update drag screen koef value 2022-07-17 18:41:02 +03:00
Insality
46bcbb596d Fix drag is_enabled, add to example 2022-07-17 18:27:38 +03:00
Insality
d237eaec59 Merge branch 'layout' into develop 2022-07-17 18:23:22 +03:00
Insality
45b4843887 Layout component update 2022-07-17 18:23:07 +03:00
Insality
43f75cd820 Solve #195 Add set_enabled to Drag component 2022-07-17 18:08:03 +03:00
Insality
0107c015a1 Update layout component 2022-06-15 10:37:45 +05:00
Insality
e029d1eac3 Solve #133 Add hotkey component 2022-06-15 10:35:56 +05:00
Insality
53f305734c Solve #189 Add temporary set input priority 2022-06-15 10:34:47 +05:00
Insality
c9f862ac03 Solve #188 Add drag component total_x/total_y 2022-06-15 10:34:19 +05:00
Insality
415869e2bf Update layout component 2022-06-15 10:29:27 +05:00
Insality
4d47b6e656 Solve #186 fix set in row static grid zero offset 2022-04-18 15:52:50 +03:00
Insality
13fd4babb1 Solve #187 Temporary removed default gui templates 2022-04-16 10:16:29 +03:00
Insality
decb9fd9fd Solve #73 fix scroll drag on stretch/zoom nodes 2022-04-10 15:20:57 +03:00
Insality
f7e6888c5a Revert "Solve #182 add table pool for events"
This reverts commit dff522fbaa.
2022-04-05 23:18:39 +03:00
Insality
70e94ec14a Fix event table pool 2022-04-05 19:20:03 +03:00
Insality
dff522fbaa Solve #182 add table pool for events 2022-04-05 18:57:40 +03:00
Insality
2779f9cf7a Start implement druid layout component 2022-04-05 18:17:39 +03:00
Insality
c263c60de8 Fix changelog type 2022-03-12 12:18:33 +02:00
479 changed files with 56090 additions and 38727 deletions

1
.defignore Normal file
View File

@@ -0,0 +1 @@
/dist

5
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
# These are supported funding model platforms
github: insality
ko_fi: insality
buy_me_a_coffee: insality

View File

@@ -12,12 +12,12 @@ jobs:
lfs: true
- uses: actions/setup-java@v1
with:
java-version: '13'
java-version: '17'
- name: Build && Run
run: |
deployer_url="https://raw.githubusercontent.com/Insality/defold-deployer/1/deployer.sh"
curl -s ${deployer_url} | bash -s lbd --headless --settings ./unit_test.txt
curl -s ${deployer_url} | bash -s lbd --headless --settings ./test/test.ini
- name: Upload test report
run: bash <(curl -s https://codecov.io/bash)

4
.gitignore vendored
View File

@@ -10,4 +10,8 @@ Thumbs.db
builtins
dist
deployer_version_settings.txt
.deployer_cache
bob*.jar
manifest.private.der
manifest.public.der

View File

@@ -1,52 +0,0 @@
std = "max"
files['.luacheckrc'].global = false
unused_args = false
max_code_line_length = 90
max_comment_line_length = false
globals = {
"sys",
"go",
"gui",
"label",
"render",
"crash",
"sprite",
"sound",
"tilemap",
"spine",
"particlefx",
"physics",
"factory",
"collectionfactory",
"iac",
"msg",
"vmath",
"url",
"http",
"image",
"json",
"zlib",
"iap",
"push",
"facebook",
"hash",
"hash_to_hex",
"pprint",
"init",
"final",
"update",
"on_input",
"on_message",
"on_reload",
"socket",
"table",
"debug",
"timer",
"window",
"buffer",
"resource",
"defos",
"html5",
}

42
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,42 @@
{
"Lua.diagnostics.globals": [
"init",
"final",
"update",
"on_message",
"on_input",
"describe",
"before",
"after",
"it",
"utf8",
"defos",
"clipboard",
"editor"
],
"Lua.workspace.checkThirdParty": false,
"Lua.diagnostics.neededFileStatus": {
"undefined-field": "Any",
"assign-type-mismatch": "Any",
"missing-return": "Any",
"missing-fields": "Any",
"return-type-mismatch": "Any",
"lowercase-global": "Any"
},
"Lua.workspace.ignoreDir": [
".vscode",
"test/tests/*.lua",
"utils/annotations_manual.lua"
],
"Lua.runtime.pathStrict": true,
"Lua.diagnostics.libraryFiles": "Enable",
"Lua.runtime.version": "Lua 5.1",
"Lua.workspace.library": [
"~/Library/Application Support/Code/User/globalStorage/astronachos.defold",
"~/Library/Application Support/Code/User/workspaceStorage/72e25b7e0fdc873ee6f7baa61edbd6b1/astronachos.defold",
"~/Library/Application Support/Code/User/workspaceStorage/1446075a23c89451a63f0e82b2291def/astronachos.defold"
],
"files.exclude": {
"**/*.gui": true
}
}

336
README.md
View File

@@ -1,207 +1,163 @@
[![](media/druid_logo.png)](https://insality.github.io/druid/)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/insality/druid)](https://github.com/Insality/druid/releases)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/insality/druid/Run%20tests)](https://github.com/Insality/druid/actions)
[![codecov](https://codecov.io/gh/Insality/druid/branch/master/graph/badge.svg)](https://codecov.io/gh/Insality/druid)
[![GitHub release (latest by date)](https://img.shields.io/github/v/tag/insality/druid?style=for-the-badge&label=Release)](https://github.com/Insality/druid/tags)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/insality/druid/ci-workflow.yml?branch=master&style=for-the-badge)](https://github.com/Insality/druid/actions)
[![codecov](https://img.shields.io/codecov/c/github/Insality/druid?style=for-the-badge)](https://codecov.io/gh/Insality/druid)
**Druid** - powerful Defold component UI library. Use basic and extended **Druid** components or make your own game-specific components to make amazing GUI in your games.
[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality)
**Druid** - powerful **Defold** component UI framework that empowers developers to create stunning and customizable GUIs by leveraging a wide range of embedded components or effortlessly designing their own game-specific components.
## Druid Example
Check the [**HTML5 version**](https://insality.github.io/druid/druid/) of the **Druid** example app.
In this example you can inspect a variety of **Druid** components and see how they work. Each example page provides a direct link to the corresponding example code, making it easier for you to understand how to use **Druid**.
## Setup
### Dependency
You can use the **Druid** extension in your own project by adding this project as a [Defold library dependency](https://www.defold.com/manuals/libraries/). Open your game.project file and in the dependencies field under project add:
To integrate the **Druid** extension into your own project, add this project as a [dependency](https://www.defold.com/manuals/libraries/) in your **Defold** game. Open your `game.project` file and add the following line to the dependencies field under the project section:
> [https://github.com/Insality/druid/archive/master.zip](https://github.com/Insality/druid/archive/master.zip)
**Druid v1.0**
Or point to the ZIP file of a [specific release](https://github.com/Insality/druid/releases).
> [https://github.com/Insality/druid/archive/refs/tags/1.0.zip](https://github.com/Insality/druid/archive/refs/tags/1.0.zip)
### Input bindings
**Druid** requires the following input bindings:
- Mouse trigger - `Button 1` -> `touch` _For basic input components_
- Mouse trigger - `Wheel up` -> `scroll_up` _For scroll component_
- Mouse trigger - `Wheel down` -> `scroll_down` _For scroll component_
- Key trigger - `Backspace` -> `key_backspace` _For back_handler component, input component_
- Key trigger - `Back` -> `key_back` _For back_handler component, Android back button, input component_
- Key trigger - `Enter` -> `key_enter` _For input component, optional_
- Key trigger - `Esc` -> `key_esc` _For input component, optional_
- Touch triggers - `Touch multi` -> `multitouch` _For scroll component_
![](media/input_binding_2.png)
![](media/input_binding_1.png)
Here is a list of [all releases](https://github.com/Insality/druid/releases).
### Change key bindings [optional]
If you have to use your own key bindings (and key name), you can change it in your *game.project* file.
### Library Size
Here is current default values for key bindings:
```
[druid]
input_text = text
input_touch = touch
input_marked_text = marked_text
input_key_esc = key_esc
input_key_back = key_back
input_key_enter = key_enter
input_key_backspace = key_backspace
input_multitouch = multitouch
input_scroll_up = scroll_up
input_scroll_down = scroll_down
```
> **Note:** The library size is calculated based on the build report per platform. The extended components are exlcuded, which are including only on demand.
| Platform | Library Size |
| ---------------- | ------------- |
| HTML5 | **38.00 KB** |
| Desktop / Mobile | **65.74 KB** |
### Input capturing [optional]
### Input Bindings
By default, **Druid** will auto-capture input focus, if any input component will be created. So you don't need to call `msg.post(".", "acquire_input_focus")`
If you don't need this behaviour, you can disable it by setting `druid.no_auto_input` field in _game.project_:
```
[druid]
no_auto_input = 1
```
**Druid** utilizes the `/builtins/input/all.input_binding` input bindings. Either use this file for your project by setting the `Runtime -> Input -> Game Binding` field in the `game.project` input section to `/builtins/input/all.input_binding`, or add the specific bindings you need to your game's input binding file. For custom input bindings, refer to the Input Binding section in the [Advanced Setup](https://github.com/Insality/druid/blob/master/docs_md/advanced-setup.md#input-bindings).
### Template name check [optional]
## Usage
By default, **Druid** will auto check the parent component template name to build the full template name for component.
### Basic usage
If for some reason you want to pass the full template name by yourself, you can disable it by setting `druid.no_auto_template` field in _game.project_:
To utilize **Druid**, begin by creating a **Druid** instance to instantiate components and include the main functions of **Druid**: *update*, *final*, *on_message*, and *on_input*.
```
[druid]
no_auto_template = 1
```
When using **Druid** components, provide a node name string as an argument. If you don't have the node name available in some cases, you can pass `gui.get_node()` instead.
### 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
```
[druid]
stencil_check = 1
```
### Code [optional]
Adjust **Druid** settings, if needed:
```lua
local druid = require("druid.druid")
-- Used for button component and custom components
-- Callback should play sound by name
druid.set_sound_function(callback)
-- Used for lang_text component
-- Callback should return localized string by locale id
druid.set_text_function(callback)
-- Used for change default druid style
druid.set_default_style(your_style)
-- Call this function on language changing in the game,
-- to retranslate all lang_text components:
druid.on_language_change()
-- Call this function inside window.set_listener
-- to catch game focus lost/gained callbacks:
druid.on_window_callback(event)
```
## Components
**Druid** provides the following *basic* components:
- **[Button](docs_md/01-components.md#button)** - Basic Druid button input component. Handles all types of interactions (tap, long-tap, hold-tap, double-tap, simple key triggers, etc)
- **[Text](docs_md/01-components.md#text)** - Basic Druid text component. Wrap on gui text node, handle text size adjusting.
- **[Scroll](docs_md/01-components.md#scroll)** - Basic Druid scroll component
- **[Blocker](docs_md/01-components.md#blocker)** - Block input in node zone component
- **[Back Handler](docs_md/01-components.md#back-handler)** - Handle back button (Android back button, backspace key)
- **[Static Grid](docs_md/01-components.md#static-grid)** - Component to manage node positions with equal sizes
- **[Hover](docs_md/01-components.md#hover)** - System Druid component, handle hover node state
- **[Swipe](docs_md/01-components.md#swipe)** - System Druid component, handle swipe gestures on node
- **[Drag](docs_md/01-components.md#drag)** - System Druid component, handle drag input on node
**Druid** also provides the following *extended* components:
***Note**: In the future, to use extended components, you should register them first. This is required to make **Druid** modular - to exclude unused components from builds*
- **[Checkbox](docs_md/01-components.md#checkbox)** - Checkbox component
- **[Checkbox group](docs_md/01-components.md#checkbox-group)** - Several checkboxes in one group
- **[Dynamic Grid](docs_md/01-components.md#dynamic-grid)** - Component to manage node positions with different sizes. Only in one row or column
- **[Data List](docs_md/01-components.md#data-list)** - Component to manage data for huge dataset in scroll
- **[Input](docs_md/01-components.md#input)** - User text input component
- **[Lang text](docs_md/01-components.md#lang-text)** - Wrap on Text component to handle localization
- **[Progress](docs_md/01-components.md#progress)** - Progress bar component
- **[Radio group](docs_md/01-components.md#radio-group)** - Several checkboxes in one group with a single choice
- **[Slider](docs_md/01-components.md#slider)** - Slider component
- **[Timer](docs_md/01-components.md#timer)** - Handle timer work on gui text node
For a complete overview, see: _[components.md](docs_md/01-components.md)_.
## Basic usage
To use **Druid**, first you should create a Druid instance to spawn components and add Druids main engine functions: *update*, *final*, *on_message* and *on_input*.
All **Druid** components take node name string as arguments, don't do `gui.get_node()` before.
All **Druid** and component methods are called with `:` like `self.druid:new_button()`.
All **Druid** and component methods are invoked using the `:` operator, such as `self.druid:new_button()`.
```lua
local druid = require("druid.druid")
local function button_callback(self)
print("Button was clicked!")
-- All component callbacks pass "self" as first argument
-- This "self" is a context data passed in `druid.new(context)`
local function on_button_callback(self)
print("The button clicked!")
end
function init(self)
self.druid = druid.new(self)
self.druid:new_button("button_node_name", button_callback)
self.button = self.druid:new_button("button_node_name", on_button_callback)
end
-- "final" is a required function for the correct Druid workflow
function final(self)
self.druid:final()
end
-- "update" is used in progress bar, scroll, and timer basic components
function update(self, dt)
self.druid:update(dt)
end
-- "on_message" is used for specific Druid events, like language change or layout change
function on_message(self, message_id, message, sender)
self.druid:on_message(message_id, message, sender)
end
-- "on_input" is used in almost all Druid components
-- The return value from `druid:on_input` is required!
function on_input(self, action_id, action)
return self.druid:on_input(action_id, action)
end
```
For all **Druid** instance functions, [see here](https://insality.github.io/druid/modules/druid_instance.html).
For all **Druid** instance functions, [see here](https://insality.github.io/druid/modules/DruidInstance.html).
### API Documentation
**Druid** offers a wide range of components and functions. To facilitate usage, **Druid** provides comprehensive API documentation with examples and annotations.
Start reading the API documentation [here](https://insality.github.io/druid/modules/Druid.html).
**Druid** provide the *EmmyLua* annotations to add autocomplete inside your IDE. Check [EmmyLua Setup here](docs_md/advanced-setup.md#emmylua-annotations).
### Create custom components
If you want to create your own components, refer to the [Create Custom Components](docs_md/02-creating_custom_components.md) section in the documentation.
Custom components are one of the most powerful features of **Druid**. They allow you to create your own components effortlessly and utilize them in your game.
## Druid Components
Here is full **Druid** components list.
### Basic Components
> Basic components always included in the build and available for use.
| Name | Description | Example | <div style="width:200px">Preview</div> |
|------|-------------|---------|---------|
| **[Button](https://insality.github.io/druid/modules/Button.html)** | Logic over GUI Node. Handle the user click interactions: click, long click, double click, etc. | [Button Example](https://insality.github.io/druid/druid/?example=general_buttons) | <img src="media/preview/button.gif" width="200" height="100"> |
| **[Text](https://insality.github.io/druid/modules/Text.html)** | Logic over GUI Text. By default Text component fit the text inside text node size area with different adjust modes. | [Text Example](https://insality.github.io/druid/druid/?example=texts_general) | <img src="media/preview/text.gif" width="200" height="100"> |
| **[Scroll](https://insality.github.io/druid/modules/Scroll.html)** | Logic over two GUI Nodes: input and content. Provides basic behaviour for scrollable content. | [Scroll Example](https://insality.github.io/druid/druid/?example=general_scroll) | <img src="media/preview/scroll.gif" width="200" height="100"> |
| **[Blocker](https://insality.github.io/druid/modules/Blocker.html)** | Logic over GUI Node. Don't pass any user input below node area size. | [Blocker Example](https://insality.github.io/druid/druid/?example=timer) | <img src="media/preview/blocker.gif" width="200" height="100"> |
| **[Back Handler](https://insality.github.io/druid/modules/BackHandler.html)** | Call callback on user "Back" action. It's a Android back button or keyboard backspace key | [Back Handler Example](https://insality.github.io/druid/druid/?example=timer) | <img src="media/preview/back_handler.gif" width="200" height="100"> |
| **[Static Grid](https://insality.github.io/druid/modules/StaticGrid.html)** | Logic over GUI Node. Component to manage node positions with all equal node sizes. | [Static Gid Example](https://insality.github.io/druid/druid/?example=general_grid) | <img src="media/preview/static_grid.gif" width="200" height="100"> |
| **[Hover](https://insality.github.io/druid/modules/Hover.html)** | Logic over GUI Node. Handle hover action over node. For both: mobile touch and mouse cursor. | [Hover Example](https://insality.github.io/druid/druid/?example=timer) | <img src="media/preview/hover.gif" width="200" height="100"> |
| **[Swipe](https://insality.github.io/druid/modules/Swipe.html)** | Logic over GUI Node. Handle swipe gestures over node. | [Swipe Example](https://insality.github.io/druid/druid/?example=general_swipe) | <img src="media/preview/swipe.gif" width="200" height="100"> |
| **[Drag](https://insality.github.io/druid/modules/Drag.html)** | Logic over GUI Node. Handle drag input actions. Can be useful to make on screen controlls. | [Drag Example](https://insality.github.io/druid/druid/?example=general_drag) | <img src="media/preview/drag.gif" width="200" height="100"> |
### Extended components
> Extended components before usage should be registered in **Druid** with [`druid.register()`](https://insality.github.io/druid/modules/Druid.html#druid.register) function.
> On usage of unregistered **Druid** component the next log will be shown in the console.
```
local data_list = require("druid.extended.data_list")
druid.register("data_list", data_list)
```
| Name | Description | Example | <div style="width:200px">Preview</div> |
|------|-------------|---------|---------|
| **[Data List](https://insality.github.io/druid/modules/DataList.html)** | Logic over Scroll and Grid components. Create only visible GUI nodes or components to make "infinity" scroll befaviour | [Data List Example](https://insality.github.io/druid/druid/?example=general_data_list) | <img src="media/preview/data_list.gif" width="200" height="100"> |
| **[Input](https://insality.github.io/druid/modules/Input.html)** | Logic over GUI Node and GUI Text (or Text component). Provides basic user text input. | [Input Example](https://insality.github.io/druid/druid/?example=general_input) | <img src="media/preview/input.gif" width="200" height="100"> |
| **[Lang text](https://insality.github.io/druid/modules/LangText.html)** | Logic over Text component to handle localization. Can be translated in real-time with `druid.on_language_change` | [Lang Text Example](https://insality.github.io/druid/druid/?example=timer) | <img src="media/preview/lang_text.gif" width="200" height="100"> |
| **[Progress](https://insality.github.io/druid/modules/Progress.html)** | Logic over GUI Node. Handle node size and scale to handle progress node size. | [Progress Example](https://insality.github.io/druid/druid/?example=general_progress_bar) | <img src="media/preview/progress.gif" width="200" height="100"> |
| **[Slider](https://insality.github.io/druid/modules/Slider.html)** | Logic over GUI Node. Handle draggable node with position restrictions. | [Slider Example](https://insality.github.io/druid/druid/?example=general_sliders) | <img src="media/preview/slider.gif" width="200" height="100"> |
| **[Timer](https://insality.github.io/druid/modules/Timer.html)** | Logic over GUI Text. Handle basic timer functions. | [Timer Example](https://insality.github.io/druid/druid/?example=timer) | <img src="media/preview/timer.gif" width="200" height="100"> |
| **[Hotkey](https://insality.github.io/druid/modules/Hotkey.html)** | Allow to set callbacks for keyboard hotkeys with key modificators. | [Hotkey Example](https://insality.github.io/druid/druid/?example=general_hotkey) | <img src="media/preview/hotkey.gif" width="200" height="100"> |
| **[Layout](https://insality.github.io/druid/modules/Layout.html)** | Logic over GUI Node. Arrange nodes inside layout node with margin/paddings settings. | [Layout Example](https://insality.github.io/druid/druid/?example=general_layout) | <img src="media/preview/layout.gif" width="200" height="100"> |
| **[Rich Input](https://insality.github.io/druid/modules/RichInput.html)** | Logic over GUI Node and GUI Text (or Text component). Provides rich text input with different styles and text formatting. | [Rich Input Example](https://insality.github.io/druid/druid/?example=general_rich_input) | <img src="media/preview/rich_input.gif" width="200" height="100"> |
| **[Rich Text](https://insality.github.io/druid/modules/RichText.html)** | Logic over GUI Text. Provides rich text formatting with different styles and text formatting. | [Rich Text Example](https://insality.github.io/druid/druid/?example=general_rich_text) | <img src="media/preview/rich_text.gif" width="200" height="100"> |
For a complete overview, see: **_[components.md](docs_md/01-components.md)_**.
## Druid Events
Any **Druid** components as callbacks use [Druid Events](https://insality.github.io/druid/modules/druid_event.html). In component API ([button example](https://insality.github.io/druid/modules/druid.button.html#Events)) pointed list of component events. You can manually subscribe to those events with the following API:
Any **Druid** components as callbacks use [Druid Events](https://insality.github.io/druid/modules/DruidEvent.html). In component API ([button example](https://insality.github.io/druid/modules/Button.html#on_click)) pointed list of component events. You can manually subscribe to these events with the following API:
- **event:subscribe**(callback)
@@ -211,71 +167,35 @@ Any **Druid** components as callbacks use [Druid Events](https://insality.github
You can subscribe several callbacks to a single event.
## Druid Lifecycle
Here is full Druid lifecycle setup for your ***.gui_script** file:
```lua
local druid = require("druid.druid")
function init(self)
self.druid = druid.new(self)
end
function final(self)
self.druid:final()
end
function update(self, dt)
self.druid:update(dt)
end
function on_input(self, action_id, action)
return self.druid:on_input(action_id, action)
end
function on_message(self, message_id, message, sender)
self.druid:on_message(message_id, message, sender)
end
```
- *final* is a **required** function for a correct Druid lifecycle
- *on_input* is used in almost all Druid components
- *update* in used in progress bar, scroll and timer base components
- *on_message* is used for specific Druid events, like language change or layout change
It is recommended to fully integrate all **Druid** lifecycles functions.
## Details
- Druid input goes as stack. Last created button will checked first. So create your GUI from back
- Don't forget about `return` in `on_input`: `return self.druid:on_input()`. It is needed if you have more than 1 acquire inputs (several Druid, other input system, etc)
- By default, Druid will automatically _acquire_input_focus_. So you don't need do it manually. But only if you have components which require _on_input_
- If you want to delete a node which has a Druid component, don't forget to remove it via `druid:remove(component)`
[See full FAQ here](docs_md/FAQ.md)
- **Druid** processes input in a stack-based manner. The most recently created button will be checked first. Create your input GUI components from back to front.
- Remember to include `return` in the `on_input` function: `return self.druid:on_input()`. This is necessary if you have multiple input sources (multiple Druid instances, other input systems, etc.).
- Druid automatically calls `acquire_input_focus` if you have input components. Therefore, manual calling of `acquire_input_focus` is not required.
- When deleting a **Druid** component node, make sure to remove it using `druid:remove(component)`.
## Examples
See the [**example folder**](https://github.com/Insality/druid/tree/develop/example) for examples of how to use **Druid**
Try the [**HTML5 version**](https://insality.github.io/druid/druid/) of the **Druid** example app.
Try the [**HTML5 version**](https://insality.github.io/druid/druid/) of the **Druid** example app
Each example page provides a direct link to the corresponding example code, making it easier for you to understand how to use **Druid**.
Or refer directly to the [**example folder**](https://github.com/Insality/druid/tree/develop/example) for code examples demonstrating how to use **Druid**.
## Documentation
To better understand **Druid**, read the following documentation:
- [How To GUI in Defold](https://forum.defold.com/t/how-to-gui-in-defold/73256)
- [Druid components](docs_md/01-components.md)
- [Create custom components](docs_md/02-creating_custom_components.md)
- [See FAQ article](docs_md/FAQ.md)
- [Druid styles](docs_md/03-styles.md)
You can fund the full **Druid** documentation here:
https://insality.github.io/druid/
You can find the full **Druid** [documentation here](https://insality.github.io/druid/modules/Druid.html).
## License
## Licenses
- Developed and supported by [Insality](https://github.com/Insality)
- Original idea by [AGulev](https://github.com/AGulev)
@@ -285,3 +205,21 @@ https://insality.github.io/druid/
## Issues and suggestions
If you have any issues, questions or suggestions please [create an issue](https://github.com/Insality/druid/issues) or contact me: [insality@gmail.com](mailto:insality@gmail.com)
## History
For a complete history of the development of **Druid**, please check the [changelog](docs_md/changelog.md).
## 👏 Contributors
<a href="https://github.com/Insality/druid/graphs/contributors">
<img src="https://contributors-img.web.app/image?repo=insality/druid"/>
</a>
## ❤️ Support project ❤️
Your donation helps me stay engaged in creating valuable projects for **Defold**. If you appreciate what I'm doing, please consider supporting me!
[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality)

View File

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

View File

@@ -1,7 +0,0 @@
date,sha,version,build_size,build_time,platform,mode,is_cache_using,commits_count
2022-02-28T19:06:43Z,3b329f9c25c9672e4030edb039b0225fa46f7ce1,0.8.521,4356,68,armv7-android,debug,true,521
2022-02-28T19:14:56Z,3b329f9c25c9672e4030edb039b0225fa46f7ce1,0.8.521,4356,51,armv7-android,debug,true,521
2022-02-28T19:16:23Z,3b329f9c25c9672e4030edb039b0225fa46f7ce1,0.8.521,4356,11,armv7-android,debug,true,521
2022-02-28T19:19:46Z,3b329f9c25c9672e4030edb039b0225fa46f7ce1,0.8.521,4356,11,armv7-android,debug,true,521
2022-02-28T19:22:51Z,3b329f9c25c9672e4030edb039b0225fa46f7ce1,0.8.521,4356,11,armv7-android,debug,true,521
2022-03-12T10:01:30Z,d0f3d6641a08b0d6b719b13017aa85907d1667e5,0.8.564,2200,44,js-web,release,true,564
1 date sha version build_size build_time platform mode is_cache_using commits_count
2 2022-02-28T19:06:43Z 3b329f9c25c9672e4030edb039b0225fa46f7ce1 0.8.521 4356 68 armv7-android debug true 521
3 2022-02-28T19:14:56Z 3b329f9c25c9672e4030edb039b0225fa46f7ce1 0.8.521 4356 51 armv7-android debug true 521
4 2022-02-28T19:16:23Z 3b329f9c25c9672e4030edb039b0225fa46f7ce1 0.8.521 4356 11 armv7-android debug true 521
5 2022-02-28T19:19:46Z 3b329f9c25c9672e4030edb039b0225fa46f7ce1 0.8.521 4356 11 armv7-android debug true 521
6 2022-02-28T19:22:51Z 3b329f9c25c9672e4030edb039b0225fa46f7ce1 0.8.521 4356 11 armv7-android debug true 521
7 2022-03-12T10:01:30Z d0f3d6641a08b0d6b719b13017aa85907d1667e5 0.8.564 2200 44 js-web release true 564

View File

@@ -1 +1 @@
{"content":[{"name":"game.projectc","size":3808,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":17168,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":417873,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":17838,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]}
{"content":[{"name":"game.projectc","size":4489,"pieces":[{"name":"game0.projectc","offset":0}]},{"name":"game.arci","size":12368,"pieces":[{"name":"game0.arci","offset":0}]},{"name":"game.arcd","size":3557359,"pieces":[{"name":"game0.arcd","offset":0},{"name":"game1.arcd","offset":2097152}]},{"name":"game.dmanifest","size":13892,"pieces":[{"name":"game0.dmanifest","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game0.public.der","offset":0}]}],"total_size":3588270}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,23 +1,25 @@
[project]
title = druid
version = 0.8.564
version = 1.0
write_log = 0
compress_archive = 1
publisher = Insality
developer = Insality
commit_sha = d0f3d6641a08b0d6b719b13017aa85907d1667e5
build_date = 2022-03-12T10:01:30Z
developer = Maksim Tuprikov
custom_resources = /example/locales
commit_sha = 13fb109ef09e1590fc14a96c2c4d2c900fb517cc
build_date = 2024-10-19T08:21:03Z
title_as_file_name = druid
[display]
width = 600
height = 900
high_dpi = 0
width = 1920
height = 1080
high_dpi = 1
samples = 0
fullscreen = 0
update_frequency = 0
swap_interval = 1
vsync = 1
display_profiles = /example/custom.display_profilesc
display_profiles = /builtins/render/default.display_profilesc
dynamic_orientation = 1
display_device_info = 0
@@ -29,6 +31,8 @@ clear_color_alpha = 0
[physics]
type = 2D
max_collision_object_count = 128
use_fixed_timestep = 0
gravity_y = -10
debug = 0
debug_alpha = 0.9
@@ -45,19 +49,21 @@ ray_cast_limit_2d = 64
ray_cast_limit_3d = 128
trigger_overlap_capacity = 16
velocity_threshold = 1
max_fixed_timesteps = 2
[bootstrap]
main_collection = /example/example.collectionc
main_collection = /example/druid.collectionc
render = /builtins/render/default.renderc
[graphics]
default_texture_min_filter = linear
default_texture_mag_filter = linear
max_draw_calls = 1024
max_draw_calls = 128
max_characters = 8192
max_font_batches = 128
max_debug_vertices = 10000
texture_profiles = /example/custom.texture_profiles
verify_graphics_calls = 1
texture_profiles = /builtins/graphics/default.texture_profiles
verify_graphics_calls = 0
memory_size = 512
[shader]
@@ -80,89 +86,100 @@ max_resources = 1024
repeat_delay = 0.5
repeat_interval = 0.2
gamepads = /builtins/input/default.gamepadsc
game_binding = /input/game.input_bindingc
game_binding = /builtins/input/all.input_bindingc
use_accelerometer = 0
[sprite]
max_count = 128
max_count = 16
subpixels = 1
[model]
max_count = 128
max_count = 0
split_meshes = 0
[mesh]
max_count = 128
max_count = 0
[gui]
max_count = 64
max_particlefx_count = 64
max_particle_count = 1024
max_animation_count = 1024
[collection]
max_instances = 1024
max_instances = 128
max_input_stack_entries = 16
[collection_proxy]
max_count = 8
[collectionfactory]
max_count = 128
max_count = 64
[factory]
max_count = 128
max_count = 16
[ios]
launch_screen = /builtins/manifests/ios/LaunchScreen.storyboardc
pre_renderered_icons = 0
bundle_identifier = example.unnamed
bundle_name =
infoplist = /builtins/manifests/ios/Info.plist
privacymanifest = /builtins/manifests/ios/PrivacyInfo.xcprivacy
default_language = en
localizations = en
[android]
version_code = 564
minimum_sdk_version = 16
target_sdk_version = 30
version_code = 817
minimum_sdk_version = 19
target_sdk_version = 34
package = com.insality.druid
gcm_sender_id =
manifest = /builtins/manifests/android/AndroidManifest.xml
iap_provider = GooglePlay
input_method = HiddenInputField
immersive_mode = 0
display_cutout = 1
debuggable = 0
proguard =
extract_native_libs = 1
[osx]
app_icon =
infoplist = /builtins/manifests/osx/Info.plist
privacymanifest = /builtins/manifests/osx/PrivacyInfo.xcprivacy
bundle_identifier = example.unnamed
bundle_name =
bundle_version = 1
default_language = en
localizations = en
[windows]
app_icon =
[html5]
custom_heap_size = 0
heap_size = 64
htmlfile = /builtins/manifests/web/engine_template.html
cssfile = /builtins/manifests/web/light_theme.css
cssfile = /builtins/manifests/web/dark_theme.css
splash_image = /media/druid_logo.png
archive_location_prefix = archive
archive_location_suffix =
engine_arguments = --verify-graphics-calls=false
wasm_streaming = 0
show_fullscreen_button = 0
show_made_with_defold = 0
show_console_banner = 1
scale_mode = fit
engine_arguments = --verify-graphics-calls=false
splash_image = /media/druid_logo.png
show_console_banner = 0
scale_mode = stretch
[particle_fx]
max_count = 64
max_emitter_count = 64
max_particle_count = 1024
[iap]
auto_finish_transactions = 1
max_count = 0
max_emitter_count = 0
max_particle_count = 0
[network]
http_timeout = 0
ssl_certificates =
http_thread_count = 4
http_cache_enabled = 1
@@ -173,26 +190,30 @@ include_dirs = druid
shared_state = 1
[label]
max_count = 64
max_count = 0
subpixels = 1
[profiler]
track_cpu = 0
sleep_between_server_updates = 0
[liveupdate]
settings = /liveupdate.settings
enabled = 1
mount_on_start = 1
[tilemap]
max_count = 16
max_tile_count = 2048
max_count = 0
max_tile_count = 0
[engine]
run_while_iconified = 0
fixed_update_frequency = 60
max_time_step = 0.5
[druid]
no_auto_input = 0
stencil_check = 0
no_stencil_check = 0
no_auto_template = 0
input_text = text
input_touch = touch
@@ -201,10 +222,18 @@ input_key_esc = key_esc
input_key_back = key_back
input_key_enter = key_enter
input_key_backspace = key_backspace
input_multitouch = multitouch
input_scroll_up = scroll_up
input_scroll_down = scroll_down
input_multitouch = touch_multi
input_scroll_up = mouse_wheel_up
input_scroll_down = mouse_wheel_down
[native_extension]
app_manifest = /example/game.appmanifest
app_manifest =
[saver]
autosave_timer = 2
[lang]
path = /example/locales
langs = en,ru,es,de,fr,ja,pt,it,kr,zh
default = es

Binary file not shown.

View File

@@ -1,3 +1,93 @@
/*
* 'archive_location_filter':
* Filter function that will run for each archive path.
*
* 'unsupported_webgl_callback':
* Function that is called if WebGL is not supported.
*
* 'engine_arguments':
* List of arguments (strings) that will be passed to the engine.
*
* 'custom_heap_size':
* Number of bytes specifying the memory heap size.
*
* 'disable_context_menu':
* Disables the right-click context menu on the canvas element if true.
*
* 'retry_time':
* Pause before retry file loading after error.
*
* 'retry_count':
* How many attempts we do when trying to download a file.
*
* 'can_not_download_file_callback':
* Function that is called if you can't download file after 'retry_count' attempts.
*
* 'exe_name':
* Executable name which used for find right binary to load
*
* 'resize_window_callback':
* Function that is called when resize/orientationchanges/focus events happened
*/
var CUSTOM_PARAMETERS = {
archive_location_filter: function( path ) {
return ("archive" + path + "");
},
engine_arguments: ["--verify-graphics-calls=false",],
custom_heap_size: 67108864,
full_screen_container: "#canvas-container",
disable_context_menu: true,
retry_time:1.0,
retry_count:10,
unsupported_webgl_callback: function() {
var e = document.getElementById("webgl-not-supported");
e.style.display = "block";
},
resize_window_callback: function() {
var is_iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
var buttonHeight = 0;
var prevInnerWidth = -1;
var prevInnerHeight = -1;
// Hack for iOS when exit from Fullscreen mode
if (is_iOS) {
window.scrollTo(0, 0);
}
var app_container = document.getElementById('app-container');
var game_canvas = document.getElementById('canvas');
var innerWidth = window.innerWidth;
var innerHeight = window.innerHeight - buttonHeight;
if (prevInnerWidth == innerWidth && prevInnerHeight == innerHeight)
{
return;
}
prevInnerWidth = innerWidth;
prevInnerHeight = innerHeight;
var width = 1920;
var height = 1080;
var targetRatio = width / height;
var actualRatio = innerWidth / innerHeight;
//Stretch
width = innerWidth;
height = innerHeight;
var dpi = 1;
dpi = window.devicePixelRatio || 1;
app_container.style.width = width + "px";
app_container.style.height = height + buttonHeight + "px";
game_canvas.width = Math.floor(width * dpi);
game_canvas.height = Math.floor(height * dpi);
}
}
// file downloader
// wraps XMLHttpRequest and adds retry support and progress updates when the
// content is gzipped (gzipped content doesn't report a computable content length
@@ -9,31 +99,36 @@ var FileLoader = {
},
// do xhr request with retries
request: function(url, method, responseType, currentAttempt) {
if (typeof method === 'undefined') throw "No method specified";
if (typeof method === 'responseType') throw "No responseType specified";
if (typeof method === 'undefined') throw TypeError("No method specified");
if (typeof method === 'responseType') throw TypeError("No responseType specified");
if (typeof currentAttempt === 'undefined') currentAttempt = 0;
var obj = {
send: function() {
var onprogress = this.onprogress;
var onload = this.onload;
var onerror = this.onerror;
var onretry = this.onretry;
var xhr = new XMLHttpRequest();
xhr._loadedSize = 0;
xhr.open(method, url, true);
xhr.responseType = responseType;
xhr.onprogress = function(e) {
if (onprogress) onprogress(xhr, e);
xhr.onprogress = function(event) {
if (onprogress) onprogress(xhr, event, xhr._loadedSize);
xhr._loadedSize = event.loaded;
};
xhr.onerror = function(e) {
xhr.onerror = function(event) {
if (currentAttempt == FileLoader.options.retryCount) {
if (onerror) onerror(xhr, e);
if (onerror) onerror(xhr, event);
return;
}
currentAttempt = currentAttempt + 1;
if (onretry) onretry(xhr, event, xhr._loadedSize, currentAttempt);
xhr._loadedSize = 0;
currentAttempt += 1;
setTimeout(obj.send.bind(obj), FileLoader.options.retryInterval);
};
xhr.onload = function(e) {
if (onload) onload(xhr, e);
xhr.onload = function(event) {
if (onload) onload(xhr, event);
};
xhr.send(null);
}
@@ -60,29 +155,21 @@ var FileLoader = {
request.send();
},
// Do HTTP GET request
// onprogress(loaded, total)
// onprogress(loadedDelta)
// onerror(error)
// onload(response)
load: function(url, responseType, estimatedSize, onprogress, onerror, onload) {
// onretry(loadedSize, currentAttempt)
load: function(url, responseType, onprogress, onerror, onload, onretry) {
var request = FileLoader.request(url, "GET", responseType);
request.onprogress = function(xhr, e) {
if (e.lengthComputable) {
onprogress(e.loaded, e.total);
return;
}
var contentLength = xhr.getResponseHeader('content-length');
var size = contentLength != undefined ? contentLength : estimatedSize;
if (size) {
onprogress(e.loaded, size);
} else {
onprogress(e.loaded, e.loaded);
}
request.onprogress = function(xhr, e, ls) {
var delta = e.loaded - ls;
onprogress(delta);
};
request.onerror = function(xhr, e) {
onerror("Error loading '" + url + "' (" + e + ")");
};
request.onload = function(xhr, e) {
if (xhr.readyState === 4) {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
var res = xhr.response;
if (responseType == "json" && typeof res === "string") {
@@ -95,93 +182,145 @@ var FileLoader = {
}
}
};
request.onretry = function(xhr, event, loadedSize, currentAttempt) {
onretry(loadedSize, currentAttempt);
}
request.send();
}
};
var EngineLoader = {
wasm_size: 2000000,
wasm_from: 0,
wasm_to: 40,
wasmjs_size: 250000,
wasmjs_from: 40,
wasmjs_to: 50,
wasm_size: 2374239,
wasmjs_size: 340441,
asmjs_size: 4000000,
asmjs_from: 0,
asmjs_to: 50,
wasm_instantiate_progress: 0,
stream_wasm: true,
stream_wasm: "false" === "true",
loadAndInstantiateWasmAsync: function(src, fromProgress, toProgress, callback) {
FileLoader.load(src, "arraybuffer", EngineLoader.wasm_size,
function(loaded, total) { Progress.calculateProgress(fromProgress, toProgress, loaded, total); },
updateWasmInstantiateProgress: function(totalDownloadedSize) {
EngineLoader.wasm_instantiate_progress = totalDownloadedSize * 0.1;
},
// load and instantiate .wasm file using XMLHttpRequest
loadAndInstantiateWasmAsync: function(src, imports, successCallback) {
FileLoader.load(src, "arraybuffer",
function(delta) {
ProgressUpdater.updateCurrent(delta);
},
function(error) { throw error; },
function(wasm) {
Module.instantiateWasm = function(imports, successCallback) {
var wasmInstantiate = WebAssembly.instantiate(new Uint8Array(wasm), imports).then(function(output) {
successCallback(output.instance);
}).catch(function(e) {
console.log('wasm instantiation failed! ' + e);
throw e;
});
return {}; // Compiling asynchronously, no exports.
if (wasm.byteLength != EngineLoader.wasm_size) {
throw "Invalid wasm size. Expected: " + EngineLoader.wasm_size + ", actual: " + wasm.byteLength;
}
callback();
var wasmInstantiate = WebAssembly.instantiate(new Uint8Array(wasm), imports).then(function(output) {
successCallback(output.instance);
}).catch(function(e) {
console.log('wasm instantiation failed! ' + e);
throw e;
});
},
function(loadedDelta, currentAttempt){
ProgressUpdater.updateCurrent(-loadedDelta);
});
},
streamAndInstantiateWasmAsync: function(src, fromProgress, toProgress, callback) {
Module.instantiateWasm = function(imports, successCallback) {
WebAssembly.instantiateStreaming(fetch(src), imports).then(function(output) {
Progress.calculateProgress(fromProgress, toProgress, 1, 1);
successCallback(output.instance);
}).catch(function(e) {
console.log('wasm streaming instantiation failed! ' + e);
throw e;
});
return {}; // Compiling asynchronously, no exports.
// stream and instantiate .wasm file
streamAndInstantiateWasmAsync: async function(src, imports, successCallback) {
// https://stackoverflow.com/a/69179454
var fetchFn = fetch;
if (typeof TransformStream === "function" && ReadableStream.prototype.pipeThrough) {
async function fetchWithProgress(path) {
const response = await fetch(path);
if (response.ok) {
const ts = new TransformStream({
transform (chunk, controller) {
ProgressUpdater.updateCurrent(chunk.byteLength);
controller.enqueue(chunk);
}
});
return new Response(response.body.pipeThrough(ts), response);
} else {
return new Response(null, response);
}
}
fetchFn = fetchWithProgress;
}
callback();
WebAssembly.instantiateStreaming(fetchFn(src), imports).then(function(output) {
ProgressUpdater.updateCurrent(EngineLoader.wasm_instantiate_progress);
successCallback(output.instance);
}).catch(function(e) {
console.log('wasm streaming instantiation failed! ' + e);
console.log('Fallback to wasm loading');
EngineLoader.loadAndInstantiateWasmAsync(src, imports, successCallback);
});
},
// instantiate the .wasm file either by streaming it or first loading and then instantiate it
// https://github.com/emscripten-core/emscripten/blob/master/tests/manual_wasm_instantiate.html#L170
loadWasmAsync: function(src, fromProgress, toProgress, callback) {
if (EngineLoader.stream_wasm && (typeof WebAssembly.instantiateStreaming === "function")) {
EngineLoader.streamAndInstantiateWasmAsync(src, fromProgress, toProgress, callback);
}
else {
EngineLoader.loadAndInstantiateWasmAsync(src, fromProgress, toProgress, callback);
}
// https://github.com/emscripten-core/emscripten/blob/main/test/manual_wasm_instantiate.html
loadWasmAsync: function(exeName) {
Module.instantiateWasm = function(imports, successCallback) {
if (EngineLoader.stream_wasm && (typeof WebAssembly.instantiateStreaming === "function")) {
EngineLoader.streamAndInstantiateWasmAsync(exeName + ".wasm", imports, successCallback);
}
else {
EngineLoader.loadAndInstantiateWasmAsync(exeName + ".wasm", imports, successCallback);
}
return {}; // Compiling asynchronously, no exports.
};
EngineLoader.loadAndRunScriptAsync(exeName + '_wasm.js');
},
loadAsmJsAsync: function(exeName) {
EngineLoader.loadAndRunScriptAsync(exeName + '_asmjs.js');
},
// load and start engine script (asm.js or wasm.js)
loadScriptAsync: function(src, estimatedSize, fromProgress, toProgress) {
FileLoader.load(src, "text", estimatedSize,
function(loaded, total) { Progress.calculateProgress(fromProgress, toProgress, loaded, total); },
loadAndRunScriptAsync: function(src) {
FileLoader.load(src, "text",
function(delta) {
ProgressUpdater.updateCurrent(delta);
},
function(error) { throw error; },
function(response) {
var tag = document.createElement("script");
tag.text = response;
document.head.appendChild(tag);
document.body.appendChild(tag);
},
function(loadedDelta, currentAttempt){
ProgressUpdater.updateCurrent(-loadedDelta);
});
},
// load engine (asm.js or wasm.js + wasm)
// engine load progress goes from 1-50% for ams.js
// engine load progress goes from 0-40% for .wasm and 40-50% for wasm.js
// left as entrypoint for backward capability
// start loading archive_files.json
// after receiving it - start loading engine and data concurrently
load: function(appCanvasId, exeName) {
Progress.addProgress(Module.setupCanvas(appCanvasId));
if (Module['isWASMSupported']) {
EngineLoader.loadWasmAsync(exeName + ".wasm", EngineLoader.wasm_from, EngineLoader.wasm_to, function(wasm) {
EngineLoader.loadScriptAsync(exeName + '_wasm.js', EngineLoader.wasmjs_size, EngineLoader.wasmjs_from, EngineLoader.wasmjs_to);
});
} else {
EngineLoader.loadScriptAsync(exeName + '_asmjs.js', EngineLoader.asmjs_size, EngineLoader.asmjs_from, EngineLoader.asmjs_to);
ProgressView.addProgress(Module.setupCanvas(appCanvasId));
CUSTOM_PARAMETERS['exe_name'] = exeName;
FileLoader.options.retryCount = CUSTOM_PARAMETERS["retry_count"];
FileLoader.options.retryInterval = CUSTOM_PARAMETERS["retry_time"] * 1000;
if (typeof CUSTOM_PARAMETERS["can_not_download_file_callback"] === "function") {
GameArchiveLoader.addFileDownloadErrorListener(CUSTOM_PARAMETERS["can_not_download_file_callback"]);
}
// Load and assemble archive
GameArchiveLoader.addFileLoadedListener(Module.onArchiveFileLoaded);
GameArchiveLoader.addArchiveLoadedListener(Module.onArchiveLoaded);
GameArchiveLoader.setFileLocationFilter(CUSTOM_PARAMETERS["archive_location_filter"]);
GameArchiveLoader.loadArchiveDescription('/archive_files.json');
// move resize callback setup here to make possible to override callback
// from outside of dmloader.js
if (typeof CUSTOM_PARAMETERS["resize_window_callback"] === "function") {
var callback = CUSTOM_PARAMETERS["resize_window_callback"]
callback();
window.addEventListener('resize', callback, false);
window.addEventListener('orientationchange', callback, false);
window.addEventListener('focus', callback, false);
}
}
}
@@ -212,9 +351,6 @@ var GameArchiveLoader = {
_onArchiveLoadedListeners:[], // signature: void
_onFileDownloadErrorListeners: [], // signature: name
_currentDownloadBytes: 0,
_totalDownloadBytes: 0,
_archiveLocationFilter: function(path) { return "split" + path; },
cleanUp: function() {
@@ -224,13 +360,10 @@ var GameArchiveLoader = {
this._onGameArchiveLoaderCompletedListeners = [];
this._onAllTargetsBuiltListeners = [];
this._onFileDownloadErrorListeners = [];
this._currentDownloadBytes = 0;
this._totalDownloadBytes = 0;
},
addListener: function(list, callback) {
if (typeof callback !== 'function') throw "Invalid callback registration";
if (typeof callback !== 'function') throw TypeError("Invalid callback registration");
list.push(callback);
},
notifyListeners: function(list, data) {
@@ -272,22 +405,31 @@ var GameArchiveLoader = {
FileLoader.load(
this._archiveLocationFilter(descriptionUrl),
"json",
undefined,
function (loaded, total) { },
function (delta) { },
function (error) { GameArchiveLoader.notifyFileDownloadError(descriptionUrl); },
function (json) { GameArchiveLoader.onReceiveDescription(json); });
function (json) { GameArchiveLoader.onReceiveDescription(json); },
function (loadedDelta, currentAttempt) { });
},
onReceiveDescription: function(json) {
var totalSize = json.total_size;
var exeName = CUSTOM_PARAMETERS['exe_name'];
this._files = json.content;
this._totalDownloadBytes = 0;
this._currentDownloadBytes = 0;
// calculate total download size of all files
for(var i=0; i<this._files.length; ++i) {
this._totalDownloadBytes += this._files[i].size;
var isWASMSupported = Module['isWASMSupported'];
if (isWASMSupported) {
EngineLoader.loadWasmAsync(exeName);
totalSize += EngineLoader.wasm_size + EngineLoader.wasmjs_size;
} else {
EngineLoader.loadAsmJsAsync(exeName);
totalSize += EngineLoader.asmjs_size;
}
this.downloadContent();
ProgressUpdater.resetCurrent();
if (isWASMSupported) {
EngineLoader.updateWasmInstantiateProgress(totalSize);
}
ProgressUpdater.setupTotal(totalSize + EngineLoader.wasm_instantiate_progress);
},
downloadContent: function() {
@@ -307,30 +449,25 @@ var GameArchiveLoader = {
}
},
notifyDownloadProgress: function() {
Progress.calculateProgress(50, 100, this._currentDownloadBytes, this._totalDownloadBytes);
notifyDownloadProgress: function(delta) {
ProgressUpdater.updateCurrent(delta);
},
downloadPiece: function(file, index) {
if (index < file.lastRequestedPiece) {
throw "Request out of order";
throw RangeError("Request out of order: " + file.name + ", index: " + index + ", last requested piece: " + file.lastRequestedPiece);
}
var piece = file.pieces[index];
file.lastRequestedPiece = index;
file.totalLoadedPieces = 0;
var total = 0;
var downloaded = 0;
var url = this._archiveLocationFilter('/' + piece.name);
FileLoader.load(
url, "arraybuffer", undefined,
function (loaded, total) {
var delta = loaded - downloaded;
downloaded = loaded;
GameArchiveLoader._currentDownloadBytes += delta;
GameArchiveLoader.notifyDownloadProgress();
url, "arraybuffer",
function (delta) {
GameArchiveLoader.notifyDownloadProgress(delta);
},
function (error) {
GameArchiveLoader.notifyFileDownloadError(error);
@@ -341,8 +478,10 @@ var GameArchiveLoader = {
total = piece.dataLength;
downloaded = piece.dataLength;
GameArchiveLoader.onPieceLoaded(file, piece);
GameArchiveLoader.notifyDownloadProgress();
piece.data = undefined;
},
function(loadedDelta, currentAttempt){
ProgressUpdater.updateCurrent(-loadedDelta);
});
},
@@ -353,10 +492,10 @@ var GameArchiveLoader = {
var start = piece.offset;
var end = start + piece.data.length;
if (0 > start) {
throw "Buffer underflow";
throw RangeError("Buffer underflow. Start: " + start);
}
if (end > file.data.length) {
throw "Buffer overflow";
throw RangeError("Buffer overflow. End : " + end + ", data length: " + file.data.length);
}
file.data.set(piece.data, piece.offset);
}
@@ -387,12 +526,11 @@ var GameArchiveLoader = {
actualSize += file.pieces[i].dataLength;
}
if (actualSize != file.size) {
throw "Unexpected data size";
throw "Unexpected data size: " + file.name + ", expected size: " + file.size + ", actual size: " + actualSize;
}
// verify the pieces
if (file.pieces.length > 1) {
var output = file.data;
var pieces = file.pieces;
for (i=0; i<pieces.length; ++i) {
var item = pieces[i];
@@ -402,13 +540,13 @@ var GameArchiveLoader = {
if (0 < i) {
var previous = pieces[i - 1];
if (previous.offset + previous.dataLength > start) {
throw "Segment underflow";
throw RangeError("Segment underflow in file: " + file.name + ", offset: " + (previous.offset + previous.dataLength) + " , start: " + start);
}
}
if (pieces.length - 2 > i) {
var next = pieces[i + 1];
if (end > next.offset) {
throw "Segment overflow";
throw RangeError("Segment overflow in file: " + file.name + ", offset: " + next.offset + ", end: " + end);
}
}
}
@@ -436,14 +574,42 @@ var GameArchiveLoader = {
/* Default splash and progress visualisation */
/* ********************************************************************* */
var Progress = {
var ProgressView = {
progress_id: "defold-progress",
bar_id: "defold-progress-bar",
addProgress : function (canvas) {
/* Insert default progress bar below canvas */
canvas.insertAdjacentHTML('afterend', '<div id="' + ProgressView.progress_id + '" class="canvas-app-progress"><div id="' + ProgressView.bar_id + '" class="canvas-app-progress-bar" style="transform: scaleX(0.0);"></div></div>');
ProgressView.bar = document.getElementById(ProgressView.bar_id);
ProgressView.progress = document.getElementById(ProgressView.progress_id);
},
updateProgress: function(percentage) {
if (ProgressView.bar) {
ProgressView.bar.style.transform = "scaleX(" + Math.min(percentage, 100) / 100 + ")";
}
},
removeProgress: function () {
if (ProgressView.progress.parentElement !== null) {
ProgressView.progress.parentElement.removeChild(ProgressView.progress);
// Remove any background/splash image that was set in runApp().
// Workaround for Safari bug DEF-3061.
Module.canvas.style.background = "";
}
}
};
var ProgressUpdater = {
current: 0,
total: 1,
listeners: [],
addListener: function(callback) {
if (typeof callback !== 'function') throw "Invalid callback registration";
if (typeof callback !== 'function') throw TypeError("Invalid callback registration");
this.listeners.push(callback);
},
@@ -453,32 +619,64 @@ var Progress = {
}
},
setupTotal: function (total) {
this.total = total;
},
setCurrent: function (current) {
this.current = current;
var percentage = this.calculateProgress();
ProgressView.updateProgress(percentage);
this.notifyListeners(percentage);
},
updateCurrent: function (diff) {
this.current += diff;
var percentage = this.calculateProgress();
ProgressView.updateProgress(percentage);
this.notifyListeners(percentage);
},
resetCurrent: function () {
this.current = 0;
},
complete: function () {
this.setCurrent(this.total);
},
calculateProgress: function () {
return this.current / this.total * 100;
}
};
/* DEPRECATED!
* Use ProgressUpdater and ProgressView instead.
* Left for backward compatability.
*/
var Progress = {
addListener: function(callback) {
ProgressUpdater.addListener(callback);
},
notifyListeners: function(percentage) {
// no-op
},
addProgress : function (canvas) {
/* Insert default progress bar below canvas */
canvas.insertAdjacentHTML('afterend', '<div id="' + Progress.progress_id + '" class="canvas-app-progress"><div id="' + Progress.bar_id + '" class="canvas-app-progress-bar" style="width: 0%;"></div></div>');
Progress.bar = document.getElementById(Progress.bar_id);
Progress.progress = document.getElementById(Progress.progress_id);
ProgressView.addProgress(canvas);
},
updateProgress: function(percentage) {
if (Progress.bar) {
Progress.bar.style.width = percentage + "%";
}
Progress.notifyListeners(percentage);
// no-op
},
calculateProgress: function (from, to, current, total) {
this.updateProgress(from + (current / total) * (to - from));
// no-op
},
removeProgress: function () {
if (Progress.progress.parentElement !== null) {
Progress.progress.parentElement.removeChild(Progress.progress);
// Remove any background/splash image that was set in runApp().
// Workaround for Safari bug DEF-3061.
Module.canvas.style.background = "";
}
ProgressView.removeProgress();
}
};
@@ -492,7 +690,7 @@ var Module = {
_filesToPreload: [],
_archiveLoaded: false,
_preLoadDone: false,
_waitingForArchive: false,
_isEngineLoaded: false,
// Persistent storage
persistentStorage: true,
@@ -530,7 +728,6 @@ var Module = {
var error = errObj || (typeof window.event != "undefined" ? window.event.error : "" ) || err || "Undefined Error";
var message = "";
var stack = "";
var backtrace = "";
if (typeof error == "object" && typeof error.stack != "undefined" && typeof error.message != "undefined") {
stack = String(error.stack);
@@ -583,61 +780,14 @@ var Module = {
/**
* Module.runApp - Starts the application given a canvas element id
*
* 'extra_params' is an optional object that can have the following fields:
*
* 'archive_location_filter':
* Filter function that will run for each archive path.
*
* 'unsupported_webgl_callback':
* Function that is called if WebGL is not supported.
*
* 'engine_arguments':
* List of arguments (strings) that will be passed to the engine.
*
* 'persistent_storage':
* Boolean toggling the usage of persistent storage.
*
* 'custom_heap_size':
* Number of bytes specifying the memory heap size.
*
* 'disable_context_menu':
* Disables the right-click context menu on the canvas element if true.
*
* 'retry_time':
* Pause before retry file loading after error.
*
* 'retry_count':
* How many attempts we do when trying to download a file.
*
* 'can_not_download_file_callback':
* Function that is called if you can't download file after 'retry_count' attempts.
**/
runApp: function(appCanvasId, extra_params) {
runApp: function(appCanvasId, _) {
Module._isEngineLoaded = true;
Module.setupCanvas(appCanvasId);
var params = {
archive_location_filter: function(path) { return 'split' + path; },
unsupported_webgl_callback: undefined,
engine_arguments: [],
persistent_storage: true,
custom_heap_size: undefined,
disable_context_menu: true,
retry_time: 1,
retry_count: 10,
can_not_download_file_callback: undefined,
};
Module.arguments = CUSTOM_PARAMETERS["engine_arguments"];
for (var k in extra_params) {
if (extra_params.hasOwnProperty(k)) {
params[k] = extra_params[k];
}
}
Module.arguments = params["engine_arguments"];
Module.persistentStorage = params["persistent_storage"];
var fullScreenContainer = params["full_screen_container"];
var fullScreenContainer = CUSTOM_PARAMETERS["full_screen_container"];
if (typeof fullScreenContainer === "string") {
fullScreenContainer = document.querySelector(fullScreenContainer);
}
@@ -647,31 +797,22 @@ var Module = {
Module.canvas.focus();
// Add context menu hide-handler if requested
if (params["disable_context_menu"])
if (CUSTOM_PARAMETERS["disable_context_menu"])
{
Module.canvas.oncontextmenu = function(e) {
e.preventDefault();
};
}
FileLoader.options.retryCount = params["retry_count"];
FileLoader.options.retryInterval = params["retry_time"] * 1000;
if (typeof params["can_not_download_file_callback"] === "function") {
GameArchiveLoader.addFileDownloadErrorListener(params["can_not_download_file_callback"]);
}
// Load and assemble archive
GameArchiveLoader.addFileLoadedListener(Module.onArchiveFileLoaded);
GameArchiveLoader.addArchiveLoadedListener(Module.onArchiveLoaded);
GameArchiveLoader.setFileLocationFilter(params["archive_location_filter"]);
GameArchiveLoader.loadArchiveDescription('/archive_files.json');
Module._preloadAndCallMain();
} else {
Progress.updateProgress(100, "Unable to start game, WebGL not supported");
// "Unable to start game, WebGL not supported"
ProgressUpdater.complete();
Module.setStatus = function(text) {
if (text) Module.printErr('[missing WebGL] ' + text);
};
if (typeof params["unsupported_webgl_callback"] === "function") {
params["unsupported_webgl_callback"]();
if (typeof CUSTOM_PARAMETERS["unsupported_webgl_callback"] === "function") {
CUSTOM_PARAMETERS["unsupported_webgl_callback"]();
}
}
},
@@ -683,11 +824,7 @@ var Module = {
onArchiveLoaded: function() {
GameArchiveLoader.cleanUp();
Module._archiveLoaded = true;
Progress.updateProgress(100, "Starting...");
if (Module._waitingForArchive) {
Module._preloadAndCallMain();
}
Module._preloadAndCallMain();
},
toggleFullscreen: function(element) {
@@ -699,11 +836,15 @@ var Module = {
},
preSync: function(done) {
if (Module.persistentStorage != true) {
done();
return;
}
// Initial persistent sync before main is called
FS.syncfs(true, function(err) {
if(err) {
if (err) {
Module._syncTries += 1;
console.error("FS syncfs error: " + err);
console.warn("Unable to synchronize mounted file systems: " + err);
if (Module._syncMaxTries > Module._syncTries) {
Module.preSync(done);
} else {
@@ -734,6 +875,9 @@ var Module = {
// It will flag that another one is needed if there is already one sync running.
persistentSync: function() {
if (Module.persistentStorage != true) {
return;
}
// Need to wait for the initial sync to finish since it
// will call close on all its file streams which will trigger
// new persistentSync for each.
@@ -747,27 +891,40 @@ var Module = {
},
preInit: [function() {
/* Mount filesystem on preinit */
// Mount filesystem on preinit
var dir = DMSYS.GetUserPersistentDataRoot();
FS.mkdir(dir);
try {
FS.mkdir(dir);
}
catch (error) {
Module.persistentStorage = false;
Module._preloadAndCallMain();
return;
}
// If IndexedDB is supported we mount the persistent data root as IDBFS,
// then try to do a IDB->MEM sync before we start the engine to get
// previously saved data before boot.
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if (Module.persistentStorage && window.indexedDB) {
try {
FS.mount(IDBFS, {}, dir);
// Patch FS.close so it will try to sync MEM->IDB
var _close = FS.close; FS.close = function(stream) { var r = _close(stream); Module.persistentSync(); return r; }
// Sync IDB->MEM before calling main()
Module.preSync(function() {
Module._preloadAndCallMain();
});
} else {
Module._preloadAndCallMain();
var _close = FS.close;
FS.close = function(stream) {
var r = _close(stream);
Module.persistentSync();
return r;
}
}
catch (error) {
Module.persistentStorage = false;
Module._preloadAndCallMain();
return;
}
// Sync IDB->MEM before calling main()
Module.preSync(function() {
Module._preloadAndCallMain();
});
}],
preRun: [function() {
@@ -779,26 +936,33 @@ var Module = {
postRun: [function() {
if(Module._archiveLoaded) {
Progress.removeProgress();
ProgressView.removeProgress();
}
}],
_preloadAndCallMain: function() {
// If the archive isn't loaded,
// we will have to wait with calling main.
if (!Module._archiveLoaded) {
Module._waitingForArchive = true;
} else {
Module.preloadAll();
Progress.removeProgress();
if (Module.callMain === undefined) {
Module.noInitialRun = false;
} else {
Module.callMain(Module.arguments);
if (Module._syncInitial || Module.persistentStorage != true) {
// If the archive isn't loaded,
// we will have to wait with calling main.
if (Module._archiveLoaded) {
Module.preloadAll();
if (Module._isEngineLoaded) {
// "Starting...."
ProgressUpdater.complete();
Module._callMain();
}
}
}
},
_callMain: function() {
ProgressView.removeProgress();
if (Module.callMain === undefined) {
Module.noInitialRun = false;
} else {
Module.callMain(Module.arguments);
}
},
// Wrap IDBFS syncfs call with logic to avoid multiple syncs
// running at the same time.
_startSyncFS: function() {
@@ -809,7 +973,7 @@ var Module = {
Module._syncInProgress = false;
if (err) {
console.error("Module._startSyncFS error: " + err);
console.warn("Unable to synchronize mounted file systems: " + err);
Module._syncTries += 1;
}
@@ -823,6 +987,26 @@ var Module = {
},
};
// common engine setup
Module['persistentStorage'] = (typeof window !== 'undefined') && !!(window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB);
Module['INITIAL_MEMORY'] = CUSTOM_PARAMETERS.custom_heap_size;
Module['onRuntimeInitialized'] = function() {
Module.runApp("canvas");
};
Module["locateFile"] = function(path, scriptDirectory)
{
// dmengine*.wasm is hardcoded in the built JS loader for WASM,
// we need to replace it here with the correct project name.
if (path == "dmengine.wasm" || path == "dmengine_release.wasm" || path == "dmengine_headless.wasm") {
path = "druid.wasm";
}
return scriptDirectory + path;
};
window.onerror = function(err, url, line, column, errObj) {
if (typeof Module.ccall !== 'undefined') {
var errorObject = Module.prepareErrorObject(err, url, line, column, errObj);

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 492 KiB

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- The above 4 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>druid 0.8.564</title>
<title>druid 1.0</title>
<style type='text/css'>
/* Disable user selection to avoid strange bug in Chrome on Windows:
* Selecting a text outside the canvas, then clicking+draging would
@@ -54,7 +54,7 @@
-moz-outline-style: none;
}
div {
body, div {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-touch-callout: none;
-webkit-user-select: none;
@@ -66,7 +66,7 @@
.canvas-app-progress {
position: absolute;
background-color: #d1dbeb;
background-color: #394046;
height: 6px;
margin-top: -6px;
width: 100%;
@@ -79,6 +79,9 @@
background-color: #1a72eb;
text-align: center;
line-height: 20px;
transition: transform 1s ease;
transform-origin: left;
transform: scaleX(1.0);
}
.link, .button {
font-family: sans-serif;
@@ -92,24 +95,24 @@
}
.buttons-background {
background-color: #ffffff;
background-color: #1e2226;
width: 100%;
height: 42px;
}
body {
background-color: #ffffff;
background-color: #1e2226;
}
.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 );
background: rgba(36,41,46,1);
background: -moz-linear-gradient(-45deg, rgba(36,41,46,1) 0%, rgba(36,41,46,1) 49%, rgba(38,43,49,1) 50%, rgba(38,43,49,1) 100%);
background: -webkit-gradient(left top, right bottom, color-stop(0%, rgba(36,41,46,1)), color-stop(49%, rgba(36,41,46,1)), color-stop(50%, rgba(38,43,49,1)), color-stop(100%, rgba(38,43,49,1)));
background: -webkit-linear-gradient(-45deg, rgba(36,41,46,1) 0%, rgba(36,41,46,1) 49%, rgba(38,43,49,1) 50%, rgba(38,43,49,1) 100%);
background: -o-linear-gradient(-45deg, rgba(36,41,46,1) 0%, rgba(36,41,46,1) 49%, rgba(38,43,49,1) 50%, rgba(38,43,49,1) 100%);
background: -ms-linear-gradient(-45deg, rgba(36,41,46,1) 0%, rgba(36,41,46,1) 49%, rgba(38,43,49,1) 50%, rgba(38,43,49,1) 100%);
background: linear-gradient(135deg, rgba(36,41,46,1) 0%, rgba(36,41,46,1) 49%, rgba(38,43,49,1) 50%, rgba(38,43,49,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#24292e', endColorstr='#262b31', GradientType=1 );
}
.canvas-app-canvas {
@@ -121,98 +124,35 @@
</head>
<body>
<div id="app-container" class="canvas-app-container">
<div id="running-from-file-warning" style="display: none; margin: 3em;">
<h1>Running from local file ⚠️</h1>
<p>It seems like you have opened this file by double-clicking on it. In order to test your build in a browser <b>you need to load this file from a web server</b>. You can either upload this file and the rest of the files from a Defold HTML5 bundle to a web hosting service OR host them using a local web server on your home network.</p>
<p><a href="https://defold.com/manuals/html5/#testing-html5-build" target="_blank">Learn more about running a local web server in the Defold HTML5 manual</a>.</p>
</div>
<div id="webgl-not-supported" style="display: none; margin: 3em;">
<h1>WebGL not supported ⚠️</h1>
<p>WebGL is not supported by your browser - visit <a href="https://get.webgl.org/">https://get.webgl.org/</a> to learn more.</p>
</div>
<div id="canvas-container" class="canvas-app-canvas-container">
<canvas id="canvas" class="canvas-app-canvas" tabindex="1" width="600" height="900"></canvas>
<canvas id="canvas" class="canvas-app-canvas" tabindex="1" width="1920" height="1080"></canvas>
</div>
<div class="buttons-background">
</div>
</div>
<!-- -->
<script id='engine-loader' type='text/javascript' src="dmloader.js"></script>
<!-- -->
<script id='engine-setup' type='text/javascript'>
var extra_params = {
archive_location_filter: function( path ) {
return ("archive" + path + "");
},
engine_arguments: ["--verify-graphics-calls=false",],
custom_heap_size: 67108864,
full_screen_container: "#canvas-container",
disable_context_menu: true
}
Module['INITIAL_MEMORY'] = extra_params.custom_heap_size;
Module['onRuntimeInitialized'] = function() {
Module.runApp("canvas", extra_params);
};
Module["locateFile"] = function(path, scriptDirectory)
{
// dmengine*.wasm is hardcoded in the built JS loader for WASM,
// we need to replace it here with the correct project name.
if (path == "dmengine.wasm" || path == "dmengine_release.wasm" || path == "dmengine_headless.wasm") {
path = "druid.wasm";
}
return scriptDirectory + path;
};
var is_iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
var buttonHeight = 0;
var prevInnerWidth = -1;
var prevInnerHeight = -1;
function resize_game_canvas() {
// Hack for iOS when exit from Fullscreen mode
if (is_iOS) {
window.scrollTo(0, 0);
}
var app_container = document.getElementById('app-container');
var game_canvas = document.getElementById('canvas');
var innerWidth = window.innerWidth;
var innerHeight = window.innerHeight - buttonHeight;
if (prevInnerWidth == innerWidth && prevInnerHeight == innerHeight)
{
return;
}
prevInnerWidth = innerWidth;
prevInnerHeight = innerHeight;
var width = 600;
var height = 900;
var targetRatio = width / height;
var actualRatio = innerWidth / innerHeight;
//Fit
if (actualRatio > targetRatio) {
width = innerHeight * targetRatio;
height = innerHeight;
app_container.style.marginLeft = ((innerWidth - width) / 2) + "px";
app_container.style.marginTop = "0px";
}
else {
width = innerWidth;
height = innerWidth / targetRatio;
app_container.style.marginLeft = "0px";
app_container.style.marginTop = ((innerHeight - height) / 2) + "px";
}
app_container.style.width = width + "px";
app_container.style.height = height + buttonHeight + "px";
game_canvas.width = width;
game_canvas.height = height;
}
resize_game_canvas();
window.addEventListener('resize', resize_game_canvas, false);
window.addEventListener('orientationchange', resize_game_canvas, false);
window.addEventListener('focus', resize_game_canvas, false);
</script>
<script id='engine-start' type='text/javascript'>
EngineLoader.load("canvas", "druid");
var runningFromFileWarning = document.getElementById("running-from-file-warning");
if (window.location.href.startsWith("file://")) {
runningFromFileWarning.style.display = "block";
}
else {
EngineLoader.load("canvas", "druid");
runningFromFileWarning.parentNode.removeChild(runningFromFileWarning);
}
</script>
</body>
</html>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -38,22 +38,21 @@
<li><a href="modules/Hover.html">Hover</a></li>
<li><a href="modules/Scroll.html">Scroll</a></li>
<li><a href="modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="modules/Swipe.html">Swipe</a></li>
<li><a href="modules/Text.html">Text</a></li>
<li><a href="modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="modules/PinKnob.html">PinKnob</a></li>
<li><a href="modules/RichInput.html">RichInput</a></li>
<li><a href="modules/druid.html">druid</a></li>
<li><a href="modules/RichText.html">RichText</a></li>
<li><a href="modules/Druid.html">Druid</a></li>
<li><a href="modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="modules/Checkbox.html">Checkbox</a></li>
<li><a href="modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="modules/DataList.html">DataList</a></li>
<li><a href="modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="modules/Hotkey.html">Hotkey</a></li>
<li><a href="modules/Input.html">Input</a></li>
<li><a href="modules/LangText.html">LangText</a></li>
<li><a href="modules/Layout.html">Layout</a></li>
<li><a href="modules/Progress.html">Progress</a></li>
<li><a href="modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="modules/Slider.html">Slider</a></li>
<li><a href="modules/Swipe.html">Swipe</a></li>
<li><a href="modules/Timer.html">Timer</a></li>
<li><a href="modules/Helper.html">Helper</a></li>
<li><a href="modules/DruidInstance.html">DruidInstance</a></li>
@@ -64,21 +63,21 @@
<div id="content">
<h2>Documentation for Druid Library</h2>
<h2>Documentation for Druid Framework</h2>
<h2>Modules</h2>
<table class="module_list">
<tr>
<td class="name" nowrap><a href="modules/BackHandler.html">BackHandler</a></td>
<td class="summary">Component to handle back key (android, backspace)</td>
<td class="summary">Component with event on back and backspace button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Blocker.html">Blocker</a></td>
<td class="summary">Component to block input on specify zone by node</td>
<td class="summary">Component to consume input in special zone defined by GUI node.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Button.html">Button</a></td>
<td class="summary">Component to handle basic GUI button</td>
<td class="summary">Druid Component for Handling User Click Interactions: Click, Long Click, Double Click, and More.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Drag.html">Drag</a></td>
@@ -94,43 +93,34 @@
</tr>
<tr>
<td class="name" nowrap><a href="modules/StaticGrid.html">StaticGrid</a></td>
<td class="summary">Component to handle placing components by row and columns.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Swipe.html">Swipe</a></td>
<td class="summary">Component to handle swipe gestures on node.</td>
<td class="summary">Component to handle component's position by row and columns.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Text.html">Text</a></td>
<td class="summary">Component to handle all GUI texts.</td>
<td class="summary">Component for Wrapping GUI Text Nodes: Druid Text
<p> ## Overview ##
<p> Druid Text is a component that provides various adjustment modes for text nodes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/BaseComponent.html">BaseComponent</a></td>
<td class="summary">Basic class for all Druid components.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/PinKnob.html">PinKnob</a></td>
<td class="summary">Druid pin knob custom component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/RichInput.html">RichInput</a></td>
<td class="summary">Druid Rich Input custom component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/druid.html">druid</a></td>
<td class="summary">Druid UI Library.</td>
<td class="name" nowrap><a href="modules/RichText.html">RichText</a></td>
<td class="summary">Druid Rich Text Custom Component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Druid.html">Druid</a></td>
<td class="summary">Druid UI Component Framework.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/DruidEvent.html">DruidEvent</a></td>
<td class="summary">Druid lua event library</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Checkbox.html">Checkbox</a></td>
<td class="summary">Druid checkbox component</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/CheckboxGroup.html">CheckboxGroup</a></td>
<td class="summary">Checkbox group module</td>
<td class="summary">Druid Event Module
<p> The Event module provides a simple class for handling callbacks.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/DataList.html">DataList</a></td>
@@ -140,38 +130,48 @@
<td class="name" nowrap><a href="modules/DynamicGrid.html">DynamicGrid</a></td>
<td class="summary">Component to handle placing components in row</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Hotkey.html">Hotkey</a></td>
<td class="summary">Druid hotkey component</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Input.html">Input</a></td>
<td class="summary">Druid input text component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/LangText.html">LangText</a></td>
<td class="summary">Component to handle all GUI texts
Good working with localization system</td>
<td class="summary">Component to wrap over GUI Text nodes with localization helpers
<p> <b># Overview #</b>
<p> • The initialization of druid.set_text_function is required to enable localization
using the localization ID.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Layout.html">Layout</a></td>
<td class="summary">Layout management on node</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Progress.html">Progress</a></td>
<td class="summary">Basic progress bar component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/RadioGroup.html">RadioGroup</a></td>
<td class="summary">Radio group module</td>
<td class="summary">Druid component to handle the progress bars.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Slider.html">Slider</a></td>
<td class="summary">Druid slider component</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Swipe.html">Swipe</a></td>
<td class="summary">Component to handle swipe gestures on node.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Timer.html">Timer</a></td>
<td class="summary">Component to handle GUI timers.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/Helper.html">Helper</a></td>
<td class="summary">Druid helper module for gui layouts</td>
<td class="summary">Helper module with various usefull GUI functions.</td>
</tr>
<tr>
<td class="name" nowrap><a href="modules/DruidInstance.html">DruidInstance</a></td>
<td class="summary">Instance of Druid.</td>
<td class="summary">Druid Instance which you use for component creation.</td>
</tr>
</table>

View File

@@ -195,7 +195,7 @@ table.index td { text-align: left; vertical-align: top; }
margin-left: 14em;
padding: 1em;
padding-left: 2em;
width: 700px;
width: 900px;
border-left: 2px solid #cccccc;
// border-right: 2px solid #cccccc;
background-color: #ffffff;

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -32,7 +32,6 @@
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Fields">Fields</a></li>
</ul>
@@ -43,28 +42,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -72,30 +70,33 @@
<div id="content">
<h1>Module <code>BackHandler</code></h1>
<p>Component to handle back key (android, backspace)</p>
<p></p>
<p>Component with event on back and backspace button.</p>
<p>
<b># Overview #</b>
<p> Back Handler is recommended to put in every game window to close it
or in main screen to call settings window.
<p> <b># Notes #</b>
<p> • Back Handler inheritance <a href="../modules/BaseComponent.html#">BaseComponent</a>, you can use all of its methods in addition to those described here.
<p> • Back Handler react on release action ACTION_BACK or ACTION_BACKSPACE</p>
<h3>Usage:</h3>
<ul>
<pre class="example">local callback = function(self, params) ... end
local params = {}
local back_handler = self.druid:new_back_handler(callback, [params])
</pre>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, callback[, params])</a></td>
<td class="summary">Component init function</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_input">on_input(self, action_id, action)</a></td>
<td class="summary">Input handler for component</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#on_back">on_back</a></td>
<td class="summary">On back handler callback(self, params)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a> Event on back handler action.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#params">params</a></td>
<td class="summary">Params to back callback</td>
<td class="summary">Custom args to pass in the callback</td>
</tr>
</table>
@@ -103,69 +104,6 @@
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "init"></a>
<strong>init(self, callback[, params])</strong>
</dt>
<dd>
Component init function
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">BackHandler</span></span>
<a href="../modules/BackHandler.html#">BackHandler</a>
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">callback</span></span>
On back button
</li>
<li><span class="parameter">params</span>
<span class="types"><span class="type">any</span></span>
Callback argument
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "on_input"></a>
<strong>on_input(self, action_id, action)</strong>
</dt>
<dd>
Input handler for component
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">BackHandler</span></span>
<a href="../modules/BackHandler.html#">BackHandler</a>
</li>
<li><span class="parameter">action_id</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
on_input action id
</li>
<li><span class="parameter">action</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
on_input action
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
@@ -174,7 +112,8 @@
<strong>on_back</strong>
</dt>
<dd>
On back handler callback(self, params)
The <a href="../modules/DruidEvent.html#">DruidEvent</a> Event on back handler action.
<p> Trigger on input action ACTION_BACK or ACTION_BACKSPACE
<ul>
@@ -187,6 +126,11 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Subscribe additional callbacks:
</span>back_handler.on_back:subscribe(callback)</pre>
</ul>
</dd>
<dt>
@@ -194,12 +138,12 @@
<strong>params</strong>
</dt>
<dd>
Params to back callback
Custom args to pass in the callback
<ul>
<li><span class="parameter">params</span>
<span class="types"><span class="type">any</span></span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
</li>
</ul>
@@ -207,6 +151,11 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Replace params on runtime:
</span>back_handler.params = { ... }</pre>
</ul>
</dd>
</dl>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -33,7 +33,6 @@
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Fields">Fields</a></li>
</ul>
@@ -43,28 +42,27 @@
<li><strong>BaseComponent</strong></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -74,22 +72,38 @@
<h1>Module <code>BaseComponent</code></h1>
<p>Basic class for all Druid components.</p>
<p>
To create you component, use `component.create`</p>
To create you custom component, use static function `component.create`</p>
<h3>Usage:</h3>
<ul>
<pre class="example">-- Create your component:
local component = require(&quot;druid.component&quot;)
local AwesomeComponent = component.create(&quot;awesome_component&quot;)
function AwesomeComponent:init(template, nodes)
self:set_template(template)
self:set_nodes(nodes)
self.druid = self:get_druid()
end
return AwesomeComponent
</pre>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#get_childrens">get_childrens(self)</a></td>
<td class="summary">Return all children components, recursive (protected)</td>
<td class="summary">Return all children components, recursive</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_context">get_context(self)</a></td>
<td class="summary">Get current component context (protected)</td>
<td class="summary">Context used as first arg in all Druid events</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_druid">get_druid(self)</a></td>
<td class="summary">Return druid with context of calling component (protected).</td>
<td class="name" nowrap><a href="#get_druid">get_druid(self, template, nodes)</a></td>
<td class="summary">Get Druid instance for inner component creation.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_input_priority">get_input_priority(self)</a></td>
@@ -101,11 +115,11 @@
</tr>
<tr>
<td class="name" nowrap><a href="#get_node">get_node(self, node_or_name)</a></td>
<td class="summary">Get node for component by name.</td>
<td class="summary">Get component node by name.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_parent_component">get_parent_component(self)</a></td>
<td class="summary">Return the parent for current component (protected)</td>
<td class="summary">Return the parent component if exist</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_parent_name">get_parent_name(self)</a></td>
@@ -113,51 +127,35 @@
</tr>
<tr>
<td class="name" nowrap><a href="#get_template">get_template(self)</a></td>
<td class="summary">Get current component template name (protected)</td>
<td class="summary">Get current component template name.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_uid">get_uid(self)</a></td>
<td class="summary">Return component uid (protected).</td>
</tr>
<tr>
<td class="name" nowrap><a href="#log_message">log_message(self, message, context)</a></td>
<td class="summary">Print log information if debug mode is enabled (protected)</td>
<td class="summary">Return component UID.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#reset_input_priority">reset_input_priority(self)</a></td>
<td class="summary">Reset component input priority to default value</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_debug">set_debug(self, is_debug)</a></td>
<td class="summary">Set debug logs for component enabled or disabled</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_input_enabled">set_input_enabled(self, state)</a></td>
<td class="summary">Set component input state.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_input_priority">set_input_priority(self, value)</a></td>
<td class="name" nowrap><a href="#set_input_priority">set_input_priority(self, value, is_temporary)</a></td>
<td class="summary">Set component input priority</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_nodes">set_nodes(self, nodes)</a></td>
<td class="summary">Set current component nodes (protected)</td>
<td class="summary">Set current component nodes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_style">set_style(self, druid_style)</a></td>
<td class="summary">Set current component style table (protected).</td>
<td class="summary">Set current component style table.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_template">set_template(self, template)</a></td>
<td class="summary">Set current component template name (protected)
It will check parent template name to build full template name</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#ON_INPUT">ON_INPUT</a></td>
<td class="summary">Component Interests</td>
<td class="summary">Set component template name.</td>
</tr>
</table>
@@ -173,7 +171,7 @@
<strong>get_childrens(self)</strong>
</dt>
<dd>
Return all children components, recursive (protected)
Return all children components, recursive
<h3>Parameters:</h3>
@@ -200,7 +198,7 @@
<strong>get_context(self)</strong>
</dt>
<dd>
Get current component context (protected)
Context used as first arg in all Druid events Context is usually self of gui_script.
<h3>Parameters:</h3>
@@ -224,11 +222,10 @@
</dd>
<dt>
<a name = "get_druid"></a>
<strong>get_druid(self)</strong>
<strong>get_druid(self, template, nodes)</strong>
</dt>
<dd>
Return druid with context of calling component (protected).
Use it to create component inside of other components.
Get Druid instance for inner component creation.
<h3>Parameters:</h3>
@@ -237,12 +234,20 @@
<span class="types"><span class="type">BaseComponent</span></span>
<a href="../modules/BaseComponent.html#">BaseComponent</a>
</li>
<li><span class="parameter">template</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
The template name
</li>
<li><span class="parameter">nodes</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">nil</span></span>
The nodes table
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Druid</span></span>
<span class="types"><span class="type">DruidInstance</span></span>
Druid instance with component context
</ol>
@@ -309,9 +314,9 @@
<strong>get_node(self, node_or_name)</strong>
</dt>
<dd>
Get node for component by name.
If component has nodes, node_or_name should be string
It auto pick node by template name or from nodes by clone_tree
Get component node by name.
<p> If component has nodes, node_or_name should be string
It autopick node by template name or from nodes by gui.clone_tree
if they was setup via component:set_nodes, component:set_template.
If node is not found, the exception will fired
@@ -344,7 +349,7 @@
<strong>get_parent_component(self)</strong>
</dt>
<dd>
Return the parent for current component (protected)
Return the parent component if exist
<h3>Parameters:</h3>
@@ -398,7 +403,7 @@
<strong>get_template(self)</strong>
</dt>
<dd>
Get current component template name (protected)
Get current component template name.
<h3>Parameters:</h3>
@@ -425,8 +430,8 @@
<strong>get_uid(self)</strong>
</dt>
<dd>
Return component uid (protected).
UID generated in component creation order
Return component UID.
<p> UID generated in component creation order.
<h3>Parameters:</h3>
@@ -447,35 +452,6 @@
</dd>
<dt>
<a name = "log_message"></a>
<strong>log_message(self, message, context)</strong>
</dt>
<dd>
Print log information if debug mode is enabled (protected)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">BaseComponent</span></span>
<a href="../modules/BaseComponent.html#">BaseComponent</a>
</li>
<li><span class="parameter">message</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
<li><span class="parameter">context</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "reset_input_priority"></a>
@@ -503,31 +479,6 @@
</dd>
<dt>
<a name = "set_debug"></a>
<strong>set_debug(self, is_debug)</strong>
</dt>
<dd>
Set debug logs for component enabled or disabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">BaseComponent</span></span>
<a href="../modules/BaseComponent.html#">BaseComponent</a>
</li>
<li><span class="parameter">is_debug</span>
<span class="types"><span class="type">bool</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "set_input_enabled"></a>
@@ -535,7 +486,7 @@
</dt>
<dd>
Set component input state. By default it enabled
You can disable any input of component by this function
<p> If input is disabled, the component will not receive input events
<h3>Parameters:</h3>
@@ -545,7 +496,7 @@
<a href="../modules/BaseComponent.html#">BaseComponent</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
The component input state
</li>
</ul>
@@ -563,10 +514,10 @@
</dd>
<dt>
<a name = "set_input_priority"></a>
<strong>set_input_priority(self, value)</strong>
<strong>set_input_priority(self, value, is_temporary)</strong>
</dt>
<dd>
Set component input priority
Set component input priority Default value: 10
<h3>Parameters:</h3>
@@ -579,6 +530,10 @@
<span class="types"><span class="type">number</span></span>
The new input priority value
</li>
<li><span class="parameter">is_temporary</span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, the reset input priority will return to previous value
</li>
</ul>
<h3>Returns:</h3>
@@ -597,7 +552,8 @@
<strong>set_nodes(self, nodes)</strong>
</dt>
<dd>
Set current component nodes (protected)
Set current component nodes.
Use if your component nodes was cloned with `gui.clone_tree` and you got the node tree.
<h3>Parameters:</h3>
@@ -621,6 +577,12 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> nodes = gui.clone_tree(self.prefab)
... In your component:
self:set_nodes(nodes)</pre>
</ul>
</dd>
<dt>
@@ -628,8 +590,8 @@
<strong>set_style(self, druid_style)</strong>
</dt>
<dd>
Set current component style table (protected).
Invoke `on_style_change` on component, if exist. BaseComponent should handle
Set current component style table.
<p> Invoke `on_style_change` on component, if exist. Component should handle
their style changing and store all style params
@@ -640,11 +602,17 @@
<a href="../modules/BaseComponent.html#">BaseComponent</a>
</li>
<li><span class="parameter">druid_style</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">nil</span></span>
Druid style module
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">BaseComponent</span></span>
<a href="../modules/BaseComponent.html#">BaseComponent</a>
</ol>
@@ -655,8 +623,9 @@
<strong>set_template(self, template)</strong>
</dt>
<dd>
Set current component template name (protected)
It will check parent template name to build full template name
Set component template name.
<p> Use on all your custom components with GUI layouts used as templates.
It will check parent template name to build full template name in self:get_node()
<h3>Parameters:</h3>
@@ -681,24 +650,6 @@
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "ON_INPUT"></a>
<strong>ON_INPUT</strong>
</dt>
<dd>
Component Interests
</dd>
</dl>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><strong>Blocker</strong></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -72,30 +71,42 @@
<div id="content">
<h1>Module <code>Blocker</code></h1>
<p>Component to block input on specify zone by node</p>
<p></p>
<p>Component to consume input in special zone defined by GUI node.</p>
<p>
<b># Overview #</b>
<p> <b># Notes #</b>
<p> Blocker consume input if `gui.pick_node` works on it.
<p> • Blocker inheritance <a href="../modules/BaseComponent.html#">BaseComponent</a>, you can use all of its methods in addition to those described here.
<p> • Blocker initial enabled state is `gui.is_enabled(node, true)`
<p> • The Blocker node should be enabled to capture the input</p>
<h3>Usage:</h3>
<ul>
<pre class="example">local node = gui.get_node(&quot;blocker_node&quot;)
local blocker = self.druid:new_blocker(node)
</pre>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, node)</a></td>
<td class="summary">Component init function</td>
<td class="summary">The <a href="../modules/Blocker.html#">Blocker</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_enabled">is_enabled(self)</a></td>
<td class="summary">Return blocked enabled state</td>
<td class="summary">Return blocker enabled state</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_enabled">set_enabled(self, state)</a></td>
<td class="summary">Set enabled blocker component state</td>
<td class="summary">Set enabled blocker component state.</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Trigger node</td>
<td class="summary">Blocker node</td>
</tr>
</table>
@@ -111,7 +122,7 @@
<strong>init(self, node)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Blocker.html#">Blocker</a> constructor
<h3>Parameters:</h3>
@@ -136,7 +147,7 @@
<strong>is_enabled(self)</strong>
</dt>
<dd>
Return blocked enabled state
Return blocker enabled state
<h3>Parameters:</h3>
@@ -150,8 +161,8 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
True, if blocker is enabled
<span class="types"><span class="type">boolean</span></span>
@True, if blocker is enabled
</ol>
@@ -163,7 +174,8 @@
<strong>set_enabled(self, state)</strong>
</dt>
<dd>
Set enabled blocker component state
Set enabled blocker component state.
<p> Don't change node enabled state itself.
<h3>Parameters:</h3>
@@ -173,7 +185,7 @@
<a href="../modules/Blocker.html#">Blocker</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Enabled state
</li>
</ul>
@@ -192,7 +204,7 @@
<strong>node</strong>
</dt>
<dd>
Trigger node
Blocker node
<ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><strong>Button</strong></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,39 +72,66 @@
<div id="content">
<h1>Module <code>Button</code></h1>
<p>Component to handle basic GUI button</p>
<p></p>
<p>Druid Component for Handling User Click Interactions: Click, Long Click, Double Click, and More.</p>
<p>
<p> <b># Overview #</b>
<p> This component provides a versatile solution for handling user click interactions.
It allows you to make any GUI node clickable and define various callbacks for different types of clicks.
<p> <b># Notes #</b>
<p> • The click callback will not trigger if the cursor moves outside the node's
area between the pressed and released states.
<p> • If a button has a double click event subscriber and the double click event is triggered,
the regular click callback will not be triggered.
<p> • Buttons can be triggered using a keyboard key by calling the button:set_key_trigger method.
<p> • To animate a small icon on a big button panel, you can use an animation node.
The trigger node name should be set as "big panel," and the animation node should be set as "small icon."
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_buttons" target="_blank"><b>Example Link</b></a></p>
<h3>Usage:</h3>
<ul>
<pre class="example">local function on_button_click(self, args, button)
print(&quot;Button has clicked with params: &quot; .. args)
print(&quot;Also the button component is passed in callback params&quot;)
end
local custom_args = &quot;Any variable to pass inside callback&quot;
local button = self.druid:new_button(&quot;button_name&quot;, on_button_click, custom_args)
</pre>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#get_key_trigger">get_key_trigger(self)</a></td>
<td class="summary">Get key-code to trigger this button</td>
<td class="summary">Get current key name to trigger this button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, node, callback[, params[, anim_node]])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, callback, custom_args, anim_node)</a></td>
<td class="summary">The <a href="../modules/Button.html#">Button</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_enabled">is_enabled(self)</a></td>
<td class="summary">Return button enabled state</td>
<td class="summary">Get button enabled state.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_check_function">set_check_function(self[, check_function[, failure_callback]])</a></td>
<td class="name" nowrap><a href="#set_check_function">set_check_function(self, check_function, failure_callback)</a></td>
<td class="summary">Set function for additional check for button click availability</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_click_zone">set_click_zone(self, zone)</a></td>
<td class="summary">Strict button click area.</td>
<td class="summary">Set additional button click area.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_enabled">set_enabled(self, state)</a></td>
<td class="summary">Set enabled button component state</td>
<td class="summary">Set button enabled state.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_key_trigger">set_key_trigger(self, key)</a></td>
<td class="summary">Set key-code to trigger this button</td>
<td class="summary">Set key name to trigger this button by keyboard.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_web_user_interaction">set_web_user_interaction(self, is_web_mode)</a></td>
<td class="summary">Set Button mode to work inside user HTML5 interaction event.</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
@@ -119,63 +145,55 @@
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#anim_node">anim_node</a></td>
<td class="summary">Animation node</td>
<td class="summary">Button animation node.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#click_zone">click_zone</a></td>
<td class="summary">Restriction zone</td>
</tr>
<tr>
<td class="name" nowrap><a href="#hash">hash</a></td>
<td class="summary">The hash of trigger node</td>
<td class="summary">Additional button click area, defined by another GUI node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#hover">hover</a></td>
<td class="summary">Druid hover logic component</td>
<td class="summary">The <a href="../modules/Hover.html#">Hover</a>: Button Hover component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Trigger node</td>
<td class="summary">Button trigger node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#node_id">node_id</a></td>
<td class="summary">The GUI node id from button node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_click">on_click</a></td>
<td class="summary">On release button callback(self, params, button_instance)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on successful release action over button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_click_outside">on_click_outside</a></td>
<td class="summary">On click outside of button(self, params, button_instance)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event calls if click event was outside of button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_double_click">on_double_click</a></td>
<td class="summary">On double tap button callback(self, params, button_instance, click_amount)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on double tap action over button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_hold_callback">on_hold_callback</a></td>
<td class="summary">On button hold before long_click callback(self, params, button_instance, time)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event calls every frame before on_long_click event.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_long_click">on_long_click</a></td>
<td class="summary">On long tap button callback(self, params, button_instance, time)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on long tap action over button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_pressed">on_pressed</a></td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event triggered if button was pressed by user.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_repeated_click">on_repeated_click</a></td>
<td class="summary">On repeated action button callback(self, params, button_instance, click_amount)</td>
<td class="summary">The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on repeated action over button.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#params">params</a></td>
<td class="summary">Params to click callbacks</td>
</tr>
<tr>
<td class="name" nowrap><a href="#pos">pos</a></td>
<td class="summary">Initial pos of anim_node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#start_pos">start_pos</a></td>
<td class="summary">Initial pos of anim_node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#start_scale">start_scale</a></td>
<td class="summary">Initial scale of anim_node</td>
<td class="summary">Custom args for any Button event.</td>
</tr>
</table>
@@ -191,7 +209,7 @@
<strong>get_key_trigger(self)</strong>
</dt>
<dd>
Get key-code to trigger this button
Get current key name to trigger this button.
<h3>Parameters:</h3>
@@ -205,20 +223,24 @@
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../modules/Button.html#hash">hash</a></span>
The action_id of the key
<span class="types"><span class="type">hash</span></span>
The action_id of the input key
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> key_hash = button:get_key_trigger()</pre>
</ul>
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, node, callback[, params[, anim_node]])</strong>
<strong>init(self, node, callback, custom_args, anim_node)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Button.html#">Button</a> constructor
<h3>Parameters:</h3>
@@ -228,22 +250,20 @@
<a href="../modules/Button.html#">Button</a>
</li>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a></span>
Gui node
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <a class="type" href="../modules/Button.html#node">node</a></span>
The node_id or gui.get_node(node_id)
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
Button callback
On click button callback
</li>
<li><span class="parameter">params</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Button callback params
(<em>optional</em>)
<li><span class="parameter">custom_args</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
Button events custom arguments
</li>
<li><span class="parameter">anim_node</span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a></span>
Button anim node (node, if not provided)
(<em>optional</em>)
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a>, <a class="type" href="../modules/Button.html#node">node</a> or <span class="type">nil</span></span>
Node to animate instead of trigger node.
</li>
</ul>
@@ -257,7 +277,8 @@
<strong>is_enabled(self)</strong>
</dt>
<dd>
Return button enabled state
Get button enabled state.
<p> By default all Buttons is enabled on creating.
<h3>Parameters:</h3>
@@ -271,17 +292,21 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
True, if button is enabled
<span class="types"><span class="type">boolean</span></span>
@True, if button is enabled now, False overwise
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> is_enabled = button:is_enabled()</pre>
</ul>
</dd>
<dt>
<a name = "set_check_function"></a>
<strong>set_check_function(self[, check_function[, failure_callback]])</strong>
<strong>set_check_function(self, check_function, failure_callback)</strong>
</dt>
<dd>
Set function for additional check for button click availability
@@ -294,14 +319,12 @@
</li>
<li><span class="parameter">check_function</span>
<span class="types"><span class="type">function</span></span>
<span class="types"><span class="type">function</span> or <span class="type">nil</span></span>
Should return true or false. If true - button can be pressed.
(<em>optional</em>)
</li>
<li><span class="parameter">failure_callback</span>
<span class="types"><span class="type">function</span></span>
Function what will be called on button click, if check function return false
(<em>optional</em>)
<span class="types"><span class="type">function</span> or <span class="type">nil</span></span>
Function will be called on button click, if check function return false
</li>
</ul>
@@ -321,8 +344,9 @@
<strong>set_click_zone(self, zone)</strong>
</dt>
<dd>
Strict button click area. Useful for
no click events outside stencil node
Set additional button click area.
Useful to restrict click outside out stencil node or scrollable content.
<p> This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check
<h3>Parameters:</h3>
@@ -332,7 +356,7 @@
<a href="../modules/Button.html#">Button</a>
</li>
<li><span class="parameter">zone</span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a></span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a>, <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Gui node
</li>
</ul>
@@ -346,6 +370,10 @@
<h3>Usage:</h3>
<ul>
<pre class="example">button:set_click_zone(<span class="string">"stencil_node"</span>)</pre>
</ul>
</dd>
<dt>
@@ -353,7 +381,9 @@
<strong>set_enabled(self, state)</strong>
</dt>
<dd>
Set enabled button component state
Set button enabled state.
The style.on_set_enabled will be triggered.
Disabled button is not clickable.
<h3>Parameters:</h3>
@@ -363,7 +393,7 @@
<a href="../modules/Button.html#">Button</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Enabled state
</li>
</ul>
@@ -377,6 +407,11 @@
<h3>Usage:</h3>
<ul>
<pre class="example">button:set_enabled(<span class="keyword">false</span>)
button:set_enabled(<span class="keyword">true</span>)</pre>
</ul>
</dd>
<dt>
@@ -384,7 +419,7 @@
<strong>set_key_trigger(self, key)</strong>
</dt>
<dd>
Set key-code to trigger this button
Set key name to trigger this button by keyboard.
<h3>Parameters:</h3>
@@ -394,8 +429,8 @@
<a href="../modules/Button.html#">Button</a>
</li>
<li><span class="parameter">key</span>
<span class="types"><a class="type" href="../modules/Button.html#hash">hash</a></span>
The action_id of the key
<span class="types"><span class="type">hash</span> or <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The action_id of the input key
</li>
</ul>
@@ -408,6 +443,48 @@
<h3>Usage:</h3>
<ul>
<pre class="example">button:set_key_trigger(<span class="string">"key_space"</span>)</pre>
</ul>
</dd>
<dt>
<a name = "set_web_user_interaction"></a>
<strong>set_web_user_interaction(self, is_web_mode)</strong>
</dt>
<dd>
Set Button mode to work inside user HTML5 interaction event.
<p> It's required to make protected things like copy & paste text, show mobile keyboard, etc
The HTML5 button's doesn't call any events except on_click event.
<p> If the game is not HTML, html mode will be not enabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Button</span></span>
</li>
<li><span class="parameter">is_web_mode</span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true - button will be called inside html5 callback
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Button</span></span>
Current button instance
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">button:set_web_user_interaction(<span class="keyword">true</span>)</pre>
</ul>
</dd>
</dl>
@@ -420,46 +497,43 @@
</dt>
<dd>
Component style params.
You can override this component styles params in druid styles table
You can override this component styles params in Druid styles table
or create your own style
<h3>Fields:</h3>
<ul>
<li><span class="parameter">LONGTAP_TIME</span>
<span class="types"><span class="type">number</span></span>
Minimum time to trigger on_hold_callback
(<em>default</em> 0.4)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Minimum time to trigger on_hold_callback. Default: 0.4
</li>
<li><span class="parameter">AUTOHOLD_TRIGGER</span>
<span class="types"><span class="type">number</span></span>
Maximum hold time to trigger button release while holding
(<em>default</em> 0.8)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Maximum hold time to trigger button release while holding. Default: 0.8
</li>
<li><span class="parameter">DOUBLETAP_TIME</span>
<span class="types"><span class="type">number</span></span>
Time between double taps
(<em>default</em> 0.4)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Time between double taps. Default: 0.4
</li>
<li><span class="parameter">on_click</span>
<span class="types"><span class="type">function</span></span>
(self, node)
function(self, node)
</li>
<li><span class="parameter">on_click_disabled</span>
<span class="types"><span class="type">function</span></span>
(self, node)
function(self, node)
</li>
<li><span class="parameter">on_hover</span>
<span class="types"><span class="type">function</span></span>
(self, node, hover_state)
function(self, node, hover_state)
</li>
<li><span class="parameter">on_mouse_hover</span>
<span class="types"><span class="type">function</span></span>
(self, node, hover_state)
function(self, node, hover_state)
</li>
<li><span class="parameter">on_set_enabled</span>
<span class="types"><span class="type">function</span></span>
(self, node, enabled_state)
function(self, node, enabled_state)
</li>
</ul>
@@ -477,14 +551,15 @@
<strong>anim_node</strong>
</dt>
<dd>
Animation node
Button animation node.
In default case equals to clickable node.
<p> Usecase: You have the big clickable panel, but want to animate only one small icon on it.
<ul>
<li><span class="parameter">anim_node</span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a></span>
(<em>default</em> node)
<span class="types"><a class="type" href="../modules/Button.html#node">node</a> or <span class="type">nil</span></span>
Default node
</li>
</ul>
@@ -498,33 +573,12 @@
<strong>click_zone</strong>
</dt>
<dd>
Restriction zone
Additional button click area, defined by another GUI node
<ul>
<li><span class="parameter">click_zone</span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a></span>
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "hash"></a>
<strong>hash</strong>
</dt>
<dd>
The hash of trigger node
<ul>
<li><span class="parameter">hash</span>
<span class="types"><a class="type" href="../modules/Button.html#node">node_id</a></span>
<span class="types"><a class="type" href="../modules/Button.html#node">node</a> or <span class="type">nil</span></span>
</li>
</ul>
@@ -539,7 +593,7 @@
<strong>hover</strong>
</dt>
<dd>
Druid hover logic component
The <a href="../modules/Hover.html#">Hover</a>: Button Hover component
<ul>
@@ -559,7 +613,7 @@
<strong>node</strong>
</dt>
<dd>
Trigger node
Button trigger node
<ul>
@@ -573,13 +627,33 @@
</dd>
<dt>
<a name = "node_id"></a>
<strong>node_id</strong>
</dt>
<dd>
The GUI node id from button node
<ul>
<li><span class="parameter">node_id</span>
<span class="types"><span class="type">hash</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "on_click"></a>
<strong>on_click</strong>
</dt>
<dd>
On release button callback(self, params, button_instance)
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on successful release action over button.
<ul>
@@ -592,6 +666,13 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_click:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance)
<span class="global">print</span>(<span class="string">"On button click!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
@@ -599,7 +680,9 @@
<strong>on_click_outside</strong>
</dt>
<dd>
On click outside of button(self, params, button_instance)
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event calls if click event was outside of button.
<p> This event will be triggered for each button what was not clicked on user click action
<p> Usecase: Hide the popup when click outside
<ul>
@@ -612,6 +695,13 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_click_outside:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance)
<span class="global">print</span>(<span class="string">"On click Button outside!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
@@ -619,7 +709,9 @@
<strong>on_double_click</strong>
</dt>
<dd>
On double tap button callback(self, params, button_instance, click_amount)
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on double tap action over button.
<p> If secondary click was too fast after previous one, the double
click will be called instead usual click (if on_double_click subscriber exists)
<ul>
@@ -632,6 +724,13 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_double_click:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance, click_amount)
<span class="global">print</span>(<span class="string">"On double Button click!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
@@ -639,7 +738,9 @@
<strong>on_hold_callback</strong>
</dt>
<dd>
On button hold before long_click callback(self, params, button_instance, time)
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event calls every frame before on_long_click event.
<p> If long_click subscriber exists, the on_hold_callback will be called before long_click trigger.
<p> Usecase: Animate button progress of long tap
<ul>
@@ -652,6 +753,13 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_double_click:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance, time)
<span class="global">print</span>(<span class="string">"On hold Button callback!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
@@ -659,7 +767,9 @@
<strong>on_long_click</strong>
</dt>
<dd>
On long tap button callback(self, params, button_instance, time)
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on long tap action over button.
<p> This callback will be triggered if user pressed the button and hold the some amount of time.
The amount of time picked from button style param: LONGTAP_TIME
<ul>
@@ -672,6 +782,40 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_long_click:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance, hold_time)
<span class="global">print</span>(<span class="string">"On long Button click!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
<a name = "on_pressed"></a>
<strong>on_pressed</strong>
</dt>
<dd>
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event triggered if button was pressed by user.
<ul>
<li><span class="parameter">on_pressed</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_pressed:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance)
<span class="global">print</span>(<span class="string">"On Button pressed!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
@@ -679,7 +823,8 @@
<strong>on_repeated_click</strong>
</dt>
<dd>
On repeated action button callback(self, params, button_instance, click_amount)
The <a href="../modules/DruidEvent.html#">DruidEvent</a>: Event on repeated action over button.
<p> This callback will be triggered if user hold the button. The repeat rate pick from `input.repeat_interval` in game.project
<ul>
@@ -692,6 +837,13 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="comment">-- Custom args passed in Button constructor
</span>button.on_repeated_click:subscribe(<span class="keyword">function</span>(self, custom_args, button_instance, click_count)
<span class="global">print</span>(<span class="string">"On repeated Button click!"</span>)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
@@ -699,7 +851,7 @@
<strong>params</strong>
</dt>
<dd>
Params to click callbacks
Custom args for any Button event. Setup in Button constructor
<ul>
@@ -713,66 +865,6 @@
</dd>
<dt>
<a name = "pos"></a>
<strong>pos</strong>
</dt>
<dd>
Initial pos of anim_node
<ul>
<li><span class="parameter">pos</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "start_pos"></a>
<strong>start_pos</strong>
</dt>
<dd>
Initial pos of anim_node
<ul>
<li><span class="parameter">start_pos</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "start_scale"></a>
<strong>start_scale</strong>
</dt>
<dd>
Initial scale of anim_node
<ul>
<li><span class="parameter">start_scale</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
</dd>
</dl>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -48,24 +48,26 @@
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -74,7 +76,7 @@
<h1>Module <code>Checkbox</code></h1>
<p>Druid checkbox component</p>
<p></p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_checkboxes" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -84,8 +86,8 @@
<td class="summary">Return checkbox state</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, node, callback[, click_node=node[, initial_state=false]])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, callback, click_node, initial_state)</a></td>
<td class="summary">The <a href="../modules/Checkbox.html#">Checkbox</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_state">set_state(self, state, is_silent, is_instant)</a></td>
@@ -145,7 +147,7 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
Checkbox state
</ol>
@@ -155,10 +157,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, node, callback[, click_node=node[, initial_state=false]])</strong>
<strong>init(self, node, callback, click_node, initial_state)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Checkbox.html#">Checkbox</a> constructor
<h3>Parameters:</h3>
@@ -176,14 +178,12 @@
Checkbox callback
</li>
<li><span class="parameter">click_node</span>
<span class="types"><a class="type" href="../modules/Checkbox.html#node">node</a></span>
Trigger node, by default equals to node
(<em>default</em> node)
<span class="types"><a class="type" href="../modules/Checkbox.html#node">node</a> or <span class="type">nil</span></span>
Trigger node, by default equals to node. Default: node
</li>
<li><span class="parameter">initial_state</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
The initial state of checkbox, default - false
(<em>default</em> false)
</li>
</ul>
@@ -207,15 +207,15 @@
<a href="../modules/Checkbox.html#">Checkbox</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Checkbox state
</li>
<li><span class="parameter">is_silent</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Don't trigger on_change_state if true
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If instant checkbox change
</li>
</ul>
@@ -286,9 +286,8 @@
<ul>
<li><span class="parameter">click_node</span>
<span class="types"><a class="type" href="../modules/Checkbox.html#node">node</a></span>
<span class="types"><a class="type" href="../modules/Checkbox.html#node">node</a> or <span class="type">nil</span></span>
(<em>default</em> node)
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -47,24 +47,26 @@
<li><strong>CheckboxGroup</strong></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,7 +75,7 @@
<h1>Module <code>CheckboxGroup</code></h1>
<p>Checkbox group module</p>
<p></p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_checkboxes" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -83,8 +85,8 @@
<td class="summary">Return checkbox group state</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, nodes, callback[, click_nodes=node])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, nodes, callback, click_nodes)</a></td>
<td class="summary">The <a href="../modules/CheckboxGroup.html#">CheckboxGroup</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_state">set_state(self, indexes, is_instant)</a></td>
@@ -129,7 +131,7 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool[]</span></span>
<span class="types"><span class="type">boolean[]</span></span>
Array if checkboxes state
</ol>
@@ -139,10 +141,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, nodes, callback[, click_nodes=node])</strong>
<strong>init(self, nodes, callback, click_nodes)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/CheckboxGroup.html#">CheckboxGroup</a> constructor
<h3>Parameters:</h3>
@@ -160,9 +162,8 @@
Checkbox callback
</li>
<li><span class="parameter">click_nodes</span>
<span class="types"><span class="type">node[]</span></span>
<span class="types"><span class="type">node[]</span> or <span class="type">nil</span></span>
Array of trigger nodes, by default equals to nodes
(<em>default</em> node)
</li>
</ul>
@@ -186,11 +187,11 @@
<a href="../modules/CheckboxGroup.html#">CheckboxGroup</a>
</li>
<li><span class="parameter">indexes</span>
<span class="types"><span class="type">bool[]</span></span>
<span class="types"><span class="type">boolean[]</span></span>
Array of checkbox state
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If instant state change
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><strong>DataList</strong></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -74,40 +73,53 @@
<h1>Module <code>DataList</code></h1>
<p>Component to manage data for huge dataset in scroll.</p>
<p>
It requires Druid Scroll and Druid Grid (Static or Dynamic) components</p>
It requires Druid Scroll and Druid Grid (Static or Dynamic) components
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_data_list" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#add">add(self, data, index, shift_policy)</a></td>
<td class="summary">Add element to DataList.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#clear">clear(self)</a></td>
<td class="summary">Clear the DataList and refresh visuals</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_first_index">get_first_index(self)</a></td>
<td class="summary">Return first index from data.</td>
<td class="name" nowrap><a href="#get_created_components">get_created_components(self)</a></td>
<td class="summary">Return all currenly created components in DataList</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_created_nodes">get_created_nodes(self)</a></td>
<td class="summary">Return all currenly created nodes in DataList</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_data">get_data(self)</a></td>
<td class="summary">Return current data from DataList component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_index">get_index(self, data)</a></td>
<td class="summary">Return index for data value</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_last_index">get_last_index(self)</a></td>
<td class="summary">Return last index from data</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_length">get_length(self)</a></td>
<td class="summary">Return amount of data</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, scroll, grid, create_function)</a></td>
<td class="summary">Data list constructor</td>
<td class="summary">The <a href="../modules/DataList.html#">DataList</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_remove">on_remove(self)</a></td>
<td class="summary">Druid System on_remove function</td>
</tr>
<tr>
<td class="name" nowrap><a href="#remove">remove(self, index, shift_policy)</a></td>
<td class="summary">Remove element from DataList.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#remove_by_data">remove_by_data(self, data, shift_policy)</a></td>
<td class="summary">Remove element from DataList by data value.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#scroll_to_index">scroll_to_index(self, index)</a></td>
<td class="summary">Instant scroll to element with passed index</td>
</tr>
@@ -115,6 +127,10 @@
<td class="name" nowrap><a href="#set_data">set_data(self, data)</a></td>
<td class="summary">Set new data set for DataList component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_use_cache">set_use_cache(self, is_use_cache)</a></td>
<td class="summary">Set refresh function for DataList component</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
@@ -124,7 +140,15 @@
</tr>
<tr>
<td class="name" nowrap><a href="#last_index">last_index</a></td>
<td class="summary">The current visual last data index</td>
<td class="summary">The current last index of visual elements</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_element_add">on_element_add</a></td>
<td class="summary">On DataList visual element created Event callback(self, index, node, instance)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_element_remove">on_element_remove</a></td>
<td class="summary">On DataList visual element created Event callback(self, index)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_scroll_progress_change">on_scroll_progress_change</a></td>
@@ -140,7 +164,7 @@
</tr>
<tr>
<td class="name" nowrap><a href="#top_index">top_index</a></td>
<td class="summary">The current visual top data index</td>
<td class="summary">The current top index of visual elements</td>
</tr>
</table>
@@ -151,6 +175,39 @@
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "add"></a>
<strong>add(self, data, index, shift_policy)</strong>
</dt>
<dd>
Add element to DataList. Currenly untested
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
<li><span class="parameter">data</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
</li>
<li><span class="parameter">index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The constant from const.SHIFT.*
</li>
</ul>
</dd>
<dt>
<a name = "clear"></a>
<strong>clear(self)</strong>
@@ -173,11 +230,11 @@
</dd>
<dt>
<a name = "get_first_index"></a>
<strong>get_first_index(self)</strong>
<a name = "get_created_components"></a>
<strong>get_created_components(self)</strong>
</dt>
<dd>
Return first index from data. It not always equals to 1
Return all currenly created components in DataList
<h3>Parameters:</h3>
@@ -188,6 +245,66 @@
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.base_component[]</span></span>
List of created nodes
</ol>
</dd>
<dt>
<a name = "get_created_nodes"></a>
<strong>get_created_nodes(self)</strong>
</dt>
<dd>
Return all currenly created nodes in DataList
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">node[]</span></span>
List of created nodes
</ol>
</dd>
<dt>
<a name = "get_data"></a>
<strong>get_data(self)</strong>
</dt>
<dd>
Return current data from DataList component
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
The current data array
</ol>
@@ -217,55 +334,13 @@
</dd>
<dt>
<a name = "get_last_index"></a>
<strong>get_last_index(self)</strong>
</dt>
<dd>
Return last index from data
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
</ul>
</dd>
<dt>
<a name = "get_length"></a>
<strong>get_length(self)</strong>
</dt>
<dd>
Return amount of data
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
</ul>
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, scroll, grid, create_function)</strong>
</dt>
<dd>
Data list constructor
The <a href="../modules/DataList.html#">DataList</a> constructor
<h3>Parameters:</h3>
@@ -279,7 +354,7 @@
The <a href="../modules/Scroll.html#">Scroll</a> instance for Data List component
</li>
<li><span class="parameter">grid</span>
<span class="types"><span class="type">StaticGrid</span> or <span class="type">DynamicGrid</span></span>
<span class="types"><span class="type">StaticGrid</span></span>
The <a href="../modules/StaticGrid.html#">StaticGrid</a> or <a href="../modules/DynamicGrid.html#">DynamicGrid</a> instance for Data List component
</li>
<li><span class="parameter">create_function</span>
@@ -313,6 +388,64 @@
</dd>
<dt>
<a name = "remove"></a>
<strong>remove(self, index, shift_policy)</strong>
</dt>
<dd>
Remove element from DataList. Currenly untested
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
<li><span class="parameter">index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The constant from const.SHIFT.*
</li>
</ul>
</dd>
<dt>
<a name = "remove_by_data"></a>
<strong>remove_by_data(self, data, shift_policy)</strong>
</dt>
<dd>
Remove element from DataList by data value. Currenly untested
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
<li><span class="parameter">data</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The constant from const.SHIFT.*
</li>
</ul>
</dd>
<dt>
<a name = "scroll_to_index"></a>
@@ -369,6 +502,37 @@
</dd>
<dt>
<a name = "set_use_cache"></a>
<strong>set_use_cache(self, is_use_cache)</strong>
</dt>
<dd>
Set refresh function for DataList component
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DataList</span></span>
<a href="../modules/DataList.html#">DataList</a>
</li>
<li><span class="parameter">is_use_cache</span>
<span class="types"><span class="type">boolean</span></span>
Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.data_list</span></span>
Current DataList instance
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
@@ -384,7 +548,7 @@
<ul>
<li><span class="parameter">grid</span>
<span class="types"><span class="type">StaticGrid</span> or <span class="type">DynamicGrid</span></span>
<span class="types"><span class="type">StaticGrid</span></span>
<a href="../modules/StaticGrid.html#">StaticGrid</a>, <a href="../modules/DynamicGrid.html#">DynamicGrid</a>
</li>
</ul>
@@ -399,7 +563,7 @@
<strong>last_index</strong>
</dt>
<dd>
The current visual last data index
The current last index of visual elements
<ul>
@@ -413,6 +577,46 @@
</dd>
<dt>
<a name = "on_element_add"></a>
<strong>on_element_add</strong>
</dt>
<dd>
On DataList visual element created Event callback(self, index, node, instance)
<ul>
<li><span class="parameter">on_element_add</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
</ul>
</dd>
<dt>
<a name = "on_element_remove"></a>
<strong>on_element_remove</strong>
</dt>
<dd>
On DataList visual element created Event callback(self, index)
<ul>
<li><span class="parameter">on_element_remove</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
</ul>
</dd>
<dt>
<a name = "on_scroll_progress_change"></a>
@@ -479,7 +683,7 @@
<strong>top_index</strong>
</dt>
<dd>
The current visual top data index
The current top index of visual elements
<ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><strong>Drag</strong></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -77,19 +76,28 @@
<p>
Drag have correct handling for multitouch and swap
touched while dragging. Drag will be processed even
the cursor is outside of node, if drag is already started</p>
the cursor is outside of node, if drag is already started
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_drag" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, node, on_drag_callback)</a></td>
<td class="summary">Drag component constructor</td>
<td class="summary">The <a href="../modules/Drag.html#">Drag</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_enabled">is_enabled(self)</a></td>
<td class="summary">Check if Drag component is enabled</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_click_zone">set_click_zone(self, node)</a></td>
<td class="summary">Strict drag click area.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_enabled">set_enabled(self, is_enabled)</a></td>
<td class="summary">Set Drag input enabled or disabled</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
@@ -117,16 +125,20 @@
<td class="summary">Is component now touching</td>
</tr>
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Drag node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_drag">on_drag</a></td>
<td class="summary">on drag progress callback(self, dx, dy)</td>
<td class="summary">on drag progress callback(self, dx, dy, total_x, total_y, touch)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_drag_end">on_drag_end</a></td>
<td class="summary">Event on drag end callback(self)</td>
<td class="summary">Event on drag end callback(self, total_x, total_y, touch)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_drag_start">on_drag_start</a></td>
<td class="summary">Event on drag start callback(self)</td>
<td class="summary">Event on drag start callback(self, touch)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_touch_end">on_touch_end</a></td>
@@ -137,6 +149,14 @@
<td class="summary">Event on touch start callback(self)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#screen_x">screen_x</a></td>
<td class="summary">Current touch x screen position</td>
</tr>
<tr>
<td class="name" nowrap><a href="#screen_y">screen_y</a></td>
<td class="summary">Current touch y screen position</td>
</tr>
<tr>
<td class="name" nowrap><a href="#touch_start_pos">touch_start_pos</a></td>
<td class="summary">Touch start position</td>
</tr>
@@ -162,7 +182,7 @@
<strong>init(self, node, on_drag_callback)</strong>
</dt>
<dd>
Drag component constructor
The <a href="../modules/Drag.html#">Drag</a> constructor
<h3>Parameters:</h3>
@@ -172,7 +192,7 @@
<a href="../modules/Drag.html#">Drag</a>
</li>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><a class="type" href="../modules/Drag.html#node">node</a></span>
GUI node to detect dragging
</li>
<li><span class="parameter">on_drag_callback</span>
@@ -185,6 +205,33 @@
</dd>
<dt>
<a name = "is_enabled"></a>
<strong>is_enabled(self)</strong>
</dt>
<dd>
Check if Drag component is enabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Drag</span></span>
<a href="../modules/Drag.html#">Drag</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
</ol>
</dd>
<dt>
<a name = "set_click_zone"></a>
@@ -202,7 +249,7 @@
<a href="../modules/Drag.html#">Drag</a>
</li>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><a class="type" href="../modules/Drag.html#node">node</a>, <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Gui node
</li>
</ul>
@@ -211,6 +258,31 @@
</dd>
<dt>
<a name = "set_enabled"></a>
<strong>set_enabled(self, is_enabled)</strong>
</dt>
<dd>
Set Drag input enabled or disabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Drag</span></span>
<a href="../modules/Drag.html#">Drag</a>
</li>
<li><span class="parameter">is_enabled</span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
@@ -229,9 +301,12 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">DRAG_DEADZONE</span>
<span class="types"><span class="type">number</span></span>
Distance in pixels to start dragging
(<em>default</em> 10)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Distance in pixels to start dragging. Default: 10
</li>
<li><span class="parameter">NO_USE_SCREEN_KOEF</span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If screen aspect ratio affects on drag values. Default: false
</li>
</ul>
@@ -254,7 +329,7 @@
<ul>
<li><span class="parameter">can_x</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -274,7 +349,7 @@
<ul>
<li><span class="parameter">can_y</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -294,7 +369,7 @@
<ul>
<li><span class="parameter">is_drag</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -314,7 +389,27 @@
<ul>
<li><span class="parameter">is_touch</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "node"></a>
<strong>node</strong>
</dt>
<dd>
Drag node
<ul>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/Drag.html#node">node</a></span>
</li>
</ul>
@@ -329,7 +424,7 @@
<strong>on_drag</strong>
</dt>
<dd>
on drag progress callback(self, dx, dy)
on drag progress callback(self, dx, dy, total_x, total_y, touch)
<ul>
@@ -349,7 +444,7 @@
<strong>on_drag_end</strong>
</dt>
<dd>
Event on drag end callback(self)
Event on drag end callback(self, total_x, total_y, touch)
<ul>
@@ -369,7 +464,7 @@
<strong>on_drag_start</strong>
</dt>
<dd>
Event on drag start callback(self)
Event on drag start callback(self, touch)
<ul>
@@ -423,6 +518,46 @@
</dd>
<dt>
<a name = "screen_x"></a>
<strong>screen_x</strong>
</dt>
<dd>
Current touch x screen position
<ul>
<li><span class="parameter">screen_x</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "screen_y"></a>
<strong>screen_y</strong>
</dt>
<dd>
Current touch y screen position
<ul>
<li><span class="parameter">screen_y</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "touch_start_pos"></a>

374
docs/modules/Druid.html Normal file
View File

@@ -0,0 +1,374 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><strong>Druid</strong></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Module <code>Druid</code></h1>
<p>Druid UI Component Framework.</p>
<p>
<b># Overview #</b>
<p> Druid - powerful Defold component UI library. Use basic and extended
Druid components or make your own game-specific components to make
amazing GUI in your games.
<p> To start using Druid, please refer to the Usage section below.
<p> <b># Notes #</b>
<p> • Each Druid instance maintains the self context from the constructor and passes it to each Druid callback.
<p> See next: <a href="../modules/DruidInstance.html#">DruidInstance</a>
</p>
<h3>Usage:</h3>
<ul>
<pre class="example">local druid = require(&quot;druid.druid&quot;)
local function on_play(self)
print(&quot;Gonna play!&quot;)
end
function init(self)
self.druid = druid.new(self)
self.druid:new_button(&quot;button_play&quot;, on_play)
end
function final(self)
self.druid:final()
end
function update(self, dt)
self.druid:update(dt)
end
function on_message(self, message_id, message, sender)
self.druid:on_message(message_id, message, sender)
end
function on_input(self, action_id, action)
return self.druid:on_input(action_id, action)
end
</pre>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#druid.new">druid.new(context, style)</a></td>
<td class="summary">Create a new Druid instance for creating GUI components.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid.on_language_change">druid.on_language_change()</a></td>
<td class="summary">Call this function when the game language changes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid.on_window_callback">druid.on_window_callback(event)</a></td>
<td class="summary">Set the window callback to enable on_focus_gain and on_focus_lost functions.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid.register">druid.register(name, module)</a></td>
<td class="summary">Register a new external Druid component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid.set_default_style">druid.set_default_style(style)</a></td>
<td class="summary">Set your own default style for all Druid instances.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid.set_sound_function">druid.set_sound_function(callback)</a></td>
<td class="summary">Set the Druid sound function to play UI sounds if used.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid.set_text_function">druid.set_text_function(callback)</a></td>
<td class="summary">Set the text function for the LangText component.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "druid.new"></a>
<strong>druid.new(context, style)</strong>
</dt>
<dd>
Create a new Druid instance for creating GUI components.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">context</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks.
</li>
<li><span class="parameter">style</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">nil</span></span>
The Druid style table to override style parameters for this Druid instance.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid_instance</span></span>
The Druid instance <a href="../modules/DruidInstance.html#">DruidInstance</a>.
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> druid = <span class="global">require</span>(<span class="string">"druid.druid"</span>)
<span class="keyword">function</span> init(self)
self.druid = druid.new(self)
<span class="keyword">end</span></pre>
</ul>
</dd>
<dt>
<a name = "druid.on_language_change"></a>
<strong>druid.on_language_change()</strong>
</dt>
<dd>
Call this function when the game language changes.
<p> This function will translate all current LangText components.
<h3>Usage:</h3>
<ul>
<pre class="example">druid.on_language_change()</pre>
</ul>
</dd>
<dt>
<a name = "druid.on_window_callback"></a>
<strong>druid.on_window_callback(event)</strong>
</dt>
<dd>
Set the window callback to enable on_focus_gain and on_focus_lost functions.
<p> This is used to trigger the on_focus_lost and on_focus_gain functions in Druid components.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">event</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Event param from window listener
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">window.set_listener(<span class="keyword">function</span>(_, event)
druid.on_window_callback(event)
<span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
<a name = "druid.register"></a>
<strong>druid.register(name, module)</strong>
</dt>
<dd>
Register a new external Druid component.
<p> You can register your own components to make new alias: the druid:new_{name} function.
For example, if you want to register a component called "my_component", you can create it using druid:new_my_component(...).
This can be useful if you have your own "basic" components that you don't want to re-create each time.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
module name
</li>
<li><span class="parameter">module</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
lua table with component
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> my_component = <span class="global">require</span>(<span class="string">"path.to.my.component"</span>)
druid.register(<span class="string">"my_component"</span>, my_component)
...
<span class="keyword">local</span> druid = druid.new(self)
<span class="keyword">local</span> component_instance = self.druid:new_my_component(...)</pre>
</ul>
</dd>
<dt>
<a name = "druid.set_default_style"></a>
<strong>druid.set_default_style(style)</strong>
</dt>
<dd>
Set your own default style for all Druid instances.
<p> To create your own style file, copy the default style file and make changes to it.
Register the new style before creating your Druid instances.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">style</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Druid style module
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> my_style = <span class="global">require</span>(<span class="string">"path.to.my.style"</span>)
druid.set_default_style(my_style)</pre>
</ul>
</dd>
<dt>
<a name = "druid.set_sound_function"></a>
<strong>druid.set_sound_function(callback)</strong>
</dt>
<dd>
Set the Druid sound function to play UI sounds if used.
<p> Set a function to play a sound given a sound_id. This function is used for button clicks to play the "click" sound.
It can also be used to play sounds in your custom components (see the default Druid style file for an example).
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
Sound play callback
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">druid.set_sound_function(<span class="keyword">function</span>(sound_id)
sound.play(sound_id) <span class="comment">-- Replace with your real function
</span><span class="keyword">end</span>)</pre>
</ul>
</dd>
<dt>
<a name = "druid.set_text_function"></a>
<strong>druid.set_text_function(callback)</strong>
</dt>
<dd>
Set the text function for the LangText component.
<p> The Druid locale component will call this function to get translated text.
After setting the text function, all existing locale components will be updated.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
Get localized text function
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example">druid.set_text_function(<span class="keyword">function</span>(text_id)
<span class="keyword">return</span> lang_data[text_id] <span class="comment">-- Replace with your real function
</span><span class="keyword">end</span>)</pre>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -42,28 +42,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><strong>DruidEvent</strong></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -71,8 +70,10 @@
<div id="content">
<h1>Module <code>DruidEvent</code></h1>
<p>Druid lua event library</p>
<p></p>
<p>Druid Event Module
<p> The Event module provides a simple class for handling callbacks.</p>
<p> It is used in many Druid components.
<p> You can subscribe to an event using the `:subscribe` method and unsubscribe using the `:unsubscribe` method.</p>
<h2><a href="#Functions">Functions</a></h2>
@@ -82,15 +83,23 @@
<td class="summary">Clear the all event handlers</td>
</tr>
<tr>
<td class="name" nowrap><a href="#initialize">initialize(self, initial_callback)</a></td>
<td class="summary">Event constructur</td>
<td class="name" nowrap><a href="#create">create(callback, callback_context)</a></td>
<td class="summary">DruidEvent constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_empty">is_empty(self)</a></td>
<td class="summary">Return true, if event not have handler</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_exist">is_exist(self)</a></td>
<td class="summary">Return true, if event have at lease one handler</td>
</tr>
<tr>
<td class="name" nowrap><a href="#subscribe">subscribe(self, callback, context)</a></td>
<td class="name" nowrap><a href="#is_subscribed">is_subscribed(self, callback, callback_context)</a></td>
<td class="summary">Check is event subscribed.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#subscribe">subscribe(self, callback, callback_context)</a></td>
<td class="summary">Subscribe callback on event</td>
</tr>
<tr>
@@ -98,7 +107,7 @@
<td class="summary">Trigger the event and call all subscribed callbacks</td>
</tr>
<tr>
<td class="name" nowrap><a href="#unsubscribe">unsubscribe(self, callback, context)</a></td>
<td class="name" nowrap><a href="#unsubscribe">unsubscribe(self, callback, callback_context)</a></td>
<td class="summary">Unsubscribe callback on event</td>
</tr>
</table>
@@ -129,14 +138,49 @@
<h3>Usage:</h3>
<ul>
<pre class="example">button.on_long_click:clear()</pre>
</ul>
</dd>
<dt>
<a name = "initialize"></a>
<strong>initialize(self, initial_callback)</strong>
<a name = "create"></a>
<strong>create(callback, callback_context)</strong>
</dt>
<dd>
Event constructur
DruidEvent constructor
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span> or <span class="type">nil</span></span>
Subscribe the callback on new event, if callback exist
</li>
<li><span class="parameter">callback_context</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
Additional context as first param to callback call
</li>
</ul>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> Event = <span class="global">require</span>(<span class="string">"druid.event"</span>)
...
<span class="keyword">local</span> event = Event(callback)</pre>
</ul>
</dd>
<dt>
<a name = "is_empty"></a>
<strong>is_empty(self)</strong>
</dt>
<dd>
Return true, if event not have handler
<h3>Parameters:</h3>
@@ -145,15 +189,21 @@
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
<li><span class="parameter">initial_callback</span>
<span class="types"><span class="type">function</span></span>
Subscribe the callback on new event, if callback exist
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
True if event not have handlers
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> is_long_click_handler_not_exists = button.on_long_click:is_empty()</pre>
</ul>
</dd>
<dt>
@@ -175,17 +225,56 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
True if event have handlers
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> is_long_click_handler_exists = button.on_long_click:is_exist()</pre>
</ul>
</dd>
<dt>
<a name = "is_subscribed"></a>
<strong>is_subscribed(self, callback, callback_context)</strong>
</dt>
<dd>
Check is event subscribed.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
Callback itself
</li>
<li><span class="parameter">callback_context</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
Additional context as first param to callback call
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean,</span></span>
number|nil @Is event subscribed, return index of callback in event as second param
</ol>
</dd>
<dt>
<a name = "subscribe"></a>
<strong>subscribe(self, callback, context)</strong>
<strong>subscribe(self, callback, callback_context)</strong>
</dt>
<dd>
Subscribe callback on event
@@ -201,15 +290,30 @@
<span class="types"><span class="type">function</span></span>
Callback itself
</li>
<li><span class="parameter">context</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Additional context as first param to callback call
<li><span class="parameter">callback_context</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
Additional context as first param to callback call, usually it's self
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
True if callback was subscribed
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> <span class="keyword">function</span> on_long_callback(self)
<span class="global">print</span>(<span class="string">"Long click!"</span>)
<span class="keyword">end</span>
...
<span class="keyword">local</span> button = self.druid:new_button(<span class="string">"button"</span>, callback)
button.on_long_click:subscribe(on_long_callback, self)</pre>
</ul>
</dd>
<dt>
@@ -235,11 +339,18 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> Event = <span class="global">require</span>(<span class="string">"druid.event"</span>)
...
<span class="keyword">local</span> event = Event()
event:trigger(<span class="string">"Param1"</span>, <span class="string">"Param2"</span>)</pre>
</ul>
</dd>
<dt>
<a name = "unsubscribe"></a>
<strong>unsubscribe(self, callback, context)</strong>
<strong>unsubscribe(self, callback, callback_context)</strong>
</dt>
<dd>
Unsubscribe callback on event
@@ -255,8 +366,8 @@
<span class="types"><span class="type">function</span></span>
Callback itself
</li>
<li><span class="parameter">context</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
<li><span class="parameter">callback_context</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
Additional context as first param to callback call
</li>
</ul>
@@ -264,6 +375,14 @@
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="keyword">local</span> <span class="keyword">function</span> on_long_callback(self)
<span class="global">print</span>(<span class="string">"Long click!"</span>)
<span class="keyword">end</span>
...
button.on_long_click:unsubscribe(on_long_callback, self)</pre>
</ul>
</dd>
</dl>

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><strong>DynamicGrid</strong></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,7 +72,7 @@
<h1>Module <code>DynamicGrid</code></h1>
<p>Component to handle placing components in row</p>
<p></p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_grid" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -83,7 +82,7 @@
<td class="summary">Return side vector to correct node shifting</td>
</tr>
<tr>
<td class="name" nowrap><a href="#add">add(self, node[, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]]])</a></td>
<td class="name" nowrap><a href="#add">add(self, node, index, shift_policy, is_instant)</a></td>
<td class="summary">Add new node to the grid</td>
</tr>
<tr>
@@ -107,7 +106,7 @@
<td class="summary">Return DynamicGrid offset, where DynamicGrid content starts.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_pos">get_pos(self, index, node[, origin_index])</a></td>
<td class="name" nowrap><a href="#get_pos">get_pos(self, index, node, origin_index)</a></td>
<td class="summary">Return pos for grid node index</td>
</tr>
<tr>
@@ -116,10 +115,10 @@
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, parent)</a></td>
<td class="summary">Component init function</td>
<td class="summary">The <a href="../modules/DynamicGrid.html#">DynamicGrid</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#remove">remove(self, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]])</a></td>
<td class="name" nowrap><a href="#remove">remove(self, index, shift_policy, is_instant)</a></td>
<td class="summary">Remove the item from the grid.</td>
</tr>
<tr>
@@ -210,7 +209,7 @@
</dd>
<dt>
<a name = "add"></a>
<strong>add(self, node[, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]]])</strong>
<strong>add(self, node, index, shift_policy, is_instant)</strong>
</dt>
<dd>
Add new node to the grid
@@ -227,19 +226,16 @@
Gui node
</li>
<li><span class="parameter">index</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The node position. By default add as last node
(<em>optional</em>)
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span></span>
How shift nodes, if required. See const.SHIFT
(<em>default</em> SHIFT.RIGHT)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
How shift nodes, if required. Default: const.SHIFT.RIGHT
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, update node positions instantly
(<em>default</em> false)
</li>
</ul>
@@ -390,7 +386,7 @@
</dd>
<dt>
<a name = "get_pos"></a>
<strong>get_pos(self, index, node[, origin_index])</strong>
<strong>get_pos(self, index, node, origin_index)</strong>
</dt>
<dd>
Return pos for grid node index
@@ -411,9 +407,8 @@
The node to be placed
</li>
<li><span class="parameter">origin_index</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Index of nearby node
(<em>optional</em>)
</li>
</ul>
@@ -421,7 +416,7 @@
<ol>
<span class="types"><span class="type">vector3</span></span>
Node position
node position
</ol>
@@ -464,7 +459,7 @@
<strong>init(self, parent)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/DynamicGrid.html#">DynamicGrid</a> constructor
<h3>Parameters:</h3>
@@ -486,7 +481,7 @@
</dd>
<dt>
<a name = "remove"></a>
<strong>remove(self, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]])</strong>
<strong>remove(self, index, shift_policy, is_instant)</strong>
</dt>
<dd>
Remove the item from the grid. Note that gui node will be not deleted
@@ -503,14 +498,12 @@
The grid node index to remove
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span></span>
How shift nodes, if required. See const.SHIFT
(<em>default</em> SHIFT.RIGHT)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
How shift nodes, if required. Default: const.SHIFT.RIGHT
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, update node positions instantly
(<em>default</em> false)
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -42,28 +42,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><strong>Helper</strong></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -71,27 +70,41 @@
<div id="content">
<h1>Module <code>Helper</code></h1>
<p>Druid helper module for gui layouts</p>
<p>Helper module with various usefull GUI functions.</p>
<p></p>
<h3>Usage:</h3>
<ul>
<pre class="example">local helper = require(&quot;druid.helper&quot;)
helper.centrate_nodes(0, node_1, node_2)
</pre>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#helper.centrate_icon_with_text">helper.centrate_icon_with_text([icon_node[, text_node[, margin=0]]])</a></td>
<td class="summary">Center two nodes.</td>
<td class="name" nowrap><a href="#helper.add_array">helper.add_array(target, source)</a></td>
<td class="summary">Add all elements from source array to the target array</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.centrate_nodes">helper.centrate_nodes([margin=0[, ...]])</a></td>
<td class="summary">Center several nodes nodes.</td>
<td class="name" nowrap><a href="#helper.centrate_nodes">helper.centrate_nodes(margin, ...)</a></td>
<td class="summary">Centerate nodes by x position with margin.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.centrate_text_with_icon">helper.centrate_text_with_icon([text_node][, icon_node], margin)</a></td>
<td class="summary">Center two nodes.</td>
<td class="name" nowrap><a href="#helper.clamp">helper.clamp(a, min, max)</a></td>
<td class="summary">Clamp value between min and max</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.deprecated">helper.deprecated(message)</a></td>
<td class="summary">Show deprecated message.</td>
<td class="name" nowrap><a href="#helper.contains">helper.contains(t, value)</a></td>
<td class="summary">Check if value is in array and return index of it</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.deepcopy">helper.deepcopy(orig_table)</a></td>
<td class="summary">Make a copy table with all nested tables</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.distance">helper.distance(x1, y1, x2, y2)</a></td>
<td class="summary">Calculate distance between two points</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_border">helper.get_border(node, offset)</a></td>
@@ -99,27 +112,75 @@
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_closest_stencil_node">helper.get_closest_stencil_node(node)</a></td>
<td class="summary">Return closest non inverted clipping parent node for node</td>
<td class="summary">Return closest non inverted clipping parent node for given node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_gui_scale">helper.get_gui_scale()</a></td>
<td class="summary">Get current GUI scale for each side</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_pivot_offset">helper.get_pivot_offset(pivot)</a></td>
<td class="summary">Get node offset for given gui pivot</td>
<td class="summary">Get node offset for given GUI pivot.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.is_enabled">helper.is_enabled(node)</a></td>
<td class="summary">Check if node is enabled in gui hierarchy.</td>
<td class="name" nowrap><a href="#helper.get_scaled_size">helper.get_scaled_size(node)</a></td>
<td class="summary">Get node size adjusted by scale</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_scene_scale">helper.get_scene_scale(node, include_passed_node_scale)</a></td>
<td class="summary">Get cumulative parent's node scale</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_screen_aspect_koef">helper.get_screen_aspect_koef()</a></td>
<td class="summary">Get current screen stretch multiplier for each side</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.get_text_metrics_from_node">helper.get_text_metrics_from_node(text_node)</a></td>
<td class="summary">Get text metric from GUI node.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.insert_with_shift">helper.insert_with_shift(array, any, index, shift_policy)</a></td>
<td class="summary">Add value to array with shift policy</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.is_mobile">helper.is_mobile()</a></td>
<td class="summary">Check if device is mobile (Android or iOS)</td>
<td class="summary">Check if device is native mobile (Android or iOS)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.is_multitouch_supported">helper.is_multitouch_supported()</a></td>
<td class="summary">Check if device is mobile and can support multitouch</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.is_web">helper.is_web()</a></td>
<td class="summary">Check if device is HTML5</td>
</tr>
<tr>
<td class="name" nowrap><a href="#table_to_string">table_to_string(t)</a></td>
<td class="summary">Transform table to oneline string</td>
<td class="name" nowrap><a href="#helper.is_web_mobile">helper.is_web_mobile()</a></td>
<td class="summary">Check if device is HTML5 mobile</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.lerp">helper.lerp(a, b, t)</a></td>
<td class="summary">Lerp between two values</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.remove_with_shift">helper.remove_with_shift(array, index, shift_policy)</a></td>
<td class="summary">Remove value from array with shift policy</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.round">helper.round(num, num_decimal_places)</a></td>
<td class="summary">Round number to specified decimal places</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.sign">helper.sign(val)</a></td>
<td class="summary">Return sign of value (-1, 0, 1)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.step">helper.step(current, target, step)</a></td>
<td class="summary">Move value from current to target value with step amount</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper.table_to_string">helper.table_to_string(t)</a></td>
<td class="summary">Simple table to one-line string converter</td>
</tr>
</table>
@@ -131,34 +192,31 @@
<dl class="function">
<dt>
<a name = "helper.centrate_icon_with_text"></a>
<strong>helper.centrate_icon_with_text([icon_node[, text_node[, margin=0]]])</strong>
<a name = "helper.add_array"></a>
<strong>helper.add_array(target, source)</strong>
</dt>
<dd>
Center two nodes.
Nodes will be center around 0 x position
icon_node will be first (at left side)
Add all elements from source array to the target array
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">icon_node</span>
<span class="types"><span class="type">box</span></span>
Gui box node
(<em>optional</em>)
<li><span class="parameter">target</span>
<span class="types"><span class="type">any[]</span></span>
Array to put elements from source
</li>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">text</span></span>
Gui text node
(<em>optional</em>)
</li>
<li><span class="parameter">margin</span>
<span class="types"><span class="type">number</span></span>
Offset between nodes
(<em>default</em> 0)
<li><span class="parameter">source</span>
<span class="types"><span class="type">any[]</span> or <span class="type">nil</span></span>
The source array to get elements from
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">any[]</span></span>
The target array
</ol>
@@ -166,24 +224,22 @@
</dd>
<dt>
<a name = "helper.centrate_nodes"></a>
<strong>helper.centrate_nodes([margin=0[, ...]])</strong>
<strong>helper.centrate_nodes(margin, ...)</strong>
</dt>
<dd>
Center several nodes nodes.
Nodes will be center around 0 x position
Centerate nodes by x position with margin.
<p> This functions calculate total width of nodes and set position for each node.
The centrate will be around 0 x position.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">margin</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Offset between nodes
(<em>default</em> 0)
</li>
<li><span class="parameter">...</span>
<span class="types"><span class="type">Node</span></span>
Any count of gui Node
(<em>optional</em>)
Gui nodes
</li>
</ul>
@@ -193,54 +249,131 @@
</dd>
<dt>
<a name = "helper.centrate_text_with_icon"></a>
<strong>helper.centrate_text_with_icon([text_node][, icon_node], margin)</strong>
<a name = "helper.clamp"></a>
<strong>helper.clamp(a, min, max)</strong>
</dt>
<dd>
Center two nodes.
Nodes will be center around 0 x position
text_node will be first (at left side)
Clamp value between min and max
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">text</span></span>
Gui text node
(<em>optional</em>)
</li>
<li><span class="parameter">icon_node</span>
<span class="types"><span class="type">box</span></span>
Gui box node
(<em>optional</em>)
</li>
<li><span class="parameter">margin</span>
<li><span class="parameter">a</span>
<span class="types"><span class="type">number</span></span>
Offset between nodes
Value
</li>
<li><span class="parameter">min</span>
<span class="types"><span class="type">number</span></span>
Min value
</li>
<li><span class="parameter">max</span>
<span class="types"><span class="type">number</span></span>
Max value
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
Clamped value
</ol>
</dd>
<dt>
<a name = "helper.deprecated"></a>
<strong>helper.deprecated(message)</strong>
<a name = "helper.contains"></a>
<strong>helper.contains(t, value)</strong>
</dt>
<dd>
Show deprecated message. Once time per message
Check if value is in array and return index of it
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">message</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The deprecated message
<li><span class="parameter">t</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Array
</li>
<li><span class="parameter">value</span>
Value
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Index of value or nil
</ol>
</dd>
<dt>
<a name = "helper.deepcopy"></a>
<strong>helper.deepcopy(orig_table)</strong>
</dt>
<dd>
Make a copy table with all nested tables
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">orig_table</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Original table
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Copy of original table
</ol>
</dd>
<dt>
<a name = "helper.distance"></a>
<strong>helper.distance(x1, y1, x2, y2)</strong>
</dt>
<dd>
Calculate distance between two points
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">x1</span>
<span class="types"><span class="type">number</span></span>
First point x
</li>
<li><span class="parameter">y1</span>
<span class="types"><span class="type">number</span></span>
First point y
</li>
<li><span class="parameter">x2</span>
<span class="types"><span class="type">number</span></span>
Second point x
</li>
<li><span class="parameter">y2</span>
<span class="types"><span class="type">number</span></span>
Second point y
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
Distance
</ol>
@@ -258,18 +391,19 @@
<ul>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
The gui node to check
GUI node
</li>
<li><span class="parameter">offset</span>
<span class="types"><span class="type">vector3</span></span>
The offset to add to result
<span class="types"><span class="type">vector3</span> or <span class="type">nil</span></span>
Offset from node position. Pass current node position to get non relative border values
</li>
</ul>
<h3>Returns:</h3>
<ol>
vector4 Vector with distance to node border: (left, top, right, down)
<span class="types"><span class="type">vector4</span></span>
Vector4 with border values (left, top, right, down)
</ol>
@@ -281,14 +415,14 @@
<strong>helper.get_closest_stencil_node(node)</strong>
</dt>
<dd>
Return closest non inverted clipping parent node for node
Return closest non inverted clipping parent node for given node
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
Gui node
GUI node
</li>
</ul>
@@ -296,7 +430,30 @@
<ol>
<span class="types"><span class="type">node</span> or <span class="type">nil</span></span>
The clipping node
The closest stencil node or nil
</ol>
</dd>
<dt>
<a name = "helper.get_gui_scale"></a>
<strong>helper.get_gui_scale()</strong>
</dt>
<dd>
Get current GUI scale for each side
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">number</span></span>
scale_x</li>
<li>
<span class="types"><span class="type">number</span></span>
scale_y</li>
</ol>
@@ -308,14 +465,15 @@
<strong>helper.get_pivot_offset(pivot)</strong>
</dt>
<dd>
Get node offset for given gui pivot
Get node offset for given GUI pivot.
<p> Offset shown in [-0.5 .. 0.5] range, where -0.5 is left or bottom, 0.5 is right or top.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pivot</span>
<span class="types"><span class="type">gui.pivot</span></span>
The node pivot
<span class="types"><span class="type">number</span></span>
The gui.PIVOT_* constant
</li>
</ul>
@@ -323,7 +481,7 @@
<ol>
<span class="types"><span class="type">vector3</span></span>
Vector offset with [-1..1] values
Vector offset with [-0.5..0.5] values
</ol>
@@ -331,12 +489,38 @@
</dd>
<dt>
<a name = "helper.is_enabled"></a>
<strong>helper.is_enabled(node)</strong>
<a name = "helper.get_scaled_size"></a>
<strong>helper.get_scaled_size(node)</strong>
</dt>
<dd>
Check if node is enabled in gui hierarchy.
Return false, if node or any his parent is disabled
Get node size adjusted by scale
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
GUI node
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">vector3</span></span>
Scaled size
</ol>
</dd>
<dt>
<a name = "helper.get_scene_scale"></a>
<strong>helper.get_scene_scale(node, include_passed_node_scale)</strong>
</dt>
<dd>
Get cumulative parent's node scale
<h3>Parameters:</h3>
@@ -345,13 +529,114 @@
<span class="types"><span class="type">node</span></span>
Gui node
</li>
<li><span class="parameter">include_passed_node_scale</span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
True if add current node scale to result
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
Is enabled in hierarchy
<span class="types"><span class="type">vector3</span></span>
The scene node scale
</ol>
</dd>
<dt>
<a name = "helper.get_screen_aspect_koef"></a>
<strong>helper.get_screen_aspect_koef()</strong>
</dt>
<dd>
Get current screen stretch multiplier for each side
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">number</span></span>
stretch_x</li>
<li>
<span class="types"><span class="type">number</span></span>
stretch_y</li>
</ol>
</dd>
<dt>
<a name = "helper.get_text_metrics_from_node"></a>
<strong>helper.get_text_metrics_from_node(text_node)</strong>
</dt>
<dd>
Get text metric from GUI node.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">node</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">GUITextMetrics</span></span>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example"><span class="global">type</span> GUITextMetrics = {
width: number,
height: number,
max_ascent: number,
max_descent: number
}</pre>
</ul>
</dd>
<dt>
<a name = "helper.insert_with_shift"></a>
<strong>helper.insert_with_shift(array, any, index, shift_policy)</strong>
</dt>
<dd>
Add value to array with shift policy Shift policy can be: left, right, no_shift
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">array</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Array
</li>
<li><span class="parameter">any</span>
Item to insert
</li>
<li><span class="parameter">index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Index to insert. If nil, item will be inserted at the end of array
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The druid_const.SHIFT.* constant
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">any</span></span>
Inserted item
</ol>
@@ -363,10 +648,36 @@
<strong>helper.is_mobile()</strong>
</dt>
<dd>
Check if device is mobile (Android or iOS)
Check if device is native mobile (Android or iOS)
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
Is mobile
</ol>
</dd>
<dt>
<a name = "helper.is_multitouch_supported"></a>
<strong>helper.is_multitouch_supported()</strong>
</dt>
<dd>
Check if device is mobile and can support multitouch
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
Is multitouch supported
</ol>
@@ -381,17 +692,206 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
Is web
</ol>
</dd>
<dt>
<a name = "table_to_string"></a>
<strong>table_to_string(t)</strong>
<a name = "helper.is_web_mobile"></a>
<strong>helper.is_web_mobile()</strong>
</dt>
<dd>
Transform table to oneline string
Check if device is HTML5 mobile
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
Is web mobile
</ol>
</dd>
<dt>
<a name = "helper.lerp"></a>
<strong>helper.lerp(a, b, t)</strong>
</dt>
<dd>
Lerp between two values
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">a</span>
<span class="types"><span class="type">number</span></span>
First value
</li>
<li><span class="parameter">b</span>
<span class="types"><span class="type">number</span></span>
Second value
</li>
<li><span class="parameter">t</span>
<span class="types"><span class="type">number</span></span>
Lerp amount
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
Lerped value
</ol>
</dd>
<dt>
<a name = "helper.remove_with_shift"></a>
<strong>helper.remove_with_shift(array, index, shift_policy)</strong>
</dt>
<dd>
Remove value from array with shift policy Shift policy can be: left, right, no_shift
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">array</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Array
</li>
<li><span class="parameter">index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Index to remove. If nil, item will be removed from the end of array
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The druid_const.SHIFT.* constant
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">any</span></span>
Removed item
</ol>
</dd>
<dt>
<a name = "helper.round"></a>
<strong>helper.round(num, num_decimal_places)</strong>
</dt>
<dd>
Round number to specified decimal places
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">num</span>
<span class="types"><span class="type">number</span></span>
Number
</li>
<li><span class="parameter">num_decimal_places</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Decimal places
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
Rounded number
</ol>
</dd>
<dt>
<a name = "helper.sign"></a>
<strong>helper.sign(val)</strong>
</dt>
<dd>
Return sign of value (-1, 0, 1)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">val</span>
<span class="types"><span class="type">number</span></span>
Value
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
Sign
</ol>
</dd>
<dt>
<a name = "helper.step"></a>
<strong>helper.step(current, target, step)</strong>
</dt>
<dd>
Move value from current to target value with step amount
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">current</span>
<span class="types"><span class="type">number</span></span>
Current value
</li>
<li><span class="parameter">target</span>
<span class="types"><span class="type">number</span></span>
Target value
</li>
<li><span class="parameter">step</span>
<span class="types"><span class="type">number</span></span>
Step amount
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
New value
</ol>
</dd>
<dt>
<a name = "helper.table_to_string"></a>
<strong>helper.table_to_string(t)</strong>
</dt>
<dd>
Simple table to one-line string converter
<h3>Parameters:</h3>

373
docs/modules/Hotkey.html Normal file
View File

@@ -0,0 +1,373 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Tables">Tables</a></li>
<li><a href="#Fields">Fields</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><strong>Hotkey</strong></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Module <code>Hotkey</code></h1>
<p>Druid hotkey component</p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_hotkey" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#add_hotkey">add_hotkey(self, keys, callback_argument)</a></td>
<td class="summary">Add hotkey for component callback</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, keys, callback, callback_argument)</a></td>
<td class="summary">The <a href="../modules/Hotkey.html#">Hotkey</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_repeat">set_repeat(self, is_enabled_repeated)</a></td>
<td class="summary">If true, the callback will be triggered on action.repeated</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#style">style</a></td>
<td class="summary">Component style params.</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#button">button</a></td>
<td class="summary">Button component from click_node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#click_node">click_node</a></td>
<td class="summary">Button trigger node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Visual node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_hotkey_pressed">on_hotkey_pressed</a></td>
<td class="summary">On hotkey released callback(self, argument)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_hotkey_released">on_hotkey_released</a></td>
<td class="summary">On hotkey released callback(self, argument)</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "add_hotkey"></a>
<strong>add_hotkey(self, keys, callback_argument)</strong>
</dt>
<dd>
Add hotkey for component callback
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Hotkey</span></span>
<a href="../modules/Hotkey.html#">Hotkey</a>
</li>
<li><span class="parameter">keys</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string[]</a>, <span class="type">hash[]</span>, <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">hash</span></span>
that have to be pressed before key pressed to activate
</li>
<li><span class="parameter">callback_argument</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
The argument to pass into the callback function
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Hotkey</span></span>
Current instance
</ol>
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, keys, callback, callback_argument)</strong>
</dt>
<dd>
The <a href="../modules/Hotkey.html#">Hotkey</a> constructor
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Hotkey</span></span>
<a href="../modules/Hotkey.html#">Hotkey</a>
</li>
<li><span class="parameter">keys</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string[]</a> or <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The keys to be pressed for trigger callback. Should contains one key and any modificator keys
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
The callback function
</li>
<li><span class="parameter">callback_argument</span>
<span class="types"><span class="type">any</span> or <span class="type">nil</span></span>
The argument to pass into the callback function
</li>
</ul>
</dd>
<dt>
<a name = "set_repeat"></a>
<strong>set_repeat(self, is_enabled_repeated)</strong>
</dt>
<dd>
If true, the callback will be triggered on action.repeated
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Hotkey</span></span>
<a href="../modules/Hotkey.html#">Hotkey</a>
</li>
<li><span class="parameter">is_enabled_repeated</span>
<span class="types"><span class="type">bool</span></span>
The flag value
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Hotkey</span></span>
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
<dl class="function">
<dt>
<a name = "style"></a>
<strong>style</strong>
</dt>
<dd>
Component style params.
You can override this component styles params in druid styles table
or create your own style
<h3>Fields:</h3>
<ul>
<li><span class="parameter">MODIFICATORS</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string[]</a></span>
The list of action_id as hotkey modificators
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "button"></a>
<strong>button</strong>
</dt>
<dd>
Button component from click_node
<ul>
<li><span class="parameter">button</span>
<span class="types"><span class="type">Button</span></span>
<a href="../modules/Button.html#">Button</a>
</li>
</ul>
</dd>
<dt>
<a name = "click_node"></a>
<strong>click_node</strong>
</dt>
<dd>
Button trigger node
<ul>
<li><span class="parameter">click_node</span>
<span class="types"><a class="type" href="../modules/Hotkey.html#node">node</a> or <span class="type">nil</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "node"></a>
<strong>node</strong>
</dt>
<dd>
Visual node
<ul>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/Hotkey.html#node">node</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "on_hotkey_pressed"></a>
<strong>on_hotkey_pressed</strong>
</dt>
<dd>
On hotkey released callback(self, argument)
<ul>
<li><span class="parameter">on_hotkey_pressed</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
</ul>
</dd>
<dt>
<a name = "on_hotkey_released"></a>
<strong>on_hotkey_released</strong>
</dt>
<dd>
On hotkey released callback(self, argument)
<ul>
<li><span class="parameter">on_hotkey_released</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -33,6 +33,7 @@
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Tables">Tables</a></li>
<li><a href="#Fields">Fields</a></li>
</ul>
@@ -43,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><strong>Hover</strong></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -79,14 +79,22 @@
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, node, on_hover_callback)</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, on_hover_callback, on_mouse_hover)</a></td>
<td class="summary">The <a href="../modules/Hover.html#">Hover</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_enabled">is_enabled(self)</a></td>
<td class="summary">Return current hover enabled state</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_hovered">is_hovered(self)</a></td>
<td class="summary">Return current hover state.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_mouse_hovered">is_mouse_hovered(self)</a></td>
<td class="summary">Return current hover state.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_click_zone">set_click_zone(self, zone)</a></td>
<td class="summary">Strict hover click area.</td>
</tr>
@@ -103,15 +111,26 @@
<td class="summary">Set mouse hover state</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#style">style</a></td>
<td class="summary">Component style params.</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Hover node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_hover">on_hover</a></td>
<td class="summary">On hover callback(self, state)</td>
<td class="summary">On hover callback(self, state, hover_instance)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_mouse_hover">on_mouse_hover</a></td>
<td class="summary">On mouse hover callback(self, state)</td>
<td class="summary">On mouse hover callback(self, state, hover_instance)</td>
</tr>
</table>
@@ -124,10 +143,10 @@
<dl class="function">
<dt>
<a name = "init"></a>
<strong>init(self, node, on_hover_callback)</strong>
<strong>init(self, node, on_hover_callback, on_mouse_hover)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Hover.html#">Hover</a> constructor
<h3>Parameters:</h3>
@@ -137,13 +156,17 @@
<a href="../modules/Hover.html#">Hover</a>
</li>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><a class="type" href="../modules/Hover.html#node">node</a></span>
Gui node
</li>
<li><span class="parameter">on_hover_callback</span>
<span class="types"><span class="type">function</span></span>
Hover callback
</li>
<li><span class="parameter">on_mouse_hover</span>
<span class="types"><span class="type">function</span></span>
On mouse hover callback
</li>
</ul>
@@ -170,13 +193,67 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
The hover enabled state
</ol>
</dd>
<dt>
<a name = "is_hovered"></a>
<strong>is_hovered(self)</strong>
</dt>
<dd>
Return current hover state. True if touch action was on the node at current time
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Hover</span></span>
<a href="../modules/Hover.html#">Hover</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
The current hovered state
</ol>
</dd>
<dt>
<a name = "is_mouse_hovered"></a>
<strong>is_mouse_hovered(self)</strong>
</dt>
<dd>
Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Hover</span></span>
<a href="../modules/Hover.html#">Hover</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
The current hovered state
</ol>
</dd>
<dt>
<a name = "set_click_zone"></a>
@@ -194,7 +271,7 @@
<a href="../modules/Hover.html#">Hover</a>
</li>
<li><span class="parameter">zone</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><a class="type" href="../modules/Hover.html#node">node</a>, <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Gui node
</li>
</ul>
@@ -221,7 +298,7 @@
<a href="../modules/Hover.html#">Hover</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
The hover enabled state
</li>
</ul>
@@ -246,7 +323,7 @@
<a href="../modules/Hover.html#">Hover</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
The hover state
</li>
</ul>
@@ -271,7 +348,7 @@
<a href="../modules/Hover.html#">Hover</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
The mouse hover state
</li>
</ul>
@@ -280,17 +357,70 @@
</dd>
</dl>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
<dl class="function">
<dt>
<a name = "style"></a>
<strong>style</strong>
</dt>
<dd>
Component style params.
You can override this component styles params in druid styles table
or create your own style
<h3>Fields:</h3>
<ul>
<li><span class="parameter">ON_HOVER_CURSOR</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Mouse hover style on node hover
(<em>optional</em>)
</li>
<li><span class="parameter">ON_MOUSE_HOVER_CURSOR</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Mouse hover style on node mouse hover
(<em>optional</em>)
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "node"></a>
<strong>node</strong>
</dt>
<dd>
Hover node
<ul>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/Hover.html#node">node</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "on_hover"></a>
<strong>on_hover</strong>
</dt>
<dd>
On hover callback(self, state)
On hover callback(self, state, hover_instance)
<ul>
@@ -310,7 +440,7 @@
<strong>on_mouse_hover</strong>
</dt>
<dd>
On mouse hover callback(self, state)
On mouse hover callback(self, state, hover_instance)
<ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><strong>Input</strong></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -75,7 +74,8 @@
<h1>Module <code>Input</code></h1>
<p>Druid input text component.</p>
<p>
Carry on user text input</p>
Carry on user text input
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_input" target="_blank"><b>Example Link</b></a></p>
<h3>Info:</h3>
<ul>
<li><strong>Author</strong>: Part of code from Britzl gooey input component</li>
@@ -89,8 +89,16 @@
<td class="summary">Return current input field text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, click_node, text_node[, keyboard_type])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#get_text_selected_replaced">get_text_selected_replaced(self, text)</a></td>
<td class="summary">Replace selected text with new text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, click_node, text_node, keyboard_type)</a></td>
<td class="summary">The <a href="../modules/Input.html#">Input</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#move_selection">move_selection(self, delta, is_add_to_selection, is_move_to_end)</a></td>
<td class="summary">Change cursor position by delta</td>
</tr>
<tr>
<td class="name" nowrap><a href="#reset_changes">reset_changes(self)</a></td>
@@ -101,6 +109,10 @@
<td class="summary">Select input field.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#select_cursor">select_cursor(self, cursor_index, start_index, end_index)</a></td>
<td class="summary">Set cursor position in input field</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_allowed_characters">set_allowed_characters(self, characters)</a></td>
<td class="summary">Set allowed charaters for input field.</td>
</tr>
@@ -135,6 +147,18 @@
<td class="summary">Button component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#current_value">current_value</a></td>
<td class="summary">Current input value with marked text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cursor_index">cursor_index</a></td>
<td class="summary">The cursor index.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#end_index">end_index</a></td>
<td class="summary">Theselection end index.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_empty">is_empty</a></td>
<td class="summary">Is current input is empty now</td>
</tr>
@@ -147,6 +171,14 @@
<td class="summary">Gui keyboard type for input field</td>
</tr>
<tr>
<td class="name" nowrap><a href="#marked_text_width">marked_text_width</a></td>
<td class="summary">Marked text width</td>
</tr>
<tr>
<td class="name" nowrap><a href="#marked_value">marked_value</a></td>
<td class="summary">Marked text for input field.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#max_length">max_length</a></td>
<td class="summary">Max length for input text</td>
</tr>
@@ -160,7 +192,7 @@
</tr>
<tr>
<td class="name" nowrap><a href="#on_input_select">on_input_select</a></td>
<td class="summary">On input field select callback(self, button_node)</td>
<td class="summary">On input field select callback(self, input_instance)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_input_text">on_input_text</a></td>
@@ -168,16 +200,36 @@
</tr>
<tr>
<td class="name" nowrap><a href="#on_input_unselect">on_input_unselect</a></td>
<td class="summary">On input field unselect callback(self, input_text)</td>
<td class="summary">On input field unselect callback(self, input_text, input_instance)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_input_wrong">on_input_wrong</a></td>
<td class="summary">On trying user input with not allowed character callback(self, params, button_instance)</td>
<td class="summary">On trying user input with not allowed character callback(self, params, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_select_cursor_change">on_select_cursor_change</a></td>
<td class="summary">On cursor position change callback(self, cursor_index, start_index, end_index)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#previous_value">previous_value</a></td>
<td class="summary">Previous input value</td>
</tr>
<tr>
<td class="name" nowrap><a href="#start_index">start_index</a></td>
<td class="summary">The selection start index.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#text">text</a></td>
<td class="summary">Text component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#text_width">text_width</a></td>
<td class="summary">Text width</td>
</tr>
<tr>
<td class="name" nowrap><a href="#value">value</a></td>
<td class="summary">Current input value</td>
</tr>
</table>
<br/>
@@ -215,11 +267,42 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, click_node, text_node[, keyboard_type])</strong>
<a name = "get_text_selected_replaced"></a>
<strong>get_text_selected_replaced(self, text)</strong>
</dt>
<dd>
Component init function
Replace selected text with new text
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Input</span></span>
<a href="../modules/Input.html#">Input</a>
</li>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text to replace selected text
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
New input text
</ol>
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, click_node, text_node, keyboard_type)</strong>
</dt>
<dd>
The <a href="../modules/Input.html#">Input</a> constructor
<h3>Parameters:</h3>
@@ -230,16 +313,48 @@
</li>
<li><span class="parameter">click_node</span>
<span class="types"><span class="type">node</span></span>
Button node to enabled input component
Node to enabled input component
</li>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">node</span> or <span class="type">Text</span></span>
Text node what will be changed on user input. You can pass text component instead of text node name <a href="../modules/Text.html#">Text</a>
</li>
<li><span class="parameter">keyboard_type</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Gui keyboard type for input field
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "move_selection"></a>
<strong>move_selection(self, delta, is_add_to_selection, is_move_to_end)</strong>
</dt>
<dd>
Change cursor position by delta
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Input</span></span>
<a href="../modules/Input.html#">Input</a>
</li>
<li><span class="parameter">delta</span>
<span class="types"><span class="type">number</span></span>
side for cursor position, -1 for left, 1 for right
</li>
<li><span class="parameter">is_add_to_selection</span>
<span class="types"><span class="type">boolean</span></span>
(Shift key)
</li>
<li><span class="parameter">is_move_to_end</span>
<span class="types"><span class="type">boolean</span></span>
(Ctrl key)
</li>
</ul>
@@ -264,6 +379,12 @@
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.input</span></span>
Current input instance
</ol>
@@ -289,6 +410,45 @@
</dd>
<dt>
<a name = "select_cursor"></a>
<strong>select_cursor(self, cursor_index, start_index, end_index)</strong>
</dt>
<dd>
Set cursor position in input field
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Input</span></span>
<a href="../modules/Input.html#">Input</a>
</li>
<li><span class="parameter">cursor_index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Cursor index for cursor position, if nil - will be set to the end of the text
</li>
<li><span class="parameter">start_index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Start index for cursor position, if nil - will be set to the end of the text
</li>
<li><span class="parameter">end_index</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
End index for cursor position, if nil - will be set to the start_index
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.input</span></span>
Current input instance
</ol>
</dd>
<dt>
<a name = "set_allowed_characters"></a>
@@ -418,19 +578,16 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">IS_LONGTAP_ERASE</span>
<span class="types"><span class="type">bool</span></span>
Is long tap will erase current input data
(<em>default</em> false)
<span class="types"><span class="type">boolean</span></span>
Is long tap will erase current input data. Default: false
</li>
<li><span class="parameter">MASK_DEFAULT_CHAR</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Default character mask for password input
(<em>default</em> *)
Default character mask for password input. Default: *]
</li>
<li><span class="parameter">IS_UNSELECT_ON_RESELECT</span>
<span class="types"><span class="type">bool</span></span>
If true, call unselect on select selected input
(<em>default</em> false)
<span class="types"><span class="type">boolean</span></span>
If true, call unselect on select selected input. Default: false
</li>
<li><span class="parameter">on_select</span>
<span class="types"><span class="type">function</span></span>
@@ -444,10 +601,6 @@
<span class="types"><span class="type">function</span></span>
(self, button_node) Callback on wrong user input
</li>
<li><span class="parameter">button_style</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Custom button style for input node
</li>
</ul>
@@ -469,9 +622,8 @@
<ul>
<li><span class="parameter">allowerd_characters</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
(<em>optional</em>)
</li>
</ul>
@@ -499,6 +651,66 @@
</dd>
<dt>
<a name = "current_value"></a>
<strong>current_value</strong>
</dt>
<dd>
Current input value with marked text
<ul>
<li><span class="parameter">current_value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "cursor_index"></a>
<strong>cursor_index</strong>
</dt>
<dd>
The cursor index. The index of letter cursor after. Leftmost cursor - 0
<ul>
<li><span class="parameter">cursor_index</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "end_index"></a>
<strong>end_index</strong>
</dt>
<dd>
Theselection end index. The index of letter cursor before. Rightmost selection - #text
<ul>
<li><span class="parameter">end_index</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "is_empty"></a>
@@ -510,7 +722,7 @@
<ul>
<li><span class="parameter">is_empty</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -530,7 +742,7 @@
<ul>
<li><span class="parameter">is_selected</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -559,6 +771,46 @@
</dd>
<dt>
<a name = "marked_text_width"></a>
<strong>marked_text_width</strong>
</dt>
<dd>
Marked text width
<ul>
<li><span class="parameter">marked_text_width</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "marked_value"></a>
<strong>marked_value</strong>
</dt>
<dd>
Marked text for input field. Info: https://defold.com/manuals/input-key-and-text/#marked-text
<ul>
<li><span class="parameter">marked_value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "max_length"></a>
@@ -570,9 +822,8 @@
<ul>
<li><span class="parameter">max_length</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
(<em>optional</em>)
</li>
</ul>
@@ -626,7 +877,7 @@
<strong>on_input_select</strong>
</dt>
<dd>
On input field select callback(self, button_node)
On input field select callback(self, input_instance)
<ul>
@@ -666,7 +917,7 @@
<strong>on_input_unselect</strong>
</dt>
<dd>
On input field unselect callback(self, input_text)
On input field unselect callback(self, input_text, input_instance)
<ul>
@@ -686,7 +937,7 @@
<strong>on_input_wrong</strong>
</dt>
<dd>
On trying user input with not allowed character callback(self, params, button_instance)
On trying user input with not allowed character callback(self, params, input_text)
<ul>
@@ -700,6 +951,66 @@
</dd>
<dt>
<a name = "on_select_cursor_change"></a>
<strong>on_select_cursor_change</strong>
</dt>
<dd>
On cursor position change callback(self, cursor_index, start_index, end_index)
<ul>
<li><span class="parameter">on_select_cursor_change</span>
<span class="types"><span class="type">DruidEvent</span></span>
<a href="../modules/DruidEvent.html#">DruidEvent</a>
</li>
</ul>
</dd>
<dt>
<a name = "previous_value"></a>
<strong>previous_value</strong>
</dt>
<dd>
Previous input value
<ul>
<li><span class="parameter">previous_value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "start_index"></a>
<strong>start_index</strong>
</dt>
<dd>
The selection start index. The index of letter cursor after. Leftmost selection - 0
<ul>
<li><span class="parameter">start_index</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "text"></a>
@@ -720,6 +1031,46 @@
</dd>
<dt>
<a name = "text_width"></a>
<strong>text_width</strong>
</dt>
<dd>
Text width
<ul>
<li><span class="parameter">text_width</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "value"></a>
<strong>value</strong>
</dt>
<dd>
Current input value
<ul>
<li><span class="parameter">value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
</dl>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><strong>LangText</strong></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -72,32 +71,42 @@
<div id="content">
<h1>Module <code>LangText</code></h1>
<p>Component to handle all GUI texts
Good working with localization system</p>
<p></p>
<p>Component to wrap over GUI Text nodes with localization helpers
<p> <b># Overview #</b>
<p> • The initialization of druid.set_text_function is required to enable localization
using the localization ID.</p>
<p>
<p> • The LangText component supports up to 7 string format parameters.
This limitation exists due to certain issues with using ... arguments.
<p> <b># Notes #</b>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=texts_lang_text" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#format">format(self[, a[, b[, c[, d[, e[, f[, g]]]]]]])</a></td>
<td class="name" nowrap><a href="#format">format(self, a, b, c, d, e, f, g)</a></td>
<td class="summary">Format string with new text params on localized text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, node, locale_id, no_adjust)</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, locale_id, adjust_type)</a></td>
<td class="summary">The <a href="../modules/LangText.html#">LangText</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_to">set_to(self, text)</a></td>
<td class="summary">Setup raw text to lang_text component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#translate">translate(self, locale_id[, a[, b[, c[, d[, e[, f[, g]]]]]]])</a></td>
<td class="name" nowrap><a href="#translate">translate(self, locale_id, a, b, c, d, e, f, g)</a></td>
<td class="summary">Translate the text by locale_id</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Text node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_change">on_change</a></td>
<td class="summary">On change text callback</td>
@@ -117,7 +126,7 @@
<dl class="function">
<dt>
<a name = "format"></a>
<strong>format(self[, a[, b[, c[, d[, e[, f[, g]]]]]]])</strong>
<strong>format(self, a, b, c, d, e, f, g)</strong>
</dt>
<dd>
Format string with new text params on localized text
@@ -130,39 +139,32 @@
<a href="../modules/LangText.html#">LangText</a>
</li>
<li><span class="parameter">a</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">b</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">c</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">d</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">e</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">f</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">g</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
</ul>
@@ -179,10 +181,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, node, locale_id, no_adjust)</strong>
<strong>init(self, node, locale_id, adjust_type)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/LangText.html#">LangText</a> constructor
<h3>Parameters:</h3>
@@ -192,16 +194,16 @@
<a href="../modules/LangText.html#">LangText</a>
</li>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
The text node
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <a class="type" href="../modules/LangText.html#node">node</a></span>
The node_id or gui.get_node(node_id)
</li>
<li><span class="parameter">locale_id</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Default locale id or text from node as default
</li>
<li><span class="parameter">no_adjust</span>
<span class="types"><span class="type">bool</span></span>
If true, will not correct text size
<li><span class="parameter">adjust_type</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference
</li>
</ul>
@@ -243,7 +245,7 @@
</dd>
<dt>
<a name = "translate"></a>
<strong>translate(self, locale_id[, a[, b[, c[, d[, e[, f[, g]]]]]]])</strong>
<strong>translate(self, locale_id, a, b, c, d, e, f, g)</strong>
</dt>
<dd>
Translate the text by locale_id
@@ -260,39 +262,32 @@
Locale id
</li>
<li><span class="parameter">a</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">b</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">c</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">d</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">e</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">f</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
<li><span class="parameter">g</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Optional param to string.format
(<em>optional</em>)
</li>
</ul>
@@ -311,6 +306,26 @@
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "node"></a>
<strong>node</strong>
</dt>
<dd>
Text node
<ul>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/LangText.html#node">node</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "on_change"></a>
<strong>on_change</strong>

147
docs/modules/Layout.html Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Fields">Fields</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><strong>Layout</strong></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Module <code>Layout</code></h1>
<p>Layout management on node</p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_layout" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#mode">mode</a></td>
<td class="summary">Current layout mode</td>
</tr>
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Layout node</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "mode"></a>
<strong>mode</strong>
</dt>
<dd>
Current layout mode
<ul>
<li><span class="parameter">mode</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "node"></a>
<strong>node</strong>
</dt>
<dd>
Layout node
<ul>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/Layout.html#node">node</a></span>
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -47,24 +47,27 @@
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><strong>PinKnob</strong></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -81,14 +84,14 @@
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, callback, template, nodes)</a></td>
<td class="summary">Component init function</td>
<td class="summary">The <a href="../modules/PinKnob.html#">PinKnob</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_angle">set_angle(self, cur_value, min, max)</a></td>
<td class="summary">Set current and min/max angles for component</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_friction">set_friction(self[, value=1])</a></td>
<td class="name" nowrap><a href="#set_friction">set_friction(self, value)</a></td>
<td class="summary">Set current and min/max angles for component</td>
</tr>
</table>
@@ -120,7 +123,7 @@
<strong>init(self, callback, template, nodes)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/PinKnob.html#">PinKnob</a> constructor
<h3>Parameters:</h3>
@@ -189,7 +192,7 @@
</dd>
<dt>
<a name = "set_friction"></a>
<strong>set_friction(self[, value=1])</strong>
<strong>set_friction(self, value)</strong>
</dt>
<dd>
Set current and min/max angles for component
@@ -202,9 +205,8 @@
<a href="../modules/PinKnob.html#">PinKnob</a>
</li>
<li><span class="parameter">value</span>
<span class="types"><span class="type">number</span></span>
The spin speed multiplier
(<em>default</em> 1)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The spin speed multiplier. Default: 1
</li>
</ul>
@@ -253,7 +255,7 @@
<ul>
<li><span class="parameter">is_drag</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><strong>Progress</strong></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,9 +72,16 @@
<div id="content">
<h1>Module <code>Progress</code></h1>
<p>Basic progress bar component.</p>
<p>Druid component to handle the progress bars.</p>
<p>
For correct progress bar init it should be in max size from gui</p>
<b># Overview #</b>
<p> <b># Notes #</b>
<p> • Progress Node should be fully filled in your GUI scene node. It will be the progress maximum size
<p> • Progress correct working with Slice9 nodes, it trying to set size by _set_size_ first, if it is not possible, it set up sizing via _set_scale_
<p> • Progress bar can fill only by vertical or horizontal size. If you want make diagonal progress bar, just rotate node in GUI scene
<p> • If you have glitchy or dark texture bug with progress bar, try to disable mipmaps in your texture profiles
<p>
<a href="https://insality.github.io/druid/druid/index.html?example=general_progress_bar" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -93,8 +99,12 @@
<td class="summary">Return current progress bar value</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, node, key[, init_value=1])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, key, init_value)</a></td>
<td class="summary">The <a href="../modules/Progress.html#">Progress</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_max_size">set_max_size(self, max_size)</a></td>
<td class="summary">Set progress bar max node size</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_steps">set_steps(self, steps, callback)</a></td>
@@ -105,7 +115,7 @@
<td class="summary">Instant fill progress bar to value</td>
</tr>
<tr>
<td class="name" nowrap><a href="#to">to(self, to[, callback])</a></td>
<td class="name" nowrap><a href="#to">to(self, to, callback)</a></td>
<td class="summary">Start animation of a progress bar</td>
</tr>
</table>
@@ -120,7 +130,7 @@
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#key">key</a></td>
<td class="summary">The progress bar direction</td>
<td class="summary">The progress bar direction.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#max_size">max_size</a></td>
@@ -220,10 +230,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, node, key[, init_value=1])</strong>
<strong>init(self, node, key, init_value)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Progress.html#">Progress</a> constructor
<h3>Parameters:</h3>
@@ -234,16 +244,15 @@
</li>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <a class="type" href="../modules/Progress.html#node">node</a></span>
Progress bar fill node or node name
Node name or GUI Node itself.
</li>
<li><span class="parameter">key</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Progress bar direction: const.SIDE.X or const.SIDE.Y
</li>
<li><span class="parameter">init_value</span>
<span class="types"><span class="type">number</span></span>
Initial value of progress bar
(<em>default</em> 1)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Initial value of progress bar. Default: 1
</li>
</ul>
@@ -251,6 +260,37 @@
</dd>
<dt>
<a name = "set_max_size"></a>
<strong>set_max_size(self, max_size)</strong>
</dt>
<dd>
Set progress bar max node size
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Progress</span></span>
<a href="../modules/Progress.html#">Progress</a>
</li>
<li><span class="parameter">max_size</span>
<span class="types"><span class="type">vector3</span></span>
The new node maximum (full) size
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Progress</span></span>
<a href="../modules/Progress.html#">Progress</a>
</ol>
</dd>
<dt>
<a name = "set_steps"></a>
@@ -312,7 +352,7 @@
</dd>
<dt>
<a name = "to"></a>
<strong>to(self, to[, callback])</strong>
<strong>to(self, to, callback)</strong>
</dt>
<dd>
Start animation of a progress bar
@@ -329,9 +369,8 @@
value between 0..1
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
<span class="types"><span class="type">function</span> or <span class="type">nil</span></span>
Callback on animation ends
(<em>optional</em>)
</li>
</ul>
@@ -357,14 +396,12 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">SPEED</span>
<span class="types"><span class="type">number</span></span>
Progress bas fill rate. More -> faster
(<em>default</em> 5)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Progress bas fill rate. More -> faster. Default: 5
</li>
<li><span class="parameter">MIN_DELTA</span>
<span class="types"><span class="type">number</span></span>
Minimum step to fill progress bar
(<em>default</em> 0.005)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Minimum step to fill progress bar. Default: 0.005
</li>
</ul>
@@ -382,7 +419,8 @@
<strong>key</strong>
</dt>
<dd>
The progress bar direction
The progress bar direction.
<p> The values are: "x" or "y". (const.SIDE.X or const.SIDE.Y)
<ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -47,24 +47,26 @@
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><strong>RadioGroup</strong></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,7 +75,7 @@
<h1>Module <code>RadioGroup</code></h1>
<p>Radio group module</p>
<p></p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_checkboxes" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -83,8 +85,8 @@
<td class="summary">Return radio group state</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, nodes, callback[, click_nodes=node])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, nodes, callback, click_nodes)</a></td>
<td class="summary">The <a href="../modules/RadioGroup.html#">RadioGroup</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_state">set_state(self, index, is_instant)</a></td>
@@ -139,10 +141,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, nodes, callback[, click_nodes=node])</strong>
<strong>init(self, nodes, callback, click_nodes)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/RadioGroup.html#">RadioGroup</a> constructor
<h3>Parameters:</h3>
@@ -160,9 +162,8 @@
Radio callback
</li>
<li><span class="parameter">click_nodes</span>
<span class="types"><span class="type">node[]</span></span>
Array of trigger nodes, by default equals to nodes
(<em>default</em> node)
<span class="types"><span class="type">node[]</span> or <span class="type">nil</span></span>
Array of trigger nodes, by default equals to nodes. Default - nodes
</li>
</ul>
@@ -190,7 +191,7 @@
Index in radio group
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If is instant state change
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><strong>RichInput</strong></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -79,14 +78,34 @@
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#get_text">get_text(self)</a></td>
<td class="summary">Set input field text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, template, nodes)</a></td>
<td class="summary">Component init function</td>
<td class="summary">The <a href="../modules/RichInput.html#">RichInput</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#select">select(self)</a></td>
<td class="summary">Select input field</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_allowed_characters">set_allowed_characters(self, characters)</a></td>
<td class="summary">Set allowed charaters for input field.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_font">set_font(self, font)</a></td>
<td class="summary">Set input field font</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_placeholder">set_placeholder(self, placeholder_text)</a></td>
<td class="summary">Set placeholder text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_text">set_text(self, text)</a></td>
<td class="summary">Set input field text</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
@@ -95,6 +114,18 @@
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cursor_position">cursor_position</a></td>
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#cursor_text">cursor_text</a></td>
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#drag">drag</a></td>
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#druid">druid</a></td>
<td class="summary">The component druid instance</td>
</tr>
@@ -103,8 +134,20 @@
<td class="summary">On input field text change callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#input_text">input_text</a></td>
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#placeholder">placeholder</a></td>
<td class="summary">On input field text change to max length string callback(self, input_text)</td>
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#root">root</a></td>
<td class="summary">Root node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#text_position">text_position</a></td>
<td class="summary">On input field text change to empty string callback(self, input_text)</td>
</tr>
</table>
@@ -115,12 +158,33 @@
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "get_text"></a>
<strong>get_text(self)</strong>
</dt>
<dd>
Set input field text
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichInput</span></span>
<a href="../modules/RichInput.html#">RichInput</a>
</li>
</ul>
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, template, nodes)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/RichInput.html#">RichInput</a> constructor
<h3>Parameters:</h3>
@@ -143,6 +207,91 @@
</dd>
<dt>
<a name = "select"></a>
<strong>select(self)</strong>
</dt>
<dd>
Select input field
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichInput</span></span>
<a href="../modules/RichInput.html#">RichInput</a>
</li>
</ul>
</dd>
<dt>
<a name = "set_allowed_characters"></a>
<strong>set_allowed_characters(self, characters)</strong>
</dt>
<dd>
Set allowed charaters for input field.
See: https://defold.com/ref/stable/string/
ex: [%a%d] for alpha and numeric
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichInput</span></span>
<a href="../modules/RichInput.html#">RichInput</a>
</li>
<li><span class="parameter">characters</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Regulax exp. for validate user input
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">RichInput</span></span>
Current instance
</ol>
</dd>
<dt>
<a name = "set_font"></a>
<strong>set_font(self, font)</strong>
</dt>
<dd>
Set input field font
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichInput</span></span>
<a href="../modules/RichInput.html#">RichInput</a>
</li>
<li><span class="parameter">font</span>
<span class="types"><span class="type">hash</span></span>
The font hash
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.input</span></span>
Current input instance
</ol>
</dd>
<dt>
<a name = "set_placeholder"></a>
@@ -168,6 +317,37 @@
</dd>
<dt>
<a name = "set_text"></a>
<strong>set_text(self, text)</strong>
</dt>
<dd>
Set input field text
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichInput</span></span>
<a href="../modules/RichInput.html#">RichInput</a>
</li>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The input text
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.input</span></span>
Current input instance
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
@@ -192,6 +372,66 @@
</dd>
<dt>
<a name = "cursor_position"></a>
<strong>cursor_position</strong>
</dt>
<dd>
On input field text change to empty string callback(self, input_text)
<ul>
<li><span class="parameter">cursor_position</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "cursor_text"></a>
<strong>cursor_text</strong>
</dt>
<dd>
On input field text change to empty string callback(self, input_text)
<ul>
<li><span class="parameter">cursor_text</span>
<span class="types"><span class="type">node</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "drag"></a>
<strong>drag</strong>
</dt>
<dd>
On input field text change to empty string callback(self, input_text)
<ul>
<li><span class="parameter">drag</span>
<span class="types"><span class="type">druid.drag</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "druid"></a>
@@ -232,19 +472,79 @@
</dd>
<dt>
<a name = "input_text"></a>
<strong>input_text</strong>
</dt>
<dd>
On input field text change to empty string callback(self, input_text)
<ul>
<li><span class="parameter">input_text</span>
<span class="types"><span class="type">druid.text</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "placeholder"></a>
<strong>placeholder</strong>
</dt>
<dd>
On input field text change to max length string callback(self, input_text)
On input field text change to empty string callback(self, input_text)
<ul>
<li><span class="parameter">placeholder</span>
<span class="types"><span class="type">druid.text</span></span>
<a href="../modules/Text.html#">Text</a>
</li>
</ul>
</dd>
<dt>
<a name = "root"></a>
<strong>root</strong>
</dt>
<dd>
Root node
<ul>
<li><span class="parameter">root</span>
<span class="types"><span class="type">node</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "text_position"></a>
<strong>text_position</strong>
</dt>
<dd>
On input field text change to empty string callback(self, input_text)
<ul>
<li><span class="parameter">text_position</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>

560
docs/modules/RichText.html Normal file
View File

@@ -0,0 +1,560 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
<li><a href="#Tables">Tables</a></li>
<li><a href="#Fields">Fields</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><strong>RichText</strong></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
</ul>
</div>
<div id="content">
<h1>Module <code>RichText</code></h1>
<p>Druid Rich Text Custom Component.</p>
<p>
<b># Overview #</b>
<p> This custom component is inspired by <a href="https://github.com/britzl/defold-richtext" target="_blank">defold-richtext</a> by britzl.
It uses a similar syntax for tags but currently supports fewer tags.
<p> Create Rich Text on your GUI Text Node. All properties of the text node will be used as default for the text.
<p> <b># Notes #</b>
<p> • Nested tags are supported
<p> <a href="https://insality.github.io/druid/druid/index.html?example=custom_rich_text" target="_blank"><b>Example Link</b></a></p>
<h3>Usage:</h3>
<ul>
<li><pre class="example">local RichText = require(&quot;druid.custom.rich_text.rich_text&quot;)
...
self.rich_text = self.druid:new(RichText, &quot;rich_text&quot;)
self.rich_text:set_text(&quot;Hello, Druid Rich Text!&quot;)
</pre></li>
<li><pre class="example">type druid.rich_text.word = {
node: Node,
relative_scale: number,
color: vector4,
position: vector3,
offset: vector3,
scale: vector3,
size: vector3,
metrics: druid.rich_text.metrics,
pivot: Pivot,
text: string,
shadow: vector4,
outline: vector4,
font: string,
image: druid.rich_text.image,
br: boolean,
nobr: boolean,
}
type druid.rich_text.word.image = {
texture: string,
anim: string,
width: number,
height: number,
}
type druid.rich_text.lines_metrics = {
text_width: number,
text_height: number,
lines: table&lt;number, druid.rich_text.metrics&gt;,
}
type druid.rich_text.metrics = {
width: number,
height: number,
offset_x: number|nil,
offset_y: number|nil,
node_size: vector3|nil @For images only,
}
</pre></li>
</ul>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#characters">characters(self, word)</a></td>
<td class="summary">Split a word into it's characters</td>
</tr>
<tr>
<td class="name" nowrap><a href="#clear">clear()</a></td>
<td class="summary">Clear all created words.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_line_metric">get_line_metric()</a></td>
<td class="summary">Get current line metrics</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_text">get_text(self)</a></td>
<td class="summary">Get current text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_words">get_words()</a></td>
<td class="summary">Get all current words.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, text_node, value)</a></td>
<td class="summary">The <a href="../modules/RichText.html#">RichText</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_text">set_text(self, text)</a></td>
<td class="summary">Set text for Rich Text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#tagged">tagged(self, tag)</a></td>
<td class="summary">Get all words, which has a passed tag.</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#style">style</a></td>
<td class="summary">Component style params.</td>
</tr>
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#druid">druid</a></td>
<td class="summary">The component druid instance</td>
</tr>
<tr>
<td class="name" nowrap><a href="#root">root</a></td>
<td class="summary">The root node of the Rich Text</td>
</tr>
<tr>
<td class="name" nowrap><a href="#text_prefab">text_prefab</a></td>
<td class="summary">The text prefab node</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "characters"></a>
<strong>characters(self, word)</strong>
</dt>
<dd>
Split a word into it's characters
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichText</span></span>
<a href="../modules/RichText.html#">RichText</a>
</li>
<li><span class="parameter">word</span>
<span class="types"><span class="type">druid.rich_text.word</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.rich_text.word[]</span></span>
characters
</ol>
</dd>
<dt>
<a name = "clear"></a>
<strong>clear()</strong>
</dt>
<dd>
Clear all created words.
</dd>
<dt>
<a name = "get_line_metric"></a>
<strong>get_line_metric()</strong>
</dt>
<dd>
Get current line metrics
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.rich_text.lines_metrics</span></span>
</ol>
</dd>
<dt>
<a name = "get_text"></a>
<strong>get_text(self)</strong>
</dt>
<dd>
Get current text
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichText</span></span>
<a href="../modules/RichText.html#">RichText</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
text
</ol>
</dd>
<dt>
<a name = "get_words"></a>
<strong>get_words()</strong>
</dt>
<dd>
Get all current words.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
druid.rich_text.word[]
</ol>
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, text_node, value)</strong>
</dt>
<dd>
The <a href="../modules/RichText.html#">RichText</a> constructor
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichText</span></span>
<a href="../modules/RichText.html#">RichText</a>
</li>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">node</span> or <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The text node to make Rich Text
</li>
<li><span class="parameter">value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
The initial text value. Default will be gui.get_text(text_node)
</li>
</ul>
</dd>
<dt>
<a name = "set_text"></a>
<strong>set_text(self, text)</strong>
</dt>
<dd>
Set text for Rich Text
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichText</span></span>
<a href="../modules/RichText.html#">RichText</a>
</li>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
The text to set
</li>
</ul>
<h3>Returns:</h3>
<ol>
<li>
<span class="types"><span class="type">druid.rich_text.word[]</span></span>
words</li>
<li>
<span class="types"><span class="type">druid.rich_text.lines_metrics</span></span>
line_metrics</li>
</ol>
<h3>Usage:</h3>
<ul>
<pre class="example">• color: Change text color
&lt;color=red&gt;Foobar&lt;/color&gt;
&lt;color=<span class="number">1.0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1.0</span>&gt;Foobar&lt;/color&gt;
&lt;color=#ff0000&gt;Foobar&lt;/color&gt;
&lt;color=#ff0000ff&gt;Foobar&lt;/color&gt;
• shadow: Change text shadow
&lt;shadow=red&gt;Foobar&lt;/shadow&gt;
&lt;shadow=<span class="number">1.0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1.0</span>&gt;Foobar&lt;/shadow&gt;
&lt;shadow=#ff0000&gt;Foobar&lt;/shadow&gt;
&lt;shadow=#ff0000ff&gt;Foobar&lt;/shadow&gt;
• outline: Change text shadow
&lt;outline=red&gt;Foobar&lt;/outline&gt;
&lt;outline=<span class="number">1.0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1.0</span>&gt;Foobar&lt;/outline&gt;
&lt;outline=#ff0000&gt;Foobar&lt;/outline&gt;
&lt;outline=#ff0000ff&gt;Foobar&lt;/outline&gt;
• font: Change font
&lt;font=MyCoolFont&gt;Foobar&lt;/font&gt;
• size: Change text size, relative to default size
&lt;size=<span class="number">2</span>&gt;Twice as large&lt;/size&gt;
• br: Insert a line <span class="keyword">break</span>
&lt;br/&gt;
• nobr: Prevent the text from breaking
Words &lt;nobr&gt;inside tag&lt;/nobr&gt; won't <span class="keyword">break</span>
• img: Display image
&lt;img=texture:image/&gt;
&lt;img=texture:image,size/&gt;
&lt;img=texture:image,width,height/&gt;</pre>
</ul>
</dd>
<dt>
<a name = "tagged"></a>
<strong>tagged(self, tag)</strong>
</dt>
<dd>
Get all words, which has a passed tag.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">RichText</span></span>
<a href="../modules/RichText.html#">RichText</a>
</li>
<li><span class="parameter">tag</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.rich_text.word[]</span></span>
words
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
<dl class="function">
<dt>
<a name = "style"></a>
<strong>style</strong>
</dt>
<dd>
Component style params.
You can override this component styles params in Druid styles table
or create your own style
<h3>Fields:</h3>
<ul>
<li><span class="parameter">COLORS</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a> or <span class="type">nil</span></span>
Rich Text color aliases. Default: {}
</li>
<li><span class="parameter">ADJUST_STEPS</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Amount steps of attemps text adjust by height. Default: 20
</li>
<li><span class="parameter">ADJUST_SCALE_DELTA</span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Scale step on each height adjust step. Default: 0.02
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "druid"></a>
<strong>druid</strong>
</dt>
<dd>
The component druid instance
<ul>
<li><span class="parameter">druid</span>
<span class="types"><span class="type">DruidInstance</span></span>
<a href="../modules/DruidInstance.html#">DruidInstance</a>
</li>
</ul>
</dd>
<dt>
<a name = "root"></a>
<strong>root</strong>
</dt>
<dd>
The root node of the Rich Text
<ul>
<li><span class="parameter">root</span>
<span class="types"><span class="type">node</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "text_prefab"></a>
<strong>text_prefab</strong>
</dt>
<dd>
The text prefab node
<ul>
<li><span class="parameter">text_prefab</span>
<span class="types"><span class="type">node</span></span>
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><strong>Scroll</strong></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -75,12 +74,26 @@
<h1>Module <code>Scroll</code></h1>
<p>Component to handle scroll content.</p>
<p>
Scroll consist from two nodes: scroll parent and scroll input
Scroll input the user input zone, it's static
Scroll parent the scroll moving part, it will change position.
Setup initial scroll size by changing scroll parent size. If scroll parent
size will be less than scroll_input size, no scroll is available. For scroll
parent size should be more than input size</p>
<b># Overview #</b>
<p> The Scroll component is designed to handle scrollable content and consists of two nodes: the scroll parent and the scroll input.
<p> The scroll input represents the user input zone and remains static.
<p> The scroll parent is the movable part of the scroll and changes its position.
<p> The initial scroll size can be set by adjusting the size of the scroll parent.
If the size of the scroll parent is smaller than the scroll input size, scrolling is not available.
<p> <b># Notes #</b>
<p> • By default, the scroll style includes inertia and extra size for a stretching effect.
These settings can be adjusted using the scroll style settings.
For more details, refer to the scroll style settings.
<p> • "Points of interest" can be set up for the scroll.
The scroll will always be centered on the closest point of interest.
This feature allows creating a slider without inertia and with points of interest on each scroll element.
<p> • The scroll content size can be adjusted using the scroll:set_size(node_size) method.
This method sets a new size for the _content node.
<p> • Inertial scrolling mode can be enabled or disabled using the scroll:set_inert(state) method.
<p> • The extra stretch size can be adjusted using the scroll:set_extra_stretch_size method.
<p> • Multitouch is required for scrolling. The scroll component correctly handles
touch ID swaps while dragging the scroll.
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_scroll" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -100,7 +113,7 @@
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, view_node, content_node)</a></td>
<td class="summary">Scroll constructor</td>
<td class="summary">The <a href="../modules/Scroll.html#">Scroll</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_inert">is_inert(self)</a></td>
@@ -111,15 +124,15 @@
<td class="summary">Check node if it visible now on scroll.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#scroll_to">scroll_to(self, point[, is_instant])</a></td>
<td class="name" nowrap><a href="#scroll_to">scroll_to(self, point, is_instant)</a></td>
<td class="summary">Start scroll to target point.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#scroll_to_index">scroll_to_index(self, index[, skip_cb])</a></td>
<td class="name" nowrap><a href="#scroll_to_index">scroll_to_index(self, index, skip_cb)</a></td>
<td class="summary">Scroll to item in scroll by point index.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#scroll_to_percent">scroll_to_percent(self, percent[, is_instant])</a></td>
<td class="name" nowrap><a href="#scroll_to_percent">scroll_to_percent(self, percent, is_instant)</a></td>
<td class="summary">Start scroll to target scroll percent</td>
</tr>
<tr>
@@ -127,7 +140,7 @@
<td class="summary">Strict drag scroll area.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_extra_stretch_size">set_extra_stretch_size(self[, stretch_size=0])</a></td>
<td class="name" nowrap><a href="#set_extra_stretch_size">set_extra_stretch_size(self, stretch_size)</a></td>
<td class="summary">Set extra size for scroll stretching.</td>
</tr>
<tr>
@@ -150,6 +163,14 @@
<td class="name" nowrap><a href="#set_vertical_scroll">set_vertical_scroll(self, state)</a></td>
<td class="summary">Lock or unlock vertical scroll</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_view_size">set_view_size(self, size)</a></td>
<td class="summary">Set new scroll view size in case the node size was changed.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#update_view_size">update_view_size(self)</a></td>
<td class="summary">Refresh scroll view size</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
@@ -160,6 +181,10 @@
</table>
<h2><a href="#Fields">Fields</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#_is_inert">_is_inert</a></td>
<td class="summary">Flag, if scroll now moving by inertion</td>
</tr>
<tr>
<td class="name" nowrap><a href="#available_pos">available_pos</a></td>
<td class="summary">Available position for content node: (min_x, max_y, max_x, min_y)</td>
@@ -185,10 +210,6 @@
<td class="summary">Flag, if scroll now animating by gui.animate</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_inert">is_inert</a></td>
<td class="summary">Flag, if scroll now moving by inertion</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_point_scroll">on_point_scroll</a></td>
<td class="summary">On scroll_to_index function callback(self, index, point)</td>
</tr>
@@ -216,6 +237,10 @@
<td class="name" nowrap><a href="#view_node">view_node</a></td>
<td class="summary">Scroll view node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#view_size">view_size</a></td>
<td class="summary">Scroll view size</td>
</tr>
</table>
<br/>
@@ -241,7 +266,7 @@
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">grid</span>
<span class="types"><span class="type">StaticGrid</span> or <span class="type">DynamicGrid</span></span>
<span class="types"><span class="type">StaticGrid</span></span>
Druid grid component
</li>
</ul>
@@ -317,7 +342,7 @@
<strong>init(self, view_node, content_node)</strong>
</dt>
<dd>
Scroll constructor
The <a href="../modules/Scroll.html#">Scroll</a> constructor
<h3>Parameters:</h3>
@@ -327,11 +352,11 @@
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">view_node</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">node</span></span>
GUI view scroll node
</li>
<li><span class="parameter">content_node</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">node</span></span>
GUI content scroll node
</li>
</ul>
@@ -360,8 +385,8 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
If scroll have inertion
<span class="types"><span class="type">boolean</span></span>
@If scroll have inertion
</ol>
@@ -402,7 +427,7 @@
</dd>
<dt>
<a name = "scroll_to"></a>
<strong>scroll_to(self, point[, is_instant])</strong>
<strong>scroll_to(self, point, is_instant)</strong>
</dt>
<dd>
Start scroll to target point.
@@ -419,9 +444,8 @@
Target point
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Instant scroll flag
(<em>optional</em>)
</li>
</ul>
@@ -437,7 +461,7 @@
</dd>
<dt>
<a name = "scroll_to_index"></a>
<strong>scroll_to_index(self, index[, skip_cb])</strong>
<strong>scroll_to_index(self, index, skip_cb)</strong>
</dt>
<dd>
Scroll to item in scroll by point index.
@@ -454,9 +478,8 @@
Point index
</li>
<li><span class="parameter">skip_cb</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, skip the point callback
(<em>optional</em>)
</li>
</ul>
@@ -467,7 +490,7 @@
</dd>
<dt>
<a name = "scroll_to_percent"></a>
<strong>scroll_to_percent(self, percent[, is_instant])</strong>
<strong>scroll_to_percent(self, percent, is_instant)</strong>
</dt>
<dd>
Start scroll to target scroll percent
@@ -484,9 +507,8 @@
target percent
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
instant scroll flag
(<em>optional</em>)
</li>
</ul>
@@ -515,7 +537,7 @@
</li>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
<span class="types"><span class="type">node</span> or <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Gui node
</li>
</ul>
@@ -527,7 +549,7 @@
</dd>
<dt>
<a name = "set_extra_stretch_size"></a>
<strong>set_extra_stretch_size(self[, stretch_size=0])</strong>
<strong>set_extra_stretch_size(self, stretch_size)</strong>
</dt>
<dd>
Set extra size for scroll stretching.
@@ -541,9 +563,8 @@
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">stretch_size</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Size in pixels of additional scroll area
(<em>default</em> 0)
</li>
</ul>
@@ -573,7 +594,7 @@
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
True, if horizontal scroll is enabled
</li>
</ul>
@@ -606,7 +627,7 @@
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Inert scroll state
</li>
</ul>
@@ -674,7 +695,7 @@
The new size for content node
</li>
<li><span class="parameter">offset</span>
<span class="types"><span class="type">vector3</span></span>
<span class="types"><span class="type">vector3</span> or <span class="type">nil</span></span>
Offset value to set, where content is starts
</li>
</ul>
@@ -705,7 +726,7 @@
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">state</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
True, if vertical scroll is enabled
</li>
</ul>
@@ -720,6 +741,58 @@
</dd>
<dt>
<a name = "set_view_size"></a>
<strong>set_view_size(self, size)</strong>
</dt>
<dd>
Set new scroll view size in case the node size was changed.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Scroll</span></span>
<a href="../modules/Scroll.html#">Scroll</a>
</li>
<li><span class="parameter">size</span>
<span class="types"><span class="type">vector3</span></span>
The new size for view node
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.scroll</span></span>
Current scroll instance
</ol>
</dd>
<dt>
<a name = "update_view_size"></a>
<strong>update_view_size(self)</strong>
</dt>
<dd>
Refresh scroll view size
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Scroll</span></span>
<a href="../modules/Scroll.html#">Scroll</a>
</li>
</ul>
</dd>
</dl>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
@@ -738,64 +811,52 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">FRICT</span>
<span class="types"><span class="type">number</span></span>
Multiplier for free inertion
(<em>default</em> 0)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Multiplier for free inertion. Default: 0
</li>
<li><span class="parameter">FRICT_HOLD</span>
<span class="types"><span class="type">number</span></span>
Multiplier for inertion, while touching
(<em>default</em> 0)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Multiplier for inertion, while touching. Default: 0
</li>
<li><span class="parameter">INERT_THRESHOLD</span>
<span class="types"><span class="type">number</span></span>
Scroll speed to stop inertion
(<em>default</em> 3)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Scroll speed to stop inertion. Default: 3
</li>
<li><span class="parameter">INERT_SPEED</span>
<span class="types"><span class="type">number</span></span>
Multiplier for inertion speed
(<em>default</em> 30)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Multiplier for inertion speed. Default: 30
</li>
<li><span class="parameter">POINTS_DEADZONE</span>
<span class="types"><span class="type">number</span></span>
Speed to check points of interests in no_inertion mode
(<em>default</em> 20)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Speed to check points of interests in no_inertion mode. Default: 20
</li>
<li><span class="parameter">BACK_SPEED</span>
<span class="types"><span class="type">number</span></span>
Scroll back returning lerp speed
(<em>default</em> 0.35)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Scroll back returning lerp speed. Default: 35
</li>
<li><span class="parameter">ANIM_SPEED</span>
<span class="types"><span class="type">number</span></span>
Scroll gui.animation speed for scroll_to function
(<em>default</em> 0.2)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Scroll gui.animation speed for scroll_to function. Default: 2
</li>
<li><span class="parameter">EXTRA_STRETCH_SIZE</span>
<span class="types"><span class="type">number</span></span>
extra size in pixels outside of scroll (stretch effect)
(<em>default</em> 0)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
extra size in pixels outside of scroll (stretch effect). Default: 0
</li>
<li><span class="parameter">SMALL_CONTENT_SCROLL</span>
<span class="types"><span class="type">bool</span></span>
If true, content node with size less than view node size can be scrolled
(<em>default</em> false)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, content node with size less than view node size can be scrolled. Default: false
</li>
<li><span class="parameter">WHEEL_SCROLL_SPEED</span>
<span class="types"><span class="type">bool</span></span>
The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling
(<em>default</em> 0)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0
</li>
<li><span class="parameter">WHEEL_SCROLL_INVERTED</span>
<span class="types"><span class="type">bool</span></span>
If true, invert direction for touchpad and mouse wheel scroll
(<em>default</em> false)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, invert direction for touchpad and mouse wheel scroll. Default: false
</li>
<li><span class="parameter">WHEEL_SCROLL_BY_INERTION</span>
<span class="types"><span class="type">bool</span></span>
If true, wheel will add inertion to scroll. Direct set position otherwise.
(<em>default</em> false)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false
</li>
</ul>
@@ -808,6 +869,26 @@
<h2 class="section-header "><a name="Fields"></a>Fields</h2>
<dl class="function">
<dt>
<a name = "_is_inert"></a>
<strong>_is_inert</strong>
</dt>
<dd>
Flag, if scroll now moving by inertion
<ul>
<li><span class="parameter">_is_inert</span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "available_pos"></a>
<strong>available_pos</strong>
@@ -918,27 +999,7 @@
<ul>
<li><span class="parameter">is_animate</span>
<span class="types"><span class="type">bool</span></span>
</li>
</ul>
</dd>
<dt>
<a name = "is_inert"></a>
<strong>is_inert</strong>
</dt>
<dd>
Flag, if scroll now moving by inertion
<ul>
<li><span class="parameter">is_inert</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -1038,9 +1099,8 @@
<ul>
<li><span class="parameter">selected</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
(<em>optional</em>)
</li>
</ul>
@@ -1088,6 +1148,26 @@
</dd>
<dt>
<a name = "view_size"></a>
<strong>view_size</strong>
</dt>
<dd>
Scroll view size
<ul>
<li><span class="parameter">view_size</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
</dd>
</dl>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><strong>Slider</strong></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,20 +72,28 @@
<h1>Module <code>Slider</code></h1>
<p>Druid slider component</p>
<p></p>
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_sliders" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, node, end_pos[, callback])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, end_pos, callback)</a></td>
<td class="summary">The <a href="../modules/Slider.html#">Slider</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set">set(self, value[, is_silent])</a></td>
<td class="name" nowrap><a href="#is_enabled">is_enabled(self)</a></td>
<td class="summary">Check if Slider component is enabled</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set">set(self, value, is_silent)</a></td>
<td class="summary">Set value for slider</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_enabled">set_enabled(self, is_enabled)</a></td>
<td class="summary">Set Slider input enabled or disabled</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_input_node">set_input_node(self, input_node)</a></td>
<td class="summary">Set input zone for slider.</td>
</tr>
@@ -144,10 +151,10 @@
<dl class="function">
<dt>
<a name = "init"></a>
<strong>init(self, node, end_pos[, callback])</strong>
<strong>init(self, node, end_pos, callback)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Slider.html#">Slider</a> constructor
<h3>Parameters:</h3>
@@ -165,9 +172,8 @@
The end position of slider
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
<span class="types"><span class="type">function</span> or <span class="type">nil</span></span>
On slider change callback
(<em>optional</em>)
</li>
</ul>
@@ -175,10 +181,37 @@
</dd>
<dt>
<a name = "is_enabled"></a>
<strong>is_enabled(self)</strong>
</dt>
<dd>
Check if Slider component is enabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Slider</span></span>
<a href="../modules/Slider.html#">Slider</a>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">boolean</span></span>
</ol>
</dd>
<dt>
<a name = "set"></a>
<strong>set(self, value[, is_silent])</strong>
<strong>set(self, value, is_silent)</strong>
</dt>
<dd>
Set value for slider
@@ -195,9 +228,33 @@
Value from 0 to 1
</li>
<li><span class="parameter">is_silent</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Don't trigger event if true
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "set_enabled"></a>
<strong>set_enabled(self, is_enabled)</strong>
</dt>
<dd>
Set Slider input enabled or disabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Slider</span></span>
<a href="../modules/Slider.html#">Slider</a>
</li>
<li><span class="parameter">is_enabled</span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>
@@ -224,7 +281,7 @@
<a href="../modules/Slider.html#">Slider</a>
</li>
<li><span class="parameter">input_node</span>
<span class="types"><span class="type">Node</span></span>
<span class="types"><a class="type" href="../modules/Slider.html#node">node</a>, <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
</li>
</ul>
@@ -290,7 +347,7 @@
<ul>
<li><span class="parameter">dist</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
@@ -330,7 +387,7 @@
<ul>
<li><span class="parameter">is_drag</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><strong>StaticGrid</strong></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,15 +72,33 @@
<div id="content">
<h1>Module <code>StaticGrid</code></h1>
<p>Component to handle placing components by row and columns.</p>
<p>Component to handle component's position by row and columns.</p>
<p>
Grid can anchor your elements, get content size and other</p>
<b># Overview #</b>
<p> The Static Grid component allows for positioning components in rows and columns.
It provides a static grid layout with constant node sizes, allowing for pre-calculated
node positions and the option to include gaps between nodes.
<p> <b># Notes #</b>
<p> • In a static grid, the node size remains constant, enabling the calculation of node
positions before placement. If you want add gaps between nodes, increase the root prefab size,
including the padding and margin.
<p> • The static grid can automatically shift elements when nodes are added or removed.
<p> • When a node is added, the grid will set the node's parent to the specified parent_node.
<p> • You can obtain an array of positions for each element, which can be used to set
points of interest in a scroll component.
<p> • The size of all elements can be retrieved for setting up the size in a scroll component.
<p> • The grid can be bound to a scroll component for automatic resizing of the scroll content size.
<p> • The pivot of the parent_node affects the node placement within the grid.
<p> • A prefab node is used to determine the node size and anchor.
<p> • You can specify a position_function for animations using the
_static_grid:set_position_function(node, pos) callback. The default position function is gui.set_position().
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_grid" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#add">add(self, item[, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]]])</a></td>
<td class="name" nowrap><a href="#add">add(self, item, index, shift_policy, is_instant)</a></td>
<td class="summary">Add new item to the grid</td>
</tr>
<tr>
@@ -117,11 +134,15 @@
<td class="summary">Return grid content size</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, parent, element[, in_row=1])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, parent, element, in_row)</a></td>
<td class="summary">The <a href="../modules/StaticGrid.html#">StaticGrid</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#remove">remove(self, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]])</a></td>
<td class="name" nowrap><a href="#refresh">refresh(self)</a></td>
<td class="summary">Update grid content</td>
</tr>
<tr>
<td class="name" nowrap><a href="#remove">remove(self, index, shift_policy, is_instant)</a></td>
<td class="summary">Remove the item from the grid.</td>
</tr>
<tr>
@@ -133,9 +154,21 @@
<td class="summary">Set new in_row elements for grid</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_item_size">set_item_size(self[, width[, height]])</a></td>
<td class="summary">Set new node size for grid</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_items">set_items(self, nodes[, is_instant=false])</a></td>
<td class="summary">Set new items to the grid.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_position_function">set_position_function(self, callback)</a></td>
<td class="summary">Change set position function for grid nodes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#sort_nodes">sort_nodes(self, comparator)</a></td>
<td class="summary">Sort grid nodes by custom comparator function</td>
</tr>
</table>
<h2><a href="#Tables">Tables</a></h2>
<table class="function_list">
@@ -148,7 +181,7 @@
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#anchor">anchor</a></td>
<td class="summary">Item anchor</td>
<td class="summary">Item anchor [0..1]</td>
</tr>
<tr>
<td class="name" nowrap><a href="#border">border</a></td>
@@ -194,6 +227,10 @@
<td class="name" nowrap><a href="#parent">parent</a></td>
<td class="summary">Parent gui node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#pivot">pivot</a></td>
<td class="summary">Item pivot [-0.5..0.5]</td>
</tr>
</table>
<br/>
@@ -205,7 +242,7 @@
<dl class="function">
<dt>
<a name = "add"></a>
<strong>add(self, item[, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]]])</strong>
<strong>add(self, item, index, shift_policy, is_instant)</strong>
</dt>
<dd>
Add new item to the grid
@@ -219,22 +256,19 @@
</li>
<li><span class="parameter">item</span>
<span class="types"><span class="type">node</span></span>
Gui node
GUI node
</li>
<li><span class="parameter">index</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
The item position. By default add as last item
(<em>optional</em>)
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span></span>
How shift nodes, if required. See const.SHIFT
(<em>default</em> SHIFT.RIGHT)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
How shift nodes, if required. Default: const.SHIFT.RIGHT
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, update node positions instantly
(<em>default</em> false)
</li>
</ul>
@@ -438,7 +472,7 @@
<ol>
<span class="types"><span class="type">vector3</span></span>
Node position
@Node position
</ol>
@@ -474,10 +508,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, parent, element[, in_row=1])</strong>
<strong>init(self, parent, element, in_row)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/StaticGrid.html#">StaticGrid</a> constructor
<h3>Parameters:</h3>
@@ -487,17 +521,37 @@
<a href="../modules/StaticGrid.html#">StaticGrid</a>
</li>
<li><span class="parameter">parent</span>
<span class="types"><span class="type">node</span></span>
The gui node parent, where items will be placed
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">node</span></span>
The GUI Node container, where grid's items will be placed
</li>
<li><span class="parameter">element</span>
<span class="types"><span class="type">node</span></span>
Element prefab. Need to get it size
</li>
<li><span class="parameter">in_row</span>
<span class="types"><span class="type">number</span></span>
How many nodes in row can be placed
(<em>default</em> 1)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
How many nodes in row can be placed. By default 1
</li>
</ul>
</dd>
<dt>
<a name = "refresh"></a>
<strong>refresh(self)</strong>
</dt>
<dd>
Update grid content
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">StaticGrid</span></span>
<a href="../modules/StaticGrid.html#">StaticGrid</a>
</li>
</ul>
@@ -508,7 +562,7 @@
</dd>
<dt>
<a name = "remove"></a>
<strong>remove(self, index[, shift_policy=SHIFT.RIGHT[, is_instant=false]])</strong>
<strong>remove(self, index, shift_policy, is_instant)</strong>
</dt>
<dd>
Remove the item from the grid. Note that gui node will be not deleted
@@ -525,21 +579,19 @@
The grid node index to remove
</li>
<li><span class="parameter">shift_policy</span>
<span class="types"><span class="type">number</span></span>
How shift nodes, if required. See const.SHIFT
(<em>default</em> SHIFT.RIGHT)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
How shift nodes, if required. Default: const.SHIFT.RIGHT
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, update node positions instantly
(<em>default</em> false)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Node</span></span>
<span class="types"><span class="type">node</span></span>
The deleted gui node from grid
</ol>
@@ -602,6 +654,73 @@
</dd>
<dt>
<a name = "set_item_size"></a>
<strong>set_item_size(self[, width[, height]])</strong>
</dt>
<dd>
Set new node size for grid
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">StaticGrid</span></span>
<a href="../modules/StaticGrid.html#">StaticGrid</a>
</li>
<li><span class="parameter">width</span>
<span class="types"><span class="type">number</span></span>
The new node width
(<em>optional</em>)
</li>
<li><span class="parameter">height</span>
<span class="types"><span class="type">number</span></span>
The new node height
(<em>optional</em>)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.static_grid</span></span>
Current grid instance
</ol>
</dd>
<dt>
<a name = "set_items"></a>
<strong>set_items(self, nodes[, is_instant=false])</strong>
</dt>
<dd>
Set new items to the grid. All previous items will be removed
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">StaticGrid</span></span>
<a href="../modules/StaticGrid.html#">StaticGrid</a>
</li>
<li><span class="parameter">nodes</span>
<span class="types"><span class="type">node[]</span></span>
The new grid nodes
</li>
<li><span class="parameter">is_instant</span>
<span class="types"><span class="type">boolean</span></span>
If true, update node positions instantly
(<em>default</em> false)
</li>
</ul>
</dd>
<dt>
<a name = "set_position_function"></a>
@@ -634,6 +753,37 @@
</dd>
<dt>
<a name = "sort_nodes"></a>
<strong>sort_nodes(self, comparator)</strong>
</dt>
<dd>
Sort grid nodes by custom comparator function
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">StaticGrid</span></span>
<a href="../modules/StaticGrid.html#">StaticGrid</a>
</li>
<li><span class="parameter">comparator</span>
<span class="types"><span class="type">function</span></span>
The comparator function. (a, b) -> boolean
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid.static_grid</span></span>
Current grid instance
</ol>
</dd>
</dl>
<h2 class="section-header "><a name="Tables"></a>Tables</h2>
@@ -652,14 +802,12 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">IS_DYNAMIC_NODE_POSES</span>
<span class="types"><span class="type">bool</span></span>
If true, always center grid content as grid pivot sets
(<em>default</em> false)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, always center grid content as grid pivot sets. Default: false
</li>
<li><span class="parameter">IS_ALIGN_LAST_ROW</span>
<span class="types"><span class="type">bool</span></span>
If true, always align last row of the grid as grid pivot sets
(<em>default</em> false)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, always align last row of the grid as grid pivot sets. Default: false
</li>
</ul>
@@ -677,7 +825,7 @@
<strong>anchor</strong>
</dt>
<dd>
Item anchor
Item anchor [0..1]
<ul>
@@ -911,6 +1059,26 @@
</dd>
<dt>
<a name = "pivot"></a>
<strong>pivot</strong>
</dt>
<dd>
Item pivot [-0.5..0.5]
<ul>
<li><span class="parameter">pivot</span>
<span class="types"><span class="type">vector3</span></span>
</li>
</ul>
</dd>
</dl>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><strong>Swipe</strong></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -76,14 +75,15 @@
<p>Component to handle swipe gestures on node.</p>
<p>
Swipe will be triggered, if swipe was started and
ended on one node</p>
ended on one node
<p> <a href="https://insality.github.io/druid/druid/index.html?example=general_swipe" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, node, on_swipe_callback)</a></td>
<td class="summary">Component init function</td>
<td class="summary">The <a href="../modules/Swipe.html#">Swipe</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_click_zone">set_click_zone(self, zone)</a></td>
@@ -125,7 +125,7 @@
<strong>init(self, node, on_swipe_callback)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Swipe.html#">Swipe</a> constructor
<h3>Parameters:</h3>
@@ -165,7 +165,7 @@
<a href="../modules/Swipe.html#">Swipe</a>
</li>
<li><span class="parameter">zone</span>
<span class="types"><a class="type" href="../modules/Swipe.html#node">node</a></span>
<span class="types"><a class="type" href="../modules/Swipe.html#node">node</a>, <a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Gui node
</li>
</ul>
@@ -192,19 +192,16 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">SWIPE_TIME</span>
<span class="types"><span class="type">number</span></span>
Maximum time for swipe trigger
(<em>default</em> 0.4)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Maximum time for swipe trigger. Default: 0.4
</li>
<li><span class="parameter">SWIPE_THRESHOLD</span>
<span class="types"><span class="type">number</span></span>
Minimum distance for swipe trigger
(<em>default</em> 50)
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Minimum distance for swipe trigger. Default: 50
</li>
<li><span class="parameter">SWIPE_TRIGGER_ON_MOVE</span>
<span class="types"><span class="type">bool</span></span>
If true, trigger on swipe moving, not only release action
(<em>default</em> false)
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
If true, trigger on swipe moving, not only release action. Default: false
</li>
</ul>
@@ -227,9 +224,8 @@
<ul>
<li><span class="parameter">click_zone</span>
<span class="types"><a class="type" href="../modules/Swipe.html#node">node</a></span>
<span class="types"><a class="type" href="../modules/Swipe.html#node">node</a> or <span class="type">nil</span></span>
(<em>optional</em>)
</li>
</ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -44,28 +44,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><strong>Text</strong></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -73,10 +72,26 @@
<div id="content">
<h1>Module <code>Text</code></h1>
<p>Component to handle all GUI texts.</p>
<p>
Druid text can adjust itself for text node size
Text will never will be outside of his text size (even multiline)</p>
<p>Component for Wrapping GUI Text Nodes: Druid Text
<p> ## Overview ##
<p> Druid Text is a component that provides various adjustment modes for text nodes.</p>
<p> It allows text to be scaled down to fit within the size of the text node.
<p> ## Notes ##
<p> • The text pivot can be changed using the text:set_pivot method.
The anchoring will be inside the text node's area size.
<p> • There are several text adjustment types available. The default is DOWNSCALE.
You can change the default adjustment type in the Text style. Refer to the example below to see all available adjustment types:
<p> - const.TEXT_ADJUST.DOWNSCALE: Changes the text's scale to fit within the text node's size.
<p> - const.TEXT_ADJUST.TRIM: Trims the text with a postfix (default: "...", can be overridden in styles)
to fit within the text node's size.
<p> - const.TEXT_ADJUST.NO_ADJUST: No adjustment is applied, similar
to the default Defold Text Node behavior.
<p> - const.TEXT_ADJUST.DOWNSCALE_LIMITED: Changes the text's scale
with a limited downscale. You can set the minimum scale using the text:set_minimal_scale() function.
<p> - const.TEXT_ADJUST.SCROLL: Changes the text's pivot to imitate scrolling within the text box.
For better effect, use with a stencil node.
<p> - const.TEXT_ADJUST.SCALE_THEN_SCROLL: Combines two modes: limited downscale first, then scroll.
<p> <a href="https://insality.github.io/druid/druid/index.html?example=texts_general" target="_blank"><b>Example Link</b></a></p>
<h2><a href="#Functions">Functions</a></h2>
@@ -86,12 +101,16 @@
<td class="summary">Return current text adjust type</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_text_size">get_text_size(self[, text])</a></td>
<td class="name" nowrap><a href="#get_text_index_by_width">get_text_index_by_width(self, width)</a></td>
<td class="summary">Get chars count by width</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_text_size">get_text_size(self, text)</a></td>
<td class="summary">Calculate text width with font with respect to trailing space</td>
</tr>
<tr>
<td class="name" nowrap><a href="#init">init(self, node[, value[, adjust_type=0]])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, value, adjust_type)</a></td>
<td class="summary">The <a href="../modules/Text.html#">Text</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_multiline">is_multiline(self)</a></td>
@@ -118,7 +137,11 @@
<td class="summary">Set scale</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_text_adjust">set_text_adjust(self[, adjust_type[, minimal_scale]])</a></td>
<td class="name" nowrap><a href="#set_size">set_size(self, size)</a></td>
<td class="summary">Set text area size</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_text_adjust">set_text_adjust(self, adjust_type, minimal_scale)</a></td>
<td class="summary">Set text adjust, refresh the current text visuals, if needed</td>
</tr>
<tr>
@@ -144,6 +167,10 @@
<td class="summary">Current text color</td>
</tr>
<tr>
<td class="name" nowrap><a href="#last_value">last_value</a></td>
<td class="summary">The last text value</td>
</tr>
<tr>
<td class="name" nowrap><a href="#node">node</a></td>
<td class="summary">Text node</td>
</tr>
@@ -161,7 +188,7 @@
</tr>
<tr>
<td class="name" nowrap><a href="#on_update_text_scale">on_update_text_scale</a></td>
<td class="summary">On adjust text size callback(self, new_scale)</td>
<td class="summary">On adjust text size callback(self, new_scale, text_metrics)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#pos">pos</a></td>
@@ -220,10 +247,41 @@
</dd>
<dt>
<a name = "get_text_index_by_width"></a>
<strong>get_text_index_by_width(self, width)</strong>
</dt>
<dd>
Get chars count by width
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Text</span></span>
<a href="../modules/Text.html#">Text</a>
</li>
<li><span class="parameter">width</span>
<span class="types"><span class="type">number</span></span>
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">number</span></span>
Chars count
</ol>
</dd>
<dt>
<a name = "get_text_size"></a>
<strong>get_text_size(self[, text])</strong>
<strong>get_text_size(self, text)</strong>
</dt>
<dd>
Calculate text width with font with respect to trailing space
@@ -237,8 +295,7 @@
</li>
<li><span class="parameter">text</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
(<em>optional</em>)
|nil
</li>
</ul>
@@ -258,10 +315,10 @@
</dd>
<dt>
<a name = "init"></a>
<strong>init(self, node[, value[, adjust_type=0]])</strong>
<strong>init(self, node, value, adjust_type)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Text.html#">Text</a> constructor
<h3>Parameters:</h3>
@@ -271,18 +328,16 @@
<a href="../modules/Text.html#">Text</a>
</li>
<li><span class="parameter">node</span>
<span class="types"><a class="type" href="../modules/Text.html#node">node</a></span>
Gui text node
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <a class="type" href="../modules/Text.html#node">node</a></span>
Node name or GUI Text Node itself
</li>
<li><span class="parameter">value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Initial text. Default value is node text from GUI scene.
(<em>optional</em>)
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Initial text. Default value is node text from GUI scene. Default: nil
</li>
<li><span class="parameter">adjust_type</span>
<span class="types"><span class="type">int</span></span>
Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference
(<em>default</em> 0)
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE
</li>
</ul>
@@ -310,7 +365,7 @@
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span></span>
Is text node with line break
</ol>
@@ -426,8 +481,8 @@
<a href="../modules/Text.html#">Text</a>
</li>
<li><span class="parameter">pivot</span>
<span class="types"><span class="type">gui.pivot</span></span>
Gui pivot constant
<span class="types"><span class="type">number</span></span>
The gui.PIVOT_* constant
</li>
</ul>
@@ -472,10 +527,41 @@
</dd>
<dt>
<a name = "set_size"></a>
<strong>set_size(self, size)</strong>
</dt>
<dd>
Set text area size
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">self</span>
<span class="types"><span class="type">Text</span></span>
<a href="../modules/Text.html#">Text</a>
</li>
<li><span class="parameter">size</span>
<span class="types"><span class="type">vector3</span></span>
The new text area size
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">Text</span></span>
Current text instance
</ol>
</dd>
<dt>
<a name = "set_text_adjust"></a>
<strong>set_text_adjust(self[, adjust_type[, minimal_scale]])</strong>
<strong>set_text_adjust(self, adjust_type, minimal_scale)</strong>
</dt>
<dd>
Set text adjust, refresh the current text visuals, if needed
@@ -488,14 +574,12 @@
<a href="../modules/Text.html#">Text</a>
</li>
<li><span class="parameter">adjust_type</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
See const.TEXT_ADJUST. If pass nil - use current adjust type
(<em>optional</em>)
</li>
<li><span class="parameter">minimal_scale</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
If pass nil - not use minimal scale
(<em>optional</em>)
</li>
</ul>
@@ -558,14 +642,20 @@
<h3>Fields:</h3>
<ul>
<li><span class="parameter">TRIM_POSTFIX</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The postfix for TRIM adjust type
(<em>default</em> ...)
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
The postfix for TRIM adjust type. Default: ...
</li>
<li><span class="parameter">DEFAULT_ADJUST</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The default adjust type for any text component
(<em>default</em> DOWNSCALE)
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
The default adjust type for any text component. Default: DOWNSCALE
</li>
<li><span class="parameter">ADJUST_STEPS</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Amount of iterations for text adjust by height. Default: 20
</li>
<li><span class="parameter">ADJUST_SCALE_DELTA</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a> or <span class="type">nil</span></span>
Scale step on each height adjust step. Default: 0.02
</li>
</ul>
@@ -617,6 +707,26 @@
</dd>
<dt>
<a name = "last_value"></a>
<strong>last_value</strong>
</dt>
<dd>
The last text value
<ul>
<li><span class="parameter">last_value</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
</li>
</ul>
</dd>
<dt>
<a name = "node"></a>
@@ -703,7 +813,7 @@
<strong>on_update_text_scale</strong>
</dt>
<dd>
On adjust text size callback(self, new_scale)
On adjust text size callback(self, new_scale, text_metrics)
<ul>

View File

@@ -3,7 +3,7 @@
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
@@ -43,28 +43,27 @@
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><strong>Timer</strong></li>
<li><a href="../modules/druid.html">druid</a></li>
</ul>
</div>
@@ -81,8 +80,8 @@
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#init">init(self, node, seconds_from[, seconds_to=0[, callback]])</a></td>
<td class="summary">Component init function</td>
<td class="name" nowrap><a href="#init">init(self, node, seconds_from, seconds_to, callback)</a></td>
<td class="summary">The <a href="../modules/Timer.html#">Timer</a> constructor</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_interval">set_interval(self, from, to)</a></td>
@@ -138,10 +137,10 @@
<dl class="function">
<dt>
<a name = "init"></a>
<strong>init(self, node, seconds_from[, seconds_to=0[, callback]])</strong>
<strong>init(self, node, seconds_from, seconds_to, callback)</strong>
</dt>
<dd>
Component init function
The <a href="../modules/Timer.html#">Timer</a> constructor
<h3>Parameters:</h3>
@@ -155,18 +154,16 @@
Gui text node
</li>
<li><span class="parameter">seconds_from</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
Start timer value in seconds
</li>
<li><span class="parameter">seconds_to</span>
<span class="types"><span class="type">number</span></span>
<span class="types"><span class="type">number</span> or <span class="type">nil</span></span>
End timer value in seconds
(<em>default</em> 0)
</li>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
<span class="types"><span class="type">function</span> or <span class="type">nil</span></span>
Function on timer end
(<em>optional</em>)
</li>
</ul>
@@ -219,7 +216,7 @@
<a href="../modules/Timer.html#">Timer</a>
</li>
<li><span class="parameter">is_on</span>
<span class="types"><span class="type">bool</span></span>
<span class="types"><span class="type">boolean</span> or <span class="type">nil</span></span>
Timer enable state
</li>
</ul>

View File

@@ -0,0 +1,95 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><strong>druid.extended.layout</strong></li>
</ul>
</div>
<div id="content">
<h1>Module <code>druid.extended.layout</code></h1>
<p>Druid layout module
<p> <b># Overview #</b>
<p> Layout component works like Dynamic Grid before - for aligning elements in a row or column.</p>
<p> Works like a Figma layout.
<p> <b># Notes</p>
<br/>
<br/>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -1,394 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/druid.html">druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><strong>druid.helper</strong></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
</ul>
</div>
<div id="content">
<h1>Module <code>druid.helper</code></h1>
<p>Text node or icon node can be nil</p>
<p></p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#centrate_text_with_icon">centrate_text_with_icon([text_node][, icon_node], margin)</a></td>
<td class="summary">Center two nodes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#centrate_icon_with_text">centrate_icon_with_text([icon_node[, text_node[, margin=0]]])</a></td>
<td class="summary">Center two nodes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#centrate_nodes">centrate_nodes([margin=0[, ...]])</a></td>
<td class="summary">Center several nodes nodes.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_enabled">is_enabled(node)</a></td>
<td class="summary">Check if node is enabled in gui hierarchy.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_closest_stencil_node">get_closest_stencil_node(node)</a></td>
<td class="summary">Return closest non inverted clipping parent node for node</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_pivot_offset">get_pivot_offset(pivot)</a></td>
<td class="summary">Get node offset for given gui pivot</td>
</tr>
<tr>
<td class="name" nowrap><a href="#helper..is_mobile">helper..is_mobile()</a></td>
<td class="summary">Check if device is mobile (Android or iOS)</td>
</tr>
<tr>
<td class="name" nowrap><a href="#is_web">is_web()</a></td>
<td class="summary">Check if device is HTML5</td>
</tr>
<tr>
<td class="name" nowrap><a href="#get_border">get_border(node, offset)</a></td>
<td class="summary">Distance from node position to his borders</td>
</tr>
<tr>
<td class="name" nowrap><a href="#deprecated">deprecated(message)</a></td>
<td class="summary">Show deprecated message.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "centrate_text_with_icon"></a>
<strong>centrate_text_with_icon([text_node][, icon_node], margin)</strong>
</dt>
<dd>
Center two nodes.
Nodes will be center around 0 x position
text_node will be first (at left side)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">text</span></span>
Gui text node
(<em>optional</em>)
</li>
<li><span class="parameter">icon_node</span>
<span class="types"><span class="type">box</span></span>
Gui box node
(<em>optional</em>)
</li>
<li><span class="parameter">margin</span>
<span class="types"><span class="type">number</span></span>
Offset between nodes
</li>
</ul>
</dd>
<dt>
<a name = "centrate_icon_with_text"></a>
<strong>centrate_icon_with_text([icon_node[, text_node[, margin=0]]])</strong>
</dt>
<dd>
Center two nodes.
Nodes will be center around 0 x position
icon_node will be first (at left side)
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">icon_node</span>
<span class="types"><span class="type">box</span></span>
Gui box node
(<em>optional</em>)
</li>
<li><span class="parameter">text_node</span>
<span class="types"><span class="type">text</span></span>
Gui text node
(<em>optional</em>)
</li>
<li><span class="parameter">margin</span>
<span class="types"><span class="type">number</span></span>
Offset between nodes
(<em>default</em> 0)
</li>
</ul>
</dd>
<dt>
<a name = "centrate_nodes"></a>
<strong>centrate_nodes([margin=0[, ...]])</strong>
</dt>
<dd>
Center several nodes nodes.
Nodes will be center around 0 x position
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">margin</span>
<span class="types"><span class="type">number</span></span>
Offset between nodes
(<em>default</em> 0)
</li>
<li><span class="parameter">...</span>
<span class="types"><span class="type">Node</span></span>
Any count of gui Node
(<em>optional</em>)
</li>
</ul>
</dd>
<dt>
<a name = "is_enabled"></a>
<strong>is_enabled(node)</strong>
</dt>
<dd>
Check if node is enabled in gui hierarchy.
Return false, if node or any his parent is disabled
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
Gui node
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">bool</span></span>
Is enabled in hierarchy
</ol>
</dd>
<dt>
<a name = "get_closest_stencil_node"></a>
<strong>get_closest_stencil_node(node)</strong>
</dt>
<dd>
Return closest non inverted clipping parent node for node
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
Gui node
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">node</span> or <span class="type">nil</span></span>
The clipping node
</ol>
</dd>
<dt>
<a name = "get_pivot_offset"></a>
<strong>get_pivot_offset(pivot)</strong>
</dt>
<dd>
Get node offset for given gui pivot
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">pivot</span>
<span class="types"><span class="type">gui.pivot</span></span>
The node pivot
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">vector3</span></span>
Vector offset with [-1..1] values
</ol>
</dd>
<dt>
<a name = "helper..is_mobile"></a>
<strong>helper..is_mobile()</strong>
</dt>
<dd>
Check if device is mobile (Android or iOS)
</dd>
<dt>
<a name = "is_web"></a>
<strong>is_web()</strong>
</dt>
<dd>
Check if device is HTML5
</dd>
<dt>
<a name = "get_border"></a>
<strong>get_border(node, offset)</strong>
</dt>
<dd>
Distance from node position to his borders
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">node</span>
<span class="types"><span class="type">node</span></span>
The gui node to check
</li>
<li><span class="parameter">offset</span>
<span class="types"><span class="type">vector3</span></span>
The offset to add to result
</li>
</ul>
<h3>Returns:</h3>
<ol>
vector4 Vector with distance to node border: (left, top, right, down)
</ol>
</dd>
<dt>
<a name = "deprecated"></a>
<strong>deprecated(message)</strong>
</dt>
<dd>
Show deprecated message. Once time per message
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">message</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
The deprecated message
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
<i style="float:right;">Last updated 2022-02-12 17:16:44 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -1,305 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Library</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Contents</h2>
<ul>
<li><a href="#Functions">Functions</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><strong>druid</strong></li>
</ul>
</div>
<div id="content">
<h1>Module <code>druid</code></h1>
<p>Druid UI Library.</p>
<p>
Powerful Defold component based UI library. Use standart
components or make your own game-specific components to
make amazing GUI in your games.
<p> Contains the several basic components and examples
to how to do your custom complex components to
separate UI game logic to small files
<p> require("druid.druid")
function init(self)
self.druid = druid.new(self)
end
</p>
<h2><a href="#Functions">Functions</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#new">new(context[, style])</a></td>
<td class="summary">Create Druid instance.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_language_change">on_language_change()</a></td>
<td class="summary">Callback on global language change event.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#on_window_callback">on_window_callback(event)</a></td>
<td class="summary">Callback on global window event.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#register">register(name, module)</a></td>
<td class="summary">Register external druid component.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_default_style">set_default_style(style)</a></td>
<td class="summary">Set new default style.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_sound_function">set_sound_function(callback)</a></td>
<td class="summary">Set sound function.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#set_text_function">set_text_function(callback)</a></td>
<td class="summary">Set text function
Druid locale component will call this function
to get translated text.</td>
</tr>
</table>
<br/>
<br/>
<h2 class="section-header "><a name="Functions"></a>Functions</h2>
<dl class="function">
<dt>
<a name = "new"></a>
<strong>new(context[, style])</strong>
</dt>
<dd>
Create Druid instance.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">context</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Druid context. Usually it is self of script
</li>
<li><span class="parameter">style</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Druid style module
(<em>optional</em>)
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">druid_instance</span></span>
Druid instance
</ol>
</dd>
<dt>
<a name = "on_language_change"></a>
<strong>on_language_change()</strong>
</dt>
<dd>
Callback on global language change event.
Use to update all lang texts
</dd>
<dt>
<a name = "on_window_callback"></a>
<strong>on_window_callback(event)</strong>
</dt>
<dd>
Callback on global window event.
Used to trigger on_focus_lost and on_focus_gain
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">event</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
Event param from window listener
</li>
</ul>
</dd>
<dt>
<a name = "register"></a>
<strong>register(name, module)</strong>
</dt>
<dd>
Register external druid component.
After register you can create the component with
druid_instance:new_{name}. For example `druid:new_button(...)`
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">name</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.4">string</a></span>
module name
</li>
<li><span class="parameter">module</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
lua table with component
</li>
</ul>
</dd>
<dt>
<a name = "set_default_style"></a>
<strong>set_default_style(style)</strong>
</dt>
<dd>
Set new default style.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">style</span>
<span class="types"><a class="type" href="https://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Druid style module
</li>
</ul>
</dd>
<dt>
<a name = "set_sound_function"></a>
<strong>set_sound_function(callback)</strong>
</dt>
<dd>
Set sound function.
Component will call this function to
play sound by sound_id
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
Sound play callback
</li>
</ul>
</dd>
<dt>
<a name = "set_text_function"></a>
<strong>set_text_function(callback)</strong>
</dt>
<dd>
Set text function
Druid locale component will call this function
to get translated text. After set_text_funtion
all existing locale component will be updated
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">callback</span>
<span class="types"><span class="type">function</span></span>
Get localized text function
</li>
</ul>
</dd>
</dl>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -0,0 +1,93 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
<title>Defold Druid UI Framework</title>
<link rel="stylesheet" href="../ldoc_fixed.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="product">
<div id="product_logo"></div>
<div id="product_name"><big><b></b></big></div>
<div id="product_description"></div>
</div> <!-- id="product" -->
<div id="main">
<!-- Menu -->
<div id="navigation">
<br/>
<h1>Druid</h1>
<ul>
<li><a href="../index.html">Index</a></li>
</ul>
<h2>Modules</h2>
<ul class="nowrap">
<li><a href="../modules/BackHandler.html">BackHandler</a></li>
<li><a href="../modules/BaseComponent.html">BaseComponent</a></li>
<li><a href="../modules/Blocker.html">Blocker</a></li>
<li><a href="../modules/Button.html">Button</a></li>
<li><a href="../modules/Checkbox.html">Checkbox</a></li>
<li><a href="../modules/CheckboxGroup.html">CheckboxGroup</a></li>
<li><a href="../modules/DataList.html">DataList</a></li>
<li><a href="../modules/Drag.html">Drag</a></li>
<li><a href="../modules/Druid.html">Druid</a></li>
<li><a href="../modules/DruidEvent.html">DruidEvent</a></li>
<li><a href="../modules/DruidInstance.html">DruidInstance</a></li>
<li><a href="../modules/DynamicGrid.html">DynamicGrid</a></li>
<li><a href="../modules/Helper.html">Helper</a></li>
<li><a href="../modules/Hotkey.html">Hotkey</a></li>
<li><a href="../modules/Hover.html">Hover</a></li>
<li><a href="../modules/Input.html">Input</a></li>
<li><a href="../modules/LangText.html">LangText</a></li>
<li><a href="../modules/Layout.html">Layout</a></li>
<li><a href="../modules/PinKnob.html">PinKnob</a></li>
<li><a href="../modules/Progress.html">Progress</a></li>
<li><a href="../modules/RadioGroup.html">RadioGroup</a></li>
<li><a href="../modules/RichInput.html">RichInput</a></li>
<li><a href="../modules/RichText.html">RichText</a></li>
<li><a href="../modules/Scroll.html">Scroll</a></li>
<li><a href="../modules/Slider.html">Slider</a></li>
<li><a href="../modules/StaticGrid.html">StaticGrid</a></li>
<li><a href="../modules/Swipe.html">Swipe</a></li>
<li><a href="../modules/Text.html">Text</a></li>
<li><a href="../modules/Timer.html">Timer</a></li>
<li><strong>druid.system.utf8</strong></li>
</ul>
</div>
<div id="content">
<h1>Module <code>druid.system.utf8</code></h1>
<p></p>
<p></p>
<br/>
<br/>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc TESTING</a></i>
<i style="float:right;">Last updated 2015-01-01 12:00:00 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>

View File

@@ -133,7 +133,7 @@ Usually, Place _view_node_ and as children add _content_node_:
- *on_scroll_to* (self, position, is_instant) On scroll_to function callback
- *on_point_scroll* (self, item_index, position) On scroll_to_index function callback
- You can adjust scroll content size by `scroll:set_size(node_size)`. It will setup new size to _content node_
- You can enabled or disable inertion mode via `scroll:set_intert(state)`
- You can enabled or disable inertion mode via `scroll:set_inert(state)`
- You can adjust extra stretch size via `scroll:set_extra_stretch_size`
- Multitouch is required for scroll. Scroll is correctly handling touch_id swap while dragging scroll
@@ -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)
@@ -192,49 +192,6 @@ Create input component with druid: `input = druid:new_input(button_node_name, te
- To make work different keyboard type, make sure value in game.project Android:InputMethod set to HidderInputField (https://defold.com/manuals/project-settings/#input-method)
## Checkbox
[Checkbox API here](https://insality.github.io/druid/modules/Checkbox.html)
### Overview
Basic Druid checkbox component.
### Setup
Create checkbox component with druid: `checkbox = druid:new_checkbox(node, callback)`
### Notes
- Checkbox uses button to handle click
- You can setup another node to handle input with click_node arg in component init: `druid:new_checkbox(node, callback, [click_node])`
## Checkbox group
[Checkbox group API here](https://insality.github.io/druid/modules/CheckboxGroup.html)
### Overview
Several checkboxes in one group
### Setup
Create checkbox_group component with druid: `group = druid:new_checkbox_group(nodes[], callback)`
### Notes
- Callback arguments: `function(self, checkbox_index)`. Index is equals in _nodes[]_ array in component constructor
- You can get/set checkbox_group state with `group:set_state()` and `group:get_state()`
## Radio group
[Radio group API here](https://insality.github.io/druid/modules/RadioGroup.html)
### Overview
Several checkboxes in one group with single choice
### Setup
Create radio_group component with druid: `group = druid:new_radio_group(nodes[], callback)`
### Notes
- Callback arguments: `function(self, checkbox_index)`. Index is equals in _nodes[]_ array in component constructor
- You can get/set radio_group state with `group:set_state()` and `group:get_state()`
- Only different from checkbox_group: on click another checkboxes in this group will be unchecked
## Timer
[Timer API here](https://insality.github.io/druid/modules/Timer.html)
@@ -277,7 +234,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 +258,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 +325,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 +346,54 @@ 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 arrange nodes inside layout node with margin/paddings settings. Works with different node sizes and pivots. Works in the same way as Figma AutoLayout
### Setup
This is extended component. Before use it, you should register it:
```
local druid = require("druid.druid")
local layout = require("druid.extended.layout")
druid.register("layout", layout)
```
Create layout component with druid: `layout = druid:new_layout(node, layout_mode)`
### Notes
- Layout mode can be next:
- `horizontal` - arrange nodes in horizontal line
- `vertical` - arrange nodes in vertical line
- `horizontal_wrap` - arrange nodes in horizontal line with wrap to next line
- You can setup margin and padding for layout nodes
- You can set "justify" alignment to place nodes with the same margin between layout node borders
- You can set "hug" by content. This option will set layout node size by content size. Can be setup separately for width and height

View File

@@ -1,220 +1,160 @@
# Creating custom components
# Creating Custom Components
## Overview
Druid allows you to create your custom components which contains your custom logic, other Druid basic components or other custom components.
Druid offers the flexibility to create custom components that contain your own logic, as well as other Druid basic components or custom components. While Druid provides a set of predefined components like buttons and scrolls, it goes beyond that and provides a way to handle all your GUI elements in a more abstract manner. Custom components are a powerful way to separate logic and create higher levels of abstraction in your code.
I wanna make a point that Druid is not only set of defined components to place buttons, scroll, etc. But mostly it's a way how to handle all your GUI elements in general. Custom components is most powerful way to separate logic and make higher abstraction in your code.
Every component is a child of the Basic Druid component. You can call methods of basic components using `self:{method_name}`.
Every component is the children of Basic Druid component. Read the [basic component API here].(https://insality.github.io/druid/modules/component.html), Methods of basic components you can call via `self:{method_name}`
## Custom Components
### Basic Component Template
A basic custom component template looks like this (you can copy it from `/druid/templates/component.template.lua`):
## Custom components
### Basic component template
Basic custom component template looks like this. It's good start to create your own component! (you can copy it from `/druid/templates/component.template.lua`)
```lua
local component = require("druid.component")
---@class component_name : druid.base_component
local Component = component.create("component_name")
---@class component_name: druid.base_component
local M = component.create("component_name")
local SCHEME = {
ROOT = "root",
BUTTON = "button",
}
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes)
self.root = self:get_node("root")
-- Component constructor. Template name and nodes are optional. Pass it if you use it in your component
function Component:init(template, nodes)
self:set_template(template)
self:set_nodes(nodes)
self.root = self:get_node(SCHEME.ROOT)
self.druid = self:get_druid()
self.button = self.druid:new_button(SCHEME.BUTTON, function() end)
self.button = self.druid:new_button("button", function() end)
end
-- [OPTIONAL] Call on component remove or on druid:final
function Component:on_remove() end
function M:hello()
print("Hello from custom component")
end
return Component
return M
```
### Full component template
Then you can create your custom component with Druid:
```lua
local druid = require("druid.druid")
local my_component = require("my.amazing.component")
function init(self)
self.druid = druid.new(self)
-- We pass a GUI template "template_name" and skip nodes due it already on the scene
self.my_component = self.druid:new(my_component, "template_name")
self.my_component:hello() -- Hello from custom component
end
```
### Full Component Template
A full custom component template looks like this (you can copy it from `/druid/templates/component_full.template.lua`):
Full custom component template looks like this (you can copy it from `/druid/templates/component_full.template.lua`:
```lua
local component = require("druid.component")
---@class component_name : druid.base_component
local Component = component.create("component_name")
-- Scheme of component gui nodes
local SCHEME = {
ROOT = "root",
BUTTON = "button",
}
---@class component_name: druid.base_component
local M = component.create("component_name")
-- Component constructor. Template name and nodes are optional. Pass it if you use it in your component
function Component:init(template, nodes)
-- If your component is gui template, pass the template name and set it
self:set_template(template)
-- If your component is cloned my gui.clone_tree, pass nodes to component and set it
self:set_nodes(nodes)
-- self:get_node will auto process component template and nodes
self.root = self:get_node(SCHEME.ROOT)
-- Use inner druid instance to create components inside this component
self.druid = self:get_druid()
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes)
self.root = self:get_node("root")
end
-- [OPTIONAL] Call every update step
function Component:update(dt) end
function M:update(dt) end
-- [OPTIONAL] Call default on_input from gui script
function Component:on_input(action_id, action) return false end
function M:on_input(action_id, action) return false end
-- [OPTIONAL] Call on component creation and on component:set_style() function
function Component:on_style_change(style) end
function M:on_style_change(style) end
-- [OPTIONAL] Call default on_message from gui script
function Component:on_message(message_id, message, sender) end
function M:on_message(message_id, message, sender) end
-- [OPTIONAL] Call if druid has triggered on_language_change
function Component:on_language_change() end
function M:on_language_change() end
-- [OPTIONAL] Call if game layout has changed and need to restore values in component
function Component:on_layout_change() end
function M:on_layout_change() 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
function M:on_window_resized() end
-- [OPTIONAL] Call, if game lost focus
function Component:on_focus_lost() end
function M:on_input_interrupt() end
-- [OPTIONAL] Call, if game gained focus
function Component:on_focus_gained() end
function M:on_focus_lost() end
-- [OPTIONAL] Call on component remove or on druid:final
function Component:on_remove() end
function M:on_focus_gained() end
return Component
function M:on_remove() end
return M
```
### Spawning a Custom Component
### Spawn custom component
After the creating your custom component, you now able to create it.
For example we made the component `my_component`. Now we able create it like this:
```lua
local druid = require("druid.druid")
local my_component = require("my.amazing.component")
function init(self)
self.druid = druid.new(self)
self.druid:new(my_component, "template_name", nodes)
end
```
The template name - is the name of GUI template file if you use it in your custom component.
The nodes - is table from `gui.clone_tree(node)`. If you spawn multiply nodes for component, pass it to component constructor.
Inside component you have to set template and nodes via
`self:set_template(template)` and `self:set_nodes(nodes)`
### Register custom component
You can register your custom component for use it without require component module in every file. Registering components is comfortable for very basic components in your game.
Add your custom component to druid via `druid.register
After creating your custom component, you can spawn it in your code. For example, if you have a component named `my_component`, you can create it like this:
```lua
local druid = require("druid.druid")
local my_component = require("my.amazing.component")
function init(self)
druid.register("my_component", my_component)
self.druid = druid.new(self)
self.druid:new(my_component, "template_name")
end
```
Registering make new function with "new_{component_name}". In our example it will be: `druid:new_my_component()`.
In the code above, `template_name` refers to the name of the GUI template file if you're using it in your custom component. `nodes` is a table obtained from `gui.clone_tree(node)`. If you're spawning multiple nodes for the component, pass the table to the component constructor. Inside the component, you need to set the template and nodes using `self:set_template(template)` and `self:set_nodes(nodes)`.
### Registering a Custom Component
You can register your custom component to use it without requiring the component module in every file. Registering components is convenient for very basic components in your game. Here's how you can register a custom component in Druid:
As component registered, you can create your component with next code:
```lua
local druid = require("druid.druid")
local my_component = require("my.amazing.component")
function init(self)
self.druid = druid.new(self)
self.my_component = self.druid:new_my_component(template, nodes)
-- Register makes a "druid:new_{component_name}" function available
druid.register("my_component", my_component)
end
```
Once the component is registered, a new function will be available with the name "new_{component_name}". In our example, it will be `druid:new_my_component()`. With the component registered, you can create an instance of it using the following code:
## Create Druid Component editor script
```lua
local druid = require("druid.druid")
local my_component = require("my.amazing.component")
The Druid has editor script to help you with creating lua file for your GUI scene.
The commands is available on *.gui scenes in menu `Edit -> Create Druid Component`
function init(self)
self.druid = druid.new(self)
self.my_component = self.druid:new_my_component(template, nodes)
end
```
The script will check current GUI scene and generate lua file with all Druid component stubs. The output file will be named as current GUI scene and placed nearby. The *.lua file should be not exists, the script will not override any file. If you want to re-generate file, delete previous one first.
## Create Druid Component Editor Script
The script required `python3` with `deftree` installed. If `deftree` is not installed the instructions will be prompt in console.
Druid provides an editor script to assist you in creating Lua files for your GUI scenes. You can find the commands under the menu `Edit -> Create Druid Component` when working with *.gui scenes.
The script analyzes the current GUI scene and generates a Lua file with stubs for all Druid components found. The output file is named after the current GUI scene and placed in the same directory. Note that the script does not override any existing *.lua files. If you want to regenerate a file, delete the previous version first.
### Auto layout components
The script requires `python` with `deftree` installed. If `deftree` is not installed, the instructions will be displayed in the console.
The generator script also check current GUI scene for Druid components to make stubs for them. The script will check the node names and if it starts with special keyword it will make component stubs in generated lua file. It will generate component declaring, callback functions stubs and annotations.
### Auto-Layout Components
Start your node names with one of next keyword to say parser make component stubs for your. For example for nodes `button` and `button_exit` will be generated two Druid Button components with callback stubs.
The generator script also checks the current GUI scene for Druid components and creates stubs for them. If a node name starts with a specific keyword, the script generates component stubs in the Lua file. For example, nodes named `button` and `button_exit` will result in the generation of two Druid Button components with callback stubs.
Available keywords:
- `button` - add [Druid Button](docs_md/01-components.md#button) and generate callback stub
- `text` - add [Druid Text](docs_md/01-components.md#text)
- `lang_text` - add Druid [Druid Lang Text](docs_md/01-components.md#lang-text)
- `grid` or `static_grid` - add Druid [Druid Static Grid](docs_md/01-components.md#static-grid). You should to setup Grid prefab for this component after file generation
- `dynamic_grid` - add Druid [Druid Dynamic Grid](docs_md/01-components.md#dynamic-grid)
- `scroll_view` - add [Druid Scroll](docs_md/01-components.md#scroll). It will add `scroll_content` node with the same postfix too. Check that is will correct node
- `blocker` - add [Druid Blocker](docs_md/01-components.md#blocker)
- `slider` - add [Druid Slider](docs_md/01-components.md#slider). You should to adjust end position of Slider after file generation
- `progress` - add [Druid Progress](docs_md/01-components.md#progress)
- `timer` - add [Druid Timer](docs_md/01-components.md#timer)
- `button`: Adds a [Druid Button](01-components.md#button) component and generates the callback stub.
- `text`: Adds a [Druid Text](01-components.md#text) component.
- `lang_text`: Adds a [Druid Lang Text](01-components.md#lang-text) component.
- `grid` or `static_grid`: Adds a [Druid Static Grid](01-components.md#static-grid) component. You should set up the Grid prefab for this component after generating the file.
- `dynamic_grid`: Adds a [Druid Dynamic Grid](01-components.md#dynamic-grid) component.
- `scroll_view`: Adds a [Druid Scroll](01-components.md#scroll) component. It also adds a `scroll_content` node with the same postfix. Ensure that it's the correct node.
- `blocker`: Adds a [Druid Blocker](01-components.md#blocker) component.
- `slider`: Adds a [Druid Slider](01-components.md#slider) component. You should adjust the end position of the Slider after generating the file.
- `progress`: Adds a [Druid Progress](01-components.md#progress) component.
- `timer`: Adds a [Druid Timer](01-components.md#timer) component.
## The Power of Using Templates
## Best practice on custom components
On each component recommended describe component scheme in next way:
To get this structure, Druid has editor script to help you with it. Select your GUI nodes in editor outline, right click and press "Print GUI Scheme". And copy the result from the output console.
```lua
-- Component module
local component = require("druid.component")
local M = component.create("your_component")
local SCHEME = {
ROOT = "root",
ITEM = "item",
TITLE = "title"
}
function M.init(self, template_name, node_table)
self:set_template(template_name)
self:set_nodes(node_table)
-- helper can get node from gui/template/table
local root = self:get_node(SCHEME.ROOT)
-- This component can spawn another druid components:
local druid = self:get_druid()
-- Button self on callback is self of _this_ component
local button = druid:new_button(...)
end
```
## Power of using templates
You can use one component, but creating and customizing templates for them. Templates only requires to match the component scheme.
For example you have component `player_panel` and two GUI templates: `player_panel` and `enemy_panel` with different layout. But the same component script can be used for both of them.
With Druid, you can use a single component but create and customize templates for it. Templates only need to match the component scheme. For example, you can have a component named `player_panel` and two GUI templates named `player_panel` and `enemy_panel` with different layouts. The same component script can be used for both templates.

View File

@@ -14,7 +14,7 @@ You can pass _nil_ or _empty_table_ to use default values for all components (no
local druid = require("druid.druid")
local my_style = require("my.amazing.style")
local function init(self)
function init(self)
druid.set_default_style(my_style)
end
```
@@ -24,7 +24,7 @@ Setup custom style to specific druid instance:
local druid = require("druid.druid")
local my_style = require("my.amazing.style")
local function init(self)
function init(self)
-- This druid instance will be use my_style as default
self.druid = druid.new(self, my_style)
end
@@ -35,7 +35,7 @@ Change component style with _set_style_ function
local druid = require("druid.druid")
local my_style = require("my.amazing.style")
local function init(self)
function init(self)
self.druid = druid.new(self)
self.button = self.druid:new_button("node", function() end)
-- Setup custom style for specific component
@@ -46,11 +46,11 @@ end
## Create your own styles
The most components have their styles. You can explore it on [Druid API](https://insality.github.io/druid/) in table style section ([button example](https://insality.github.io/druid/modules/druid.button.html#Style)). Or you can see, what fields component uses in code in function `on_style_change`
The most components have their styles. You can explore it on [Druid API](https://insality.github.io/druid/) in table style section ([button example](https://insality.github.io/druid/modules/Button.html#style)). Or you can see, what fields component uses in code in function `on_style_change`
To create you style, create lua module, what return <_component_name_, _component_style_> table
Example: [default druid style](styles/default/style.lua)
Example: [default druid style](https://github.com/Insality/druid/blob/master/druid/styles/default/style.lua)
Override all fields you want and set your style with one of next ways:

View File

@@ -1,67 +1,36 @@
# Druid FAQ
>_Have questions about Druid? Ask me!_
> _Here is questions you might have_
Welcome to the Druid FAQ! Here are answers to some common questions you may have:
### Q: Why I want use Druid?
**A:** ---
### Q: How do I remove a Druid component instance?
**A:** To remove a created Druid component, use the `druid:remove` function. You can find more information in the [API reference](https://insality.github.io/druid/modules/druid_instance.html#druid:remove).
### Q: How does Druid process input?
**A:** Input processing in Druid follows a Last-In-First-Out (LIFO) queue. Buttons added later have higher priority than those added earlier. To ensure correct button behavior, place your buttons from back to front in most cases.
### Q: How to remove the Druid component instance?
**A:** Any created **Druid** component can be removed with _druid:remove_. [API reference link](https://insality.github.io/druid/modules/druid_instance.html#druid:remove).
### Q: What is the purpose of the Blocker component?
**A:** The Blocker component is used to block input in a specific zone. It is useful for creating unclickable zones within buttons or for creating a panel of buttons on top of another button (e.g., closing windows by clicking on the window background). You can find more information about the Blocker component [here](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#notes-2).
### Q: What can I do with custom components?
**A:** With custom components in Druid, the possibilities are endless! Custom components allow you to separate component placement and game logic from other elements, making them reusable and easier to test and develop. Custom components can be used for scroll elements with buttons, custom GUI widgets, or even components with custom game logic. Templates often accompany custom components, allowing you to create multiple visual variations for a single component module. You can find some examples of custom components [here](https://github.com/Insality/druid-assets).
### Q: How to make scroll work?
**A:** ---
### Q: How does `self:get_node()` work?
**A:** The `self:get_node()` function in a Druid component searches for nodes in the GUI directly or in cloned nodes created using `gui.clone_tree()`. It also considers nodes placed as templates, with the full node ID composed of the template name and node name (including cloned nodes). To ensure correct usage of `self:get_node()`, set up the component nodes using `self:set_template()` and `self:set_component_nodes()` before calling `self:get_node()`. It's best to pass the string name of the node, rather than the GUI node itself.
### Q: How the input is processing?
**A:**
*SImply*: the **Druid** has a LIFO queue to check input. Last added buttons have more priority than first. Placing your buttons from behind to the front is correct in most cases.
### Q: For what purpose Blocker component is exist?
**A:** Component explanation [here](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#notes-2).
With Blocker you can block input in some zone. It is useful for make unclickable zone in buttons or kind of buttons panel on other big button (ex. close windows on window background click)
### Q: Which stuff can I do with custom components?
**A:** Any of you can imagine! There is a lot of examples, but in general: custom components allow you place component and some game logic separately from other stuff. It will be reusable, easier for testing and developing.
For example it can be element in scroll with buttons, your custom GUI widget or even component with your game logic. Usually custom components going with templates. You can do several templates for single component module (for different visuals!)
Some examples of custom components you can find [here](https://github.com/Insality/druid-assets).
### Q: How *self:get_node()* is working?
**A:** The node can be placed in gui directly or can be cloned via *gui.clone_tree()*. Also nodes can be placed as templates, so full node id will be composed from template name and node name (in cloned nodes too).
**Druid** component *self:get_node()* trying to search in all of this places. Use *self:set_template()* and *self:set_component_nodes()* for correct setup component nodes before any call of *self:get_node()*.
Remember, usually you should pass *__string name__ of the node*, not gui node itself. It's better and more druid-way.
### Q: My button in scroll is clickable outside the stencil node
**A:** Since **Druid** checking click node with _gui.pick_node_, stencil is not prevent this. You can setup additional click zone on your buttons with _button:set_click_zone_.
The usual Druid way after add button to the scroll do:
### Q: My button in a scroll is clickable outside the stencil node. How can I fix this?
**A:** When using Druid, the stencil node does not prevent buttons from being clickable outside its bounds. To address this, you can set up an additional click zone on your buttons using the `button:set_click_zone()` function. After adding a button to the scroll, you can use the following code:
```lua
-- Scroll view node usually is stencil node
-- Assuming the scroll view node is the stencil node
button:set_click_zone(scroll.view_node)
```
### Q: How to use EmmyLua annotations? _(from Druid 0.6.0)_
**A:** Since the dependencies can't be processed by external editors, for use generated EmmyLua annotations you should copy the _druid/annotations.lua_ to your project. For EmmyLua it will be enough. Remember you can _restart emmylua server_ for refresh the changes, if something goes wrong.
After the annotations is processed, you should point the type of Druid in requires:
### Q: How do I use EmmyLua annotations? (from Druid 0.6.0)
**A:** EmmyLua annotations are used for better autocompletion and type inference in editors. To use the generated EmmyLua annotations, copy the `druid/annotations.lua` file to your project. After copying, you may need to restart the EmmyLua server to ensure the changes take effect. Once the annotations are processed, you can specify the type of Druid in your code:
```lua
---@type druid
local druid = require("druid.druid")
-- Now the autocomplete is working
-- Autocomplete and type information should now work
```
### Q: When I should use *on_layout_change*?
**A:** ---
Feel free to ask any additional questions you have about Druid!

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

@@ -0,0 +1,141 @@
# Advanced Druid Setup
## Input Bindings
By default, **Druid** uses all key names from Defold's default `/builtins/input/all.input_binding` for input bindings.
**Druid** requires the following input bindings:
- Mouse trigger: `Button 1` -> `touch` (for basic input components)
- Mouse trigger: `Wheel up` -> `mouse_wheel_up` (for Scroll component)
- Mouse trigger: `Wheel down` -> `mouse_wheel_down` (for Scroll component)
- Key trigger: `Backspace` -> `key_backspace` (for BackHandler component, input component)
- Key trigger: `Back` -> `key_back` (for BackHandler component, Android back button, input component)
- Key trigger: `Enter` -> `key_enter` (for Input component, optional)
- Key trigger: `Esc` -> `key_esc` (for Input component, optional)
- Key trigger: `Left` -> `key_left` (for Rich Input component, optional)
- Key trigger: `Right` -> `key_right` (for Rich Input component, optional)
- Key trigger: `Shift` -> `key_lshift` (for Rich Input component, optional)
- Key trigger: `Ctrl` -> `key_lctrl` (for Rich Input component, optional)
- Key trigger: `Super` -> `key_lsuper` (for Rich Input component, optional)
- Touch triggers: `Touch multi` -> `touch_multi` (for Scroll component)
![](../media/input_binding_2.png)
![](../media/input_binding_1.png)
## Changing Key Bindings
If you need to use your own key bindings or key names, you can modify them in your *game.project* file.
Here are the default values for key bindings:
```
[druid]
input_text = text
input_touch = touch
input_marked_text = marked_text
input_key_esc = key_esc
input_key_back = key_back
input_key_enter = key_enter
input_key_backspace = key_backspace
input_multitouch = touch_multi
input_scroll_up = mouse_wheel_up
input_scroll_down = mouse_wheel_down
input_key_left = key_left
input_key_right = key_right
input_key_lshift = key_lshift
input_key_lctrl = key_lctrl
input_key_lsuper = key_lsuper
```
## Input Capturing
By default, **Druid** automatically captures input focus if any input component is created. Therefore, you do not need to call `msg.post(".", "acquire_input_focus")`.
If you do not require this behavior, you can disable it by setting the `druid.no_auto_input` field in the _game.project_ file:
```
[druid]
no_auto_input = 1
```
## Template Name Check
By default, **Druid** automatically checks the parent component's template name to construct the full template name for the component. It's used in user custom components.
If, for some reason, you want to pass the full template name manually, you can disable this feature by setting the `druid.no_auto_template` field in the _game.project_ file:
```
[druid]
no_auto_template = 1
```
## Stencil Check
When creating input components inside stencil nodes, **Druid** automatically sets up `component:set_click_zone()` during the _late_init_ component step to restrict input clicks outside of the stencil zone. This is particularly useful for buttons inside scroll stencil nodes.
To disable this feature, add the following field to your _game.project_ file:
```
[druid]
no_stencil_check = 1
```
## Code Bindings
Adjust **Druid** settings as needed:
```lua
local druid = require("druid.druid")
-- Used for button component and custom components
-- The callback should play the sound by name: function(sound_id) ... end
druid.set_sound_function(function(sound_id)
-- sound_system.play(sound_id)
end)
-- Used for lang_text component
-- The callback should return the localized string by locale ID: function(locale_id) ... end
druid.set_text_function(function(locale_id)
-- return lang.get(locale_id)
end)
-- Used to change the default Druid style
druid.set_default_style(your_style)
-- Call this function when the language changes in the game,
-- to retranslate all lang_text components:
local function on_language_change()
druid.on_language_change()
end
-- Call this function inside window.set_listener
-- to capture game focus lost/gained callbacks:
-- window.set_listener(function(self, event, data) druid.on_window_callback(event, data) end))
local function on_window_callback(self, event, data)
druid.on_window_callback(event)
end
window.set_listener(on_window_callback)
```
## EmmyLua Annotations
[EmmyLua](https://emmylua.github.io/annotation.html) is a Lua annotation library. It is a useful tool for enabling Lua code autocompletion in editors such as [VSCode](https://github.com/EmmyLua/VSCode-EmmyLua) and [IntelliJ IDEA](https://github.com/EmmyLua/IntelliJ-EmmyLua).
Since dependencies cannot be processed by external editors, to use the EmmyLua annotations, you should copy the _druid/annotations.lua_ file to your project.
Remember that you can restart the EmmyLua server to refresh the changes if something goes wrong.
After the annotations are processed, you should specify the type of "Druid" in the "require" statement:
```lua
---@type druid
local druid = require("druid.druid")
-- Now the autocomplete is working
```
<img src="../media/emmy_lua_preview.png" width="700">

View File

@@ -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,200 @@ 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, progress bar, data list + component examples
### Druid 0.11.0
Hello! What a wonderful day for the new **Druid** update!
Alright, let's get straight to the point. Look at what I have for you!
**Druid Rich Text** has finally been released. The main difference from the existing **Bjorn's** Rich Text is that all visual parameters are customizable directly in the GUI. This allows you to integrate **Rich Text** more accurately and quickly. Additionally, this **Rich Text** aligns pixel perfect (well, [almost](https://github.com/defold/defold/issues/7197)) with regular GUI text node.
This version is the most basic one. Honestly, just wanna to publish current version for your and polish it later. Read [RichText API here](https://insality.github.io/druid/modules/RichText.html)
Another addition is the ability to enable the "HTML mode" for the Button component. In this mode, the button's action occurs in the context of `user action`, allowing operations like "copy and paste text" "show the keyboard" and more. However, in this mode, the button only responds to regular clicks due to the technical implementation of it (so no double clicks or long taps for this button).
The huge work was done on documentation. Now it's more clear and have more examples. All documentation now moved to the API section. The separate `componentd.md` manual will be deleted soon as all documentation will be moved to the API section.
The API section now filled with overview and usage examples. I've started with the basic modules, in future I will add more examples for all modules.
Also, I've added the **Unit Tests**. It's not cover all **Druid** code, but it's a good start! 🎉
Have a good day!
**Changelog 0.11.0**
---
- **#191**: [RichText] Finally add **Druid [Rich Text](https://insality.github.io/druid/modules/RichText.html)** custom component. Component is used to make formatted text in your's GUI. This Rich Text mostly adjusted visually in GUI and have almost pixel-perfect match with similar GUI text node
- **#39**: [System] Finally add **Unit Tests**. Yeah, it cover not all **Druid** code, but it's a good start! 🎉
- **#219**: [System] UTF-8 performance optimization. Now Druid will try to use *utf8* native extension over lua utf8 library if exists. If you wanna use native utf8, just [add the extension](https://github.com/d954mas/defold-utf8) in your `game.project` dependency.
- **#156**: [Button] Now button can work in HTML5 with `html5.set_interaction_listener`.
- The API is `button:set_web_user_interaction(true)`. In HTML5 mode button have several restrictions. Basically, only the single tap event will work.
- **#227**: [System] Update current URL in HTML5 example
- Now if you will open the example from direct URL, it will be updated to the current URL in your browser. So now it's much easier to share the example link with each other.
- **#183**: [Docs] Documentation about [GUI in World Space](https://forum.defold.com/t/how-to-gui-in-defold/73256#gui-in-world-coordinates-49)
- Also not only the GUI in World Space, but overall How to GUI in Defold article.
- **#234**: [**BREAKING**] [Blocker] Now `blocker:set_enabled` and `blocker:is_enabled` affects only inner state of component. To consume input, the blocker component should be enabled and the node itself should be enabled.
- Breaking due the changes can affect your current logic. Please if use this re-check Blocker component usage.
- **#235**: [Drag] Fix Drag coordinates on streched screen.
- **#236**: [Hover] Fix nil return in `hover:on_input`.
- **#237**: [Layout] Add `layout:set_max_gui_upscale` function.
- This functions will scale down element, if current GUI scale is bigger than `max_gui_upscale` value. It can be useful for adapt mobile device to desktop screen.
- **#238**: [System] Add Helper documentation.
- [System] Now the documentation contains the **Druid** size. The current size as dependency is around **67KB**. It counted without extended components, which is not included by default in the build.
Thanks to the my supporters:
- [Defold Foundation](https://defold.com)
- [Ragetto](https://forum.defold.com/u/ragetto)
❤️ Support ❤️
Please support me if you like this project! It will help me keep engaged to update **Druid** and make it even better!
[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality)
### Druid 1.0
**Description**
Hello! The long-awaited update for Druid is finally here!
I'm releasing this version as 1.0, since Druid is pretty stable and packed with features.
This update brings a lot of improvements, so let's dive in:
**New Example Page**
Ive updated Druid's main examples page. Since Druid has become quite popular, I wanted to ensure the examples meet high standards of quality and aesthetics. The examples are now clearer and provide more information. Ive also added many new examples. Check them out!
**Component Reworking**
Several components have been reworked. While I generally avoid introducing breaking changes, sometimes they are necessary for progress.
- Rich Text is now applied directly to the text node, rather than using a Rich Text Template. This makes setup and usage much easier! Im still working on figuring out how to apply this approach to Rich Input.
- The Layout component has been completely replaced. It now functions similarly to Dynamic Grid but is responsible for adjusting nodes in the GUI. Its easier to use and offers more configuration options.
- Dynamic Grid will be deprecated in the future, with the new Layout component serving as its replacement.
- Data List now works exclusively with Static Grid, making it more stable and optimized. Additionally, a new "cached" version is available, which optimizes node reuse. However, the cached version requires using `on_add_element` and `on_remove_element` events to properly set up nodes.
**Code Cleanup**
Ive finally removed "middleclass" from Druid. If you were using it for some reason, youll need to copy the "middleclass" code into your project.
**Annotations**
Druids annotations were originally created when there were no Lua language servers. These annotations are of the older LDoc type and not EmmyLua. In the future, I aim to eliminate annotations altogether and rely on annotated code, which is easier to read, maintain, and feature-rich. The Defold will support the LLS (Lua Language Server) as well as VSCode with amazing Defold-Kit extension.
---
**Milestone**: https://github.com/Insality/druid/milestone/12
**Changelog 1.0.0**
- New Druid logo!
- **[Example]** New Example Page with 40+ examples.
- **[Data List]** Reworked Data List to work only with **Static Grid**. Its now more stable and has an extended API.
- Added a **Cached Data List** option, which uses less memory (highly optimized) but requires `on_add_element` and `on_remove_element` events for node setup. All components must be of the same class in this case.
- **[Rich Text]** Now applied directly to the text node instead of using a Rich Text Template (which previously contained three nodes: root, text, and image prefabs). This simplifies usage in the GUI.
- **[Rich Input]** Updated with new features such as selection and cursor navigation. New input keys can be configured in Druid (arrows, ctrl, shift).
- **[Input]** Users can now switch between text input areas with a single click, instead of needing to tap twice (once to close the focus and once to open the new input).
- **[Layout]** Reworked the Layout component. The new version allows arranging nodes in various modes (vertical, horizontal, horizontal wrap) and includes more settings (margins, padding, justification, pivots, and content hugging options). This will replace Dynamic Grid in the future.
- **[Dynamic Grid]** Deprecated in favor of the new Layout component.
- **[Drag]** Added a touch parameter to Drag callbacks, making it easier to add custom logic with input action data.
- **[Scroll]** Added `scroll.view_size`, `scroll:set_view_size(size)`, and `scroll:update_view_size()` functions for better management of the scroll input area and visible part.
- **[Static Grid]** Added `grid:set_item_size(size)` and `grid:sort_nodes(comparator)` functions.
- **[Text]** Adjustments for multiline text height seem to be working correctly now.
- **[Progress Bar]** Improved accuracy when scaling progress bars for images with slice9 parameters.
- **[Slider]** Fixed several slider setup issues.
- **[System]** Updated and fixed annotations.
- **[System]** Removed `middleclass.lua`.
- **[System]** Removed: `checkbox`, `checkbox_group`, and `radio_button` components. These components can be easily created using the Button component. Check the examples for implementation.
- **[System]** Removed: `pin_knob` custom component. It mostly was created as an example and now is not needed.
- **[System]** Added `self:get_druid(template, nodes)` to replace `self:set_template(template)` and `self:set_nodes(nodes)` calls in custom components.
- Various improvements and fixes.
A big thanks to the my Github supporters:
- [Defold Foundation](https://defold.com)
- [Ragetto](https://forum.defold.com/u/ragetto)
- [Pawel](https://forum.defold.com/u/pawel/summary)
And all my other supporters! Very appreciated!
❤️ Support ❤️
Please support me if you like this project! It will help me keep engaged to update **Druid** and make it even better!
[![Github-sponsors](https://img.shields.io/badge/sponsor-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#EA4AAA)](https://github.com/sponsors/insality) [![Ko-Fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/insality) [![BuyMeACoffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/insality)
---
**Postmortem**
Thoughts, wrong decisions, future plans, and how to update correctly:
- No styles should exist.
- Annotations should be updated or removed.
- Non-explicit event parameters can cause confusion, particularly with `self` parameters.
- There is room for performance optimization. Memory usage is not optimized, though it can still handle heavy-load GUIs like Panthera.
- Creating custom components could be made easier.
- There can be a much less code bindings between elements. Like bind_grid, update_size after some changes etc.

View File

@@ -22,6 +22,7 @@
"input": true,
"media": true,
"build": true,
"docs": true,
".github": true,
".deployer_cache": true,
"dist": true

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,38 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
-- Copyright (c) 2023 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle back key (android, backspace)
--- Component with event on back and backspace button.
-- <b># Overview #</b>
--
-- Back Handler is recommended to put in every game window to close it
-- or in main screen to call settings window.
--
-- <b># Notes #</b>
--
-- • Back Handler inheritance @{BaseComponent}, you can use all of its methods in addition to those described here.
--
-- • Back Handler react on release action ACTION_BACK or ACTION_BACKSPACE
-- @usage
-- local callback = function(self, params) ... end
--
-- local params = {}
-- local back_handler = self.druid:new_back_handler(callback, [params])
-- @module BackHandler
-- @within BaseComponent
-- @alias druid.back_handler
--- On back handler callback(self, params)
--- The @{DruidEvent} Event on back handler action.
--
-- Trigger on input action ACTION_BACK or ACTION_BACKSPACE
-- @usage
-- -- Subscribe additional callbacks:
-- back_handler.on_back:subscribe(callback)
-- @tfield DruidEvent on_back @{DruidEvent}
--- Params to back callback
-- @tfield any params
--- Custom args to pass in the callback
-- @usage
-- -- Replace params on runtime:
-- back_handler.params = { ... }
-- @tfield any|nil params
---
@@ -20,22 +43,24 @@ local component = require("druid.component")
local BackHandler = component.create("back_handler")
--- Component init function
--- The @{BackHandler} constructor
-- @tparam BackHandler self @{BackHandler}
-- @tparam callback callback On back button
-- @tparam[opt] any params Callback argument
function BackHandler.init(self, callback, params)
self.params = params
-- @tparam function callback @The callback(self, custom_args) to call on back event
-- @tparam any|nil custom_args Button events custom arguments
-- @local
function BackHandler.init(self, callback, custom_args)
self.params = custom_args
self.on_back = Event(callback)
end
--- Input handler for component
--- Component input handler
-- @tparam BackHandler self @{BackHandler}
-- @tparam string action_id on_input action id
-- @tparam table action on_input action
-- @local
function BackHandler.on_input(self, action_id, action)
if not action[const.RELEASED] then
if not action.released then
return false
end

View File

@@ -1,11 +1,25 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
-- Copyright (c) 2023 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to block input on specify zone by node
--- Component to consume input in special zone defined by GUI node.
-- <b># Overview #</b>
--
-- <b># Notes #</b>
--
-- Blocker consume input if `gui.pick_node` works on it.
--
-- • Blocker inheritance @{BaseComponent}, you can use all of its methods in addition to those described here.
--
-- • Blocker initial enabled state is `gui.is_enabled(node, true)`
--
-- • The Blocker node should be enabled to capture the input
-- @usage
-- local node = gui.get_node("blocker_node")
-- local blocker = self.druid:new_blocker(node)
-- @module Blocker
-- @within BaseComponent
-- @alias druid.blocker
---Trigger node
---Blocker node
-- @tfield node node
---
@@ -16,14 +30,20 @@ local component = require("druid.component")
local Blocker = component.create("blocker")
--- Component init function
--- The @{Blocker} constructor
-- @tparam Blocker self @{Blocker}
-- @tparam node node Gui node
function Blocker.init(self, node)
self.node = self:get_node(node)
self._is_enabled = gui.is_enabled(self.node, true)
end
--- Component input handler
-- @tparam Blocker self @{Blocker}
-- @tparam string action_id on_input action id
-- @tparam table action on_input action
-- @local
function Blocker.on_input(self, action_id, action)
if action_id ~= const.ACTION_TOUCH and
action_id ~= const.ACTION_MULTITOUCH and
@@ -31,7 +51,11 @@ function Blocker.on_input(self, action_id, action)
return false
end
if not self:is_enabled(self.node) then
if not self:is_enabled() then
return false
end
if not gui.is_enabled(self.node, true) then
return false
end
@@ -43,19 +67,21 @@ function Blocker.on_input(self, action_id, action)
end
--- Set enabled blocker component state
--- Set enabled blocker component state.
--
-- Don't change node enabled state itself.
-- @tparam Blocker self @{Blocker}
-- @tparam bool state Enabled state
-- @tparam boolean|nil state Enabled state
function Blocker.set_enabled(self, state)
gui.set_enabled(self.node, state)
self._is_enabled = state
end
--- Return blocked enabled state
--- Return blocker enabled state
-- @tparam Blocker self @{Blocker}
-- @treturn bool True, if blocker is enabled
-- @treturn boolean @True, if blocker is enabled
function Blocker.is_enabled(self)
return gui.is_enabled(self.node)
return self._is_enabled
end

View File

@@ -1,54 +1,138 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle basic GUI button
--- Druid Component for Handling User Click Interactions: Click, Long Click, Double Click, and More.
--
-- <b># Overview #</b>
--
-- This component provides a versatile solution for handling user click interactions.
-- It allows you to make any GUI node clickable and define various callbacks for different types of clicks.
--
-- <b># Notes #</b>
--
-- • The click callback will not trigger if the cursor moves outside the node's
-- area between the pressed and released states.
--
-- • If a button has a double click event subscriber and the double click event is triggered,
-- the regular click callback will not be triggered.
--
-- • Buttons can be triggered using a keyboard key by calling the button:set_key_trigger method.
--
-- • To animate a small icon on a big button panel, you can use an animation node.
-- The trigger node name should be set as "big panel," and the animation node should be set as "small icon."
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_buttons" target="_blank"><b>Example Link</b></a>
-- @usage
-- local function on_button_click(self, args, button)
-- print("Button has clicked with params: " .. args)
-- print("Also the button component is passed in callback params")
-- end
--
-- local custom_args = "Any variable to pass inside callback"
-- local button = self.druid:new_button("button_name", on_button_click, custom_args)
--
-- @module Button
-- @within BaseComponent
-- @alias druid.button
--- On release button callback(self, params, button_instance)
--- The @{DruidEvent}: Event on successful release action over button.
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_click:subscribe(function(self, custom_args, button_instance)
-- print("On button click!")
-- end)
-- @tfield DruidEvent on_click @{DruidEvent}
--- On repeated action button callback(self, params, button_instance, click_amount)
--- The @{DruidEvent}: Event on repeated action over button.
--
-- This callback will be triggered if user hold the button. The repeat rate pick from `input.repeat_interval` in game.project
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_repeated_click:subscribe(function(self, custom_args, button_instance, click_count)
-- print("On repeated Button click!")
-- end)
-- @tfield DruidEvent on_repeated_click @{DruidEvent}
---On long tap button callback(self, params, button_instance, time)
--- The @{DruidEvent}: Event on long tap action over button.
--
-- This callback will be triggered if user pressed the button and hold the some amount of time.
-- The amount of time picked from button style param: LONGTAP_TIME
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_long_click:subscribe(function(self, custom_args, button_instance, hold_time)
-- print("On long Button click!")
-- end)
-- @tfield DruidEvent on_long_click @{DruidEvent}
---On double tap button callback(self, params, button_instance, click_amount)
--- The @{DruidEvent}: Event on double tap action over button.
--
-- If secondary click was too fast after previous one, the double
-- click will be called instead usual click (if on_double_click subscriber exists)
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_double_click:subscribe(function(self, custom_args, button_instance, click_amount)
-- print("On double Button click!")
-- end)
-- @tfield DruidEvent on_double_click @{DruidEvent}
---On button hold before long_click callback(self, params, button_instance, time)
--- The @{DruidEvent}: Event calls every frame before on_long_click event.
--
-- If long_click subscriber exists, the on_hold_callback will be called before long_click trigger.
--
-- Usecase: Animate button progress of long tap
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_double_click:subscribe(function(self, custom_args, button_instance, time)
-- print("On hold Button callback!")
-- end)
-- @tfield DruidEvent on_hold_callback @{DruidEvent}
---On click outside of button(self, params, button_instance)
--- The @{DruidEvent}: Event calls if click event was outside of button.
--
-- This event will be triggered for each button what was not clicked on user click action
--
-- Usecase: Hide the popup when click outside
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_click_outside:subscribe(function(self, custom_args, button_instance)
-- print("On click Button outside!")
-- end)
-- @tfield DruidEvent on_click_outside @{DruidEvent}
---Trigger node
--- The @{DruidEvent}: Event triggered if button was pressed by user.
-- @usage
-- -- Custom args passed in Button constructor
-- button.on_pressed:subscribe(function(self, custom_args, button_instance)
-- print("On Button pressed!")
-- end)
-- @tfield DruidEvent on_pressed @{DruidEvent}
--- Button trigger node
-- @tfield node node
---The hash of trigger node
-- @tfield node_id hash
---The GUI node id from button node
-- @tfield hash node_id
---Animation node
-- @tfield[opt=node] node anim_node
--- Button animation node.
-- In default case equals to clickable node.
--
-- Usecase: You have the big clickable panel, but want to animate only one small icon on it.
-- @tfield node|nil anim_node Default node
---Initial scale of anim_node
-- @tfield vector3 start_scale
---Initial pos of anim_node
-- @tfield vector3 start_pos
---Initial pos of anim_node
-- @tfield vector3 pos
---Params to click callbacks
---Custom args for any Button event. Setup in Button constructor
-- @tfield any params
---Druid hover logic component
--- The @{Hover}: Button Hover component
-- @tfield Hover hover @{Hover}
---Restriction zone
-- @tfield[opt] node click_zone
--- Additional button click area, defined by another GUI node
-- @tfield node|nil click_zone
---
@@ -61,7 +145,7 @@ local Button = component.create("button")
local function is_input_match(self, action_id)
if action_id == const.ACTION_TOUCH then
if action_id == const.ACTION_TOUCH or action_id == const.ACTION_MULTITOUCH then
return true
end
@@ -84,6 +168,10 @@ end
local function on_button_click(self)
if self._is_html5_mode then
self._is_html5_listener_set = false
html5.set_interaction_listener(nil)
end
self.click_in_row = 1
self.on_click:trigger(self:get_context(), self.params, self)
self.style.on_click(self, self.anim_node)
@@ -141,18 +229,23 @@ local function on_button_release(self)
end
return true
else
if self.can_action then
if self.can_action and not self._is_html5_mode then
self.can_action = false
local time = socket.gettime()
local is_long_click = (time - self.last_pressed_time) > self.style.LONGTAP_TIME
local is_long_click = (time - self.last_pressed_time) >= self.style.LONGTAP_TIME
is_long_click = is_long_click and self.on_long_click:is_exist()
local is_double_click = (time - self.last_released_time) < self.style.DOUBLETAP_TIME
is_double_click = is_double_click and self.on_double_click:is_exist()
if is_long_click then
on_button_long_click(self)
local is_hold_complete = (time - self.last_pressed_time) >= self.style.AUTOHOLD_TRIGGER
if is_hold_complete then
on_button_long_click(self)
else
self.on_click_outside:trigger(self:get_context(), self.params, self)
end
elseif is_double_click then
on_button_double_click(self)
else
@@ -167,17 +260,17 @@ end
--- Component style params.
-- You can override this component styles params in druid styles table
-- You can override this component styles params in Druid styles table
-- or create your own style
-- @table style
-- @tfield[opt=0.4] number LONGTAP_TIME Minimum time to trigger on_hold_callback
-- @tfield[opt=0.8] number AUTOHOLD_TRIGGER Maximum hold time to trigger button release while holding
-- @tfield[opt=0.4] number DOUBLETAP_TIME Time between double taps
-- @tfield function on_click (self, node)
-- @tfield function on_click_disabled (self, node)
-- @tfield function on_hover (self, node, hover_state)
-- @tfield function on_mouse_hover (self, node, hover_state)
-- @tfield function on_set_enabled (self, node, enabled_state)
-- @tfield number|nil LONGTAP_TIME Minimum time to trigger on_hold_callback. Default: 0.4
-- @tfield number|nil AUTOHOLD_TRIGGER Maximum hold time to trigger button release while holding. Default: 0.8
-- @tfield number|nil DOUBLETAP_TIME Time between double taps. Default: 0.4
-- @tfield function on_click function(self, node)
-- @tfield function on_click_disabled function(self, node)
-- @tfield function on_hover function(self, node, hover_state)
-- @tfield function on_mouse_hover function(self, node, hover_state)
-- @tfield function on_set_enabled function(self, node, enabled_state)
function Button.on_style_change(self, style)
self.style = {}
self.style.LONGTAP_TIME = style.LONGTAP_TIME or 0.4
@@ -192,13 +285,13 @@ function Button.on_style_change(self, style)
end
--- Component init function
--- The @{Button} constructor
-- @tparam Button self @{Button}
-- @tparam node node Gui node
-- @tparam function callback Button callback
-- @tparam[opt] table params Button callback params
-- @tparam[opt] node anim_node Button anim node (node, if not provided)
function Button.init(self, node, callback, params, anim_node)
-- @tparam string|node node The node_id or gui.get_node(node_id)
-- @tparam function callback On click button callback
-- @tparam any|nil custom_args Button events custom arguments
-- @tparam string|node|nil anim_node Node to animate instead of trigger node.
function Button.init(self, node, callback, custom_args, anim_node)
self.druid = self:get_druid()
self.node = self:get_node(node)
self.node_id = gui.get_id(self.node)
@@ -206,7 +299,7 @@ function Button.init(self, node, callback, params, anim_node)
self.anim_node = anim_node and self:get_node(anim_node) or self.node
self.start_scale = gui.get_scale(self.anim_node)
self.start_pos = gui.get_position(self.anim_node)
self.params = params
self.params = custom_args
self.hover = self.druid:new_hover(node, on_button_hover)
self.hover.on_mouse_hover:subscribe(on_button_mouse_hover)
self.click_zone = nil
@@ -218,9 +311,12 @@ function Button.init(self, node, callback, params, anim_node)
self._check_function = nil
self._failure_callback = nil
self._is_html5_mode = false
self._is_html5_listener_set = false
-- Event stubs
-- Events
self.on_click = Event(callback)
self.on_pressed = Event()
self.on_repeated_click = Event()
self.on_long_click = Event()
self.on_double_click = Event()
@@ -244,17 +340,15 @@ function Button.on_input(self, action_id, action)
return false
end
if not helper.is_enabled(self.node) then
if not gui.is_enabled(self.node, true) then
return false
end
local is_consume = true
local is_pick = true
local is_key_trigger = (action_id == self.key_trigger)
if not is_key_trigger then
is_pick = gui.pick_node(self.node, action.x, action.y)
if self.click_zone then
is_pick = is_pick and gui.pick_node(self.click_zone, action.x, action.y)
end
is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone)
end
if not is_pick then
@@ -263,11 +357,17 @@ function Button.on_input(self, action_id, action)
if action.released then
self.on_click_outside:trigger(self:get_context(), self.params, self)
end
if self._is_html5_mode and self._is_html5_listener_set then
self._is_html5_listener_set = false
html5.set_interaction_listener(nil)
end
return false
end
if is_key_trigger then
self.hover:set_hover(not action.released)
is_consume = false
end
if action.pressed then
@@ -275,46 +375,56 @@ function Button.on_input(self, action_id, action)
self.can_action = true
self.is_repeated_started = false
self.last_pressed_time = socket.gettime()
return true
self.on_pressed:trigger(self:get_context(), self.params, self)
if self._is_html5_mode then
self._is_html5_listener_set = true
html5.set_interaction_listener(function()
on_button_click(self)
end)
end
return is_consume
end
-- While hold button, repeat rate pick from input.repeat_interval
if action.repeated then
if not self.disabled and self.on_repeated_click:is_exist() and self.can_action then
if self.on_repeated_click:is_exist() and self.can_action then
on_button_repeated_click(self)
return true
return is_consume
end
end
if action.released then
return on_button_release(self)
return on_button_release(self) and is_consume
end
if not self.disabled and self.can_action and self.on_long_click:is_exist() then
if self.can_action and self.on_long_click:is_exist() then
local press_time = socket.gettime() - self.last_pressed_time
if self.style.AUTOHOLD_TRIGGER <= press_time then
on_button_release(self)
return true
return is_consume
end
if press_time >= self.style.LONGTAP_TIME then
on_button_hold(self, press_time)
return true
return is_consume
end
end
return not self.disabled
return not self.disabled and is_consume
end
function Button.on_input_interrupt(self)
self.can_action = false
self.hover:set_hover(false)
self.hover:set_mouse_hover(false)
end
function Button.on_message_input(self, node_id, message)
if node_id ~= self.node_id or self.disabled or not helper.is_enabled(self.node) then
if node_id ~= self.node_id or self.disabled or not gui.is_enabled(self.node) then
return false
end
@@ -338,10 +448,15 @@ function Button.on_message_input(self, node_id, message)
end
--- Set enabled button component state
--- Set button enabled state.
-- The style.on_set_enabled will be triggered.
-- Disabled button is not clickable.
-- @tparam Button self @{Button}
-- @tparam bool state Enabled state
-- @tparam boolean|nil state Enabled state
-- @treturn Button Current button instance
-- @usage
-- button:set_enabled(false)
-- button:set_enabled(true)
function Button.set_enabled(self, state)
self.disabled = not state
self.hover:set_enabled(state)
@@ -351,19 +466,27 @@ function Button.set_enabled(self, state)
end
--- Return button enabled state
--- Get button enabled state.
--
-- By default all Buttons is enabled on creating.
-- @tparam Button self @{Button}
-- @treturn bool True, if button is enabled
-- @treturn boolean @True, if button is enabled now, False overwise
-- @usage
-- local is_enabled = button:is_enabled()
function Button.is_enabled(self)
return not self.disabled
end
--- Strict button click area. Useful for
-- no click events outside stencil node
--- Set additional button click area.
-- Useful to restrict click outside out stencil node or scrollable content.
--
-- This functions calls automatically if you don't disable it in game.project: druid.no_stencil_check
-- @tparam Button self @{Button}
-- @tparam node zone Gui node
-- @tparam node|string|nil zone Gui node
-- @treturn Button Current button instance
-- @usage
-- button:set_click_zone("stencil_node")
function Button.set_click_zone(self, zone)
self.click_zone = self:get_node(zone)
self.hover:set_click_zone(zone)
@@ -372,10 +495,12 @@ function Button.set_click_zone(self, zone)
end
--- Set key-code to trigger this button
--- Set key name to trigger this button by keyboard.
-- @tparam Button self @{Button}
-- @tparam hash key The action_id of the key
-- @tparam hash|string key The action_id of the input key
-- @treturn Button Current button instance
-- @usage
-- button:set_key_trigger("key_space")
function Button.set_key_trigger(self, key)
self.key_trigger = hash(key)
@@ -383,9 +508,11 @@ function Button.set_key_trigger(self, key)
end
--- Get key-code to trigger this button
--- Get current key name to trigger this button.
-- @tparam Button self
-- @treturn hash The action_id of the key
-- @treturn hash The action_id of the input key
-- @usage
-- local key_hash = button:get_key_trigger()
function Button.get_key_trigger(self)
return self.key_trigger
end
@@ -393,8 +520,8 @@ end
--- Set function for additional check for button click availability
-- @tparam Button self
-- @tparam[opt] function check_function Should return true or false. If true - button can be pressed.
-- @tparam[opt] function failure_callback Function what will be called on button click, if check function return false
-- @tparam function|nil check_function Should return true or false. If true - button can be pressed.
-- @tparam function|nil failure_callback Function will be called on button click, if check function return false
-- @treturn Button Current button instance
function Button.set_check_function(self, check_function, failure_callback)
self._check_function = check_function
@@ -402,4 +529,21 @@ function Button.set_check_function(self, check_function, failure_callback)
end
--- Set Button mode to work inside user HTML5 interaction event.
--
-- It's required to make protected things like copy & paste text, show mobile keyboard, etc
-- The HTML5 button's doesn't call any events except on_click event.
--
-- If the game is not HTML, html mode will be not enabled
-- @tparam Button self
-- @tparam boolean|nil is_web_mode If true - button will be called inside html5 callback
-- @treturn Button Current button instance
-- @usage
-- button:set_web_user_interaction(true)
function Button.set_web_user_interaction(self, is_web_mode)
self._is_html5_mode = not not (is_web_mode and html5)
return self
end
return Button

View File

@@ -4,36 +4,41 @@
-- Drag have correct handling for multitouch and swap
-- touched while dragging. Drag will be processed even
-- the cursor is outside of node, if drag is already started
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_drag" target="_blank"><b>Example Link</b></a>
-- @module Drag
-- @within BaseComponent
-- @alias druid.drag
--- Drag node
-- @tfield node node
--- Event on touch start callback(self)
-- @tfield DruidEvent on_touch_start @{DruidEvent}
--- Event on touch end callback(self)
-- @tfield DruidEvent on_touch_end @{DruidEvent}
--- Event on drag start callback(self)
--- Event on drag start callback(self, touch)
-- @tfield DruidEvent on_drag_start @{DruidEvent}
--- on drag progress callback(self, dx, dy)
--- on drag progress callback(self, dx, dy, total_x, total_y, touch)
-- @tfield DruidEvent on_drag Event @{DruidEvent}
--- Event on drag end callback(self)
--- Event on drag end callback(self, total_x, total_y, touch)
-- @tfield DruidEvent on_drag_end @{DruidEvent}
--- Is component now touching
-- @tfield bool is_touch
-- @tfield boolean is_touch
--- Is component now dragging
-- @tfield bool is_drag
-- @tfield boolean is_drag
--- Is drag component process vertical dragging. Default - true
-- @tfield bool can_x
-- @tfield boolean can_x
--- Is drag component process horizontal. Default - true
-- @tfield bool can_y
-- @tfield boolean can_y
--- Current touch x position
-- @tfield number x
@@ -41,6 +46,12 @@
--- Current touch y position
-- @tfield number y
--- Current touch x screen position
-- @tfield number screen_x
--- Current touch y screen position
-- @tfield number screen_y
--- Touch start position
-- @tfield vector3 touch_start_pos
@@ -64,19 +75,29 @@ local function start_touch(self, touch)
self.x = touch.x
self.y = touch.y
self.on_touch_start:trigger(self:get_context())
self.screen_x = touch.screen_x
self.screen_y = touch.screen_y
self._scene_scale = helper.get_scene_scale(self.node)
self.on_touch_start:trigger(self:get_context(), touch)
end
local function end_touch(self)
local function end_touch(self, touch)
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,
touch
)
end
self.is_drag = false
if self.is_touch then
self.is_touch = false
self.on_touch_end:trigger(self:get_context())
self.on_touch_end:trigger(self:get_context(), touch)
end
self:reset_input_priority()
self.touch_id = 0
@@ -95,8 +116,8 @@ local function process_touch(self, touch)
local distance = helper.distance(touch.x, touch.y, self.touch_start_pos.x, self.touch_start_pos.y)
if not self.is_drag and distance >= self.style.DRAG_DEADZONE then
self.is_drag = true
self.on_drag_start:trigger(self:get_context())
self:set_input_priority(const.PRIORITY_INPUT_MAX)
self.on_drag_start:trigger(self:get_context(), touch)
self:set_input_priority(const.PRIORITY_INPUT_MAX, true)
end
end
@@ -154,14 +175,16 @@ end
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield[opt=10] number DRAG_DEADZONE Distance in pixels to start dragging
-- @tfield number|nil DRAG_DEADZONE Distance in pixels to start dragging. Default: 10
-- @tfield boolean|nil NO_USE_SCREEN_KOEF If screen aspect ratio affects on drag values. Default: false
function Drag.on_style_change(self, style)
self.style = {}
self.style.DRAG_DEADZONE = style.DRAG_DEADZONE or 10
self.style.NO_USE_SCREEN_KOEF = style.NO_USE_SCREEN_KOEF or false
end
--- Drag component constructor
--- The @{Drag} constructor
-- @tparam Drag self @{Drag}
-- @tparam node node GUI node to detect dragging
-- @tparam function on_drag_callback Callback for on_drag_event(self, dx, dy)
@@ -173,19 +196,26 @@ function Drag.init(self, node, on_drag_callback)
self.touch_id = 0
self.x = 0
self.y = 0
self.screen_x = 0
self.screen_y = 0
self.is_touch = false
self.is_drag = false
self.touch_start_pos = vmath.vector3(0)
self._is_enabled = true
self.can_x = true
self.can_y = true
self._scene_scale = helper.get_scene_scale(self.node)
self.click_zone = nil
self.on_touch_start = Event()
self.on_touch_end = Event()
self.on_drag_start = Event()
self.on_drag = Event(on_drag_callback)
self.on_drag_end = Event()
self:on_window_resized()
end
@@ -199,6 +229,14 @@ 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
self._scene_scale = helper.get_scene_scale(self.node)
end
function Drag.on_input_interrupt(self)
if self.is_drag or self.is_touch then
end_touch(self)
@@ -211,15 +249,11 @@ function Drag.on_input(self, action_id, action)
return false
end
if not helper.is_enabled(self.node) then
if not self._is_enabled or not gui.is_enabled(self.node, true) then
return false
end
local is_pick = gui.pick_node(self.node, action.x, action.y)
if self.click_zone then
is_pick = is_pick and gui.pick_node(self.click_zone, action.x, action.y)
end
local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone)
if not is_pick and not self.is_drag then
end_touch(self)
return false
@@ -248,7 +282,7 @@ function Drag.on_input(self, action_id, action)
on_touch_release(self, action_id, action)
else
-- PC
end_touch(self)
end_touch(self, touch)
end
end
@@ -265,10 +299,22 @@ function Drag.on_input(self, action_id, action)
if touch_modified then
self.x = touch_modified.x
self.y = touch_modified.y
self.screen_x = touch_modified.screen_x
self.screen_y = touch_modified.screen_y
end
if self.is_drag then
self.on_drag:trigger(self:get_context(), self.dx, self.dy)
if self.is_drag and (self.dx ~= 0 or self.dy ~= 0) then
local x_koef, y_koef = self._x_koef, self._y_koef
if self.style.NO_USE_SCREEN_KOEF then
x_koef, y_koef = 1, 1
end
self.on_drag:trigger(self:get_context(),
self.dx * x_koef / self._scene_scale.x,
self.dy * y_koef / self._scene_scale.y,
(self.x - self.touch_start_pos.x) * x_koef / self._scene_scale.x,
(self.y - self.touch_start_pos.y) * y_koef / self._scene_scale.y, touch_modified)
end
return self.is_drag
@@ -278,10 +324,26 @@ end
--- Strict drag click area. Useful for
-- restrict events outside stencil node
-- @tparam Drag self @{Drag}
-- @tparam node node Gui node
-- @tparam node|string|nil node Gui node
function Drag.set_click_zone(self, node)
self.click_zone = self:get_node(node)
end
--- Set Drag input enabled or disabled
-- @tparam Drag self @{Drag}
-- @tparam boolean|nil is_enabled
function Drag.set_enabled(self, is_enabled)
self._is_enabled = is_enabled
end
--- Check if Drag component is enabled
-- @tparam Drag self @{Drag}
-- @treturn boolean
function Drag.is_enabled(self)
return self._is_enabled
end
return Drag

View File

@@ -5,10 +5,13 @@
-- @within BaseComponent
-- @alias druid.hover
--- On hover callback(self, state)
--- Hover node
-- @tfield node node
--- On hover callback(self, state, hover_instance)
-- @tfield DruidEvent on_hover @{DruidEvent}
--- On mouse hover callback(self, state)
--- On mouse hover callback(self, state, hover_instance)
-- @tfield DruidEvent on_mouse_hover @{DruidEvent}
---
@@ -21,11 +24,12 @@ local component = require("druid.component")
local Hover = component.create("hover")
--- Component init function
--- The @{Hover} constructor
-- @tparam Hover self @{Hover}
-- @tparam node node Gui node
-- @tparam function on_hover_callback Hover callback
function Hover.init(self, node, on_hover_callback)
-- @tparam function on_mouse_hover On mouse hover callback
function Hover.init(self, node, on_hover_callback, on_mouse_hover)
self.node = self:get_node(node)
self._is_hovered = false
@@ -34,7 +38,7 @@ function Hover.init(self, node, on_hover_callback)
self._is_mobile = helper.is_mobile()
self.on_hover = Event(on_hover_callback)
self.on_mouse_hover = Event()
self.on_mouse_hover = Event(on_mouse_hover)
end
@@ -48,6 +52,19 @@ function Hover.on_late_init(self)
end
--- Component style params.
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield[opt] string ON_HOVER_CURSOR Mouse hover style on node hover
-- @tfield[opt] string ON_MOUSE_HOVER_CURSOR Mouse hover style on node mouse hover
function Hover.on_style_change(self, style)
self.style = {}
self.style.ON_HOVER_CURSOR = style.ON_HOVER_CURSOR or nil
self.style.ON_MOUSE_HOVER_CURSOR = style.ON_MOUSE_HOVER_CURSOR or nil
end
function Hover.on_input(self, action_id, action)
if action_id ~= const.ACTION_TOUCH and action_id ~= nil then
return false
@@ -58,17 +75,13 @@ function Hover.on_input(self, action_id, action)
return false
end
if not helper.is_enabled(self.node) or not self._is_enabled then
if not gui.is_enabled(self.node, true) or not self._is_enabled then
self:set_hover(false)
self:set_mouse_hover(false)
return false
end
local is_pick = gui.pick_node(self.node, action.x, action.y)
if self.click_zone then
is_pick = is_pick and gui.pick_node(self.click_zone, action.x, action.y)
end
local is_pick = helper.pick_node(self.node, action.x, action.y, self.click_zone)
local hover_function = action_id and self.set_hover or self.set_mouse_hover
if not is_pick then
@@ -81,6 +94,8 @@ function Hover.on_input(self, action_id, action)
else
hover_function(self, true)
end
return false
end
@@ -91,29 +106,58 @@ end
--- Set hover state
-- @tparam Hover self @{Hover}
-- @tparam bool state The hover state
-- @tparam boolean|nil state The hover state
function Hover.set_hover(self, state)
if self._is_hovered ~= state then
self._is_hovered = state
self.on_hover:trigger(self:get_context(), state)
if self._is_hovered == state then
return
end
self._is_hovered = state
self.on_hover:trigger(self:get_context(), state, self)
if defos and self.style.ON_HOVER_CURSOR then
self:_set_cursor(3, state and self.style.ON_HOVER_CURSOR or nil)
end
end
--- Return current hover state. True if touch action was on the node at current time
-- @tparam Hover self @{Hover}
-- @treturn boolean The current hovered state
function Hover.is_hovered(self)
return self._is_hovered
end
--- Set mouse hover state
-- @tparam Hover self @{Hover}
-- @tparam bool state The mouse hover state
-- @tparam boolean|nil state The mouse hover state
function Hover.set_mouse_hover(self, state)
if self._is_mouse_hovered ~= state then
self._is_mouse_hovered = state
self.on_mouse_hover:trigger(self:get_context(), state)
if self._is_mouse_hovered == state then
return
end
self._is_mouse_hovered = state
self.on_mouse_hover:trigger(self:get_context(), state, self)
if defos and self.style.ON_MOUSE_HOVER_CURSOR then
self:_set_cursor(2, state and self.style.ON_MOUSE_HOVER_CURSOR or nil)
end
end
--- Return current hover state. True if nil action_id (usually desktop mouse) was on the node at current time
-- @tparam Hover self @{Hover}
-- @treturn boolean The current hovered state
function Hover.is_mouse_hovered(self)
return self._is_mouse_hovered
end
--- Strict hover click area. Useful for
-- no click events outside stencil node
-- @tparam Hover self @{Hover}
-- @tparam node zone Gui node
-- @tparam node|string|nil zone Gui node
function Hover.set_click_zone(self, zone)
self.click_zone = self:get_node(zone)
end
@@ -123,7 +167,7 @@ end
-- If hover is not enabled, it will not generate
-- any hover events
-- @tparam Hover self @{Hover}
-- @tparam bool state The hover enabled state
-- @tparam boolean|nil state The hover enabled state
function Hover.set_enabled(self, state)
self._is_enabled = state
@@ -140,10 +184,37 @@ end
--- Return current hover enabled state
-- @tparam Hover self @{Hover}
-- @treturn bool The hover enabled state
-- @treturn boolean The hover enabled state
function Hover.is_enabled(self)
return self._is_enabled
end
-- Internal cursor stack
local cursor_stack = {}
function Hover:_set_cursor(priority, cursor)
if not defos then
return
end
local uid = self:get_uid()
cursor_stack[uid] = cursor_stack[uid] or {}
cursor_stack[uid][priority] = cursor
-- set cursor with high priority via pairs
local priority = nil
local cursor_to_set = nil
for _, stack in pairs(cursor_stack) do
for pr, _ in pairs(stack) do
if pr > (priority or 0) then
priority = pr
cursor_to_set = stack[priority]
end
end
end
defos.set_cursor(cursor_to_set)
end
return Hover

View File

@@ -1,12 +1,38 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle scroll content.
-- Scroll consist from two nodes: scroll parent and scroll input
-- Scroll input the user input zone, it's static
-- Scroll parent the scroll moving part, it will change position.
-- Setup initial scroll size by changing scroll parent size. If scroll parent
-- size will be less than scroll_input size, no scroll is available. For scroll
-- parent size should be more than input size
-- <b># Overview #</b>
--
-- The Scroll component is designed to handle scrollable content and consists of two nodes: the scroll parent and the scroll input.
--
-- The scroll input represents the user input zone and remains static.
--
-- The scroll parent is the movable part of the scroll and changes its position.
--
-- The initial scroll size can be set by adjusting the size of the scroll parent.
-- If the size of the scroll parent is smaller than the scroll input size, scrolling is not available.
--
-- <b># Notes #</b>
--
-- • By default, the scroll style includes inertia and extra size for a stretching effect.
-- These settings can be adjusted using the scroll style settings.
-- For more details, refer to the scroll style settings.
--
-- • "Points of interest" can be set up for the scroll.
-- The scroll will always be centered on the closest point of interest.
-- This feature allows creating a slider without inertia and with points of interest on each scroll element.
--
-- • The scroll content size can be adjusted using the scroll:set_size(node_size) method.
-- This method sets a new size for the _content node.
--
-- • Inertial scrolling mode can be enabled or disabled using the scroll:set_inert(state) method.
--
-- • The extra stretch size can be adjusted using the scroll:set_extra_stretch_size method.
--
-- • Multitouch is required for scrolling. The scroll component correctly handles
-- touch ID swaps while dragging the scroll.
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_scroll" target="_blank"><b>Example Link</b></a>
-- @module Scroll
-- @within BaseComponent
-- @alias druid.scroll
@@ -24,11 +50,14 @@
--- Scroll view node
-- @tfield node view_node
--- Scroll view size
-- @tfield vector3 view_size
--- Scroll content node
-- @tfield node content_node
--- Flag, if scroll now moving by inertion
-- @tfield bool is_inert
-- @tfield boolean _is_inert
--- Current inert speed
-- @tfield vector3 inertion
@@ -49,10 +78,10 @@
-- @tfield Drag drag @{Drag}
--- Current index of points of interests
-- @tfield[opt] number selected
-- @tfield number|nil selected
--- Flag, if scroll now animating by gui.animate
-- @tfield bool is_animate
-- @tfield boolean is_animate
---
@@ -97,18 +126,18 @@ end
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield[opt=0] number FRICT Multiplier for free inertion
-- @tfield[opt=0] number FRICT_HOLD Multiplier for inertion, while touching
-- @tfield[opt=3] number INERT_THRESHOLD Scroll speed to stop inertion
-- @tfield[opt=30] number INERT_SPEED Multiplier for inertion speed
-- @tfield[opt=20] number POINTS_DEADZONE Speed to check points of interests in no_inertion mode
-- @tfield[opt=0.35] number BACK_SPEED Scroll back returning lerp speed
-- @tfield[opt=0.2] number ANIM_SPEED Scroll gui.animation speed for scroll_to function
-- @tfield[opt=0] number EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect)
-- @tfield[opt=false] bool SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled
-- @tfield[opt=0] bool WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling
-- @tfield[opt=false] bool WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll
-- @tfield[opt=false] bool WHEEL_SCROLL_BY_INERTION If true, wheel will add inertion to scroll. Direct set position otherwise.
-- @tfield number|nil FRICT Multiplier for free inertion. Default: 0
-- @tfield number|nil FRICT_HOLD Multiplier for inertion, while touching. Default: 0
-- @tfield number|nil INERT_THRESHOLD Scroll speed to stop inertion. Default: 3
-- @tfield number|nil INERT_SPEED Multiplier for inertion speed. Default: 30
-- @tfield number|nil POINTS_DEADZONE Speed to check points of interests in no_inertion mode. Default: 20
-- @tfield number|nil BACK_SPEED Scroll back returning lerp speed. Default: 35
-- @tfield number|nil ANIM_SPEED Scroll gui.animation speed for scroll_to function. Default: 2
-- @tfield number|nil EXTRA_STRETCH_SIZE extra size in pixels outside of scroll (stretch effect). Default: 0
-- @tfield boolean|nil SMALL_CONTENT_SCROLL If true, content node with size less than view node size can be scrolled. Default: false
-- @tfield boolean|nil WHEEL_SCROLL_SPEED The scroll speed via mouse wheel scroll or touchpad. Set to 0 to disable wheel scrolling. Default: 0
-- @tfield boolean|nil WHEEL_SCROLL_INVERTED If true, invert direction for touchpad and mouse wheel scroll. Default: false
-- @tfield boolean|nil WHEEL_SCROLL_BY_INERTION If true, wheel will add inertion to scroll. Direct set position otherwise.. Default: false
function Scroll.on_style_change(self, style)
self.style = {}
self.style.EXTRA_STRETCH_SIZE = style.EXTRA_STRETCH_SIZE or 0
@@ -132,10 +161,10 @@ function Scroll.on_style_change(self, style)
end
--- Scroll constructor
--- The @{Scroll} constructor
-- @tparam Scroll self @{Scroll}
-- @tparam node view_node GUI view scroll node
-- @tparam node content_node GUI content scroll node
-- @tparam string|node view_node GUI view scroll node
-- @tparam string|node content_node GUI content scroll node
function Scroll.init(self, view_node, content_node)
self.druid = self:get_druid()
@@ -143,7 +172,7 @@ function Scroll.init(self, view_node, content_node)
self.view_border = helper.get_border(self.view_node)
self.content_node = self:get_node(content_node)
self.view_size = vmath.mul_per_elem(gui.get_size(self.view_node), gui.get_scale(self.view_node))
self.view_size = helper.get_scaled_size(self.view_node)
self.position = gui.get_position(self.content_node)
self.target_position = vmath.vector3(self.position)
@@ -190,6 +219,12 @@ end
function Scroll.update(self, dt)
if self.is_animate then
self.position.x = gui.get(self.content_node, "position.x")
self.position.y = gui.get(self.content_node, "position.y")
self.on_scroll:trigger(self:get_context(), self.position)
end
if self.drag.is_drag then
self:_update_hand_scroll(dt)
else
@@ -211,7 +246,7 @@ end
--- Start scroll to target point.
-- @tparam Scroll self @{Scroll}
-- @tparam vector3 point Target point
-- @tparam[opt] bool is_instant Instant scroll flag
-- @tparam boolean|nil is_instant Instant scroll flag
-- @usage scroll:scroll_to(vmath.vector3(0, 50, 0))
-- @usage scroll:scroll_to(vmath.vector3(0), true)
function Scroll.scroll_to(self, point, is_instant)
@@ -229,12 +264,12 @@ function Scroll.scroll_to(self, point, is_instant)
if is_instant then
self.target_position = target
self:_set_scroll_position(target)
self:_set_scroll_position(target.x, target.y)
else
gui.animate(self.content_node, gui.PROP_POSITION, target, gui.EASING_OUTSINE, self.style.ANIM_SPEED, 0, function()
self.is_animate = false
self.target_position = target
self:_set_scroll_position(target)
self:_set_scroll_position(target.x, target.y)
end)
end
@@ -245,7 +280,7 @@ end
--- Scroll to item in scroll by point index.
-- @tparam Scroll self @{Scroll}
-- @tparam number index Point index
-- @tparam[opt] bool skip_cb If true, skip the point callback
-- @tparam boolean|nil skip_cb If true, skip the point callback
function Scroll.scroll_to_index(self, index, skip_cb)
if not self.points then
return
@@ -268,7 +303,7 @@ end
--- Start scroll to target scroll percent
-- @tparam Scroll self @{Scroll}
-- @tparam vector3 percent target percent
-- @tparam[opt] bool is_instant instant scroll flag
-- @tparam boolean|nil is_instant instant scroll flag
-- @usage scroll:scroll_to_percent(vmath.vector3(0.5, 0, 0))
function Scroll.scroll_to_percent(self, percent, is_instant)
local border = self.available_pos
@@ -279,6 +314,13 @@ function Scroll.scroll_to_percent(self, percent, is_instant)
0
)
if not self.drag.can_x then
pos.x = self.position.x
end
if not self.drag.can_y then
pos.y = self.position.y
end
self:scroll_to(pos, is_instant)
end
@@ -299,7 +341,7 @@ end
-- It will change content gui node size
-- @tparam Scroll self @{Scroll}
-- @tparam vector3 size The new size for content node
-- @tparam vector3 offset Offset value to set, where content is starts
-- @tparam vector3|nil offset Offset value to set, where content is starts
-- @treturn druid.scroll Current scroll instance
function Scroll.set_size(self, size, offset)
if offset then
@@ -312,11 +354,36 @@ function Scroll.set_size(self, size, offset)
end
--- Set new scroll view size in case the node size was changed.
-- @tparam Scroll self @{Scroll}
-- @tparam vector3 size The new size for view node
-- @treturn druid.scroll Current scroll instance
function Scroll.set_view_size(self, size)
gui.set_size(self.view_node, size)
self.view_size = size
self.view_border = helper.get_border(self.view_node)
self:_update_size()
return self
end
--- Refresh scroll view size
-- @tparam Scroll self @{Scroll}
function Scroll.update_view_size(self)
self.view_size = helper.get_scaled_size(self.view_node)
self.view_border = helper.get_border(self.view_node)
self:_update_size()
return self
end
--- Enable or disable scroll inert.
-- If disabled, scroll through points (if exist)
-- If no points, just simple drag without inertion
-- @tparam Scroll self @{Scroll}
-- @tparam bool state Inert scroll state
-- @tparam boolean|nil state Inert scroll state
-- @treturn druid.scroll Current scroll instance
function Scroll.set_inert(self, state)
self._is_inert = state
@@ -327,7 +394,7 @@ end
--- Return if scroll have inertion.
-- @tparam Scroll self @{Scroll}
-- @treturn bool If scroll have inertion
-- @treturn boolean @If scroll have inertion
function Scroll.is_inert(self)
return self._is_inert
end
@@ -336,7 +403,7 @@ end
--- Set extra size for scroll stretching.
-- Set 0 to disable stretching effect
-- @tparam Scroll self @{Scroll}
-- @tparam[opt=0] number stretch_size Size in pixels of additional scroll area
-- @tparam number|nil stretch_size Size in pixels of additional scroll area
-- @treturn druid.scroll Current scroll instance
function Scroll.set_extra_stretch_size(self, stretch_size)
self.style.EXTRA_STRETCH_SIZE = stretch_size or 0
@@ -374,7 +441,7 @@ end
--- Lock or unlock horizontal scroll
-- @tparam Scroll self @{Scroll}
-- @tparam bool state True, if horizontal scroll is enabled
-- @tparam boolean|nil state True, if horizontal scroll is enabled
-- @treturn druid.scroll Current scroll instance
function Scroll.set_horizontal_scroll(self, state)
self._is_horizontal_scroll = state
@@ -385,7 +452,7 @@ end
--- Lock or unlock vertical scroll
-- @tparam Scroll self @{Scroll}
-- @tparam bool state True, if vertical scroll is enabled
-- @tparam boolean|nil state True, if vertical scroll is enabled
-- @treturn druid.scroll Current scroll instance
function Scroll.set_vertical_scroll(self, state)
self._is_vertical_scroll = state
@@ -438,7 +505,7 @@ end
--- Bind the grid component (Static or Dynamic) to recalculate
-- scroll size on grid changes
-- @tparam Scroll self @{Scroll}
-- @tparam StaticGrid|DynamicGrid grid Druid grid component
-- @tparam StaticGrid grid Druid grid component
-- @treturn druid.scroll Current scroll instance
function Scroll.bind_grid(self, grid)
if self._grid_on_change then
@@ -457,7 +524,6 @@ function Scroll.bind_grid(self, grid)
local size = grid:get_size()
local offset = grid:get_offset()
self:set_size(size, offset)
self:log_message("Change size from grid", { size = size, offset = offset })
end)
self:set_size(grid:get_size(), grid:get_offset())
@@ -468,7 +534,7 @@ end
--- Strict drag scroll area. Useful for
-- restrict events outside stencil node
-- @tparam Drag self
-- @tparam node node Gui node
-- @tparam node|string node Gui node
function Scroll.set_click_zone(self, node)
self.drag:set_click_zone(node)
end
@@ -558,15 +624,15 @@ function Scroll._cancel_animate(self)
end
function Scroll._set_scroll_position(self, position)
function Scroll._set_scroll_position(self, position_x, position_y)
local available_extra = self.available_pos_extra
position.x = helper.clamp(position.x, available_extra.x, available_extra.z)
position.y = helper.clamp(position.y, available_extra.w, available_extra.y)
position_x = helper.clamp(position_x, available_extra.x, available_extra.z)
position_y = helper.clamp(position_y, available_extra.w, available_extra.y)
if self.position.x ~= position.x or self.position.y ~= position.y then
self.position.x = position.x
self.position.y = position.y
gui.set_position(self.content_node, position)
if self.position.x ~= position_x or self.position.y ~= position_y then
self.position.x = position_x
self.position.y = position_y
gui.set_position(self.content_node, self.position)
self.on_scroll:trigger(self:get_context(), self.position)
end
@@ -599,8 +665,8 @@ function Scroll._check_points(self)
local temp_dist = math.huge
local temp_dist_on_inert = math.huge
local index = false
local index_on_inert = false
local index = -1
local index_on_inert = -1
local pos = self.position
for i = 1, #self.points do
@@ -625,7 +691,11 @@ function Scroll._check_points(self)
end
end
self:scroll_to_index(index_on_inert or index)
if index_on_inert >= 0 then
self:scroll_to_index(index_on_inert)
else
self:scroll_to_index(index)
end
end
@@ -648,6 +718,10 @@ end
function Scroll._update_free_scroll(self, dt)
if self.is_animate then
return
end
local target = self.target_position
if self._is_inert and (self.inertion.x ~= 0 or self.inertion.y ~= 0) then
@@ -663,19 +737,23 @@ function Scroll._update_free_scroll(self, dt)
self:_check_soft_zone()
if self.position.x ~= target.x or self.position.y ~= target.y then
self:_set_scroll_position(target)
self:_set_scroll_position(target.x, target.y)
end
end
function Scroll._update_hand_scroll(self, dt)
if self.is_animate then
self:_cancel_animate()
end
local dx = self.target_position.x - self.position.x
local dy = self.target_position.y - self.position.y
self.inertion.x = (self.inertion.x + dx) * self.style.FRICT_HOLD
self.inertion.y = (self.inertion.y + dy) * self.style.FRICT_HOLD
self:_set_scroll_position(self.target_position)
self:_set_scroll_position(self.target_position.x, self.target_position.y)
end
@@ -694,7 +772,7 @@ end
function Scroll._update_size(self)
local content_border = helper.get_border(self.content_node)
local content_size = vmath.mul_per_elem(gui.get_size(self.content_node), gui.get_scale(self.content_node))
local content_size = helper.get_scaled_size(self.content_node)
self.available_pos = get_border_vector(self.view_border - content_border, self._offset)
self.available_size = get_size_vector(self.available_pos)
@@ -708,27 +786,23 @@ function Scroll._update_size(self)
local content_border_extra = helper.get_border(self.content_node)
local stretch_size = self.style.EXTRA_STRETCH_SIZE
if self.drag.can_x then
local sign = content_size.x > self.view_size.x and 1 or -1
content_border_extra.x = content_border_extra.x - stretch_size * sign
content_border_extra.z = content_border_extra.z + stretch_size * sign
end
local sign_x = content_size.x > self.view_size.x and 1 or -1
content_border_extra.x = content_border_extra.x - stretch_size * sign_x
content_border_extra.z = content_border_extra.z + stretch_size * sign_x
if self.drag.can_y then
local sign = content_size.y > self.view_size.y and 1 or -1
content_border_extra.y = content_border_extra.y + stretch_size * sign
content_border_extra.w = content_border_extra.w - stretch_size * sign
end
local sign_y = content_size.y > self.view_size.y and 1 or -1
content_border_extra.y = content_border_extra.y + stretch_size * sign_y
content_border_extra.w = content_border_extra.w - stretch_size * sign_y
if not self.style.SMALL_CONTENT_SCROLL then
self.drag.can_x = content_size.x > self.view_size.x
self.drag.can_y = content_size.y > self.view_size.y
self.drag.can_x = content_size.x > self.view_size.x and self._is_horizontal_scroll
self.drag.can_y = content_size.y > self.view_size.y and self._is_vertical_scroll
end
self.available_pos_extra = get_border_vector(self.view_border - content_border_extra, self._offset)
self.available_size_extra = get_size_vector(self.available_pos_extra)
self:_set_scroll_position(self.position)
self:_set_scroll_position(self.position.x, self.position.y)
self.target_position.x = self.position.x
self.target_position.y = self.position.y
end
@@ -743,7 +817,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
@@ -764,7 +837,8 @@ function Scroll._process_scroll_wheel(self, action_id, action)
self.inertion.x = 0
end
self:_set_scroll_position(self.target_position)
self:_set_scroll_position(self.target_position.x, self.target_position.y)
self:_check_points()
end
return true

View File

@@ -1,7 +1,37 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle placing components by row and columns.
-- Grid can anchor your elements, get content size and other
--- Component to handle component's position by row and columns.
-- <b># Overview #</b>
--
-- The Static Grid component allows for positioning components in rows and columns.
-- It provides a static grid layout with constant node sizes, allowing for pre-calculated
-- node positions and the option to include gaps between nodes.
--
-- <b># Notes #</b>
--
-- • In a static grid, the node size remains constant, enabling the calculation of node
-- positions before placement. If you want add gaps between nodes, increase the root prefab size,
-- including the padding and margin.
--
-- • The static grid can automatically shift elements when nodes are added or removed.
--
-- • When a node is added, the grid will set the node's parent to the specified parent_node.
--
-- • You can obtain an array of positions for each element, which can be used to set
-- points of interest in a scroll component.
--
-- • The size of all elements can be retrieved for setting up the size in a scroll component.
--
-- • The grid can be bound to a scroll component for automatic resizing of the scroll content size.
--
-- • The pivot of the parent_node affects the node placement within the grid.
--
-- • A prefab node is used to determine the node size and anchor.
--
-- • You can specify a position_function for animations using the
-- _static_grid:set_position_function(node, pos) callback. The default position function is gui.set_position().
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_grid" target="_blank"><b>Example Link</b></a>
-- @module StaticGrid
-- @within BaseComponent
-- @alias druid.static_grid
@@ -33,9 +63,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
@@ -69,8 +102,8 @@ end
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield[opt=false] bool IS_DYNAMIC_NODE_POSES If true, always center grid content as grid pivot sets
-- @tfield[opt=false] bool IS_ALIGN_LAST_ROW If true, always align last row of the grid as grid pivot sets
-- @tfield boolean|nil IS_DYNAMIC_NODE_POSES If true, always center grid content as grid pivot sets. Default: false
-- @tfield boolean|nil IS_ALIGN_LAST_ROW If true, always align last row of the grid as grid pivot sets. Default: false
function StaticGrid.on_style_change(self, style)
self.style = {}
self.style.IS_DYNAMIC_NODE_POSES = style.IS_DYNAMIC_NODE_POSES or false
@@ -78,11 +111,11 @@ function StaticGrid.on_style_change(self, style)
end
--- Component init function
--- The @{StaticGrid} constructor
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam node parent The gui node parent, where items will be placed
-- @tparam string|node parent The GUI Node container, where grid's items will be placed
-- @tparam node element Element prefab. Need to get it size
-- @tparam[opt=1] number in_row How many nodes in row can be placed
-- @tparam number|nil in_row How many nodes in row can be placed. By default 1
function StaticGrid.init(self, parent, element, in_row)
self.parent = self:get_node(parent)
self.nodes = {}
@@ -104,7 +137,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()
@@ -119,7 +151,7 @@ local _temp_pos = vmath.vector3(0)
--- Return pos for grid node index
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam number index The grid element index
-- @treturn vector3 Node position
-- @treturn vector3 @Node position
function StaticGrid.get_pos(self, index)
local row = math.ceil(index / self.in_row) - 1
local col = (index - row * self.in_row) - 1
@@ -139,8 +171,12 @@ end
-- @tparam vector3 pos The node position in the grid
-- @treturn number The node index
function StaticGrid.get_index(self, pos)
local col = pos.x / self.node_size.x + 1
local row = -pos.y / self.node_size.y
-- Offset to left-top corner from node pivot
local node_offset_x = self.node_size.x * (-0.5 + self.node_pivot.x)
local node_offset_y = self.node_size.y * (0.5 - self.node_pivot.y)
local col = (pos.x + node_offset_x) / self.node_size.x + 1
local row = -(pos.y + node_offset_y) / self.node_size.y
col = helper.round(col)
row = helper.round(row)
@@ -179,30 +215,54 @@ function StaticGrid.set_anchor(self, anchor)
end
--- Update grid content
-- @tparam StaticGrid self @{StaticGrid}
function StaticGrid.refresh(self)
self:_update(true)
end
function StaticGrid.set_pivot(self, pivot)
local prev_pivot = helper.get_pivot_offset(gui.get_pivot(self.parent))
self.pivot = helper.get_pivot_offset(pivot)
local width = gui.get(self.parent, "size.x")
local height = gui.get(self.parent, "size.y")
--local pos_offset = vmath.vector3(
-- width * (self.pivot.x - prev_pivot.x),
-- height * (self.pivot.y - prev_pivot.y),
-- 0
--)
local position = gui.get_position(self.parent)
position.x = position.x + width * (self.pivot.x - prev_pivot.x)
position.y = position.y + height * (self.pivot.y - prev_pivot.y)
gui.set_position(self.parent, position)
gui.set_pivot(self.parent, pivot)
self.anchor = vmath.vector3(0.5 + self.pivot.x, 0.5 - self.pivot.y, 0)
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)
end
--- Add new item to the grid
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam node item Gui node
-- @tparam[opt] number index The item position. By default add as last item
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
-- @tparam[opt=false] boolean is_instant If true, update node positions instantly
-- @tparam node item GUI node
-- @tparam number|nil index The item position. By default add as last item
-- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT
-- @tparam boolean|nil is_instant If true, update node positions instantly
function StaticGrid.add(self, item, index, shift_policy, is_instant)
shift_policy = shift_policy or const.SHIFT.RIGHT
index = index or ((self.last_index or 0) + 1)
if self.nodes[index] then
if shift_policy == const.SHIFT.RIGHT then
for i = self.last_index, index, -1 do
self.nodes[i + 1] = self.nodes[i]
end
end
if shift_policy == const.SHIFT.LEFT then
for i = self.first_index, index do
self.nodes[i - 1] = self.nodes[i]
end
end
end
self.nodes[index] = item
helper.insert_with_shift(self.nodes, item, index, shift_policy)
gui.set_parent(item, self.parent)
-- Add new item instantly in new pos. Break update function for correct positioning
@@ -218,29 +278,34 @@ function StaticGrid.add(self, item, index, shift_policy, is_instant)
end
--- Set new items to the grid. All previous items will be removed
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam node[] nodes The new grid nodes
-- @tparam[opt=false] boolean is_instant If true, update node positions instantly
function StaticGrid.set_items(self, nodes, is_instant)
self.nodes = nodes
for index = 1, #nodes do
local item = nodes[index]
gui.set_parent(item, self.parent)
end
self:_update(is_instant)
self.on_change_items:trigger(self:get_context())
end
--- Remove the item from the grid. Note that gui node will be not deleted
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam number index The grid node index to remove
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
-- @tparam[opt=false] boolean is_instant If true, update node positions instantly
-- @treturn Node The deleted gui node from grid
-- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT
-- @tparam boolean|nil is_instant If true, update node positions instantly
-- @treturn node The deleted gui node from grid
function StaticGrid.remove(self, index, shift_policy, is_instant)
shift_policy = shift_policy or const.SHIFT.RIGHT
assert(self.nodes[index], "No grid item at given index " .. index)
local remove_node = self.nodes[index]
self.nodes[index] = nil
if shift_policy == const.SHIFT.RIGHT then
for i = index, self.last_index do
self.nodes[i] = self.nodes[i + 1]
end
end
if shift_policy == const.SHIFT.LEFT then
for i = index, self.first_index, -1 do
self.nodes[i] = self.nodes[i - 1]
end
end
helper.remove_with_shift(self.nodes, index, shift_policy)
self:_update(is_instant)
@@ -331,6 +396,7 @@ function StaticGrid.clear(self)
self:_update()
self.on_clear:trigger(self:get_context())
self.on_change_items:trigger(self:get_context())
return self
end
@@ -359,6 +425,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())
@@ -366,9 +437,44 @@ function StaticGrid.set_in_row(self, in_row)
end
--- Set new node size for grid
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam[opt] number width The new node width
-- @tparam[opt] number height The new node height
-- @treturn druid.static_grid Current grid instance
function StaticGrid.set_item_size(self, width, height)
if width then
self.node_size.x = width
end
if height then
self.node_size.y = height
end
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()
self.on_change_items:trigger(self:get_context())
return self
end
--- Sort grid nodes by custom comparator function
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam function comparator The comparator function. (a, b) -> boolean
-- @treturn druid.static_grid Current grid instance
function StaticGrid.sort_nodes(self, comparator)
table.sort(self.nodes, comparator)
self:_update(true)
end
--- Update grid inner state
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @local
function StaticGrid._update(self, is_instant)
self:_update_indexes()
@@ -414,7 +520,7 @@ end
--- Update grid nodes position
-- @tparam StaticGrid self @{StaticGrid}
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @local
function StaticGrid._update_pos(self, is_instant)
local zero_offset = self:_get_zero_offset()

View File

@@ -1,8 +1,36 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle all GUI texts.
-- Druid text can adjust itself for text node size
-- Text will never will be outside of his text size (even multiline)
--- Component for Wrapping GUI Text Nodes: Druid Text
--
-- ## Overview ##
--
-- Druid Text is a component that provides various adjustment modes for text nodes. It allows text to be scaled down to fit within the size of the text node.
--
-- ## Notes ##
--
-- • The text pivot can be changed using the text:set_pivot method.
-- The anchoring will be inside the text node's area size.
--
-- • There are several text adjustment types available. The default is DOWNSCALE.
-- You can change the default adjustment type in the Text style. Refer to the example below to see all available adjustment types:
--
-- - const.TEXT_ADJUST.DOWNSCALE: Changes the text's scale to fit within the text node's size.
--
-- - const.TEXT_ADJUST.TRIM: Trims the text with a postfix (default: "...", can be overridden in styles)
-- to fit within the text node's size.
--
-- - const.TEXT_ADJUST.NO_ADJUST: No adjustment is applied, similar
-- to the default Defold Text Node behavior.
--
-- - const.TEXT_ADJUST.DOWNSCALE_LIMITED: Changes the text's scale
-- with a limited downscale. You can set the minimum scale using the text:set_minimal_scale() function.
--
-- - const.TEXT_ADJUST.SCROLL: Changes the text's pivot to imitate scrolling within the text box.
-- For better effect, use with a stencil node.
--
-- - const.TEXT_ADJUST.SCALE_THEN_SCROLL: Combines two modes: limited downscale first, then scroll.
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=texts_general" target="_blank"><b>Example Link</b></a>
-- @module Text
-- @within BaseComponent
-- @alias druid.text
@@ -10,7 +38,7 @@
--- On set text callback(self, text)
-- @tfield DruidEvent on_set_text @{DruidEvent}
--- On adjust text size callback(self, new_scale)
--- On adjust text size callback(self, new_scale, text_metrics)
-- @tfield DruidEvent on_update_text_scale @{DruidEvent}
--- On change pivot callback(self, pivot)
@@ -25,6 +53,9 @@
--- Current text position
-- @tfield vector3 pos
--- The last text value
-- @tfield string last_value
--- Initial text node scale
-- @tfield vector3 start_scale
@@ -47,13 +78,21 @@
local Event = require("druid.event")
local const = require("druid.const")
local utf8 = require("druid.system.utf8")
local helper = require("druid.helper")
local utf8_lua = require("druid.system.utf8")
local component = require("druid.component")
local utf8 = utf8 or utf8_lua --[[@as utf8]]
local Text = component.create("text")
local function update_text_size(self)
if self.scale.x == 0 or self.scale.y == 0 then
return
end
if self.start_scale.x == 0 or self.start_scale.y == 0 then
return
end
local size = vmath.vector3(
self.start_size.x * (self.start_scale.x / self.scale.x),
self.start_size.y * (self.start_scale.y / self.scale.y),
@@ -65,41 +104,99 @@ end
--- Reset initial scale for text
local function reset_default_scale(self)
self.scale.x = self.start_scale.x
self.scale.y = self.start_scale.y
self.scale.z = self.start_scale.z
gui.set_scale(self.node, self.start_scale)
gui.set_size(self.node, self.start_size)
end
local function is_fit_info_area(self, metrics)
return metrics.width * self.scale.x <= self.text_area.x and
metrics.height * self.scale.y <= self.text_area.y
end
--- Setup scale x, but can only be smaller, than start text scale
local function update_text_area_size(self)
reset_default_scale(self)
local max_width = self.text_area.x
local max_height = self.text_area.y
local metrics = helper.get_text_metrics_from_node(self.node)
local metrics = gui.get_text_metrics_from_node(self.node)
if metrics.width == 0 then
reset_default_scale(self)
self.on_update_text_scale:trigger(self:get_context(), self.start_scale, metrics)
return
end
local scale_modifier = max_width / metrics.width
scale_modifier = math.min(scale_modifier, self.start_scale.x)
local text_area_width = self.text_area.x
local text_area_height = self.text_area.y
-- Adjust by width
local scale_modifier = text_area_width / metrics.width
-- Adjust by height
if self:is_multiline() then
local max_text_area_square = max_width * max_height
local cur_text_area_square = metrics.height * metrics.width * self.start_scale.x
scale_modifier = self.start_scale.x * math.sqrt(max_text_area_square / cur_text_area_square)
-- Approximate scale by height to start adjust scale
scale_modifier = math.sqrt(text_area_height / metrics.height)
if metrics.width * scale_modifier > text_area_width then
scale_modifier = text_area_width / metrics.width
end
-- #RMME
if self._minimal_scale then
scale_modifier = math.max(scale_modifier, self._minimal_scale)
end
-- Limit max scale by initial scale
scale_modifier = math.min(scale_modifier, self.start_scale.x)
-- #RMME
local is_fit = is_fit_info_area(self, metrics)
local step = is_fit and self.style.ADJUST_SCALE_DELTA or -self.style.ADJUST_SCALE_DELTA
for i = 1, self.style.ADJUST_STEPS do
-- Grow down to check if we fit
if step < 0 and is_fit then
break
end
-- Grow up to check if we still fit
if step > 0 and not is_fit then
break
end
scale_modifier = scale_modifier + step
if self._minimal_scale then
scale_modifier = math.max(scale_modifier, self._minimal_scale)
end
-- Limit max scale by initial scale
scale_modifier = math.min(scale_modifier, self.start_scale.x)
self.scale.x = scale_modifier
self.scale.y = scale_modifier
self.scale.z = self.start_scale.z
gui.set_scale(self.node, self.scale)
update_text_size(self)
metrics = helper.get_text_metrics_from_node(self.node)
is_fit = is_fit_info_area(self, metrics)
end
end
if self._minimal_scale then
scale_modifier = math.max(scale_modifier, self._minimal_scale)
end
local new_scale = vmath.vector3(scale_modifier, scale_modifier, self.start_scale.z)
gui.set_scale(self.node, new_scale)
self.scale = new_scale
-- Limit max scale by initial scale
scale_modifier = math.min(scale_modifier, self.start_scale.x)
self.scale.x = scale_modifier
self.scale.y = scale_modifier
self.scale.z = self.start_scale.z
gui.set_scale(self.node, self.scale)
update_text_size(self)
self.on_update_text_scale:trigger(self:get_context(), new_scale)
self.on_update_text_scale:trigger(self:get_context(), self.scale, metrics)
end
@@ -114,9 +211,14 @@ local function update_text_with_trim(self, trim_postfix)
text_length = text_length - 1
new_text = utf8.sub(self.last_value, 1, text_length)
text_width = self:get_text_size(new_text .. trim_postfix)
if text_length == 0 then
break
end
end
gui.set_text(self.node, new_text .. trim_postfix)
else
gui.set_text(self.node, self.last_value)
end
end
@@ -130,18 +232,6 @@ local function update_text_with_anchor_shift(self)
end
-- calculate space width with font
local function get_space_width(self, font)
if not self._space_width[font] then
local no_space = gui.get_text_metrics(font, "1", 0, false, 0, 0).width
local with_space = gui.get_text_metrics(font, " 1", 0, false, 0, 0).width
self._space_width[font] = with_space - no_space
end
return self._space_width[font]
end
local function update_adjust(self)
if not self.adjust_type or self.adjust_type == const.TEXT_ADJUST.NO_ADJUST then
reset_default_scale(self)
@@ -175,20 +265,24 @@ end
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield[opt=...] string TRIM_POSTFIX The postfix for TRIM adjust type
-- @tfield[opt=DOWNSCALE] string DEFAULT_ADJUST The default adjust type for any text component
-- @tfield string|nil TRIM_POSTFIX The postfix for TRIM adjust type. Default: ...
-- @tfield string|nil DEFAULT_ADJUST The default adjust type for any text component. Default: DOWNSCALE
-- @tfield string|nil ADJUST_STEPS Amount of iterations for text adjust by height. Default: 20
-- @tfield string|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02
function Text.on_style_change(self, style)
self.style = {}
self.style.TRIM_POSTFIX = style.TRIM_POSTFIX or "..."
self.style.DEFAULT_ADJUST = style.DEFAULT_ADJUST or const.TEXT_ADJUST.DOWNSCALE
self.style.ADJUST_STEPS = style.ADJUST_STEPS or 20
self.style.ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02
end
--- Component init function
--- The @{Text} constructor
-- @tparam Text self @{Text}
-- @tparam node node Gui text node
-- @tparam[opt] string value Initial text. Default value is node text from GUI scene.
-- @tparam[opt=0] int adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference
-- @tparam string|node node Node name or GUI Text Node itself
-- @tparam string|nil value Initial text. Default value is node text from GUI scene. Default: nil
-- @tparam string|nil adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference. Default: DOWNSCALE
function Text.init(self, node, value, adjust_type)
self.node = self:get_node(node)
self.pos = gui.get_position(self.node)
@@ -210,8 +304,6 @@ function Text.init(self, node, value, adjust_type)
self.on_set_pivot = Event()
self.on_update_text_scale = Event()
self._space_width = {}
self:set_to(value or gui.get_text(self.node))
return self
end
@@ -235,26 +327,60 @@ end
--- Calculate text width with font with respect to trailing space
-- @tparam Text self @{Text}
-- @tparam[opt] string text
-- @tparam string text|nil
-- @treturn number Width
-- @treturn number Height
function Text.get_text_size(self, text)
text = text or self.last_value
local font = gui.get_font(self.node)
local scale = gui.get_scale(self.node)
local font_name = gui.get_font(self.node)
local font = gui.get_font_resource(font_name)
local scale = self.last_scale or 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 width = metrics.width
for i = #text, 1, -1 do
local c = string.sub(text, i, i)
if c ~= ' ' then
local dot_width = resource.get_text_metrics(font, ".").width
local metrics = resource.get_text_metrics(font, text .. ".", {
line_break = linebreak,
leading = 1,
tracking = 0,
width = self.start_size.x
})
local width = metrics.width - dot_width
return width * scale.x, metrics.height * scale.y
end
--- Get chars count by width
-- @tparam Text self @{Text}
-- @tparam number width
-- @treturn number Chars count
function Text.get_text_index_by_width(self, width)
local text = self.last_value
local font_name = gui.get_font(self.node)
local font = gui.get_font_resource(font_name)
local scale = self.last_scale or gui.get_scale(self.node)
local text_index = 0
local text_width = 0
local text_length = utf8.len(text)
local dot_width = resource.get_text_metrics(font, ".").width
local previous_width = 0
for i = 1, text_length do
local subtext = utf8.sub(text, 1, i) .. "."
local subtext_width = resource.get_text_metrics(font, subtext).width
subtext_width = subtext_width - dot_width
text_width = subtext_width * scale.x
local width_delta = text_width - previous_width
previous_width = text_width
if (text_width - width_delta/2) < width then
text_index = i
else
break
end
width = width + get_space_width(self, font)
end
return width * scale.x, metrics.height * scale.y
return text_index
end
@@ -276,6 +402,19 @@ function Text.set_to(self, set_to)
end
--- Set text area size
-- @tparam Text self @{Text}
-- @tparam vector3 size The new text area size
-- @treturn Text Current text instance
function Text.set_size(self, size)
self.start_size = size
self.text_area = vmath.vector3(size)
self.text_area.x = self.text_area.x * self.start_scale.x
self.text_area.y = self.text_area.y * self.start_scale.y
update_adjust(self)
end
--- Set color
-- @tparam Text self @{Text}
-- @tparam vector4 color Color for node
@@ -314,7 +453,7 @@ end
--- Set text pivot. Text will re-anchor inside text area
-- @tparam Text self @{Text}
-- @tparam gui.pivot pivot Gui pivot constant
-- @tparam number pivot The gui.PIVOT_* constant
-- @treturn Text Current text instance
function Text.set_pivot(self, pivot)
local prev_pivot = gui.get_pivot(self.node)
@@ -340,7 +479,7 @@ end
--- Return true, if text with line break
-- @tparam Text self @{Text}
-- @treturn bool Is text node with line break
-- @treturn boolean Is text node with line break
function Text.is_multiline(self)
return gui.get_line_break(self.node)
end
@@ -348,8 +487,8 @@ end
--- Set text adjust, refresh the current text visuals, if needed
-- @tparam Text self @{Text}
-- @tparam[opt] number adjust_type See const.TEXT_ADJUST. If pass nil - use current adjust type
-- @tparam[opt] number minimal_scale If pass nil - not use minimal scale
-- @tparam string|nil adjust_type See const.TEXT_ADJUST. If pass nil - use current adjust type
-- @tparam number|nil minimal_scale If pass nil - not use minimal scale
-- @treturn Text Current text instance
function Text.set_text_adjust(self, adjust_type, minimal_scale)
self.adjust_type = adjust_type

View File

@@ -1,22 +1,32 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Basic class for all Druid components.
-- To create you component, use `component.create`
-- To create you custom component, use static function `component.create`
-- @usage
-- -- Create your component:
-- local component = require("druid.component")
--
-- local AwesomeComponent = component.create("awesome_component")
--
-- function AwesomeComponent:init(template, nodes)
-- self:set_template(template)
-- self:set_nodes(nodes)
-- self.druid = self:get_druid()
-- end
--
-- return AwesomeComponent
-- @module BaseComponent
-- @alias druid.base_component
local const = require("druid.const")
local class = require("druid.system.middleclass")
local helper = require("druid.helper")
local BaseComponent = {}
local BaseComponent = class("druid.component")
local INTERESTS = {} -- Cache interests per component class in runtime
local IS_AUTO_TEMPLATE = not (sys.get_config_int("druid.no_auto_template", 0) == 1)
local INTERESTS = {} -- Cache interests by component class in runtime
local IS_AUTO_TEMPLATE = not (sys.get_config("druid.no_auto_template") == "1")
--- Component Interests
-- Component Interests
BaseComponent.ON_INPUT = const.ON_INPUT
BaseComponent.ON_UPDATE = const.ON_UPDATE
BaseComponent.ON_MESSAGE = const.ON_MESSAGE
@@ -25,9 +35,9 @@ 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
BaseComponent.ALL_INTERESTS = {
BaseComponent.ON_INPUT,
BaseComponent.ON_UPDATE,
@@ -37,49 +47,56 @@ BaseComponent.ALL_INTERESTS = {
BaseComponent.ON_FOCUS_GAINED,
BaseComponent.ON_LAYOUT_CHANGE,
BaseComponent.ON_MESSAGE_INPUT,
BaseComponent.ON_WINDOW_RESIZED,
BaseComponent.ON_LANGUAGE_CHANGE,
}
-- Mapping from on_message method to specific method name
BaseComponent.SPECIFIC_UI_MESSAGES = {
[hash("layout_changed")] = BaseComponent.ON_LAYOUT_CHANGE, -- The message_id from Defold
[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,
}
local uid = 0
function BaseComponent.static.get_uid()
function BaseComponent.create_uid()
uid = uid + 1
return uid
end
--- Set current component style table (protected).
-- Invoke `on_style_change` on component, if exist. BaseComponent should handle
--- Set current component style table.
--
-- Invoke `on_style_change` on component, if exist. Component should handle
-- their style changing and store all style params
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam table druid_style Druid style module
-- @tparam table|nil druid_style Druid style module
-- @treturn BaseComponent @{BaseComponent}
function BaseComponent.set_style(self, druid_style)
self._meta.style = druid_style or const.EMPTY_TABLE
local component_style = self._meta.style[self._component.name] or const.EMPTY_TABLE
self._meta.style = druid_style or {}
local component_style = self._meta.style[self._component.name] or {}
if self.on_style_change then
self:on_style_change(component_style)
end
return self
end
--- Set current component template name (protected)
-- It will check parent template name to build full template name
--- Set component template name.
--
-- Use on all your custom components with GUI layouts used as templates.
-- It will check parent template name to build full template name in self:get_node()
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam string template BaseComponent template name
-- @treturn BaseComponent @{BaseComponent}
function BaseComponent.set_template(self, template)
template = template or const.EMPTY_STRING
template = template or ""
local parent = self:get_parent_component()
if parent and IS_AUTO_TEMPLATE then
@@ -97,7 +114,7 @@ function BaseComponent.set_template(self, template)
end
--- Get current component template name (protected)
--- Get current component template name.
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn string Component full template name
function BaseComponent.get_template(self)
@@ -105,10 +122,15 @@ function BaseComponent.get_template(self)
end
--- Set current component nodes (protected)
--- Set current component nodes.
-- Use if your component nodes was cloned with `gui.clone_tree` and you got the node tree.
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam table nodes BaseComponent nodes table
-- @treturn BaseComponent @{BaseComponent}
-- @usage
-- local nodes = gui.clone_tree(self.prefab)
-- ... In your component:
-- self:set_nodes(nodes)
function BaseComponent.set_nodes(self, nodes)
self._meta.nodes = nodes
@@ -125,7 +147,9 @@ function BaseComponent.set_nodes(self, nodes)
end
--- Get current component context (protected)
--- Context used as first arg in all Druid events
--
-- Context is usually self of gui_script.
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn table BaseComponent context
function BaseComponent.get_context(self)
@@ -133,7 +157,7 @@ function BaseComponent.get_context(self)
end
--- Increase input priority in current input stack
--- Increase input priority in input stack
-- @tparam BaseComponent self @{BaseComponent}
-- @local
function BaseComponent.increase_input_priority(self)
@@ -141,15 +165,21 @@ function BaseComponent.increase_input_priority(self)
end
--- Get node for component by name.
--- Get component node by name.
--
-- If component has nodes, node_or_name should be string
-- It auto pick node by template name or from nodes by clone_tree
-- It autopick node by template name or from nodes by gui.clone_tree
-- if they was setup via component:set_nodes, component:set_template.
-- If node is not found, the exception will fired
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam string|node node_or_name Node name or node itself
-- @treturn node Gui node
function BaseComponent.get_node(self, node_or_name)
if type(node_or_name) ~= "string" then
-- Assume it's already node from gui.get_node
return node_or_name
end
local template_name = self:get_template()
local nodes = self:__get_nodes()
@@ -158,32 +188,38 @@ function BaseComponent.get_node(self, node_or_name)
end
local node
if type(node_or_name) == const.STRING then
if nodes then
node = nodes[template_name .. node_or_name]
else
node = gui.get_node(template_name .. node_or_name)
end
if nodes then
node = nodes[template_name .. node_or_name]
else
-- Assume it's already node from gui.get_node
node = node_or_name
node = gui.get_node(template_name .. 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
end
--- Return druid with context of calling component (protected).
-- Use it to create component inside of other components.
--- Get Druid instance for inner component creation.
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn Druid Druid instance with component context
function BaseComponent.get_druid(self)
-- @tparam string|nil template The template name
-- @tparam table|nil nodes The nodes table
-- @treturn DruidInstance Druid instance with component context
function BaseComponent.get_druid(self, template, nodes)
local context = { _context = self }
return setmetatable(context, { __index = self._meta.druid })
local druid_instance = setmetatable(context, { __index = self._meta.druid })
if template then
self:set_template(template)
end
if nodes then
self:set_nodes(nodes)
end
return druid_instance
end
@@ -191,7 +227,7 @@ end
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn string The component name
function BaseComponent.get_name(self)
return self._component.name .. self:get_uid()
return self._component.name .. BaseComponent.create_uid()
end
@@ -213,20 +249,29 @@ end
--- Set component input priority
--
-- Default value: 10
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam number value The new input priority value
-- @tparam boolean|nil 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 self._component.input_priority == value then
return self
end
local children = self:get_childrens()
for i = 1, #children do
children[i]:set_input_priority(value)
end
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, is_temporary)
end
return self
@@ -242,8 +287,9 @@ function BaseComponent.reset_input_priority(self)
end
--- Return component uid (protected).
--- UID generated in component creation order
--- Return component UID.
--
-- UID generated in component creation order.
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn number The component uid
function BaseComponent.get_uid(self)
@@ -252,9 +298,10 @@ end
--- Set component input state. By default it enabled
-- You can disable any input of component by this function
--
-- If input is disabled, the component will not receive input events
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam bool state The component input state
-- @tparam boolean|nil state The component input state
-- @treturn BaseComponent BaseComponent itself
function BaseComponent.set_input_enabled(self, state)
self._meta.input_enabled = state
@@ -267,7 +314,7 @@ function BaseComponent.set_input_enabled(self, state)
end
--- Return the parent for current component (protected)
--- Return the parent component if exist
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn BaseComponent|nil The druid component instance or nil
function BaseComponent.get_parent_component(self)
@@ -300,35 +347,18 @@ function BaseComponent.setup_component(self, druid_instance, context, style, ins
self:set_template("")
if self._meta.parent then
self._meta.parent:__add_children(self)
self._meta.parent:__add_child(self)
end
return self
end
--- Basic constructor of component. It will call automaticaly
-- by `BaseComponent.static.create`
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam string name BaseComponent name
-- @tparam[opt=DEFAULT] number input_priority The input priority. The bigger number processed first
-- @local
function BaseComponent.initialize(self, name, input_priority)
self._component = {
name = name,
input_priority = input_priority or const.PRIORITY_INPUT,
default_input_priority = input_priority or const.PRIORITY_INPUT,
is_debug = false,
_is_input_priority_changed = true, -- Default true for sort once time after GUI init
_uid = BaseComponent.get_uid()
}
end
--- Print log information if debug mode is enabled (protected)
--- Print log information if debug mode is enabled
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam string message
-- @tparam table context
-- @local
function BaseComponent.log_message(self, message, context)
if not self._component.is_debug then
return
@@ -339,7 +369,8 @@ end
--- Set debug logs for component enabled or disabled
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam bool is_debug
-- @tparam boolean|nil is_debug
-- @local
function BaseComponent.set_debug(self, is_debug)
self._component.is_debug = is_debug
end
@@ -405,27 +436,28 @@ end
--- Add child to component children list
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam component children The druid component instance
-- @tparam component child The druid component instance
-- @local
function BaseComponent.__add_children(self, children)
table.insert(self._meta.children, children)
function BaseComponent.__add_child(self, child)
table.insert(self._meta.children, child)
end
--- Remove child from component children list
-- @tparam BaseComponent self @{BaseComponent}
-- @tparam component children The druid component instance
-- @tparam component child The druid component instance
-- @local
function BaseComponent.__remove_children(self, children)
function BaseComponent.__remove_child(self, child)
for i = #self._meta.children, 1, -1 do
if self._meta.children[i] == children then
if self._meta.children[i] == child then
table.remove(self._meta.children, i)
return true
end
end
end
--- Return all children components, recursive (protected)
--- Return all children components, recursive
-- @tparam BaseComponent self @{BaseComponent}
-- @treturn table Array of childrens if the Druid component instance
function BaseComponent.get_childrens(self)
@@ -435,28 +467,37 @@ function BaseComponent.get_childrens(self)
local children = self._meta.children[i]
table.insert(childrens, children)
local recursive_childrens = children:get_childrens()
for j = 1, #recursive_childrens do
table.insert(childrens, recursive_childrens[j])
end
helper.add_array(childrens, children:get_childrens())
end
return childrens
end
--- Create new component. It will inheritance from basic
-- druid component.
--- Create new component. It will inheritance from basic Druid component.
-- @function BaseComponent.create
-- @tparam string name BaseComponent name
-- @tparam[opt=DEFAULT] number input_priority The input priority. The bigger number processed first
-- @tparam number|nil input_priority The input priority. The bigger number processed first
-- @local
function BaseComponent.static.create(name, input_priority)
-- Yea, inheritance here
local new_class = class(name, BaseComponent)
new_class.initialize = function(self)
BaseComponent.initialize(self, name, input_priority)
end
function BaseComponent.create(name, input_priority)
local new_class = setmetatable({}, {
__index = BaseComponent,
__call = function(cls, ...)
local self = setmetatable({
_component = {
name = name,
input_priority = input_priority or const.PRIORITY_INPUT,
default_input_priority = input_priority or const.PRIORITY_INPUT,
is_debug = false,
_is_input_priority_changed = true, -- Default true for sort once time after GUI init
_uid = BaseComponent.create_uid()
}
}, {
__index = cls
})
return self
end
})
return new_class
end

View File

@@ -7,31 +7,25 @@
local M = {}
M.ACTION_TEXT = hash(sys.get_config("druid.input_text", "text"))
M.ACTION_TOUCH = hash(sys.get_config("druid.input_touch", "touch"))
M.ACTION_MARKED_TEXT = hash(sys.get_config("druid.input_marked_text", "marked_text"))
M.ACTION_TEXT = hash(sys.get_config_string("druid.input_text", "text"))
M.ACTION_TOUCH = hash(sys.get_config_string("druid.input_touch", "touch"))
M.ACTION_MARKED_TEXT = hash(sys.get_config_string("druid.input_marked_text", "marked_text"))
M.ACTION_ESC = hash(sys.get_config_string("druid.input_key_esc", "key_esc"))
M.ACTION_BACK = hash(sys.get_config_string("druid.input_key_back", "key_back"))
M.ACTION_ENTER = hash(sys.get_config_string("druid.input_key_enter", "key_enter"))
M.ACTION_MULTITOUCH = hash(sys.get_config_string("druid.input_multitouch", "touch_multi"))
M.ACTION_BACKSPACE = hash(sys.get_config_string("druid.input_key_backspace", "key_backspace"))
M.ACTION_SCROLL_UP = hash(sys.get_config_string("druid.input_scroll_up", "mouse_wheel_up"))
M.ACTION_SCROLL_DOWN = hash(sys.get_config_string("druid.input_scroll_down", "mouse_wheel_down"))
M.ACTION_LEFT = hash(sys.get_config_string("druid.input_key_left", "key_left"))
M.ACTION_RIGHT = hash(sys.get_config_string("druid.input_key_right", "key_right"))
M.ACTION_LSHIFT = hash(sys.get_config_string("druid.input_key_lshift", "key_lshift"))
M.ACTION_LCTRL = hash(sys.get_config_string("druid.input_key_lctrl", "key_lctrl"))
M.ACTION_LCMD = hash(sys.get_config_string("druid.input_key_lsuper", "key_lsuper"))
M.ACTION_ESC = hash(sys.get_config("druid.input_key_esc", "key_esc"))
M.ACTION_BACK = hash(sys.get_config("druid.input_key_back", "key_back"))
M.ACTION_ENTER = hash(sys.get_config("druid.input_key_enter", "key_enter"))
M.ACTION_MULTITOUCH = hash(sys.get_config("druid.input_multitouch", "multitouch"))
M.ACTION_BACKSPACE = hash(sys.get_config("druid.input_key_backspace", "key_backspace"))
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 = not (sys.get_config_int("druid.no_stencil_check", 0) == 1)
M.IS_STENCIL_CHECK = sys.get_config("druid.stencil_check") == "1"
M.RELEASED = "released"
M.PRESSED = "pressed"
M.STRING = "string"
M.TABLE = "table"
M.ZERO = "0"
--- Component Interests
M.ON_INPUT = "on_input"
M.ON_UPDATE = "update"
M.ON_MESSAGE = "on_message"
@@ -40,24 +34,22 @@ 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"
-- Components with higher priority value processed first
M.PRIORITY_INPUT = 10
M.PRIORITY_INPUT_HIGH = 20
M.PRIORITY_INPUT_MAX = 100
M.MESSAGE_INPUT = {
BUTTON_CLICK = "button_click",
BUTTON_LONG_CLICK = "button_long_click",
BUTTON_DOUBLE_CLICK = "button_double_click",
BUTTON_REPEATED_CLICK = "button_repeated_click",
-- (value)
TEXT_SET = "text_set",
}
M.PIVOTS = {
[gui.PIVOT_CENTER] = vmath.vector3(0),
[gui.PIVOT_N] = vmath.vector3(0, 0.5, 0),
@@ -82,13 +74,19 @@ M.REVERSE_PIVOTS = {
[gui.PIVOT_NW] = gui.PIVOT_SE,
}
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()
M.CURRENT_SYSTEM_NAME = M.SYS_INFO.system_name
M.OS = {
ANDROID = "Android",
IOS = "iPhone OS",
@@ -98,14 +96,12 @@ M.OS = {
BROWSER = "HTML5",
}
M.SHIFT = {
NO_SHIFT = 0,
LEFT = -1,
RIGHT = 1,
}
M.TEXT_ADJUST = {
DOWNSCALE = "downscale",
TRIM = "trim",
@@ -115,13 +111,11 @@ M.TEXT_ADJUST = {
SCALE_THEN_SCROLL = "scale_then_scroll",
}
M.SIDE = {
X = "x",
Y = "y"
}
M.SWIPE = {
UP = "up",
DOWN = "down",
@@ -129,16 +123,10 @@ M.SWIPE = {
RIGHT = "right",
}
M.ERRORS = {
GRID_DYNAMIC_ANCHOR = "The pivot of dynamic grid node should be West, East, South or North"
}
M.EMPTY_FUNCTION = function() end
M.EMPTY_STRING = ""
M.SPACE_STRING = " "
M.EMPTY_TABLE = {}
return M

View File

@@ -1,123 +0,0 @@
-- Copyright (c) 2022 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid pin knob custom component.
-- It's simple rotating input element
-- @module PinKnob
-- @within BaseComponent
-- @alias druid.pin_knob
--- The component druid instance
-- @tfield DruidInstance druid @{DruidInstance}
--- Is currently under user control
-- @tfield bool is_drag
--- The pin node
-- @tfield node node
---
local const = require("druid.const")
local component = require("druid.component")
local PinKnob = component.create("druid.pin_knob", { const.ON_INPUT })
local SCHEME = {
ROOT = "root",
PIN = "pin",
}
local function update_visual(self)
local rotation = vmath.vector3(0, 0, self.angle)
gui.set_rotation(self.node, rotation)
end
local function set_angle(self, value)
local prev_value = self.angle
self.angle = value
self.angle = math.min(self.angle, self.angle_max)
self.angle = math.max(self.angle, self.angle_min)
update_visual(self)
if prev_value ~= self.angle and self.callback then
local output_value = self.angle
if output_value ~= 0 then
output_value = -output_value
end
self.callback(self:get_context(), output_value)
end
end
--- Component init function
-- @tparam PinKnob self @{PinKnob}
-- @tparam function callback Callback(self, value) on value changed
-- @tparam string template The template string name
-- @tparam table nodes Nodes table from gui.clone_tree
function PinKnob.init(self, callback, template, nodes)
self:set_template(template)
self:set_nodes(nodes)
self.druid = self:get_druid()
self.node = self:get_node(SCHEME.PIN)
self.is_drag = false
self.callback = callback
self:set_angle(0, -100, 100)
self._friction = 0.75
end
--- Set current and min/max angles for component
-- @tparam PinKnob self @{PinKnob}
-- @tparam number cur_value The new value for pin knob
-- @tparam number min The minimum value for pin knob
-- @tparam number max The maximum value for pin knob
-- @treturn PinKnob @{PinKnob}
function PinKnob.set_angle(self, cur_value, min, max)
self.angle_min = min or self.angle_min
self.angle_max = max or self.angle_max
set_angle(self, cur_value)
return self
end
--- Set current and min/max angles for component
-- @tparam PinKnob self @{PinKnob}
-- @tparam[opt=1] number value The spin speed multiplier
-- @treturn PinKnob @{PinKnob}
function PinKnob.set_friction(self, value)
self._friction = value or 1
return self
end
function PinKnob.on_input(self, action_id, action)
if action_id ~= const.ACTION_TOUCH then
return false
end
if gui.pick_node(self.node, action.x, action.y) then
if action.pressed then
self.pos = gui.get_position(self.node)
self.is_drag = true
end
end
if self.is_drag and not action.pressed then
set_angle(self, self.angle - action.dx * self._friction - action.dy * self._friction)
end
if action.released then
self.is_drag = false
end
return self.is_drag
end
return PinKnob

View File

@@ -3,25 +3,47 @@
--- Druid Rich Input custom component.
-- It's wrapper on Input component with cursor and placeholder text
-- @module RichInput
-- @within Input
-- @alias druid.rich_input
--- The component druid instance
-- @tfield DruidInstance druid @{DruidInstance}
--- Root node
-- @tfield node root
--- On input field text change callback(self, input_text)
-- @tfield Input input @{Input}
--- On input field text change to empty string callback(self, input_text)
-- @tfield node cursor
--- On input field text change to max length string callback(self, input_text)
-- @tfield druid.text placeholder @{Text}
--- On input field text change to empty string callback(self, input_text)
-- @tfield node cursor_text
--- On input field text change to empty string callback(self, input_text)
-- @tfield vector3 cursor_position
--- On input field text change to empty string callback(self, input_text)
-- @tfield druid.text input_text
--- On input field text change to empty string callback(self, input_text)
-- @tfield druid.drag drag
--- On input field text change to empty string callback(self, input_text)
-- @tfield druid.text placeholder
--- On input field text change to empty string callback(self, input_text)
-- @tfield vector3 text_position
---
local component = require("druid.component")
local helper = require("druid.helper")
local const = require("druid.const")
local utf8_lua = require("druid.system.utf8")
local utf8 = utf8 or utf8_lua
local input = require("druid.extended.input")
local RichInput = component.create("druid.rich_input")
local SCHEME = {
@@ -30,56 +52,208 @@ local SCHEME = {
PLACEHOLDER = "placeholder_text",
INPUT = "input_text",
CURSOR = "cursor_node",
CURSOR_TEXT = "cursor_text",
}
local DOUBLE_CLICK_TIME = 0.35
local function animate_cursor(self)
gui.cancel_animation(self.cursor, gui.PROP_COLOR)
gui.set_color(self.cursor, vmath.vector4(1))
gui.animate(self.cursor, gui.PROP_COLOR, vmath.vector4(1,1,1,0), gui.EASING_INSINE, 0.8, 0, nil, gui.PLAYBACK_LOOP_PINGPONG)
gui.cancel_animation(self.cursor_text, "color.w")
gui.set_alpha(self.cursor_text, 1)
gui.animate(self.cursor_text, "color.w", 0, gui.EASING_INSINE, 0.8, 0, nil, gui.PLAYBACK_LOOP_PINGPONG)
end
local function update_text(self, text)
local text_width = self.input.total_width
animate_cursor(self)
gui.set_position(self.cursor, vmath.vector3(text_width/2, 0, 0))
local function set_selection_width(self, selection_width)
gui.set_visible(self.cursor, selection_width > 0)
local width = selection_width / self.input.text.scale.x
local height = gui.get_size(self.cursor).y
gui.set_size(self.cursor, vmath.vector3(width, height, 0))
local is_selection_to_right = self.input.cursor_index == self.input.end_index
gui.set_pivot(self.cursor, is_selection_to_right and gui.PIVOT_E or gui.PIVOT_W)
end
local function update_text(self)
local left_text_part = utf8.sub(self.input:get_text(), 0, self.input.cursor_index)
local selected_text_part = utf8.sub(self.input:get_text(), self.input.start_index + 1, self.input.end_index)
local left_part_width = self.input.text:get_text_size(left_text_part)
local selected_part_width = self.input.text:get_text_size(selected_text_part)
local pivot_text = gui.get_pivot(self.input.text.node)
local pivot_offset = helper.get_pivot_offset(pivot_text)
self.cursor_position.x = self.text_position.x - self.input.total_width * (0.5 + pivot_offset.x) + left_part_width
gui.set_position(self.cursor, self.cursor_position)
gui.set_scale(self.cursor, self.input.text.scale)
set_selection_width(self, selected_part_width)
end
local function on_select(self)
gui.set_enabled(self.cursor, true)
gui.set_enabled(self.placeholder.node, false)
gui.set_enabled(self.input.button.node, true)
animate_cursor(self)
self.drag:set_enabled(true)
end
local function on_unselect(self)
gui.cancel_animation(self.cursor, gui.PROP_COLOR)
gui.set_enabled(self.cursor, false)
gui.set_enabled(self.input.button.node, self.is_button_input_enabled)
gui.set_enabled(self.placeholder.node, true and #self.input:get_text() == 0)
self.drag:set_enabled(false)
end
--- Component init function
--- Update selection
local function update_selection(self)
update_text(self)
end
local TEMP_VECTOR = vmath.vector3(0)
local function get_index_by_touch(self, touch)
local text_node = self.input.text.node
TEMP_VECTOR.x = touch.screen_x
TEMP_VECTOR.y = touch.screen_y
-- Distance to the text node position
local scene_scale = helper.get_scene_scale(text_node)
local local_pos = gui.screen_to_local(text_node, TEMP_VECTOR)
local_pos.x = local_pos.x / scene_scale.x
-- Offset to the left side of the text node
local pivot_offset = helper.get_pivot_offset(gui.get_pivot(text_node))
local_pos.x = local_pos.x + self.input.total_width * (0.5 + pivot_offset.x)
local_pos.x = local_pos.x - self.text_position.x
local cursor_index = self.input.text:get_text_index_by_width(local_pos.x)
return cursor_index
end
local function on_touch_start_callback(self, touch)
local cursor_index = get_index_by_touch(self, touch)
if self._last_touch_info.cursor_index == cursor_index then
local time = socket.gettime()
if time - self._last_touch_info.time < DOUBLE_CLICK_TIME then
local len = utf8.len(self.input:get_text())
self.input:select_cursor(len, 0, len)
self._last_touch_info.cursor_index = nil
return
end
end
self._last_touch_info.cursor_index = cursor_index
self._last_touch_info.time = socket.gettime()
if self.input.is_lshift then
local start_index = self.input.start_index
local end_index = self.input.end_index
if cursor_index < start_index then
self.input:select_cursor(cursor_index, cursor_index, end_index)
elseif cursor_index > end_index then
self.input:select_cursor(cursor_index, start_index, cursor_index)
end
else
self.input:select_cursor(cursor_index)
end
end
local function on_drag_callback(self, dx, dy, x, y, touch)
if not self._last_touch_info.cursor_index then
return
end
local index = get_index_by_touch(self, touch)
if self._last_touch_info.cursor_index <= index then
self.input:select_cursor(index, self._last_touch_info.cursor_index, index)
else
self.input:select_cursor(index, index, self._last_touch_info.cursor_index)
end
end
--- The @{RichInput} constructor
-- @tparam RichInput self @{RichInput}
-- @tparam string template The template string name
-- @tparam table nodes Nodes table from gui.clone_tree
function RichInput.init(self, template, nodes)
self:set_template(template)
self:set_nodes(nodes)
self.druid = self:get_druid()
self.input = self.druid:new_input(self:get_node(SCHEME.BUTTON), self:get_node(SCHEME.INPUT))
self.druid = self:get_druid(template, nodes)
self.root = self:get_node(SCHEME.ROOT)
self._last_touch_info = {
cursor_index = nil,
time = 0,
}
self.is_lshift = false
self.is_lctrl = false
self.input = self.druid:new(input, self:get_node(SCHEME.BUTTON), self:get_node(SCHEME.INPUT))
self.is_button_input_enabled = gui.is_enabled(self.input.button.node)
self.cursor = self:get_node(SCHEME.CURSOR)
self.cursor_position = gui.get_position(self.cursor)
self.cursor_text = self:get_node(SCHEME.CURSOR_TEXT)
self.drag = self.druid:new_drag(self:get_node(SCHEME.BUTTON), on_drag_callback)
self.drag.on_touch_start:subscribe(on_touch_start_callback)
self.drag:set_input_priority(const.PRIORITY_INPUT_MAX + 1)
self.drag:set_enabled(false)
self.input:set_text("")
self.placeholder = self.druid:new_text(self:get_node(SCHEME.PLACEHOLDER))
self.text_position = gui.get_position(self.input.text.node)
self.input.on_input_text:subscribe(update_text)
self.input.on_input_select:subscribe(on_select)
self.input.on_input_unselect:subscribe(on_unselect)
self.input.on_select_cursor_change:subscribe(update_selection)
on_unselect(self)
update_text(self, "")
update_text(self)
end
function RichInput.on_input(self, action_id, action)
if action_id == const.ACTION_LSHIFT then
if action.pressed then
self.is_lshift = true
elseif action.released then
self.is_lshift = false
end
end
if action_id == const.ACTION_LCTRL or action_id == const.ACTION_LCMD then
if action.pressed then
self.is_lctrl = true
elseif action.released then
self.is_lctrl = false
end
end
if action_id == const.ACTION_LEFT and (action.pressed or action.repeated) then
self.input:move_selection(-1, self.is_lshift, self.is_lctrl)
end
if action_id == const.ACTION_RIGHT and (action.pressed or action.repeated) then
self.input:move_selection(1, self.is_lshift, self.is_lctrl)
end
end
@@ -92,4 +266,55 @@ function RichInput.set_placeholder(self, placeholder_text)
end
--- Select input field
-- @tparam RichInput self @{RichInput}
function RichInput.select(self)
self.input:select()
end
--- Set input field text
-- @tparam RichInput self @{RichInput}
-- @treturn druid.input Current input instance
-- @tparam string text The input text
function RichInput.set_text(self, text)
self.input:set_text(text)
gui.set_enabled(self.placeholder.node, true and #self.input:get_text() == 0)
return self
end
--- Set input field font
-- @tparam RichInput self @{RichInput}
-- @tparam hash font The font hash
-- @treturn druid.input Current input instance
function RichInput.set_font(self, font)
gui.set_font(self.input.text.node, font)
gui.set_font(self.placeholder.node, font)
return self
end
--- Set input field text
-- @tparam RichInput self @{RichInput}
function RichInput.get_text(self)
return self.input:get_text()
end
--- Set allowed charaters for input field.
-- See: https://defold.com/ref/stable/string/
-- ex: [%a%d] for alpha and numeric
-- @tparam RichInput self @{RichInput}
-- @tparam string characters Regulax exp. for validate user input
-- @treturn RichInput Current instance
function RichInput.set_allowed_characters(self, characters)
self.input:set_allowed_characters(characters)
return self
end
return RichInput

View File

@@ -0,0 +1,557 @@
-- Source: https://github.com/britzl/defold-richtext version 5.19.0
-- Author: Britzl
-- Modified by: Insality
--- RT
-- @module rich_text.rt
-- @local
local helper = require("druid.helper")
local parser = require("druid.custom.rich_text.module.rt_parse")
local utf8_lua = require("druid.system.utf8")
local utf8 = utf8 or utf8_lua
local VECTOR_ZERO = vmath.vector3(0)
local COLOR_WHITE = vmath.vector4(1)
local M = {}
-- Trim spaces on string start
local function ltrim(text)
return text:match('^%s*(.*)')
end
-- compare two words and check that they have the same size, color, font and tags
local function compare_words(one, two)
if one == nil
or two == nil
or one.size ~= two.size
or one.color ~= two.color
or one.shadow ~= two.shadow
or one.outline ~= two.outline
or one.font ~= two.font then
return false
end
local one_tags, two_tags = one.tags, two.tags
if one_tags == two_tags then
return true
end
if one_tags == nil or two_tags == nil then
return false
end
for k, v in pairs(one_tags) do
if two_tags[k] ~= v then
return false
end
end
for k, v in pairs(two_tags) do
if one_tags[k] ~= v then
return false
end
end
return true
end
--- Get the length of a text ignoring any tags except image tags
-- which are treated as having a length of 1
-- @param text String with text or a list of words (from richtext.create)
-- @return Length of text
function M.length(text)
assert(text)
if type(text) == "string" then
return parser.length(text)
else
local count = 0
for i = 1, #text do
local word = text[i]
local is_text_node = not word.image
count = count + (is_text_node and utf8.len(word.text) or 1)
end
return count
end
end
---@param word druid.rich_text.word
---@param previous_word druid.rich_text.word|nil
---@param settings druid.rich_text.settings
---@return druid.rich_text.metrics
local function get_text_metrics(word, previous_word, settings)
local text = word.text
local font_resource = gui.get_font_resource(word.font)
---@type druid.rich_text.metrics
local metrics
local word_scale_x = word.relative_scale * settings.scale.x * settings.adjust_scale
local word_scale_y = word.relative_scale * settings.scale.y * settings.adjust_scale
if utf8.len(text) == 0 then
metrics = resource.get_text_metrics(font_resource, "|")
metrics.width = 0
metrics.height = metrics.height * word_scale_y
else
metrics = resource.get_text_metrics(font_resource, text)
metrics.width = metrics.width * word_scale_x
metrics.height = metrics.height * word_scale_y
if previous_word and not previous_word.image then
local previous_word_metrics = resource.get_text_metrics(font_resource, previous_word.text)
local union_metrics = resource.get_text_metrics(font_resource, previous_word.text .. text)
local without_previous_width = metrics.width
metrics.width = (union_metrics.width - previous_word_metrics.width) * word_scale_x
-- Since the several characters can be ajusted to fit the space between the previous word and this word
-- For example: chars: [.,?!]
metrics.offset_x = metrics.width - without_previous_width
end
end
metrics.offset_x = metrics.offset_x or 0
metrics.offset_y = metrics.offset_y or 0
return metrics
end
---@param word druid.rich_text.word
---@param settings druid.rich_text.settings
---@return druid.rich_text.metrics
local function get_image_metrics(word, settings)
local node = word.node
gui.set_texture(node, word.image.texture)
gui.play_flipbook(node, word.image.anim)
local node_size = gui.get_size(node)
local aspect = node_size.x / node_size.y
node_size.x = word.image.width or node_size.x
node_size.y = word.image.height or (node_size.x / aspect)
return {
width = node_size.x * word.relative_scale * settings.scale.x * settings.adjust_scale,
height = node_size.y * word.relative_scale * settings.scale.y * settings.adjust_scale,
node_size = node_size,
}
end
---@param word druid.rich_text.word
---@param settings druid.rich_text.settings
---@param previous_word druid.rich_text.word|nil
---@return druid.rich_text.metrics
local function measure_node(word, settings, previous_word)
do -- Clone node if required
local node
if word.image then
node = word.node or gui.new_box_node(vmath.vector3(0), vmath.vector3(word.image.width, word.image.height, 0))
else
node = word.node or gui.clone(settings.text_prefab)
end
word.node = node
end
local metrics = word.image and get_image_metrics(word, settings) or get_text_metrics(word, previous_word, settings)
return metrics
end
-- Create rich text gui nodes from text
--- @param text string The text to create rich text nodes from
--- @param settings table Optional settings table (refer to documentation for details)
--- @param style druid.rich_text.style
--- @return druid.rich_text.word[]
--- @return druid.rich_text.settings
--- @return druid.rich_text.lines_metrics
function M.create(text, settings, style)
assert(text, "You must provide a text")
-- default settings for a word
-- will be assigned to each word unless tags override the values
local word_params = {
node = nil, -- Autofill on node creation
relative_scale = 1,
color = nil,
position = nil, -- Autofill later
scale = nil, -- Autofill later
size = nil, -- Autofill later
pivot = nil, -- Autofill later
offset = nil, -- Autofill later
metrics = {},
-- text params
source_text = nil,
text = nil, -- Autofill later in parse.lua
text_color = gui.get_color(settings.text_prefab),
shadow = settings.shadow,
outline = settings.outline,
font = gui.get_font(settings.text_prefab),
-- Image params
---@type druid.rich_text.image
image = nil,
-- Tags
br = nil,
nobr = nil,
}
local parsed_words = parser.parse(text, word_params, style)
local lines = M._split_on_lines(parsed_words, settings)
local lines_metrics = M._position_lines(lines, settings)
M._update_nodes(lines, settings)
local words = {}
for index = 1, #lines do
helper.add_array(words, lines[index])
end
return words, settings, lines_metrics
end
---@param word druid.rich_text.word
---@param metrics druid.rich_text.metrics
---@param settings druid.rich_text.settings
function M._fill_properties(word, metrics, settings)
word.metrics = metrics
word.position = vmath.vector3(0)
if word.image then
-- Image properties
word.scale = vmath.vector3(word.relative_scale * settings.adjust_scale)
word.pivot = gui.PIVOT_CENTER
word.size = metrics.node_size
word.offset = vmath.vector3(0, 0, 0)
if word.image.width then
word.size.y = word.image.height or (word.size.y * word.image.width / word.size.x)
word.size.x = word.image.width
end
else
-- Text properties
word.scale = settings.scale * word.relative_scale * settings.adjust_scale
word.pivot = gui.PIVOT_SW -- With this pivot adjustments works more correctly than with other pivots
word.size = vmath.vector3(metrics.width, metrics.height, 0)
word.offset = vmath.vector3(metrics.offset_x, metrics.offset_y, 0)
end
end
---@param words druid.rich_text.word[]
---@param settings druid.rich_text.settings
---@return druid.rich_text.word[][]
function M._split_on_lines(words, settings)
local i = 1
local lines = {}
local current_line = {}
local word_count = #words
local current_line_width = 0
local current_line_height = 0
repeat
local word = words[i]
if word == nil then
break
end
-- Reset texts to start measure again
word.text = word.source_text
-- get the previous word, so we can combine
local previous_word = current_line[#current_line]
if settings.combine_words then
if not compare_words(previous_word, word) then
previous_word = nil
end
end
local word_metrics = measure_node(word, settings)
local next_words_width = word_metrics.width
-- Collect width of nobr words from current to next words with nobr
if word.nobr then
for index = i + 1, word_count do
if words[index].nobr then
local next_word_measure = measure_node(words[index], settings, words[index-1])
next_words_width = next_words_width + next_word_measure.width
else
break
end
end
end
local overflow = (current_line_width + next_words_width) > settings.width
local is_new_line = (overflow or word.br) and settings.is_multiline and not word.nobr
-- We recalculate metrics with previous_word if it follow for word on current line
if not is_new_line and previous_word then
word_metrics = measure_node(word, settings, previous_word)
end
-- Trim first word of the line
if is_new_line or not previous_word then
word.text = ltrim(word.text)
word_metrics = measure_node(word, settings, nil)
end
M._fill_properties(word, word_metrics, settings)
-- check if the line overflows due to this word
if not is_new_line then
-- the word fits on the line, add it and update text metrics
current_line_width = current_line_width + word.metrics.width
current_line_height = math.max(current_line_height, word.metrics.height)
current_line[#current_line + 1] = word
else
-- overflow, position the words that fit on the line
lines[#lines + 1] = current_line
word.text = ltrim(word.text)
current_line = { word }
current_line_height = word.metrics.height
current_line_width = word.metrics.width
end
i = i + 1
until i > word_count
if #current_line > 0 then
lines[#lines + 1] = current_line
end
return lines
end
---@param lines druid.rich_text.word[][]
---@param settings druid.rich_text.settings
---@return druid.rich_text.lines_metrics
function M._position_lines(lines, settings)
local lines_metrics = M._get_lines_metrics(lines, settings)
-- current x-y is left top point of text spawn
local parent_size = gui.get_size(settings.parent)
local pivot = helper.get_pivot_offset(gui.get_pivot(settings.parent))
local offset_y = (parent_size.y - lines_metrics.text_height) * (pivot.y - 0.5) - (parent_size.y * (pivot.y - 0.5))
local current_y = offset_y
for line_index = 1, #lines do
local line = lines[line_index]
local line_metrics = lines_metrics.lines[line_index]
local current_x = (parent_size.x - line_metrics.width) * (pivot.x + 0.5) - (parent_size.x * (pivot.x + 0.5))
local max_height = 0
for word_index = 1, #line do
local word = line[word_index]
local pivot_offset = helper.get_pivot_offset(word.pivot)
local word_width = word.metrics.width
word.position.x = current_x + word_width * (pivot_offset.x + 0.5) + word.offset.x
word.position.y = current_y + word.metrics.height * (pivot_offset.y - 0.5) + word.offset.y
-- Align item on text line depends on anchor
word.position.y = word.position.y - (word.metrics.height - line_metrics.height) * (pivot_offset.y - 0.5)
current_x = current_x + word_width
-- TODO: check if we need to calculate images
if not word.image then
max_height = math.max(max_height, word.metrics.height)
end
if settings.image_pixel_grid_snap and word.image then
word.position.x = helper.round(word.position.x)
word.position.y = helper.round(word.position.y)
end
end
current_y = current_y - line_metrics.height
end
return lines_metrics
end
---@param lines druid.rich_text.word[][]
---@param settings druid.rich_text.settings
---@return druid.rich_text.lines_metrics
function M._get_lines_metrics(lines, settings)
local metrics = {}
local text_width = 0
local text_height = 0
for line_index = 1, #lines do
local line = lines[line_index]
local width = 0
local height = 0
for word_index = 1, #line do
local word = line[word_index]
local word_width = word.metrics.width
width = width + word_width
-- TODO: Here too
if not word.image then
height = math.max(height, word.metrics.height)
end
end
if line_index > 1 then
height = height * settings.text_leading
end
text_width = math.max(text_width, width)
text_height = text_height + height
metrics[#metrics + 1] = {
width = width,
height = height,
}
end
---@type druid.rich_text.lines_metrics
local lines_metrics = {
text_width = text_width,
text_height = text_height,
lines = metrics,
}
return lines_metrics
end
---@param lines druid.rich_text.word[][]
---@param settings druid.rich_text.settings
function M._update_nodes(lines, settings)
for line_index = 1, #lines do
local line = lines[line_index]
for word_index = 1, #line do
local word = line[word_index]
local node
if word.image then
node = word.node or gui.new_box_node(VECTOR_ZERO, word.size)
gui.set_size_mode(node, gui.SIZE_MODE_MANUAL)
gui.set_texture(node, word.image.texture)
gui.play_flipbook(node, hash(word.image.anim))
gui.set_color(node, word.color or COLOR_WHITE)
else
node = word.node or gui.clone(settings.text_prefab)
gui.set_outline(node, word.outline)
gui.set_shadow(node, word.shadow)
gui.set_text(node, word.text)
gui.set_color(node, word.color or word.text_color)
gui.set_font(node, word.font or settings.font)
end
word.node = node
gui.set_enabled(node, true)
gui.set_parent(node, settings.parent)
gui.set_pivot(node, word.pivot)
gui.set_size(node, word.size)
gui.set_scale(node, word.scale)
gui.set_position(node, word.position)
end
end
end
---@param words druid.rich_text.word[]
---@param settings druid.rich_text.settings
---@param scale number
---@return druid.rich_text.lines_metrics
function M.set_text_scale(words, settings, scale)
settings.adjust_scale = scale
local lines = M._split_on_lines(words, settings)
local line_metrics = M._position_lines(lines, settings)
M._update_nodes(lines, settings)
return line_metrics
end
---@param words druid.rich_text.word[]
---@param settings druid.rich_text.settings
---@param lines_metrics druid.rich_text.lines_metrics
---@param style druid.rich_text.style
function M.adjust_to_area(words, settings, lines_metrics, style)
local last_line_metrics = lines_metrics
if not settings.is_multiline then
if lines_metrics.text_width > settings.width then
last_line_metrics = M.set_text_scale(words, settings, settings.width / lines_metrics.text_width)
end
else
-- Multiline adjusting is very tricky stuff...
-- It's doing a lot of calculations, beware!
if lines_metrics.text_width > settings.width or lines_metrics.text_height > settings.height then
local scale_koef = math.sqrt(settings.height / lines_metrics.text_height)
if lines_metrics.text_width * scale_koef > settings.width then
scale_koef = math.sqrt(settings.width / lines_metrics.text_width)
end
local adjust_scale = math.min(scale_koef, settings.scale.x)
local lines = M.apply_scale_without_update(words, settings, adjust_scale)
local is_fit = M.is_fit_info_area(lines, settings)
local step = is_fit and style.ADJUST_SCALE_DELTA or -style.ADJUST_SCALE_DELTA
for i = 1, style.ADJUST_STEPS do
-- Grow down to check if we fit
if step < 0 and is_fit then
last_line_metrics = M.set_text_scale(words, settings, adjust_scale)
break
end
-- Grow up to check if we still fit
if step > 0 and not is_fit then
last_line_metrics = M.set_text_scale(words, settings, adjust_scale - step)
break
end
adjust_scale = adjust_scale + step
lines = M.apply_scale_without_update(words, settings, adjust_scale)
is_fit = M.is_fit_info_area(lines, settings)
if i == style.ADJUST_STEPS then
last_line_metrics = M.set_text_scale(words, settings, adjust_scale)
end
end
end
end
return last_line_metrics
end
---@return druid.rich_text.word[][] lines
function M.apply_scale_without_update(words, settings, scale)
settings.adjust_scale = scale
return M._split_on_lines(words, settings)
end
---@param lines druid.rich_text.word[][]
---@param settings druid.rich_text.settings
function M.is_fit_info_area(lines, settings)
local lines_metrics = M._get_lines_metrics(lines, settings)
local area_size = gui.get_size(settings.parent)
return lines_metrics.text_width <= area_size.x and lines_metrics.text_height <= area_size.y
end
--- Get all words with a specific tag
-- @param words The words to search (as received from richtext.create)
-- @param tag The tag to search for. Nil to search for words without a tag
-- @return Words matching the tag
function M.tagged(words, tag)
local tagged = {}
for i = 1, #words do
local word = words[i]
if not tag and not word.tags then
tagged[#tagged + 1] = word
elseif word.tags and word.tags[tag] then
tagged[#tagged + 1] = word
end
end
return tagged
end
---Removes the gui nodes created by rich text
function M.remove(words)
assert(words)
for i = 1, #words do
gui.delete_node(words[i].node)
end
end
return M

View File

@@ -0,0 +1,50 @@
-- Source: https://github.com/britzl/defold-richtext version 5.19.0
-- Author: Britzl
-- Modified by: Insality
local M = {}
local cache = {}
function M.parse_hex(hex)
if cache[hex] then
return cache[hex]
end
local r,g,b,a = hex:match("#?(%x%x)(%x%x)(%x%x)(%x?%x?)")
if a == "" then a = "ff" end
if r and g and b and a then
local color = vmath.vector4(
tonumber(r, 16) / 255,
tonumber(g, 16) / 255,
tonumber(b, 16) / 255,
tonumber(a, 16) / 255
)
cache[hex] = color
return color
end
return nil
end
function M.parse_decimal(dec)
if cache[dec] then
return cache[dec]
end
local r,g,b,a = dec:match("(%d*%.?%d*),(%d*%.?%d*),(%d*%.?%d*),(%d*%.?%d*)")
if r and g and b and a then
local color = vmath.vector4(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
cache[dec] = color
return color
end
return nil
end
function M.parse(c)
return M.parse_hex(c) or M.parse_decimal(c)
end
return M

View File

@@ -0,0 +1,193 @@
-- Source: https://github.com/britzl/defold-richtext version 5.19.0
-- Author: Britzl
-- Modified by: Insality
local tags = require("druid.custom.rich_text.module.rt_tags")
local utf8_lua = require("druid.system.utf8")
local utf8 = utf8 or utf8_lua
local M = {}
local function parse_tag(tag, params, style)
local settings = { tags = { [tag] = params }, tag = tag }
if not tags.apply(tag, params, settings, style) then
settings[tag] = params
end
return settings
end
-- add a single word to the list of words
local function add_word(text, settings, words)
-- handle HTML entities
text = text:gsub("&lt;", "<"):gsub("&gt;", ">"):gsub("&nbsp;", " ")
local data = { text = text, source_text = text }
for k,v in pairs(settings) do
data[k] = v
end
words[#words + 1] = data
end
-- split a line into words
local function split_line(line, settings, words)
assert(line)
assert(settings)
assert(words)
local ws_start, trimmed_text, ws_end = line:match("^(%s*)(.-)(%s*)$")
if trimmed_text == "" then
add_word(ws_start .. ws_end, settings, words)
else
local wi = #words
for word in trimmed_text:gmatch("%S+") do
add_word(word .. " ", settings, words)
end
local first = words[wi + 1]
first.text = ws_start .. first.text
first.source_text = first.text
local last = words[#words]
last.text = utf8.sub(last.text, 1, utf8.len(last.text) - 1) .. ws_end
last.source_text = last.text
end
end
-- split text
-- split by lines first
local function split_text(text, settings, words)
assert(text)
assert(settings)
assert(words)
-- special treatment of empty text with a linebreak <br/>
if text == "" and settings.linebreak then
add_word(text, settings, words)
return
end
-- we don't want to deal with \r\n, remove all \r
text = text:gsub("\r", "")
-- the Lua pattern expects the text to have a linebreak at the end
local added_linebreak = false
if text:sub(-1)~="\n" then
added_linebreak = true
text = text .. "\n"
end
-- split into lines
for line in text:gmatch("(.-)\n") do
split_line(line, settings, words)
-- flag last word of a line as having a linebreak
local last = words[#words]
last.linebreak = true
end
-- remove the last linebreak if we manually added it above
if added_linebreak then
local last = words[#words]
last.linebreak = false
end
end
-- Merge one tag into another
local function merge_tags(dst, src)
for k, v in pairs(src) do
if k ~= "tags" then
dst[k] = v
end
end
for tag, params in pairs(src.tags or {}) do
dst.tags[tag] = (params == "") and true or params
end
end
--- Parse the text into individual words
-- @param text The text to parse
-- @param default_settings Default settings for each word
-- @param color_aliases Color aliases table
-- @return List of all words
function M.parse(text, default_settings, style)
assert(text)
assert(default_settings)
text = text:gsub("&zwsp;", "<zwsp>\226\128\139</zwsp>")
-- Replace all \n with <br/> to make it easier to split the text
text = text:gsub("\n", "<br/>")
local all_words = {}
local open_tags = {}
while true do
-- merge list of word settings from defaults and all open tags
local word_settings = { tags = {} }
merge_tags(word_settings, default_settings)
for _, open_tag in ipairs(open_tags) do
merge_tags(word_settings, open_tag)
end
-- find next tag, with the text before and after the tag
local before_tag, tag, after_tag = text:match("(.-)(</?%S->)(.*)")
-- no more tags, split and add rest of the text
if not before_tag or not tag or not after_tag then
if text ~= "" then
split_text(text, word_settings, all_words)
end
break
end
-- split and add text before the encountered tag
if before_tag ~= "" then
split_text(before_tag, word_settings, all_words)
end
-- parse the tag, split into name and optional parameters
local endtag, name, params, empty = tag:match("<(/?)([%a_]+)=?(%S-)(/?)>")
local is_endtag = endtag == "/"
local is_empty = empty == "/"
if is_empty then
-- empty tag, ie tag without content
-- example <br/> and <img=texture:image/>
local empty_tag_settings = parse_tag(name, params, style)
merge_tags(empty_tag_settings, word_settings)
add_word("", empty_tag_settings, all_words)
elseif not is_endtag then
-- open tag - parse and add it
local tag_settings = parse_tag(name, params, style)
open_tags[#open_tags + 1] = tag_settings
else
-- end tag - remove it from the list of open tags
local found = false
for i=#open_tags,1,-1 do
if open_tags[i].tag == name then
table.remove(open_tags, i)
found = true
break
end
end
if not found then print(("Found end tag '%s' without matching start tag"):format(name)) end
end
-- parse text after the tag on the next iteration
text = after_tag
end
return all_words
end
--- Get the length of a text, excluding any tags (except image and spine tags)
function M.length(text)
return utf8.len(text:gsub("<img.-/>", " "):gsub("<.->", ""))
end
return M

View File

@@ -0,0 +1,108 @@
-- Source: https://github.com/britzl/defold-richtext version 5.19.0
-- Author: Britzl
-- Modified by: Insality
local color = require("druid.custom.rich_text.module.rt_color")
local M = {}
local tags = {}
function M.apply(tag, params, settings, style)
local fn = tags[tag]
if not fn then
return false
end
fn(params, settings, style)
return true
end
function M.register(tag, fn)
assert(tag, "You must provide a tag")
assert(fn, "You must provide a tag function")
tags[tag] = fn
end
-- Split string at first occurrence of token
-- If the token doesn't exist the whole string is returned
-- @param s The string to split
-- @param token The token to split string on
-- @return before The string before the token or the whole string if token doesn't exist
-- @return after The string after the token or nul
local function split(s, token)
if not s then return nil, nil end
local before, after = s:match("(.-)" .. token .. "(.*)")
before = before or s
return before, after
end
-- Format: <color=[#]{HEX_VALUE}>{Text}</color>
-- Format: <color={COLOR_NAME}>{Text}</color>
-- Example: <color=FF0000>Rich Text</color>
M.register("color", function(params, settings, style)
params = style.COLORS[params] or params
settings.color = color.parse(params)
end)
M.register("shadow", function(params, settings, style)
params = style.COLORS[params] or params
settings.shadow = color.parse(params)
end)
M.register("outline", function(params, settings, style)
params = style.COLORS[params] or params
settings.outline = color.parse(params)
end)
M.register("font", function(params, settings)
settings.font = params
end)
M.register("size", function(params, settings)
settings.relative_scale = tonumber(params)
end)
-- Example: </br>
M.register("br", function(params, settings)
settings.br = true
end)
-- Example: <nobr></nobr>
M.register("nobr", function(params, settings)
settings.nobr = true
end)
-- Format: <img={animation_id},[width],[height]/>
-- Example: <img=logo/>
-- Example: <img=logo,48/>
-- Example: <img=logo,48,48/>
M.register("img", function(params, settings)
local texture_and_anim, params = split(params, ",")
local width, height
width, params = split(params, ",")
height = split(params, ",")
local texture, anim = split(texture_and_anim, ":")
width = width and tonumber(width)
height = height and tonumber(height)
settings.image = {
texture = texture,
anim = anim,
width = width,
height = height or width,
}
end)
return M

View File

@@ -0,0 +1,283 @@
-- Copyright (c) 2022 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid Rich Text Custom Component.
-- <b># Overview #</b>
--
-- This custom component is inspired by <a href="https://github.com/britzl/defold-richtext" target="_blank">defold-richtext</a> by britzl.
-- It uses a similar syntax for tags but currently supports fewer tags.
--
-- Create Rich Text on your GUI Text Node. All properties of the text node will be used as default for the text.
--
-- <b># Notes #</b>
--
-- • Nested tags are supported
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=custom_rich_text" target="_blank"><b>Example Link</b></a>
-- @usage
-- local RichText = require("druid.custom.rich_text.rich_text")
-- ...
-- self.rich_text = self.druid:new(RichText, "rich_text")
-- self.rich_text:set_text("Hello, Druid Rich Text!")
-- @usage
-- type druid.rich_text.word = {
-- node: Node,
-- relative_scale: number,
-- color: vector4,
-- position: vector3,
-- offset: vector3,
-- scale: vector3,
-- size: vector3,
-- metrics: druid.rich_text.metrics,
-- pivot: Pivot,
-- text: string,
-- shadow: vector4,
-- outline: vector4,
-- font: string,
-- image: druid.rich_text.image,
-- br: boolean,
-- nobr: boolean,
-- }
--
-- type druid.rich_text.word.image = {
-- texture: string,
-- anim: string,
-- width: number,
-- height: number,
-- }
--
-- type druid.rich_text.lines_metrics = {
-- text_width: number,
-- text_height: number,
-- lines: table<number, druid.rich_text.metrics>,
-- }
--
-- type druid.rich_text.metrics = {
-- width: number,
-- height: number,
-- offset_x: number|nil,
-- offset_y: number|nil,
-- node_size: vector3|nil @For images only,
-- }
-- @module RichText
-- @within BaseComponent
-- @alias druid.rich_text
--- The component druid instance
-- @tfield DruidInstance druid @{DruidInstance}
--- The root node of the Rich Text
-- @tfield node root
--- The text prefab node
-- @tfield node text_prefab
--
local component = require("druid.component")
local rich_text = require("druid.custom.rich_text.module.rt")
local RichText = component.create("rich_text")
--- The @{RichText} constructor
-- @tparam RichText self @{RichText}
-- @tparam node|string text_node The text node to make Rich Text
-- @tparam string|nil value The initial text value. Default will be gui.get_text(text_node)
function RichText.init(self, text_node, value)
self.root = self:get_node(text_node)
self.text_prefab = self.root
self._last_value = value or gui.get_text(self.text_prefab)
self._settings = self:_create_settings()
gui.set_text(self.root, "")
if value then
self:set_text(value)
end
end
function RichText.on_layout_change(self)
if self._last_value then
self:set_text(self._last_value)
end
end
--- Component style params.
-- You can override this component styles params in Druid styles table
-- or create your own style
-- @table style
-- @tfield table|nil COLORS Rich Text color aliases. Default: {}
-- @tfield number|nil ADJUST_STEPS Amount steps of attemps text adjust by height. Default: 20
-- @tfield number|nil ADJUST_SCALE_DELTA Scale step on each height adjust step. Default: 0.02
function RichText.on_style_change(self, style)
self.style = {}
self.style.COLORS = style.COLORS or {}
self.style.ADJUST_STEPS = style.ADJUST_STEPS or 20
self.style.ADJUST_SCALE_DELTA = style.ADJUST_SCALE_DELTA or 0.02
end
--- Set text for Rich Text
-- @tparam RichText self @{RichText}
-- @tparam string|nil text The text to set
-- @treturn druid.rich_text.word[] words
-- @treturn druid.rich_text.lines_metrics line_metrics
-- @usage
-- • color: Change text color
--
-- <color=red>Foobar</color>
-- <color=1.0,0,0,1.0>Foobar</color>
-- <color=#ff0000>Foobar</color>
-- <color=#ff0000ff>Foobar</color>
--
-- • shadow: Change text shadow
--
-- <shadow=red>Foobar</shadow>
-- <shadow=1.0,0,0,1.0>Foobar</shadow>
-- <shadow=#ff0000>Foobar</shadow>
-- <shadow=#ff0000ff>Foobar</shadow>
--
-- • outline: Change text shadow
--
-- <outline=red>Foobar</outline>
-- <outline=1.0,0,0,1.0>Foobar</outline>
-- <outline=#ff0000>Foobar</outline>
-- <outline=#ff0000ff>Foobar</outline>
--
-- • font: Change font
--
-- <font=MyCoolFont>Foobar</font>
--
-- • size: Change text size, relative to default size
--
-- <size=2>Twice as large</size>
--
-- • br: Insert a line break
--
-- <br/>
--
-- • nobr: Prevent the text from breaking
--
-- Words <nobr>inside tag</nobr> won't break
--
-- • img: Display image
--
-- <img=texture:image/>
-- <img=texture:image,size/>
-- <img=texture:image,width,height/>
function RichText.set_text(self, text)
text = text or ""
self:clear()
self._last_value = text
local words, settings, line_metrics = rich_text.create(text, self._settings, self.style)
line_metrics = rich_text.adjust_to_area(words, settings, line_metrics, self.style)
self._words = words
self._line_metrics = line_metrics
return words, line_metrics
end
--- Get current text
-- @tparam RichText self @{RichText}
-- @treturn string text
function RichText.get_text(self)
return self._last_value
end
function RichText:on_remove()
gui.set_scale(self.root, self._default_scale)
gui.set_size(self.root, self._default_size)
self:clear()
end
--- Clear all created words.
function RichText:clear()
if self._words then
rich_text.remove(self._words)
self._words = nil
end
self._last_value = nil
end
--- Get all words, which has a passed tag.
-- @tparam RichText self @{RichText}
-- @tparam string tag
-- @treturn druid.rich_text.word[] words
function RichText.tagged(self, tag)
if not self._words then
return
end
return rich_text.tagged(self._words, tag)
end
---Split a word into it's characters
-- @tparam RichText self @{RichText}
-- @tparam druid.rich_text.word word
-- @treturn druid.rich_text.word[] characters
function RichText.characters(self, word)
return rich_text.characters(word)
end
--- Get all current words.
-- @treturn table druid.rich_text.word[]
function RichText:get_words()
return self._words
end
--- Get current line metrics
--- @treturn druid.rich_text.lines_metrics
function RichText:get_line_metric()
return self._line_metrics
end
function RichText:_create_settings()
local root_size = gui.get_size(self.root)
local scale = gui.get_scale(self.root)
self._default_size = root_size
self._default_scale = scale
root_size.x = root_size.x * scale.x
root_size.y = root_size.y * scale.y
gui.set_size(self.root, root_size)
gui.set_scale(self.root, vmath.vector3(1))
return {
-- General settings
-- Adjust scale using to fit the text to the root node area
adjust_scale = 1,
parent = self.root,
scale = scale,
width = root_size.x,
height = root_size.y,
combine_words = false, -- disabled now
text_prefab = self.text_prefab,
pivot = gui.get_pivot(self.root),
-- Text Settings
shadow = gui.get_shadow(self.root),
outline = gui.get_outline(self.root),
text_leading = gui.get_leading(self.root),
is_multiline = gui.get_line_break(self.root),
-- Image settings
image_pixel_grid_snap = false, -- disabled now
}
end
return RichText

22
druid/druid.atlas Normal file
View File

@@ -0,0 +1,22 @@
images {
image: "/druid/images/empty.png"
}
images {
image: "/druid/images/panels/rect_round2_width1.png"
}
images {
image: "/druid/images/panels/ui_circle_8.png"
}
images {
image: "/druid/images/panels/ui_circle_16.png"
}
images {
image: "/druid/images/panels/ui_circle_32.png"
}
images {
image: "/druid/images/panels/ui_circle_64.png"
}
images {
image: "/druid/images/pixel.png"
}
extrude_borders: 2

View File

@@ -1,20 +1,49 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid UI Library.
-- Powerful Defold component based UI library. Use standart
-- components or make your own game-specific components to
-- make amazing GUI in your games.
--- Druid UI Component Framework.
-- <b># Overview #</b>
--
-- Contains the several basic components and examples
-- to how to do your custom complex components to
-- separate UI game logic to small files
-- Druid - powerful Defold component UI library. Use basic and extended
-- Druid components or make your own game-specific components to make
-- amazing GUI in your games.
--
-- require("druid.druid")
-- function init(self)
-- self.druid = druid.new(self)
-- end
-- To start using Druid, please refer to the Usage section below.
--
-- @module druid
-- <b># Notes #</b>
--
-- • Each Druid instance maintains the self context from the constructor and passes it to each Druid callback.
--
-- See next: @{DruidInstance}
--
-- @usage
-- local druid = require("druid.druid")
--
-- local function on_play(self)
-- print("Gonna play!")
-- end
--
-- function init(self)
-- self.druid = druid.new(self)
-- self.druid:new_button("button_play", on_play)
-- end
--
-- function final(self)
-- self.druid:final()
-- end
--
-- function update(self, dt)
-- self.druid:update(dt)
-- end
--
-- function on_message(self, message_id, message, sender)
-- self.druid:on_message(message_id, message, sender)
-- end
--
-- function on_input(self, action_id, action)
-- return self.druid:on_input(action_id, action)
-- end
--
-- @module Druid
local const = require("druid.const")
local base_component = require("druid.component")
@@ -27,82 +56,126 @@ local M = {}
local _instances = {}
local function get_druid_instances()
local function clean_deleted_druid_instances()
for i = #_instances, 1, -1 do
if _instances[i]._deleted then
table.remove(_instances, i)
end
end
end
local function get_druid_instances()
clean_deleted_druid_instances()
return _instances
end
--- Register external druid component.
-- After register you can create the component with
-- druid_instance:new_{name}. For example `druid:new_button(...)`
-- @function druid:register
--- Register a new external Druid component.
--
-- You can register your own components to make new alias: the druid:new_{name} function.
-- For example, if you want to register a component called "my_component", you can create it using druid:new_my_component(...).
-- This can be useful if you have your own "basic" components that you don't want to re-create each time.
-- @function druid.register
-- @tparam string name module name
-- @tparam table module lua table with component
-- @usage
-- local my_component = require("path.to.my.component")
-- druid.register("my_component", my_component)
-- ...
-- local druid = druid.new(self)
-- local component_instance = self.druid:new_my_component(...)
function M.register(name, module)
-- TODO: Find better solution to creating elements?
-- Current way is very implicit
druid_instance["new_" .. name] = function(self, ...)
return druid_instance.new(self, module, ...)
end
return druid_instance["new_" .. name]
end
--- Create Druid instance.
--- Create a new Druid instance for creating GUI components.
--
-- @function druid.new
-- @tparam table context Druid context. Usually it is self of script
-- @tparam[opt] table style Druid style module
-- @treturn druid_instance Druid instance
-- @tparam table context The Druid context. Usually, this is the self of the gui_script. It is passed into all Druid callbacks.
-- @tparam table|nil style The Druid style table to override style parameters for this Druid instance.
-- @treturn druid_instance The Druid instance @{DruidInstance}.
-- @usage
-- local druid = require("druid.druid")
--
-- function init(self)
-- self.druid = druid.new(self)
-- end
function M.new(context, style)
clean_deleted_druid_instances()
if settings.default_style == nil then
M.set_default_style(default_style)
end
local new_instance = druid_instance(context, style)
local new_instance = setmetatable({}, { __index = druid_instance })
new_instance:initialize(context, style)
table.insert(_instances, new_instance)
return new_instance
end
--- Set new default style.
--- Set your own default style for all Druid instances.
--
-- To create your own style file, copy the default style file and make changes to it.
-- Register the new style before creating your Druid instances.
-- @function druid.set_default_style
-- @tparam table style Druid style module
-- @usage
-- local my_style = require("path.to.my.style")
-- druid.set_default_style(my_style)
function M.set_default_style(style)
settings.default_style = style or {}
end
--- Set text function
-- Druid locale component will call this function
-- to get translated text. After set_text_funtion
-- all existing locale component will be updated
--- Set the text function for the LangText component.
--
-- The Druid locale component will call this function to get translated text.
-- After setting the text function, all existing locale components will be updated.
-- @function druid.set_text_function
-- @tparam function callback Get localized text function
-- @usage
-- druid.set_text_function(function(text_id)
-- return lang_data[text_id] -- Replace with your real function
-- end)
function M.set_text_function(callback)
settings.get_text = callback or const.EMPTY_FUNCTION
M.on_language_change()
end
--- Set sound function.
-- Component will call this function to
-- play sound by sound_id
--- Set the Druid sound function to play UI sounds if used.
--
-- Set a function to play a sound given a sound_id. This function is used for button clicks to play the "click" sound.
-- It can also be used to play sounds in your custom components (see the default Druid style file for an example).
-- @function druid.set_sound_function
-- @tparam function callback Sound play callback
-- @usage
-- druid.set_sound_function(function(sound_id)
-- sound.play(sound_id) -- Replace with your real function
-- end)
function M.set_sound_function(callback)
settings.play_sound = callback or const.EMPTY_FUNCTION
end
--- Callback on global window event.
-- Used to trigger on_focus_lost and on_focus_gain
--- Set the window callback to enable on_focus_gain and on_focus_lost functions.
--
-- This is used to trigger the on_focus_lost and on_focus_gain functions in Druid components.
-- @function druid.on_window_callback
-- @tparam string event Event param from window listener
-- @usage
-- window.set_listener(function(_, event)
-- druid.on_window_callback(event)
-- end)
function M.on_window_callback(event)
local instances = get_druid_instances()
@@ -110,19 +183,24 @@ function M.on_window_callback(event)
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_FOCUS_LOST)
end
end
if event == window.WINDOW_EVENT_FOCUS_GAINED then
elseif event == window.WINDOW_EVENT_FOCUS_GAINED then
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_FOCUS_GAINED)
end
elseif event == window.WINDOW_EVENT_RESIZED then
for i = 1, #instances do
msg.post(instances[i].url, base_component.ON_WINDOW_RESIZED)
end
end
end
--- Callback on global language change event.
-- Use to update all lang texts
--- Call this function when the game language changes.
--
-- This function will translate all current LangText components.
-- @function druid.on_language_change
-- @usage
-- druid.on_language_change()
function M.on_language_change()
local instances = get_druid_instances()

View File

@@ -1,32 +1,22 @@
--- For component interest functions
--- see https://github.com/Insality/druid/blob/develop/docs_md/02-creating_custom_components.md
--- see https://github.com/Insality/druid/blob/master/docs_md/02-creating_custom_components.md
--- Require this component in you gui file:
--- local {COMPONENT_NAME} = require("{COMPONENT_PATH}")
--- $ local {COMPONENT_NAME} = require("{COMPONENT_PATH}")
--- And create this component via:
--- self.{COMPONENT_TYPE} = self.druid:new({COMPONENT_NAME}, template, nodes)
--- $ self.{COMPONENT_TYPE} = self.druid:new({COMPONENT_NAME}, template, nodes)
local component = require("druid.component")
---@class {COMPONENT_TYPE}: druid.base_component{COMPONENT_ANNOTATIONS}
---@field druid druid_instance
local {COMPONENT_NAME} = component.create("{COMPONENT_TYPE}")
local SCHEME = {
{SCHEME_LIST}
}
---@class {COMPONENT_TYPE}: druid.component
---@field druid druid_instance{COMPONENT_ANNOTATIONS}
local M = component.create("{COMPONENT_TYPE}")
---@param template string
---@param nodes table<hash, node>
function {COMPONENT_NAME}:init(template, nodes)
self:set_template(template)
self:set_nodes(nodes)
self.druid = self:get_druid(){COMPONENT_DEFINE}
end
function {COMPONENT_NAME}:on_remove()
function M:init(template, nodes)
self.druid = self:get_druid(template, nodes){COMPONENT_DEFINE}
end
{COMPONENT_FUNCTIONS}
return {COMPONENT_NAME}
return M

View File

@@ -28,54 +28,54 @@ def process_component(node_name, component_name):
if node_name == "root":
component_annotations += "\n---@field root node"
component_define += "\n\tself.root = self:get_node(SCHEME.ROOT)"
component_define += "\n\tself.root = self:get_node(\"root\")"
if node_name.startswith("button"):
component_annotations += "\n---@field {0} druid.button".format(node_name)
component_functions += "\nfunction {1}:_on_{0}()\n\tprint(\"Click on {0}\")\nend\n\n".format(node_name, component_name)
component_define += "\n\tself.{0} = self.druid:new_button(SCHEME.{1}, self._on_{0})".format(node_name, get_id(node_name))
component_functions += "\nfunction M:_on_{0}()\n\tprint(\"Click on {0}\")\nend\n\n".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_button(\"{1}\", self._on_{0})".format(node_name, node_name)
if node_name.startswith("text"):
component_annotations += "\n---@field {0} druid.text".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_text(SCHEME.{1})".format(node_name, get_id(node_name))
component_define += "\n\tself.{0} = self.druid:new_text(\"{1}\")".format(node_name, node_name)
if node_name.startswith("lang_text"):
component_annotations += "\n---@field {0} druid.text".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_lang_text(SCHEME.{1}, \"lang_id\")".format(node_name, get_id(node_name))
component_define += "\n\tself.{0} = self.druid:new_lang_text(\"{1}\", \"lang_id\")".format(node_name, node_name)
if node_name.startswith("grid") or node_name.startswith("static_grid"):
component_annotations += "\n---@field {0} druid.static_grid".format(node_name)
component_define += "\n--TODO: Replace prefab_name with grid element prefab"
component_define += "\n\tself.{0} = self.druid:new_static_grid(SCHEME.{1}, \"prefab_name\", 1)".format(node_name, get_id(node_name))
component_define += "\n\tself.{0} = self.druid:new_static_grid(\"{1}\", \"prefab_name\", 1)".format(node_name, node_name)
if node_name.startswith("dynamic_grid"):
component_annotations += "\n---@field {0} druid.dynamic_grid".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_dynamic_grid(SCHEME.{1})".format(node_name, get_id(node_name))
component_define += "\n\tself.{0} = self.druid:new_dynamic_grid(\"{1}\")".format(node_name, node_name)
if node_name.startswith("scroll_view"):
field_name = node_name.replace("_view", "")
content_name = node_name.replace("_view", "_content")
component_annotations += "\n---@field {0} druid.scroll".format(field_name)
component_define += "\n\tself.{0} = self.druid:new_scroll(SCHEME.{1}, SCHEME.{2})".format(field_name, get_id(node_name), get_id(content_name))
component_define += "\n\tself.{0} = self.druid:new_scroll(\"{1}\", \"{2}\")".format(field_name, node_name, content_name)
if node_name.startswith("blocker"):
component_annotations += "\n---@field {0} druid.blocker".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_blocker(SCHEME.{1})".format(node_name, get_id(node_name))
component_define += "\n\tself.{0} = self.druid:new_blocker(\"{1}\")".format(node_name, node_name)
if node_name.startswith("slider"):
component_annotations += "\n---@field {0} druid.slider".format(node_name)
component_define += "\n--TODO: Replace slider end position. It should be only vertical or horizontal"
component_define += "\n\tself.{0} = self.druid:new_slider(SCHEME.{1}, vmath.vector3(100, 0, 0), self._on_{0}_change)".format(node_name, get_id(node_name))
component_functions += "\nfunction {1}:_on_{0}_change(value)\n\tprint(\"Slider change:\", value)\nend\n\n".format(node_name, component_name)
component_define += "\n\tself.{0} = self.druid:new_slider(\"{1}\", vmath.vector3(100, 0, 0), self._on_{0}_change)".format(node_name, node_name)
component_functions += "\nfunction M:_on_{0}_change(value)\n\tprint(\"Slider change:\", value)\nend\n\n".format(node_name)
if node_name.startswith("progress"):
component_annotations += "\n---@field {0} druid.progress".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_progress(SCHEME.{1}, \"x\")".format(node_name, get_id(node_name))
component_define += "\n\tself.{0} = self.druid:new_progress(\"{1}\", \"x\")".format(node_name, get_id(node_name))
if node_name.startswith("timer"):
component_annotations += "\n---@field {0} druid.timer".format(node_name)
component_define += "\n\tself.{0} = self.druid:new_timer(SCHEME.{1}, 59, 0, self._on_{0}_end)".format(node_name, get_id(node_name))
component_functions += "\nfunction {1}:_on_{0}_end()\n\tprint(\"Timer {0} trigger\")\nend\n\n".format(node_name, component_name)
component_define += "\n\tself.{0} = self.druid:new_timer(\"{1}\", 59, 0, self._on_{0}_end)".format(node_name, get_id(node_name))
component_functions += "\nfunction M:_on_{0}_end()\n\tprint(\"Timer {0} trigger\")\nend\n\n".format(node_name)
def main():
@@ -126,7 +126,7 @@ def main():
filedata = filedata.replace("{COMPONENT_DEFINE}", component_define)
filedata = filedata.replace("{COMPONENT_FUNCTIONS}", component_functions)
filedata = filedata.replace("{COMPONENT_ANNOTATIONS}", component_annotations)
filedata = filedata.replace("{SCHEME_LIST}", ",\n".join(scheme_list))
#filedata = filedata.replace("{SCHEME_LIST}", ",\n".join(scheme_list))
output_file = open(output_full_path, "w")
output_file.write(filedata)

View File

@@ -26,36 +26,7 @@ end
function M.get_commands()
return {
{
label = "Print gui scheme",
locations = { "Outline" },
query = {
selection = {type = "outline", cardinality = "many"}
},
active = function(opts)
return true
end,
run = function(opts)
print("local SCHEME = {")
for i = 1, #opts.selection do
local file = opts.selection[i]
if editor.can_get(file, "id") then
local id = editor.get(file, "id")
print("\t" .. string.upper(id) .. " = \"" .. id .. "\",")
end
end
print("}")
print("")
end
},
{
label = "Assign layers",
label = "Assign Layers",
locations = {"Edit"},

View File

@@ -5,11 +5,20 @@
echo "Run bash for $1"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
is_defree_installed=$(pip3 list --disable-pip-version-check | grep -E "deftree")
# Check if pip3 is installed
if command -v pip3 &> /dev/null; then
PIP_CMD="pip3"
PYTHON_CMD="python3"
else
PIP_CMD="pip"
PYTHON_CMD="python"
fi
is_defree_installed=$($PIP_CMD list --disable-pip-version-check | grep -E "deftree")
if [ -z "$is_defree_installed" ]; then
echo "The python deftree is not installed. Please install it via"
echo "pip3 install deftree"
echo "$ $PIP_CMD install deftree"
exit 0
fi
python3 $1 $2
$PYTHON_CMD $1 $2

View File

@@ -1,96 +1,205 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid lua event library
--- Druid Event Module
--
-- The Event module provides a simple class for handling callbacks. It is used in many Druid components.
--
-- You can subscribe to an event using the `:subscribe` method and unsubscribe using the `:unsubscribe` method.
-- @module DruidEvent
-- @alias druid.event
local class = require("druid.system.middleclass")
local M = {}
M.COUNTER = 0
local DruidEvent = class("druid.event")
-- Forward declaration
local EVENT_METATABLE
-- Local versions
local pcall = pcall
local tinsert = table.insert
local tremove = table.remove
--- Event constructur
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function initial_callback Subscribe the callback on new event, if callback exist
function DruidEvent.initialize(self, initial_callback)
self._callbacks = nil -- initialize later
--- DruidEvent constructor
-- @tparam function|nil callback Subscribe the callback on new event, if callback exist
-- @tparam any|nil callback_context Additional context as first param to callback call
-- @usage
-- local Event = require("druid.event")
-- ...
-- local event = Event(callback)
function M.create(callback, callback_context)
local instance = setmetatable({}, EVENT_METATABLE)
if initial_callback then
self:subscribe(initial_callback)
if callback then
instance:subscribe(callback, callback_context)
end
M.COUNTER = M.COUNTER + 1
return instance
end
--- Check is event subscribed.
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself
-- @tparam any|nil callback_context Additional context as first param to callback call
-- @treturn boolean, number|nil @Is event subscribed, return index of callback in event as second param
function M.is_subscribed(self, callback, callback_context)
if #self == 0 then
return false, nil
end
for index = 1, #self do
local cb = self[index]
if cb[1] == callback and cb[2] == callback_context then
return true, index
end
end
return false, nil
end
--- Subscribe callback on event
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself
-- @tparam table context Additional context as first param to callback call
function DruidEvent.subscribe(self, callback, context)
-- @tparam any|nil callback_context Additional context as first param to callback call, usually it's self
-- @treturn boolean True if callback was subscribed
-- @usage
-- local function on_long_callback(self)
-- print("Long click!")
-- end
-- ...
-- local button = self.druid:new_button("button", callback)
-- button.on_long_click:subscribe(on_long_callback, self)
function M.subscribe(self, callback, callback_context)
assert(type(self) == "table", "You should subscribe to event with : syntax")
assert(type(callback) == "function", "Callback should be function")
assert(callback, "A function must be passed to subscribe to an event")
self._callbacks = self._callbacks or {}
table.insert(self._callbacks, {
callback = callback,
context = context
})
if self:is_subscribed(callback, callback_context) then
return false
end
return callback
tinsert(self, { callback, callback_context })
return true
end
--- Unsubscribe callback on event
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam function callback Callback itself
-- @tparam table context Additional context as first param to callback call
function DruidEvent.unsubscribe(self, callback, context)
if not self._callbacks then
return
-- @tparam any|nil callback_context Additional context as first param to callback call
-- @usage
-- local function on_long_callback(self)
-- print("Long click!")
-- end
-- ...
-- button.on_long_click:unsubscribe(on_long_callback, self)
function M.unsubscribe(self, callback, callback_context)
assert(callback, "A function must be passed to subscribe to an event")
local _, event_index = self:is_subscribed(callback, callback_context)
if not event_index then
return false
end
for index, callback_info in ipairs(self._callbacks) do
if callback_info.callback == callback and callback_info.context == context then
table.remove(self._callbacks, index)
return
end
end
tremove(self, event_index)
return true
end
--- Return true, if event have at lease one handler
-- @tparam DruidEvent self @{DruidEvent}
-- @treturn bool True if event have handlers
function DruidEvent.is_exist(self)
if not self._callbacks then
return false
end
return #self._callbacks > 0
-- @treturn boolean True if event have handlers
-- @usage
-- local is_long_click_handler_exists = button.on_long_click:is_exist()
function M.is_exist(self)
return #self > 0
end
--- Return true, if event not have handler
--- @tparam DruidEvent self @{DruidEvent}
--- @treturn boolean True if event not have handlers
--- @usage
--- local is_long_click_handler_not_exists = button.on_long_click:is_empty()
function M:is_empty()
return #self == 0
end
--- Clear the all event handlers
-- @tparam DruidEvent self @{DruidEvent}
function DruidEvent.clear(self)
self._callbacks = nil
-- @usage
-- button.on_long_click:clear()
function M.clear(self)
for index = #self, 1, -1 do
self[index] = nil
end
end
--- Trigger the event and call all subscribed callbacks
-- @tparam DruidEvent self @{DruidEvent}
-- @tparam any ... All event params
function DruidEvent.trigger(self, ...)
if not self._callbacks then
return false
-- @usage
-- local Event = require("druid.event")
-- ...
-- local event = Event()
-- event:trigger("Param1", "Param2")
function M.trigger(self, ...)
if #self == 0 then
return
end
for index, callback_info in ipairs(self._callbacks) do
if callback_info.context then
callback_info.callback(callback_info.context, ...)
else
callback_info.callback(...)
end
local result = nil
local call_callback = self.call_callback
for index = 1, #self do
result = call_callback(self, self[index], ...)
end
return result
end
return DruidEvent
-- @tparam table callback Callback data {function, context}
-- @tparam any ... All event params
-- @treturn any Result of the callback
-- @local
function M:call_callback(callback, ...)
local event_callback = callback[1]
local event_callback_context = callback[2]
-- Call callback
local ok, result_or_error
if event_callback_context then
ok, result_or_error = pcall(event_callback, event_callback_context, ...)
else
ok, result_or_error = pcall(event_callback, ...)
end
-- Handle errors
if not ok then
local caller_info = debug.getinfo(2)
pprint("An error occurred during event processing", {
trigger = caller_info.short_src .. ":" .. caller_info.currentline,
error = result_or_error,
})
pprint("Traceback", debug.traceback())
return nil
end
return result_or_error
end
-- Construct event metatable
EVENT_METATABLE = {
__index = M,
__call = M.trigger,
}
return setmetatable(M, {
__call = function(_, callback)
return M.create(callback)
end,
})

View File

@@ -1,95 +0,0 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid checkbox component
-- @module Checkbox
-- @within BaseComponent
-- @alias druid.checkbox
--- 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 Event = require("druid.event")
local component = require("druid.component")
local Checkbox = component.create("checkbox")
local function on_click(self)
self:set_state(not self.state)
end
--- Component style params.
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield function on_change_state (self, node, state)
function Checkbox.on_style_change(self, style)
self.style = {}
self.style.on_change_state = style.on_change_state or function(_, node, state)
gui.set_enabled(node, state)
end
end
--- Component init function
-- @tparam Checkbox self @{Checkbox}
-- @tparam node node Gui node
-- @tparam function callback Checkbox callback
-- @tparam[opt=node] node click_node Trigger node, by default equals to node
-- @tparam[opt=false] boolean initial_state The initial state of checkbox, default - false
function Checkbox.init(self, node, callback, click_node, initial_state)
self.druid = self:get_druid()
self.node = self:get_node(node)
self.click_node = self:get_node(click_node or node)
self.button = self.druid:new_button(self.click_node or self.node, on_click)
self:set_state(initial_state, true, true)
self.on_change_state = Event(callback)
end
function Checkbox.on_layout_change(self)
self:set_state(self.state, true)
end
--- Set checkbox state
-- @tparam Checkbox self @{Checkbox}
-- @tparam bool state Checkbox state
-- @tparam bool is_silent Don't trigger on_change_state if true
-- @tparam bool is_instant If instant checkbox change
function Checkbox.set_state(self, state, is_silent, is_instant)
self.state = state
self.style.on_change_state(self, self.node, state, is_instant)
if not is_silent then
self.on_change_state:trigger(self:get_context(), state)
end
return self
end
--- Return checkbox state
-- @tparam Checkbox self @{Checkbox}
-- @treturn bool Checkbox state
function Checkbox.get_state(self)
return self.state
end
return Checkbox

View File

@@ -1,71 +0,0 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Checkbox group module
-- @module CheckboxGroup
-- @within BaseComponent
-- @alias druid.checkbox_group
--- On any checkbox click callback(self, index)
-- @tfield DruidEvent on_checkbox_click @{DruidEvent}
--- Array of checkbox components
-- @tfield table checkboxes @{Checkbox}
---
local Event = require("druid.event")
local component = require("druid.component")
local CheckboxGroup = component.create("checkbox_group")
--- Component init function
-- @tparam CheckboxGroup self @{CheckboxGroup}
-- @tparam node[] nodes Array of gui node
-- @tparam function callback Checkbox callback
-- @tparam[opt=node] node[] click_nodes Array of trigger nodes, by default equals to nodes
function CheckboxGroup.init(self, nodes, callback, click_nodes)
self.druid = self:get_druid()
self.checkboxes = {}
self.on_checkbox_click = Event(callback)
for i = 1, #nodes do
local click_node = click_nodes and click_nodes[i] or nil
local checkbox = self.druid:new_checkbox(nodes[i], function()
self.on_checkbox_click:trigger(self:get_context(), i)
end, click_node)
table.insert(self.checkboxes, checkbox)
end
end
--- Set checkbox group state
-- @tparam CheckboxGroup self @{CheckboxGroup}
-- @tparam bool[] indexes Array of checkbox state
-- @tparam boolean is_instant If instant state change
function CheckboxGroup.set_state(self, indexes, is_instant)
for i = 1, #indexes do
if self.checkboxes[i] then
self.checkboxes[i]:set_state(indexes[i], true, is_instant)
end
end
end
--- Return checkbox group state
-- @tparam CheckboxGroup self @{CheckboxGroup}
-- @treturn bool[] Array if checkboxes state
function CheckboxGroup.get_state(self)
local result = {}
for i = 1, #self.checkboxes do
table.insert(result, self.checkboxes[i]:get_state())
end
return result
end
return CheckboxGroup

View File

@@ -2,6 +2,8 @@
--- Component to manage data for huge dataset in scroll.
-- It requires Druid Scroll and Druid Grid (Static or Dynamic) components
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_data_list" target="_blank"><b>Example Link</b></a>
-- @module DataList
-- @within BaseComponent
-- @alias druid.data_list
@@ -11,20 +13,26 @@
-- @tfield Scroll scroll @{Scroll}
--- The Druid Grid component
-- @tfield StaticGrid|DynamicGrid grid @{StaticGrid}, @{DynamicGrid}
--- The current visual top data index
-- @tfield number top_index
--- The current visual last data index
-- @tfield number last_index
-- @tfield StaticGrid grid @{StaticGrid}, @{DynamicGrid}
--- The current progress of scroll posititon
-- @tfield number scroll_progress
--- The current top index of visual elements
-- @tfield number top_index
--- The current last index of visual elements
-- @tfield number last_index
--- Event triggered when scroll progress is changed; event(self, progress_value)
-- @tfield DruidEvent on_scroll_progress_change @{DruidEvent}
---On DataList visual element created Event callback(self, index, node, instance)
-- @tfield DruidEvent on_element_add @{DruidEvent}
---On DataList visual element created Event callback(self, index)
-- @tfield DruidEvent on_element_remove @{DruidEvent}
---
local const = require("druid.const")
@@ -35,19 +43,17 @@ local Event = require("druid.event")
local DataList = component.create("data_list")
--- Data list constructor
--- The @{DataList} constructor
-- @tparam DataList self @{DataList}
-- @tparam Scroll scroll The @{Scroll} instance for Data List component
-- @tparam StaticGrid|DynamicGrid grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component
-- @tparam StaticGrid grid The @{StaticGrid} or @{DynamicGrid} instance for Data List component
-- @tparam function create_function The create function callback(self, data, index, data_list). Function should return (node, [component])
function DataList.init(self, scroll, grid, create_function)
self.druid = self:get_druid()
self.scroll = scroll
self.grid = grid
if self.grid.style then
self.grid.style.IS_DYNAMIC_NODE_POSES = false
end
self.scroll:bind_grid(grid)
-- Current visual elements indexes
self.top_index = 1
@@ -55,24 +61,34 @@ function DataList.init(self, scroll, grid, create_function)
self.scroll_progress = 0
self._create_function = create_function
self._is_use_cache = false
self._cache = {}
self._data = {}
self._data_first_index = false
self._data_last_index = false
self._data_length = 0
self._data_visual = {}
self.scroll.on_scroll:subscribe(self._check_elements, self)
self.scroll.on_scroll:subscribe(self._refresh, self)
self.on_scroll_progress_change = Event()
self:set_data()
self.on_element_add = Event()
self.on_element_remove = Event()
end
--- Druid System on_remove function
-- @tparam DataList self @{DataList}
function DataList.on_remove(self)
self.scroll.on_scroll:unsubscribe(self._check_elements, self)
self:clear()
self.scroll.on_scroll:unsubscribe(self._refresh, self)
end
--- Set refresh function for DataList component
-- @tparam DataList self @{DataList}
-- @tparam boolean is_use_cache Use cache version of DataList. Requires make setup of components in on_element_add callback and clean in on_element_remove
-- @treturn druid.data_list Current DataList instance
function DataList.set_use_cache(self, is_use_cache)
self._is_use_cache = is_use_cache
return self
end
@@ -82,65 +98,52 @@ end
-- @treturn druid.data_list Current DataList instance
function DataList.set_data(self, data)
self._data = data or {}
self:_update_data_info()
self:_refresh()
return self
end
--- Return current data from DataList component
-- @tparam DataList self @{DataList}
-- @treturn table The current data array
function DataList.get_data(self)
return self._data
end
--- Add element to DataList. Currenly untested
-- @tparam DataList self @{DataList}
-- @tparam table data
-- @tparam number index
-- @tparam number shift_policy The constant from const.SHIFT.*
-- @local
-- @tparam number|nil index
-- @tparam number|nil shift_policy The constant from const.SHIFT.*
function DataList.add(self, data, index, shift_policy)
index = index or self._data_last_index + 1
index = index or #self._data + 1
shift_policy = shift_policy or const.SHIFT.RIGHT
if self._data[index] then
if shift_policy == const.SHIFT.RIGHT then
for i = self._data_last_index, index, -1 do
self._data[i + 1] = self._data[i]
end
end
if shift_policy == const.SHIFT.LEFT then
for i = self._data_first_index, index do
self._data[i - 1] = self._data[i]
end
end
end
self._data[index] = data
self:_update_data_info()
self:_check_elements()
self:log_message("Add element", { index = index })
helper.insert_with_shift(self._data, data, index, shift_policy)
self:_refresh()
end
--- Remove element from DataList. Currenly untested
-- @tparam DataList self @{DataList}
-- @tparam number index
-- @tparam number shift_policy The constant from const.SHIFT.*
-- @local
-- @tparam number|nil index
-- @tparam number|nil shift_policy The constant from const.SHIFT.*
function DataList.remove(self, index, shift_policy)
table.remove(self._data, index)
helper.remove_with_shift(self._data, index, shift_policy)
self:_refresh()
self:log_message("Remove element", { index = index })
end
--- Remove element from DataList by data value. Currenly untested
-- @tparam DataList self @{DataList}
-- @tparam tabe data
-- @tparam number shift_policy The constant from const.SHIFT.*
-- @local
-- @tparam table data
-- @tparam number|nil shift_policy The constant from const.SHIFT.*
function DataList.remove_by_data(self, data, shift_policy)
local index = helper.contains(self._data, data)
if index then
table.remove(self._data, index)
helper.remove_with_shift(self._data, index, shift_policy)
self:_refresh()
end
end
@@ -154,27 +157,6 @@ function DataList.clear(self)
end
--- Return first index from data. It not always equals to 1
-- @tparam DataList self @{DataList}
function DataList.get_first_index(self)
return self._data_first_index
end
--- Return last index from data
-- @tparam DataList self @{DataList}
function DataList.get_last_index(self)
return self._data_last_index
end
--- Return amount of data
-- @tparam DataList self @{DataList}
function DataList.get_length(self)
return self._data_length
end
--- Return index for data value
-- @tparam DataList self @{DataList}
-- @tparam table data
@@ -189,21 +171,44 @@ function DataList.get_index(self, data)
end
--- Return all currenly created nodes in DataList
-- @tparam DataList self @{DataList}
-- @treturn node[] List of created nodes
function DataList.get_created_nodes(self)
local nodes = {}
for index, data in pairs(self._data_visual) do
nodes[index] = data.node
end
return nodes
end
--- Return all currenly created components in DataList
-- @tparam DataList self @{DataList}
-- @treturn druid.base_component[] List of created nodes
function DataList.get_created_components(self)
local components = {}
for index, data in pairs(self._data_visual) do
components[index] = data.component
end
return components
end
--- Instant scroll to element with passed index
-- @tparam DataList self @{DataList}
-- @tparam number index
function DataList.scroll_to_index(self, index)
local target = helper.clamp(index, self:get_first_index(), self:get_last_index())
self.top_index = target
self:_refresh()
if self._data_visual[target] then
self.scroll:scroll_to(gui.get_position(self._data_visual[target].node), true)
end
local pos = self.grid:get_pos(index)
self.scroll:scroll_to(pos)
end
--- Add element at passed index
--- Add element at passed index using cache or create new
-- @tparam DataList self @{DataList}
-- @tparam number index
-- @local
@@ -212,138 +217,98 @@ function DataList._add_at(self, index)
self:_remove_at(index)
end
local node, instance = self._create_function(self:get_context(), self._data[index], index, self)
self.grid:add(node, index, const.SHIFT.NO_SHIFT)
self._data_visual[index] = {
node = node,
component = instance
}
local data = self._data[index]
local node, instance
self:log_message("Add element at", { index = index })
-- Use cache if available and is_use_cache is set
if #self._cache > 0 and self._is_use_cache then
local cached = table.remove(self._cache)
node = cached.node
instance = cached.component
gui.set_enabled(node, true)
else
-- Create a new element if no cache or refresh function is not set
node, instance = self._create_function(self:get_context(), data, index, self)
end
self._data_visual[index] = {
data = data,
node = node,
component = instance,
}
self.grid:add(node, index, const.SHIFT.NO_SHIFT)
self.on_element_add:trigger(self:get_context(), index, node, instance, data)
end
--- Remove element from passed index
--- Remove element from passed index and add it to cache if applicable
-- @tparam DataList self @{DataList}
-- @tparam number index
-- @local
function DataList._remove_at(self, index)
self.grid:remove(index, const.SHIFT.NO_SHIFT)
local node = self._data_visual[index].node
gui.delete_node(node)
local visual_data = self._data_visual[index]
local node = visual_data.node
local instance = visual_data.component
local data = visual_data.data
if self._data_visual[index].component then
self.druid:remove(self._data_visual[index].component)
self.on_element_remove:trigger(self:get_context(), index, node, instance, data)
if self._is_use_cache then
-- Disable the node and add it to the cache instead of deleting it
gui.set_enabled(node, false)
table.insert(self._cache, visual_data) -- Cache the removed element
else
-- If no refresh function, delete the node and component as usual
gui.delete_node(node)
if instance then
instance._meta.druid:remove(instance)
end
end
self._data_visual[index] = nil
self:log_message("Remove element at", { index = index })
self._data_visual[index] = nil
end
--- Fully refresh all DataList elements
--- Refresh all elements in DataList
-- @tparam DataList self @{DataList}
-- @local
function DataList._refresh(self)
for index, _ in pairs(self._data_visual) do
self:_remove_at(index)
end
self:_check_elements()
end
self.scroll:set_size(self.grid:get_size_for(#self._data))
local start_pos = -self.scroll.position --[[@as vector3]]
local start_index = self.grid:get_index(start_pos)
start_index = math.max(1, start_index)
--- Check elements which should be created
-- @tparam DataList self @{DataList}
-- @local
function DataList._check_elements(self)
local pivot = helper.get_pivot_offset(gui.get_pivot(self.scroll.view_node))
local offset_x = self.scroll.view_size.x * (0.5 - pivot.x)
local offset_y = self.scroll.view_size.y * (0.5 + pivot.y)
local end_pos = vmath.vector3(start_pos.x + offset_x, start_pos.y - offset_y, 0)
local end_index = self.grid:get_index(end_pos)
end_index = math.min(#self._data, end_index)
self.top_index = start_index
self.last_index = end_index
-- Clear from non range elements
for index, data in pairs(self._data_visual) do
if self.scroll:is_node_in_view(data.node) then
self.top_index = index
self.last_index = index
if index < start_index or index > end_index then
self:_remove_at(index)
elseif self._data[index] ~= data.data then
-- TODO We want to find currently created data instances and move them to new positions
-- Now it will re-create them
self:_remove_at(index)
end
end
self:_check_elements_from(self.top_index, -1)
self:_check_elements_from(self.top_index + 1, 1)
for index, data in pairs(self._data_visual) do
self.top_index = math.min(self.top_index or index, index)
self.last_index = math.max(self.last_index or index, index)
end
-- Progress report
local middle_index = (self.last_index + self.top_index) / 2
local progress = (middle_index - self._data_first_index) / (self._data_last_index - self._data_first_index)
progress = helper.clamp(progress, 0, 1)
if self.last_index == self:get_last_index() then
progress = 1
end
if self.top_index == self:get_first_index() then
progress = 0
end
self:log_message("Check elements", { top_index = self.top_index, last_index = self.last_index, progress = progress })
if self.scroll_progress ~= progress then
self.scroll_progress = progress
self.on_scroll_progress_change:trigger(self:get_context(), progress)
end
end
--- Check elements which should be created.
-- Start from index with step until element is outside of scroll view
-- @tparam DataList self @{DataList}
-- @tparam number index
-- @tparam number step
-- @local
function DataList._check_elements_from(self, index, step)
local is_outside = false
while not is_outside do
if not self._data[index] then
break
end
if not self._data_visual[index] then
-- Add new elements
for index = start_index, end_index do
if not self._data_visual[index] and self._data[index] then
self:_add_at(index)
end
if not self.scroll:is_node_in_view(self._data_visual[index].node) then
is_outside = true
-- remove nexts:
-- We add one more element, which is not in view to
-- check what it's always outside to stop spawning
local remove_index = index + step
while self._data_visual[remove_index] do
self:_remove_at(remove_index)
remove_index = remove_index + step
end
end
index = index + step
end
end
--- Update actual data params
-- @tparam DataList self @{DataList}
-- @local
function DataList._update_data_info(self)
self._data_first_index = false
self._data_last_index = false
self._data_length = 0
for index, data in pairs(self._data) do
self._data_first_index = math.min(self._data_first_index or index, index)
self._data_last_index = math.max(self._data_last_index or index, index)
self._data_length = self._data_length + 1
end
if self._data_length == 0 then
self._data_first_index = 1
self._data_last_index = 1
end
end

View File

@@ -1,6 +1,8 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle placing components in row
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_grid" target="_blank"><b>Example Link</b></a>
-- @module DynamicGrid
-- @within BaseComponent
-- @alias druid.dynamic_grid
@@ -63,7 +65,7 @@ local AVAILABLE_PIVOTS = {
}
--- Component init function
--- The @{DynamicGrid} constructor
-- @tparam DynamicGrid self @{DynamicGrid}
-- @tparam node parent The gui node parent, where items will be placed
function DynamicGrid.init(self, parent)
@@ -98,8 +100,8 @@ end
-- @tparam DynamicGrid self @{DynamicGrid}
-- @tparam number index The grid element index
-- @tparam node node The node to be placed
-- @tparam[opt] number origin_index Index of nearby node
-- @treturn vector3 Node position
-- @tparam number|nil origin_index Index of nearby node
-- @treturn vector3 node position
function DynamicGrid.get_pos(self, index, node, origin_index)
local origin_node = self.nodes[origin_index]
@@ -118,7 +120,7 @@ function DynamicGrid.get_pos(self, index, node, origin_index)
assert(not self.first_index, "Dynamic Grid can't have gaps between nodes. Error on grid:add")
-- If not origin node, so it should be first element in the grid
local size = self:_get_node_size(node)
local size = helper.get_scaled_size(node)
local pivot = const.PIVOTS[gui.get_pivot(node)]
return vmath.vector3(
size.x * pivot.x - size.x * self.pivot.x,
@@ -138,9 +140,9 @@ end
--- Add new node to the grid
-- @tparam DynamicGrid self @{DynamicGrid}
-- @tparam node node Gui node
-- @tparam[opt] number index The node position. By default add as last node
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
-- @tparam[opt=false] boolean is_instant If true, update node positions instantly
-- @tparam number|nil index The node position. By default add as last node
-- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT
-- @tparam boolean|nil is_instant If true, update node positions instantly
function DynamicGrid.add(self, node, index, shift_policy, is_instant)
shift_policy = shift_policy or const.SHIFT.RIGHT
local delta = shift_policy -- -1 or 1 or 0
@@ -181,8 +183,8 @@ end
--- Remove the item from the grid. Note that gui node will be not deleted
-- @tparam DynamicGrid self @{DynamicGrid}
-- @tparam number index The grid node index to remove
-- @tparam[opt=SHIFT.RIGHT] number shift_policy How shift nodes, if required. See const.SHIFT
-- @tparam[opt=false] boolean is_instant If true, update node positions instantly
-- @tparam number|nil shift_policy How shift nodes, if required. Default: const.SHIFT.RIGHT
-- @tparam boolean|nil is_instant If true, update node positions instantly
-- @treturn node The deleted gui node from grid
function DynamicGrid.remove(self, index, shift_policy, is_instant)
shift_policy = shift_policy or const.SHIFT.RIGHT
@@ -272,7 +274,7 @@ end
function DynamicGrid.get_all_pos(self)
local result = {}
for i, node in pairs(self.nodes) do
table.insert(result, gui.get_position(node))
table.insert(result, gui.get_position(node.node))
end
return result
@@ -308,7 +310,7 @@ function DynamicGrid._add_node(self, node, index, origin_index)
self.nodes[index] = {
node = node,
pos = self:get_pos(index, node, origin_index),
size = self:_get_node_size(node),
size = helper.get_scaled_size(node),
pivot = const.PIVOTS[gui.get_pivot(node)]
}
@@ -320,7 +322,7 @@ end
--- Update grid inner state
-- @tparam DynamicGrid self @{DynamicGrid}
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @local
function DynamicGrid._update(self, is_instant)
self:_update_indexes()
@@ -376,7 +378,7 @@ end
--- Update grid nodes position
-- @tparam DynamicGrid self @{DynamicGrid}
-- @tparam bool is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @tparam boolean|nil is_instant If true, node position update instantly, otherwise with set_position_function callback
-- @local
function DynamicGrid._update_pos(self, is_instant)
for index, node in pairs(self.nodes) do
@@ -394,7 +396,7 @@ end
function DynamicGrid._get_next_node_pos(self, origin_node_index, new_node, place_side)
local node = self.nodes[origin_node_index]
local new_node_size = self:_get_node_size(new_node)
local new_node_size = helper.get_scaled_size(new_node)
local new_pivot = const.PIVOTS[gui.get_pivot(new_node)]
local dist_x = (node.size.x/2 + new_node_size.x/2) * place_side.x
@@ -410,11 +412,6 @@ function DynamicGrid._get_next_node_pos(self, origin_node_index, new_node, place
end
function DynamicGrid._get_node_size(self, node)
return vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
end
--- Return side vector to correct node shifting
function DynamicGrid._get_side_vector(self, side, is_forward)
if side == const.SIDE.X then

180
druid/extended/hotkey.lua Normal file
View File

@@ -0,0 +1,180 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Druid hotkey component
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_hotkey" target="_blank"><b>Example Link</b></a>
-- @module Hotkey
-- @within BaseComponent
-- @alias druid.hotkey
--- On hotkey released callback(self, argument)
-- @tfield DruidEvent on_hotkey_pressed @{DruidEvent}
--- On hotkey released callback(self, argument)
-- @tfield DruidEvent on_hotkey_released @{DruidEvent}
--- Visual node
-- @tfield node node
--- Button trigger node
-- @tfield node|nil click_node
--- Button component from click_node
-- @tfield Button button @{Button}
---
local helper = require("druid.helper")
local component = require("druid.component")
local Event = require("druid.event")
local Hotkey = component.create("hotkey")
--- The @{Hotkey} constructor
-- @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 any|nil 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.on_hotkey_pressed = Event()
self.on_hotkey_released = Event(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 any|nil callback_argument The argument to pass into the callback function
-- @treturn Hotkey Current instance
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_focus_gained(self)
for k, v in pairs(self._modificators) do
self._modificators[k] = false
end
end
function Hotkey.on_input(self, action_id, action)
if not action_id or #self._hotkeys == 0 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
self.on_hotkey_pressed:trigger(self:get_context(), hotkey.callback_argument)
end
if not action.pressed and self._is_process_repeated and action.repeated and is_modificator_ok and hotkey.is_processing then
self.on_hotkey_released:trigger(self:get_context(), hotkey.callback_argument)
return true
end
if action.released and is_modificator_ok and hotkey.is_processing then
hotkey.is_processing = false
self.on_hotkey_released:trigger(self:get_context(), hotkey.callback_argument)
return true
end
end
end
return false
end
--- If true, the callback will be triggered on action.repeated
-- @tparam Hotkey self @{Hotkey}
-- @tparam bool is_enabled_repeated The flag value
-- @treturn Hotkey
function Hotkey.set_repeat(self, is_enabled_repeated)
self._is_process_repeated = is_enabled_repeated
return self
end
return Hotkey

View File

@@ -2,15 +2,17 @@
--- Druid input text component.
-- Carry on user text input
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_input" target="_blank"><b>Example Link</b></a>
-- @author Part of code from Britzl gooey input component
-- @module Input
-- @within BaseComponent
-- @alias druid.input
--- On input field select callback(self, button_node)
--- On input field select callback(self, input_instance)
-- @tfield DruidEvent on_input_select @{DruidEvent}
--- On input field unselect callback(self, input_text)
--- On input field unselect callback(self, input_text, input_instance)
-- @tfield DruidEvent on_input_unselect @{DruidEvent}
--- On input field text change callback(self, input_text)
@@ -22,26 +24,56 @@
--- On input field text change to max length string callback(self, input_text)
-- @tfield DruidEvent on_input_full @{DruidEvent}
--- On trying user input with not allowed character callback(self, params, button_instance)
--- On trying user input with not allowed character callback(self, params, input_text)
-- @tfield DruidEvent on_input_wrong @{DruidEvent}
--- On cursor position change callback(self, cursor_index, start_index, end_index)
-- @tfield DruidEvent on_select_cursor_change @{DruidEvent}
--- The cursor index. The index of letter cursor after. Leftmost cursor - 0
-- @tfield number cursor_index
--- The selection start index. The index of letter cursor after. Leftmost selection - 0
-- @tfield number start_index
--- Theselection end index. The index of letter cursor before. Rightmost selection - #text
-- @tfield number end_index
--- Text component
-- @tfield Text text @{Text}
--- Current input value
-- @tfield string value
--- Previous input value
-- @tfield string previous_value
--- Current input value with marked text
-- @tfield string current_value
--- Marked text for input field. Info: https://defold.com/manuals/input-key-and-text/#marked-text
-- @tfield string marked_value
--- Text width
-- @tfield number text_width
--- Marked text width
-- @tfield number marked_text_width
--- Button component
-- @tfield Button button @{Button}
--- Is current input selected now
-- @tfield bool is_selected
-- @tfield boolean is_selected
--- Is current input is empty now
-- @tfield bool is_empty
-- @tfield boolean is_empty
--- Max length for input text
-- @tfield[opt] number max_length
-- @tfield number|nil max_length
--- Pattern matching for user input
-- @tfield[opt] string allowerd_characters
-- @tfield string|nil allowerd_characters
--- Gui keyboard type for input field
-- @tfield number keyboard_type
@@ -50,11 +82,21 @@
local Event = require("druid.event")
local const = require("druid.const")
local helper = require("druid.helper")
local component = require("druid.component")
local utf8 = require("druid.system.utf8")
local utf8_lua = require("druid.system.utf8")
local utf8 = utf8 or utf8_lua
local Input = component.create("input")
Input.ALLOWED_ACTIONS = {
[const.ACTION_TOUCH] = true,
[const.ACTION_TEXT] = true,
[const.ACTION_MARKED_TEXT] = true,
[const.ACTION_BACKSPACE] = true,
[const.ACTION_ENTER] = true,
[const.ACTION_ESC] = true,
}
--- Mask text by replacing every character with a mask character
-- @tparam string text
@@ -84,13 +126,12 @@ end
-- You can override this component styles params in druid styles table
-- or create your own style
-- @table style
-- @tfield[opt=false] bool IS_LONGTAP_ERASE Is long tap will erase current input data
-- @tfield[opt=*] string MASK_DEFAULT_CHAR Default character mask for password input
-- @tfield[opt=false] bool IS_UNSELECT_ON_RESELECT If true, call unselect on select selected input
-- @tfield boolean IS_LONGTAP_ERASE Is long tap will erase current input data. Default: false
-- @tfield string MASK_DEFAULT_CHAR Default character mask for password input. Default: *]
-- @tfield boolean IS_UNSELECT_ON_RESELECT If true, call unselect on select selected input. Default: false
-- @tfield function on_select (self, button_node) Callback on input field selecting
-- @tfield function on_unselect (self, button_node) Callback on input field unselecting
-- @tfield function on_input_wrong (self, button_node) Callback on wrong user input
-- @tfield table button_style Custom button style for input node
function Input.on_style_change(self, style)
self.style = {}
@@ -101,24 +142,18 @@ function Input.on_style_change(self, style)
self.style.on_select = style.on_select or function(_, button_node) end
self.style.on_unselect = style.on_unselect or function(_, button_node) end
self.style.on_input_wrong = style.on_input_wrong or function(_, button_node) end
self.style.button_style = style.button_style or {
LONGTAP_TIME = 0.4,
AUTOHOLD_TRIGGER = 0.8,
DOUBLETAP_TIME = 0.4
}
end
--- Component init function
--- The @{Input} constructor
-- @tparam Input self @{Input}
-- @tparam node click_node Button node to enabled input component
-- @tparam node click_node Node to enabled input component
-- @tparam node|Text text_node Text node what will be changed on user input. You can pass text component instead of text node name @{Text}
-- @tparam[opt] number keyboard_type Gui keyboard type for input field
-- @tparam number|nil keyboard_type Gui keyboard type for input field
function Input.init(self, click_node, text_node, keyboard_type)
self.druid = self:get_druid(self)
self.druid = self:get_druid()
if type(text_node) == const.TABLE then
if type(text_node) == "table" then
self.text = text_node
else
self.text = self.druid:new_text(text_node)
@@ -134,6 +169,9 @@ function Input.init(self, click_node, text_node, keyboard_type)
self.text_width = 0
self.market_text_width = 0
self.total_width = 0
self.cursor_index = utf8.len(self.value)
self.start_index = self.cursor_index
self.end_index = self.cursor_index
self.max_length = nil
self.allowed_characters = nil
@@ -141,39 +179,54 @@ function Input.init(self, click_node, text_node, keyboard_type)
self.keyboard_type = keyboard_type or gui.KEYBOARD_TYPE_DEFAULT
self.button = self.druid:new_button(click_node, self.select)
self.button:set_style(self.button_style)
self.button.on_click_outside:subscribe(self.unselect)
self.button.on_long_click:subscribe(clear_and_select)
if defos then
self.button.hover.style.ON_HOVER_CURSOR = defos.CURSOR_IBEAM
self.button.hover.style.ON_MOUSE_HOVER_CURSOR = defos.CURSOR_IBEAM
end
if html5 then
self.button:set_web_user_interaction(true)
end
self.on_input_select = Event()
self.on_input_unselect = Event()
self.on_input_text = Event()
self.on_input_empty = Event()
self.on_input_full = Event()
self.on_input_wrong = Event()
self.on_select_cursor_change = Event()
end
function Input.on_input(self, action_id, action)
if not (action_id == nil or Input.ALLOWED_ACTIONS[action_id]) then
return false
end
if self.is_selected then
local input_text = nil
local is_marked_text_changed = false
local cursor_shift_indexes = nil
if action_id == const.ACTION_TEXT then
-- ignore return key
if action.text == "\n" or action.text == "\r" then
return true
end
local hex = string.gsub(action.text,"(.)", function (c)
local hex = string.gsub(action.text, "(.)", function(c)
return string.format("%02X%s",string.byte(c), "")
end)
-- ignore arrow keys
if not utf8.match(hex, "EF9C8[0-3]") then
if not self.allowed_characters or utf8.match(action.text, self.allowed_characters) then
input_text = self.value .. action.text
if self.max_length then
input_text = utf8.sub(input_text, 1, self.max_length)
end
local shift_offset = self.cursor_index - self.start_index
input_text = self:get_text_selected_replaced(action.text)
cursor_shift_indexes = utf8.len(action.text) - shift_offset
else
self.on_input_wrong:trigger(self:get_context(), action.text)
self.style.on_input_wrong(self, self.button.node)
@@ -187,10 +240,28 @@ function Input.on_input(self, action_id, action)
if self.max_length then
self.marked_value = utf8.sub(self.marked_value, 1, self.max_length)
end
is_marked_text_changed = true
end
if action_id == const.ACTION_BACKSPACE and (action.pressed or action.repeated) then
input_text = utf8.sub(self.value, 1, -2)
local start_index = self.start_index or utf8.len(self.value)
local end_index = self.end_index or utf8.len(self.value)
-- If start == end index, remove left of this selection letter, else delete all selection
if start_index == end_index then
local left_part = utf8.sub(self.value, 1, math.max(0, start_index - 1))
local right_part = utf8.sub(self.value, end_index + 1, utf8.len(self.value))
input_text = left_part .. right_part
cursor_shift_indexes = -1
else
local left_part = utf8.sub(self.value, 1, start_index)
local right_part = utf8.sub(self.value, end_index + 1, utf8.len(self.value))
input_text = left_part .. right_part
-- Calculate offsets from cursor pos to start index
cursor_shift_indexes = start_index - self.cursor_index
end
end
if action_id == const.ACTION_ENTER and action.released then
@@ -208,12 +279,22 @@ function Input.on_input(self, action_id, action)
return true
end
if input_text or #self.marked_value > 0 then
if input_text or is_marked_text_changed then
self:set_text(input_text)
if cursor_shift_indexes then
self:select_cursor(self.cursor_index + cursor_shift_indexes)
end
return true
end
end
local is_mouse_action = action_id == const.ACTION_TOUCH or not action_id
if is_mouse_action then
return false
end
return self.is_selected
end
@@ -224,7 +305,33 @@ end
function Input.on_input_interrupt(self)
-- self:unselect()
--self:unselect()
end
function Input.get_text_selected(self)
if self.start_index == self.end_index then
return self.value
end
return utf8.sub(self.value, self.start_index + 1, self.end_index)
end
--- Replace selected text with new text
-- @tparam Input self @{Input}
-- @tparam string text The text to replace selected text
-- @treturn string New input text
function Input.get_text_selected_replaced(self, text)
local left_part = utf8.sub(self.value, 1, self.start_index)
local right_part = utf8.sub(self.value, self.end_index + 1, utf8.len(self.value))
local result = left_part .. text .. right_part
if self.max_length then
result = utf8.sub(result, 1, self.max_length)
end
return result
end
@@ -232,6 +339,8 @@ end
-- @tparam Input self @{Input}
-- @tparam string input_text The string to apply for input field
function Input.set_text(self, input_text)
input_text = tostring(input_text or "")
-- Case when update with marked text
if input_text then
self.value = input_text
@@ -281,18 +390,20 @@ 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
gui.show_keyboard(self.keyboard_type, false)
self.on_input_select:trigger(self:get_context())
local len = utf8.len(self.value)
self:select_cursor(len, len, len)
self.on_input_select:trigger(self:get_context(), self)
self.style.on_select(self, self.button.node)
else
if self.style.IS_UNSELECT_ON_RESELECT then
self:unselect(self)
self:unselect()
end
end
end
@@ -303,13 +414,14 @@ end
function Input.unselect(self)
gui.reset_keyboard()
self.marked_value = ""
self.value = self.current_value
if self.is_selected then
self:reset_input_priority()
self.button:reset_input_priority()
self.is_selected = false
gui.hide_keyboard()
self.on_input_unselect:trigger(self:get_context(), self:get_text())
self.on_input_unselect:trigger(self:get_context(), self:get_text(), self)
self.style.on_unselect(self, self.button.node)
end
@@ -320,7 +432,11 @@ end
-- @tparam Input self @{Input}
-- @treturn string The current input field text
function Input.get_text(self)
return self.value .. self.marked_value
if self.marked_value ~= "" then
return self.value .. self.marked_value
end
return self.value
end
@@ -349,9 +465,97 @@ end
--- Reset current input selection and return previous value
-- @tparam Input self @{Input}
-- @treturn druid.input Current input instance
function Input.reset_changes(self)
self:set_text(self.previous_value)
self:unselect()
return self
end
--- Set cursor position in input field
-- @tparam Input self @{Input}
-- @tparam number|nil cursor_index Cursor index for cursor position, if nil - will be set to the end of the text
-- @tparam number|nil start_index Start index for cursor position, if nil - will be set to the end of the text
-- @tparam number|nil end_index End index for cursor position, if nil - will be set to the start_index
-- @treturn druid.input Current input instance
function Input.select_cursor(self, cursor_index, start_index, end_index)
local len = utf8.len(self.value)
self.cursor_index = cursor_index or len
self.start_index = start_index or self.cursor_index
self.end_index = end_index or self.start_index
self.cursor_index = helper.clamp(self.cursor_index, 0, len)
self.start_index = helper.clamp(self.start_index, 0, len)
self.end_index = helper.clamp(self.end_index, 0, len)
self.on_select_cursor_change:trigger(self:get_context(), self.cursor_index, self.start_index, self.end_index)
return self
end
--- Change cursor position by delta
-- @tparam Input self @{Input}
-- @tparam number delta side for cursor position, -1 for left, 1 for right
-- @tparam boolean is_add_to_selection (Shift key)
-- @tparam boolean is_move_to_end (Ctrl key)
function Input.move_selection(self, delta, is_add_to_selection, is_move_to_end)
local len = utf8.len(self.value)
local cursor_index = self.cursor_index
local start_index, end_index -- if nil, the selection will be 0 at cursor position
local is_right = delta > 0
local target_index = cursor_index + delta
if is_move_to_end then
target_index = is_right and len or 0
end
-- The Shift is not pressed
if not is_add_to_selection then
cursor_index = target_index
if self.start_index ~= self.end_index then
-- Reset selection without moving cursor
cursor_index = self.cursor_index
end
end
-- The Shift is pressed
if is_add_to_selection then
cursor_index = target_index
start_index = self.start_index
end_index = self.end_index
local is_cursor_extends_selection = (self.cursor_index == (is_right and end_index or start_index))
if is_cursor_extends_selection then
if is_right then
end_index = cursor_index
else
start_index = cursor_index
end
else
if is_right then
start_index = cursor_index
if is_move_to_end then
start_index = end_index
end_index = cursor_index
end
else
end_index = cursor_index
if is_move_to_end then
end_index = start_index
start_index = cursor_index
end
end
end
end
self:select_cursor(cursor_index, start_index, end_index)
end

View File

@@ -1,7 +1,18 @@
-- Copyright (c) 2021 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Component to handle all GUI texts
-- Good working with localization system
--- Component to wrap over GUI Text nodes with localization helpers
--
-- <b># Overview #</b>
--
-- • The initialization of druid.set_text_function is required to enable localization
-- using the localization ID.
--
-- • The LangText component supports up to 7 string format parameters.
-- This limitation exists due to certain issues with using ... arguments.
--
-- <b># Notes #</b>
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=texts_lang_text" target="_blank"><b>Example Link</b></a>
-- @module LangText
-- @within BaseComponent
-- @alias druid.lang_text
@@ -12,6 +23,9 @@
--- The text component
-- @tfield Text text @{Text}
--- Text node
-- @tfield node node
---
local Event = require("druid.event")
@@ -21,20 +35,21 @@ local component = require("druid.component")
local LangText = component.create("lang_text")
--- Component init function
--- The @{LangText} constructor
-- @tparam LangText self @{LangText}
-- @tparam node node The text node
-- @tparam string locale_id Default locale id or text from node as default
-- @tparam bool no_adjust If true, will not correct text size
function LangText.init(self, node, locale_id, no_adjust)
-- @tparam string|node node The node_id or gui.get_node(node_id)
-- @tparam string|nil locale_id Default locale id or text from node as default
-- @tparam string|nil adjust_type Adjust type for text. By default is DOWNSCALE. Look const.TEXT_ADJUST for reference
function LangText.init(self, node, locale_id, adjust_type)
self.druid = self:get_druid()
self.text = self.druid:new_text(node, locale_id, no_adjust)
self.text = self.druid:new_text(node, locale_id, adjust_type)
self.node = self.text.node
self.last_locale_args = {}
self.on_change = Event()
self:translate(locale_id or gui.get_text(self.node))
self.text.on_set_text:subscribe(self.on_change.trigger, self.on_change)
return self
end
@@ -63,13 +78,13 @@ end
--- Translate the text by locale_id
-- @tparam LangText self @{LangText}
-- @tparam string locale_id Locale id
-- @tparam[opt] string a Optional param to string.format
-- @tparam[opt] string b Optional param to string.format
-- @tparam[opt] string c Optional param to string.format
-- @tparam[opt] string d Optional param to string.format
-- @tparam[opt] string e Optional param to string.format
-- @tparam[opt] string f Optional param to string.format
-- @tparam[opt] string g Optional param to string.format
-- @tparam string|nil a Optional param to string.format
-- @tparam string|nil b Optional param to string.format
-- @tparam string|nil c Optional param to string.format
-- @tparam string|nil d Optional param to string.format
-- @tparam string|nil e Optional param to string.format
-- @tparam string|nil f Optional param to string.format
-- @tparam string|nil g Optional param to string.format
-- @treturn LangText Current instance
function LangText.translate(self, locale_id, a, b, c, d, e, f, g)
self.last_locale_args = { a, b, c, d, e, f, g }
@@ -82,13 +97,13 @@ end
--- Format string with new text params on localized text
-- @tparam LangText self @{LangText}
-- @tparam[opt] string a Optional param to string.format
-- @tparam[opt] string b Optional param to string.format
-- @tparam[opt] string c Optional param to string.format
-- @tparam[opt] string d Optional param to string.format
-- @tparam[opt] string e Optional param to string.format
-- @tparam[opt] string f Optional param to string.format
-- @tparam[opt] string g Optional param to string.format
-- @tparam string|nil a Optional param to string.format
-- @tparam string|nil b Optional param to string.format
-- @tparam string|nil c Optional param to string.format
-- @tparam string|nil d Optional param to string.format
-- @tparam string|nil e Optional param to string.format
-- @tparam string|nil f Optional param to string.format
-- @tparam string|nil g Optional param to string.format
-- @treturn LangText Current instance
function LangText.format(self, a, b, c, d, e, f, g)
self.last_locale_args = { a, b, c, d, e, f, g }

425
druid/extended/layout.lua Normal file
View File

@@ -0,0 +1,425 @@
-- Copyright (c) 2024 Maksim Tuprikov <insality@gmail.com>. This code is licensed under MIT license
--- Layout management on node
--
-- <a href="https://insality.github.io/druid/druid/index.html?example=general_layout" target="_blank"><b>Example Link</b></a>
-- @module Layout
-- @within BaseComponent
-- @alias druid.layout
--- Layout node
-- @tfield node node
--- Current layout mode
-- @tfield string mode
---
local helper = require("druid.helper")
local component = require("druid.component")
-- @class druid.layout.row_data
-- @tfield width number
-- @tfield height number
-- @tfield count number
-- @class druid.layout.rows_data
-- @tfield total_width number
-- @tfield total_height number
-- @tfield nodes_width table<node, number>
-- @tfield nodes_height table<node, number>
-- @tfield rows druid.layout.row_data[]>
-- @class druid.layout: druid.base_component
local M = component.create("layout")
-- The @{Layout} constructor
-- @tparam Layout self @{Layout}
-- @tparam node node Gui node
-- @tparam string layout_type The layout mode (from const.LAYOUT_MODE)
-- @tparam function|nil on_size_changed_callback The callback on window resize
function M.init(self, node, layout_type)
self.node = self:get_node(node)
self.is_dirty = true
self.entities = {}
self.margin = { x = 0, y = 0 }
self.padding = gui.get_slice9(self.node)
self.type = layout_type or "horizontal"
self.is_resize_width = false
self.is_resize_height = false
self.is_justify = false
end
function M:update()
if not self.is_dirty then
return
end
self:refresh_layout()
end
-- @tparam Layout self @{Layout}
-- @tparam number|nil margin_x
-- @tparam number|nil margin_y
-- @treturn druid.layout @{Layout}
function M.set_margin(self, margin_x, margin_y)
self.margin.x = margin_x or self.margin.x
self.margin.y = margin_y or self.margin.y
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @tparam vector4 padding The vector4 with padding values, where x - left, y - top, z - right, w - bottom
-- @treturn druid.layout @{Layout}
function M.set_padding(self, padding)
self.padding = padding
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @treturn druid.layout @{Layout}
function M.set_dirty(self)
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @tparam boolean is_justify
-- @treturn druid.layout @{Layout}
function M.set_justify(self, is_justify)
self.is_justify = is_justify
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @tparam string type The layout type: "horizontal", "vertical", "horizontal_wrap"
-- @treturn druid.layout @{Layout}
function M.set_type(self, type)
self.type = type
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @tparam boolean is_hug_width
-- @tparam boolean is_hug_height
-- @treturn druid.layout @{Layout}
function M.set_hug_content(self, is_hug_width, is_hug_height)
self.is_resize_width = is_hug_width or false
self.is_resize_height = is_hug_height or false
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @tparam string|node node_or_node_id
-- @treturn druid.layout @{Layout}
function M.add(self, node_or_node_id)
-- Acquire node from entity or by id
local node = node_or_node_id
if type(node_or_node_id) == "table" then
assert(node_or_node_id.node, "The entity should have a node")
node = node_or_node_id.node
else
-- @cast node_or_node_id string|node
node = self:get_node(node_or_node_id)
end
-- @cast node node
table.insert(self.entities, node)
gui.set_parent(node, self.node)
self.is_dirty = true
return self
end
-- @tparam Layout self @{Layout}
-- @treturn druid.layout @{Layout}
function M.refresh_layout(self)
local layout_node = self.node
local entities = self.entities
local type = self.type -- vertical, horizontal, horizontal_wrap
local margin = self.margin -- {x: horizontal, y: vertical} in pixels, between elements
local padding = self.padding -- {x: left, y: top, z: right, w: bottom} in pixels
local is_justify = self.is_justify
local size = gui.get_size(layout_node)
local max_width = size.x - padding.x - padding.z
local max_height = size.y - padding.y - padding.w
local layout_pivot_offset = helper.get_pivot_offset(gui.get_pivot(layout_node)) -- {x: -0.5, y: -0.5} - is left bot, {x: 0.5, y: 0.5} - is right top
local rows_data = self:calculate_rows_data()
local rows = rows_data.rows
local row_index = 1
local row = rows[row_index]
-- Current x and Current y is a top left corner of the node
local current_x = -row.width * (0.5 + layout_pivot_offset.x)
local current_y = rows_data.total_height * (0.5 - layout_pivot_offset.y)
if is_justify then
if (type == "horizontal" or type == "horizontal_wrap") and row.count > 1 then
current_x = -max_width * (0.5 + layout_pivot_offset.x)
end
if type == "vertical" then
current_y = max_height * (0.5 - layout_pivot_offset.y)
end
end
for index = 1, #entities do
local node = entities[index]
local node_width = rows_data.nodes_width[node]
local node_height = rows_data.nodes_height[node]
local pivot_offset = helper.get_pivot_offset(gui.get_pivot(node))
if node_width > 0 and node_height > 0 then
-- Calculate position for current node
local position_x, position_y
if type == "horizontal" then
position_x = current_x + node_width * (0.5 + pivot_offset.x)
position_y = current_y - row.height * (0.5 - pivot_offset.y)
local node_margin = margin.x
if is_justify and row.count > 1 then
node_margin = (max_width - row.width) / (row.count - 1) + margin.x
end
current_x = current_x + node_width + node_margin
end
if type == "vertical" then
local node_margin = margin.y
if is_justify then
node_margin = (max_height - rows_data.total_height) / (#rows - 1) + margin.y
end
current_x = -row.width * (0.5 + layout_pivot_offset.x)
position_x = current_x + row.width * (0.5 + pivot_offset.x)
position_y = current_y - node_height * (0.5 - pivot_offset.y)
current_y = current_y - node_height - node_margin
row_index = row_index + 1
row = rows[row_index]
end
if type == "horizontal_wrap" then
local width = row.width
if is_justify and row.count > 0 then
width = math.max(row.width, max_width)
end
local new_row_width = width * (0.5 - layout_pivot_offset.x)
-- Compare with eps due the float loss and element flickering
if current_x + node_width - new_row_width > 0.0001 then
if row_index < #rows then
row_index = row_index + 1
row = rows[row_index]
end
current_x = -row.width * (0.5 + layout_pivot_offset.x)
current_y = current_y - row.height - margin.y
if is_justify and row.count > 1 then
current_x = -max_width * (0.5 + layout_pivot_offset.x)
end
end
position_x = current_x + node_width * (0.5 + pivot_offset.x)
position_y = current_y - row.height * (0.5 - pivot_offset.y)
local node_margin = margin.x
if is_justify and row.count > 1 then
node_margin = (max_width - row.width) / (row.count - 1) + margin.x
end
current_x = current_x + node_width + node_margin
end
do -- Padding offset
if layout_pivot_offset.x == -0.5 then
position_x = position_x + padding.x
end
if layout_pivot_offset.y == 0.5 then
position_y = position_y - padding.y
end
if layout_pivot_offset.x == 0.5 then
position_x = position_x - padding.z
end
if layout_pivot_offset.y == -0.5 then
position_y = position_y + padding.w
end
end
self:set_node_position(node, position_x, position_y)
end
end
if self.is_resize_width or self.is_resize_height then
if self.is_resize_width then
size.x = rows_data.total_width + padding.x + padding.z
end
if self.is_resize_height then
size.y = rows_data.total_height + padding.y + padding.w
end
gui.set_size(layout_node, size)
end
self.is_dirty = false
return self
end
-- @tparam Layout self @{Layout}
-- @treturn druid.layout @{Layout}
function M.clear_layout(self)
for index = #self.entities, 1, -1 do
self.entities[index] = nil
end
self.is_dirty = true
return self
end
-- @tparam node node
-- @treturn number, number
-- @local
function M.get_node_size(node)
if not gui.is_enabled(node, false) then
return 0, 0
end
local scale = gui.get_scale(node)
-- If node has text - get text size instead of node size
if gui.get_text(node) then
local text_metrics = helper.get_text_metrics_from_node(node)
return text_metrics.width * scale.x, text_metrics.height * scale.y
end
local size = gui.get_size(node)
return size.x * scale.x, size.y * scale.y
end
-- @tparam Layout self @{Layout}
-- Calculate rows data for layout. Contains total width, height and rows info (width, height, count of elements in row)
-- @treturn druid.layout.rows_data
-- @local
function M.calculate_rows_data(self)
local entities = self.entities
local margin = self.margin
local type = self.type
local padding = self.padding
local size = gui.get_size(self.node)
local max_width = size.x - padding.x - padding.z
-- Collect rows info about width, height and count of elements in row
local current_row = { width = 0, height = 0, count = 0 }
local rows_data = {
total_width = 0,
total_height = 0,
nodes_width = {},
nodes_height = {},
rows = { current_row }
}
for index = 1, #entities do
local node = entities[index]
local node_width = rows_data.nodes_width[node]
local node_height = rows_data.nodes_height[node]
-- Get node size if it's not calculated yet
if not node_width or not node_height then
node_width, node_height = M.get_node_size(node)
rows_data.nodes_width[node] = node_width
rows_data.nodes_height[node] = node_height
end
if node_width > 0 and node_height > 0 then
if type == "horizontal" then
current_row.width = current_row.width + node_width + margin.x
current_row.height = math.max(current_row.height, node_height)
current_row.count = current_row.count + 1
end
if type == "vertical" then
if current_row.count > 0 then
current_row = { width = 0, height = 0, count = 0 }
table.insert(rows_data.rows, current_row)
end
current_row.width = math.max(current_row.width, node_width + margin.x)
current_row.height = node_height
current_row.count = current_row.count + 1
end
if type == "horizontal_wrap" then
if current_row.width + node_width > max_width and current_row.count > 0 then
current_row = { width = 0, height = 0, count = 0 }
table.insert(rows_data.rows, current_row)
end
current_row.width = current_row.width + node_width + margin.x
current_row.height = math.max(current_row.height, node_height)
current_row.count = current_row.count + 1
end
end
end
-- Remove last margin of each row
-- Calculate total width and height
local rows_count = #rows_data.rows
for index = 1, rows_count do
local row = rows_data.rows[index]
if row.width > 0 then
row.width = row.width - margin.x
end
rows_data.total_width = math.max(rows_data.total_width, row.width)
rows_data.total_height = rows_data.total_height + row.height
end
rows_data.total_height = rows_data.total_height + margin.y * (rows_count - 1)
return rows_data
end
-- @tparam node node
-- @tparam number x
-- @tparam number y
-- @treturn node
-- @local
function M:set_node_position(node, x, y)
local position = gui.get_position(node)
position.x = x
position.y = y
gui.set_position(node, position)
return node
end
return M

Some files were not shown because too many files have changed in this diff Show More